Merge branch 'master' of https://github.com/DFHack/dfhack
Conflicts: library/xml plugins/isoworld plugins/rendermax/CMakeLists.txt plugins/rendermax/renderer_light.cpp plugins/rendermax/renderer_light.hpp plugins/rendermax/renderer_opengl.hpp plugins/rendermax/rendermax.cpp plugins/rendermax/rendermax.luadevelop
@ -1,2 +1,4 @@
|
|||||||
VC2010
|
VC2010
|
||||||
DF_PATH.txt
|
DF_PATH.txt
|
||||||
|
_CPack_Packages
|
||||||
|
*.tar.*
|
||||||
|
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 10 KiB |
@ -1,773 +0,0 @@
|
|||||||
/*
|
|
||||||
https://github.com/peterix/dfhack
|
|
||||||
|
|
||||||
A thread-safe logging console with a line editor.
|
|
||||||
|
|
||||||
Based on linenoise:
|
|
||||||
linenoise -- guerrilla line editing library against the idea that a
|
|
||||||
line editing lib needs to be 20,000 lines of C code.
|
|
||||||
|
|
||||||
You can find the latest source code at:
|
|
||||||
|
|
||||||
http://github.com/antirez/linenoise
|
|
||||||
|
|
||||||
Does a number of crazy assumptions that happen to be true in 99.9999% of
|
|
||||||
the 2010 UNIX computers around.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
|
||||||
Copyright (c) 2011, Petr Mrázek <peterix@gmail.com>
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <deque>
|
|
||||||
|
|
||||||
// George Vulov for MacOSX
|
|
||||||
#ifndef __LINUX__
|
|
||||||
#define TEMP_FAILURE_RETRY(expr) \
|
|
||||||
({ long int _res; \
|
|
||||||
do _res = (long int) (expr); \
|
|
||||||
while (_res == -1L && errno == EINTR); \
|
|
||||||
_res; })
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Console.h"
|
|
||||||
#include "Hooks.h"
|
|
||||||
using namespace DFHack;
|
|
||||||
|
|
||||||
#include "tinythread.h"
|
|
||||||
using namespace tthread;
|
|
||||||
|
|
||||||
static int isUnsupportedTerm(void)
|
|
||||||
{
|
|
||||||
static const char *unsupported_term[] = {"dumb","cons25",NULL};
|
|
||||||
char *term = getenv("TERM");
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (term == NULL) return 0;
|
|
||||||
for (j = 0; unsupported_term[j]; j++)
|
|
||||||
if (!strcasecmp(term,unsupported_term[j])) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * ANSI_CLS = "\033[2J";
|
|
||||||
const char * ANSI_BLACK = "\033[22;30m";
|
|
||||||
const char * ANSI_RED = "\033[22;31m";
|
|
||||||
const char * ANSI_GREEN = "\033[22;32m";
|
|
||||||
const char * ANSI_BROWN = "\033[22;33m";
|
|
||||||
const char * ANSI_BLUE = "\033[22;34m";
|
|
||||||
const char * ANSI_MAGENTA = "\033[22;35m";
|
|
||||||
const char * ANSI_CYAN = "\033[22;36m";
|
|
||||||
const char * ANSI_GREY = "\033[22;37m";
|
|
||||||
const char * ANSI_DARKGREY = "\033[01;30m";
|
|
||||||
const char * ANSI_LIGHTRED = "\033[01;31m";
|
|
||||||
const char * ANSI_LIGHTGREEN = "\033[01;32m";
|
|
||||||
const char * ANSI_YELLOW = "\033[01;33m";
|
|
||||||
const char * ANSI_LIGHTBLUE = "\033[01;34m";
|
|
||||||
const char * ANSI_LIGHTMAGENTA = "\033[01;35m";
|
|
||||||
const char * ANSI_LIGHTCYAN = "\033[01;36m";
|
|
||||||
const char * ANSI_WHITE = "\033[01;37m";
|
|
||||||
const char * RESETCOLOR = "\033[0m";
|
|
||||||
|
|
||||||
const char * getANSIColor(const int c)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case -1: return RESETCOLOR; // HACK! :P
|
|
||||||
case 0 : return ANSI_BLACK;
|
|
||||||
case 1 : return ANSI_BLUE; // non-ANSI
|
|
||||||
case 2 : return ANSI_GREEN;
|
|
||||||
case 3 : return ANSI_CYAN; // non-ANSI
|
|
||||||
case 4 : return ANSI_RED; // non-ANSI
|
|
||||||
case 5 : return ANSI_MAGENTA;
|
|
||||||
case 6 : return ANSI_BROWN;
|
|
||||||
case 7 : return ANSI_GREY;
|
|
||||||
case 8 : return ANSI_DARKGREY;
|
|
||||||
case 9 : return ANSI_LIGHTBLUE; // non-ANSI
|
|
||||||
case 10: return ANSI_LIGHTGREEN;
|
|
||||||
case 11: return ANSI_LIGHTCYAN; // non-ANSI;
|
|
||||||
case 12: return ANSI_LIGHTRED; // non-ANSI;
|
|
||||||
case 13: return ANSI_LIGHTMAGENTA;
|
|
||||||
case 14: return ANSI_YELLOW; // non-ANSI
|
|
||||||
case 15: return ANSI_WHITE;
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace DFHack
|
|
||||||
{
|
|
||||||
class Private
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Private()
|
|
||||||
{
|
|
||||||
dfout_C = NULL;
|
|
||||||
rawmode = false;
|
|
||||||
in_batch = false;
|
|
||||||
supported_terminal = false;
|
|
||||||
state = con_unclaimed;
|
|
||||||
};
|
|
||||||
virtual ~Private()
|
|
||||||
{
|
|
||||||
//sync();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
bool read_char(unsigned char & out)
|
|
||||||
{
|
|
||||||
FD_ZERO(&descriptor_set);
|
|
||||||
FD_SET(STDIN_FILENO, &descriptor_set);
|
|
||||||
FD_SET(exit_pipe[0], &descriptor_set);
|
|
||||||
int ret = TEMP_FAILURE_RETRY(
|
|
||||||
select (FD_SETSIZE,&descriptor_set, NULL, NULL, NULL)
|
|
||||||
);
|
|
||||||
if(ret == -1)
|
|
||||||
return false;
|
|
||||||
if (FD_ISSET(exit_pipe[0], &descriptor_set))
|
|
||||||
return false;
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &descriptor_set))
|
|
||||||
{
|
|
||||||
// read byte from stdin
|
|
||||||
ret = TEMP_FAILURE_RETRY(
|
|
||||||
read(STDIN_FILENO, &out, 1)
|
|
||||||
);
|
|
||||||
if(ret == -1)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void print(const char *data)
|
|
||||||
{
|
|
||||||
fputs(data, dfout_C);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_text(color_ostream::color_value clr, const std::string &chunk)
|
|
||||||
{
|
|
||||||
if(!in_batch && state == con_lineedit)
|
|
||||||
{
|
|
||||||
disable_raw();
|
|
||||||
fprintf(dfout_C,"\x1b[1G");
|
|
||||||
fprintf(dfout_C,"\x1b[0K");
|
|
||||||
|
|
||||||
color(clr);
|
|
||||||
print(chunk.c_str());
|
|
||||||
|
|
||||||
reset_color();
|
|
||||||
enable_raw();
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
color(clr);
|
|
||||||
print(chunk.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void begin_batch()
|
|
||||||
{
|
|
||||||
assert(!in_batch);
|
|
||||||
|
|
||||||
in_batch = true;
|
|
||||||
|
|
||||||
if (state == con_lineedit)
|
|
||||||
{
|
|
||||||
disable_raw();
|
|
||||||
fprintf(dfout_C,"\x1b[1G");
|
|
||||||
fprintf(dfout_C,"\x1b[0K");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void end_batch()
|
|
||||||
{
|
|
||||||
assert(in_batch);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
|
|
||||||
in_batch = false;
|
|
||||||
|
|
||||||
if (state == con_lineedit)
|
|
||||||
{
|
|
||||||
reset_color();
|
|
||||||
enable_raw();
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush()
|
|
||||||
{
|
|
||||||
if (!rawmode)
|
|
||||||
fflush(dfout_C);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the console, along with its scrollback
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
if(rawmode)
|
|
||||||
{
|
|
||||||
const char * clr = "\033c\033[3J\033[H";
|
|
||||||
::write(STDIN_FILENO,clr,strlen(clr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
print("\033c\033[3J\033[H");
|
|
||||||
fflush(dfout_C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Position cursor at x,y. 1,1 = top left corner
|
|
||||||
void gotoxy(int x, int y)
|
|
||||||
{
|
|
||||||
char tmp[64];
|
|
||||||
sprintf(tmp,"\033[%d;%dH", y,x);
|
|
||||||
print(tmp);
|
|
||||||
}
|
|
||||||
/// Set color (ANSI color number)
|
|
||||||
void color(Console::color_value index)
|
|
||||||
{
|
|
||||||
if(!rawmode)
|
|
||||||
fprintf(dfout_C,getANSIColor(index));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const char * colstr = getANSIColor(index);
|
|
||||||
int lstr = strlen(colstr);
|
|
||||||
::write(STDIN_FILENO,colstr,lstr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Reset color to default
|
|
||||||
void reset_color(void)
|
|
||||||
{
|
|
||||||
color(COLOR_RESET);
|
|
||||||
if(!rawmode)
|
|
||||||
fflush(dfout_C);
|
|
||||||
}
|
|
||||||
/// Enable or disable the caret/cursor
|
|
||||||
void cursor(bool enable = true)
|
|
||||||
{
|
|
||||||
if(enable)
|
|
||||||
print("\033[?25h");
|
|
||||||
else
|
|
||||||
print("\033[?25l");
|
|
||||||
}
|
|
||||||
/// Waits given number of milliseconds before continuing.
|
|
||||||
void msleep(unsigned int msec);
|
|
||||||
/// get the current number of columns
|
|
||||||
int get_columns(void)
|
|
||||||
{
|
|
||||||
winsize ws;
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 80;
|
|
||||||
return ws.ws_col;
|
|
||||||
}
|
|
||||||
/// get the current number of rows
|
|
||||||
int get_rows(void)
|
|
||||||
{
|
|
||||||
winsize ws;
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 25;
|
|
||||||
return ws.ws_row;
|
|
||||||
}
|
|
||||||
/// beep. maybe?
|
|
||||||
//void beep (void);
|
|
||||||
/// A simple line edit (raw mode)
|
|
||||||
int lineedit(const std::string& prompt, std::string& output, recursive_mutex * lock, CommandHistory & ch)
|
|
||||||
{
|
|
||||||
output.clear();
|
|
||||||
reset_color();
|
|
||||||
this->prompt = prompt;
|
|
||||||
if (!supported_terminal)
|
|
||||||
{
|
|
||||||
print(prompt.c_str());
|
|
||||||
fflush(dfout_C);
|
|
||||||
// FIXME: what do we do here???
|
|
||||||
//SDL_recursive_mutexV(lock);
|
|
||||||
std::getline(std::cin, output);
|
|
||||||
//SDL_recursive_mutexP(lock);
|
|
||||||
return output.size();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
if (enable_raw() == -1) return 0;
|
|
||||||
if(state == con_lineedit)
|
|
||||||
return -1;
|
|
||||||
state = con_lineedit;
|
|
||||||
count = prompt_loop(lock,ch);
|
|
||||||
state = con_unclaimed;
|
|
||||||
disable_raw();
|
|
||||||
print("\n");
|
|
||||||
if(count != -1)
|
|
||||||
{
|
|
||||||
output = raw_buffer;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int enable_raw()
|
|
||||||
{
|
|
||||||
struct termios raw;
|
|
||||||
|
|
||||||
if (!supported_terminal)
|
|
||||||
return -1;
|
|
||||||
if (tcgetattr(STDIN_FILENO,&orig_termios) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
raw = orig_termios; //modify the original mode
|
|
||||||
// input modes: no break, no CR to NL, no parity check, no strip char,
|
|
||||||
// no start/stop output control.
|
|
||||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
|
||||||
// output modes - disable post processing
|
|
||||||
raw.c_oflag &= ~(OPOST);
|
|
||||||
// control modes - set 8 bit chars
|
|
||||||
raw.c_cflag |= (CS8);
|
|
||||||
// local modes - choing off, canonical off, no extended functions,
|
|
||||||
// no signal chars (^Z,^C)
|
|
||||||
#ifdef CONSOLE_NO_CATCH
|
|
||||||
raw.c_lflag &= ~( ECHO | ICANON | IEXTEN );
|
|
||||||
#else
|
|
||||||
raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
|
|
||||||
#endif
|
|
||||||
// control chars - set return condition: min number of bytes and timer.
|
|
||||||
// We want read to return every single byte, without timeout.
|
|
||||||
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;// 1 byte, no timer
|
|
||||||
// put terminal in raw mode after flushing
|
|
||||||
if (tcsetattr(STDIN_FILENO,TCSAFLUSH,&raw) < 0)
|
|
||||||
return -1;
|
|
||||||
rawmode = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_raw()
|
|
||||||
{
|
|
||||||
/* Don't even check the return value as it's too late. */
|
|
||||||
if (rawmode && tcsetattr(STDIN_FILENO,TCSAFLUSH,&orig_termios) != -1)
|
|
||||||
rawmode = 0;
|
|
||||||
}
|
|
||||||
void prompt_refresh()
|
|
||||||
{
|
|
||||||
char seq[64];
|
|
||||||
int cols = get_columns();
|
|
||||||
int plen = prompt.size();
|
|
||||||
const char * buf = raw_buffer.c_str();
|
|
||||||
int len = raw_buffer.size();
|
|
||||||
int cooked_cursor = raw_cursor;
|
|
||||||
// Use math! This is silly.
|
|
||||||
while((plen+cooked_cursor) >= cols)
|
|
||||||
{
|
|
||||||
buf++;
|
|
||||||
len--;
|
|
||||||
cooked_cursor--;
|
|
||||||
}
|
|
||||||
while (plen+len > cols)
|
|
||||||
{
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
/* Cursor to left edge */
|
|
||||||
snprintf(seq,64,"\x1b[1G");
|
|
||||||
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
|
|
||||||
/* Write the prompt and the current buffer content */
|
|
||||||
if (::write(STDIN_FILENO,prompt.c_str(),plen) == -1) return;
|
|
||||||
if (::write(STDIN_FILENO,buf,len) == -1) return;
|
|
||||||
/* Erase to right */
|
|
||||||
snprintf(seq,64,"\x1b[0K");
|
|
||||||
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
|
|
||||||
/* Move cursor to original position. */
|
|
||||||
snprintf(seq,64,"\x1b[1G\x1b[%dC", (int)(cooked_cursor+plen));
|
|
||||||
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int prompt_loop(recursive_mutex * lock, CommandHistory & history)
|
|
||||||
{
|
|
||||||
int fd = STDIN_FILENO;
|
|
||||||
size_t plen = prompt.size();
|
|
||||||
int history_index = 0;
|
|
||||||
raw_buffer.clear();
|
|
||||||
raw_cursor = 0;
|
|
||||||
/* The latest history entry is always our current buffer, that
|
|
||||||
* initially is just an empty string. */
|
|
||||||
const std::string empty;
|
|
||||||
history.add(empty);
|
|
||||||
if (::write(fd,prompt.c_str(),prompt.size()) == -1) return -1;
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
unsigned char c;
|
|
||||||
int isok;
|
|
||||||
unsigned char seq[2], seq2;
|
|
||||||
lock->unlock();
|
|
||||||
if(!read_char(c))
|
|
||||||
{
|
|
||||||
lock->lock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
lock->lock();
|
|
||||||
/* Only autocomplete when the callback is set. It returns < 0 when
|
|
||||||
* there was an error reading from fd. Otherwise it will return the
|
|
||||||
* character that should be handled next. */
|
|
||||||
if (c == 9)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if( completionCallback != NULL) {
|
|
||||||
c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
|
|
||||||
// Return on errors
|
|
||||||
if (c < 0) return len;
|
|
||||||
// Read next character when 0
|
|
||||||
if (c == 0) continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// ignore tab
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// just ignore tabs
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(c)
|
|
||||||
{
|
|
||||||
case 13: // enter
|
|
||||||
history.remove();
|
|
||||||
return raw_buffer.size();
|
|
||||||
case 3: // ctrl-c
|
|
||||||
errno = EAGAIN;
|
|
||||||
return -1;
|
|
||||||
case 127: // backspace
|
|
||||||
case 8: // ctrl-h
|
|
||||||
if (raw_cursor > 0 && raw_buffer.size() > 0)
|
|
||||||
{
|
|
||||||
raw_buffer.erase(raw_cursor-1,1);
|
|
||||||
raw_cursor--;
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 27: // escape sequence
|
|
||||||
lock->unlock();
|
|
||||||
if(!read_char(seq[0]) || !read_char(seq[1]))
|
|
||||||
{
|
|
||||||
lock->lock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
lock->lock();
|
|
||||||
if(seq[0] == '[')
|
|
||||||
{
|
|
||||||
if (seq[1] == 'D')
|
|
||||||
{
|
|
||||||
left_arrow:
|
|
||||||
if (raw_cursor > 0)
|
|
||||||
{
|
|
||||||
raw_cursor--;
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( seq[1] == 'C')
|
|
||||||
{
|
|
||||||
right_arrow:
|
|
||||||
/* right arrow */
|
|
||||||
if (size_t(raw_cursor) != raw_buffer.size())
|
|
||||||
{
|
|
||||||
raw_cursor++;
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (seq[1] == 'A' || seq[1] == 'B')
|
|
||||||
{
|
|
||||||
/* up and down arrow: history */
|
|
||||||
if (history.size() > 1)
|
|
||||||
{
|
|
||||||
/* Update the current history entry before to
|
|
||||||
* overwrite it with tne next one. */
|
|
||||||
history[history_index] = raw_buffer;
|
|
||||||
/* Show the new entry */
|
|
||||||
history_index += (seq[1] == 'A') ? 1 : -1;
|
|
||||||
if (history_index < 0)
|
|
||||||
{
|
|
||||||
history_index = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (size_t(history_index) >= history.size())
|
|
||||||
{
|
|
||||||
history_index = history.size()-1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
raw_buffer = history[history_index];
|
|
||||||
raw_cursor = raw_buffer.size();
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(seq[1] == 'H')
|
|
||||||
{
|
|
||||||
// home
|
|
||||||
raw_cursor = 0;
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
else if(seq[1] == 'F')
|
|
||||||
{
|
|
||||||
// end
|
|
||||||
raw_cursor = raw_buffer.size();
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
else if (seq[1] > '0' && seq[1] < '7')
|
|
||||||
{
|
|
||||||
// extended escape
|
|
||||||
lock->unlock();
|
|
||||||
if(!read_char(seq2))
|
|
||||||
{
|
|
||||||
lock->lock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
lock->lock();
|
|
||||||
if (seq[1] == '3' && seq2 == '~' )
|
|
||||||
{
|
|
||||||
// delete
|
|
||||||
if (raw_buffer.size() > 0 && size_t(raw_cursor) < raw_buffer.size())
|
|
||||||
{
|
|
||||||
raw_buffer.erase(raw_cursor,1);
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (raw_buffer.size() == size_t(raw_cursor))
|
|
||||||
{
|
|
||||||
raw_buffer.append(1,c);
|
|
||||||
raw_cursor++;
|
|
||||||
if (plen+raw_buffer.size() < size_t(get_columns()))
|
|
||||||
{
|
|
||||||
/* Avoid a full update of the line in the
|
|
||||||
* trivial case. */
|
|
||||||
if (::write(fd,&c,1) == -1) return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
raw_buffer.insert(raw_cursor,1,c);
|
|
||||||
raw_cursor++;
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 21: // Ctrl+u, delete the whole line.
|
|
||||||
raw_buffer.clear();
|
|
||||||
raw_cursor = 0;
|
|
||||||
prompt_refresh();
|
|
||||||
break;
|
|
||||||
case 11: // Ctrl+k, delete from current to end of line.
|
|
||||||
raw_buffer.erase(raw_cursor);
|
|
||||||
prompt_refresh();
|
|
||||||
break;
|
|
||||||
case 1: // Ctrl+a, go to the start of the line
|
|
||||||
raw_cursor = 0;
|
|
||||||
prompt_refresh();
|
|
||||||
break;
|
|
||||||
case 5: // ctrl+e, go to the end of the line
|
|
||||||
raw_cursor = raw_buffer.size();
|
|
||||||
prompt_refresh();
|
|
||||||
break;
|
|
||||||
case 12: // ctrl+l, clear screen
|
|
||||||
clear();
|
|
||||||
prompt_refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return raw_buffer.size();
|
|
||||||
}
|
|
||||||
FILE * dfout_C;
|
|
||||||
bool supported_terminal;
|
|
||||||
// state variables
|
|
||||||
bool rawmode; // is raw mode active?
|
|
||||||
termios orig_termios; // saved/restored by raw mode
|
|
||||||
// current state
|
|
||||||
enum console_state
|
|
||||||
{
|
|
||||||
con_unclaimed,
|
|
||||||
con_lineedit
|
|
||||||
} state;
|
|
||||||
bool in_batch;
|
|
||||||
std::string prompt; // current prompt string
|
|
||||||
std::string raw_buffer; // current raw mode buffer
|
|
||||||
int raw_cursor; // cursor position in the buffer
|
|
||||||
// thread exit mechanism
|
|
||||||
int exit_pipe[2];
|
|
||||||
fd_set descriptor_set;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Console::Console()
|
|
||||||
{
|
|
||||||
d = 0;
|
|
||||||
inited = false;
|
|
||||||
// we can't create the mutex at this time. the SDL functions aren't hooked yet.
|
|
||||||
wlock = new recursive_mutex();
|
|
||||||
}
|
|
||||||
Console::~Console()
|
|
||||||
{
|
|
||||||
if(inited)
|
|
||||||
shutdown();
|
|
||||||
if(wlock)
|
|
||||||
delete wlock;
|
|
||||||
if(d)
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Console::init(bool sharing)
|
|
||||||
{
|
|
||||||
if(sharing)
|
|
||||||
{
|
|
||||||
inited = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
freopen("stdout.log", "w", stdout);
|
|
||||||
d = new Private();
|
|
||||||
// make our own weird streams so our IO isn't redirected
|
|
||||||
d->dfout_C = fopen("/dev/tty", "w");
|
|
||||||
std::cin.tie(this);
|
|
||||||
clear();
|
|
||||||
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
|
|
||||||
// init the exit mechanism
|
|
||||||
pipe(d->exit_pipe);
|
|
||||||
FD_ZERO(&d->descriptor_set);
|
|
||||||
FD_SET(STDIN_FILENO, &d->descriptor_set);
|
|
||||||
FD_SET(d->exit_pipe[0], &d->descriptor_set);
|
|
||||||
inited = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Console::shutdown(void)
|
|
||||||
{
|
|
||||||
if(!d)
|
|
||||||
return true;
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if(d->rawmode)
|
|
||||||
d->disable_raw();
|
|
||||||
d->print("\n");
|
|
||||||
inited = false;
|
|
||||||
// kill the thing
|
|
||||||
close(d->exit_pipe[1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::begin_batch()
|
|
||||||
{
|
|
||||||
//color_ostream::begin_batch();
|
|
||||||
|
|
||||||
wlock->lock();
|
|
||||||
|
|
||||||
if (inited)
|
|
||||||
d->begin_batch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::end_batch()
|
|
||||||
{
|
|
||||||
if (inited)
|
|
||||||
d->end_batch();
|
|
||||||
|
|
||||||
wlock->unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::flush_proxy()
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if (inited)
|
|
||||||
d->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::add_text(color_value color, const std::string &text)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if (inited)
|
|
||||||
d->print_text(color, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Console::get_columns(void)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
int ret = -1;
|
|
||||||
if(inited)
|
|
||||||
ret = d->get_columns();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Console::get_rows(void)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
int ret = -1;
|
|
||||||
if(inited)
|
|
||||||
ret = d->get_rows();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::clear()
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if(inited)
|
|
||||||
d->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::gotoxy(int x, int y)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if(inited)
|
|
||||||
d->gotoxy(x,y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::cursor(bool enable)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
if(inited)
|
|
||||||
d->cursor(enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch)
|
|
||||||
{
|
|
||||||
lock_guard <recursive_mutex> g(*wlock);
|
|
||||||
int ret = -2;
|
|
||||||
if(inited)
|
|
||||||
ret = d->lineedit(prompt,output,wlock,ch);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console::msleep (unsigned int msec)
|
|
||||||
{
|
|
||||||
if (msec > 1000) sleep(msec/1000000);
|
|
||||||
usleep((msec % 1000000) * 1000);
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
file_compressorst& operator=(const file_compressorst &in) {
|
||||||
|
compressed = in.compressed;
|
||||||
|
/* fstream cannot be assigned */
|
||||||
|
in_buffer = in.in_buffer;
|
||||||
|
in_buffersize = in.in_buffersize;
|
||||||
|
in_buffer_amount_loaded = in.in_buffer_amount_loaded;
|
||||||
|
in_buffer_position = in.in_buffer_position;
|
||||||
|
out_buffer = in.out_buffer;
|
||||||
|
out_buffersize = in.out_buffersize;
|
||||||
|
out_buffer_amount_written = in.out_buffer_amount_written;
|
||||||
|
return *this;
|
||||||
|
}
|
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/peterix/dfhack
|
||||||
|
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
/* Based on luafilesystem
|
||||||
|
Copyright © 2003-2014 Kepler Project.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Export.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#ifndef _AIX
|
||||||
|
#define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
|
||||||
|
#else
|
||||||
|
#define _LARGE_FILES 1 /* AIX */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _LARGEFILE64_SOURCE
|
||||||
|
#define _LARGEFILE64_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <sys/locking.h>
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#include <utime.h>
|
||||||
|
#else
|
||||||
|
#include <sys/utime.h>
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LFS_VERSION "1.6.2"
|
||||||
|
#define LFS_LIBNAME "lfs"
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM < 502
|
||||||
|
# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define 'strerror' for systems that do not implement it */
|
||||||
|
#ifdef NO_STRERROR
|
||||||
|
#define strerror(_) "System unable to describe the error"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define 'getcwd' for systems that do not implement it */
|
||||||
|
#ifdef NO_GETCWD
|
||||||
|
#define getcwd(p,s) NULL
|
||||||
|
#define getcwd_error "Function 'getcwd' not provided by system"
|
||||||
|
#else
|
||||||
|
#define getcwd_error strerror(errno)
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
|
||||||
|
#define LFS_MAXPATHLEN MAX_PATH
|
||||||
|
#else
|
||||||
|
/* For MAXPATHLEN: */
|
||||||
|
#include <sys/param.h>
|
||||||
|
#define LFS_MAXPATHLEN MAXPATHLEN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct dir_data {
|
||||||
|
int closed;
|
||||||
|
#ifdef _WIN32
|
||||||
|
intptr_t hFile;
|
||||||
|
char pattern[MAX_PATH+1];
|
||||||
|
#else
|
||||||
|
DIR *dir;
|
||||||
|
#endif
|
||||||
|
} dir_data;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m))
|
||||||
|
#define STAT_STRUCT struct stati64
|
||||||
|
#else
|
||||||
|
#define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
|
||||||
|
#define STAT_STRUCT struct _stati64
|
||||||
|
#endif
|
||||||
|
#define STAT_FUNC _stati64
|
||||||
|
#define LSTAT_FUNC STAT_FUNC
|
||||||
|
#else
|
||||||
|
#define _O_TEXT 0
|
||||||
|
#define _O_BINARY 0
|
||||||
|
#define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0)
|
||||||
|
#define STAT_STRUCT struct stat
|
||||||
|
#define STAT_FUNC stat
|
||||||
|
#define LSTAT_FUNC lstat
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef S_ISDIR
|
||||||
|
#define S_ISDIR(mode) (mode&_S_IFDIR)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISREG
|
||||||
|
#define S_ISREG(mode) (mode&_S_IFREG)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISLNK
|
||||||
|
#define S_ISLNK(mode) (0)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISSOCK
|
||||||
|
#define S_ISSOCK(mode) (0)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISFIFO
|
||||||
|
#define S_ISFIFO(mode) (0)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISCHR
|
||||||
|
#define S_ISCHR(mode) (mode&_S_IFCHR)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISBLK
|
||||||
|
#define S_ISBLK(mode) (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum _filetype {
|
||||||
|
FILETYPE_NONE = -2,
|
||||||
|
FILETYPE_UNKNOWN = -1,
|
||||||
|
FILETYPE_FILE = 1,
|
||||||
|
FILETYPE_DIRECTORY,
|
||||||
|
FILETYPE_LINK,
|
||||||
|
FILETYPE_SOCKET,
|
||||||
|
FILETYPE_NAMEDPIPE,
|
||||||
|
FILETYPE_CHAR_DEVICE,
|
||||||
|
FILETYPE_BLOCK_DEVICE
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace DFHack {
|
||||||
|
namespace Filesystem {
|
||||||
|
DFHACK_EXPORT bool chdir (std::string path);
|
||||||
|
DFHACK_EXPORT std::string getcwd ();
|
||||||
|
DFHACK_EXPORT bool mkdir (std::string path);
|
||||||
|
DFHACK_EXPORT bool rmdir (std::string path);
|
||||||
|
DFHACK_EXPORT bool stat (std::string path, STAT_STRUCT &info);
|
||||||
|
DFHACK_EXPORT bool exists (std::string path);
|
||||||
|
DFHACK_EXPORT _filetype filetype (std::string path);
|
||||||
|
DFHACK_EXPORT bool isfile (std::string path);
|
||||||
|
DFHACK_EXPORT bool isdir (std::string path);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,230 @@
|
|||||||
|
|
||||||
|
local _ENV = mkmodule('persist-table')
|
||||||
|
|
||||||
|
--[[
|
||||||
|
persist-table.lua
|
||||||
|
author expwnent
|
||||||
|
|
||||||
|
This module is intended to help facilitate persistent table lookups.
|
||||||
|
It is a wrapper over dfhack.persistent calls.
|
||||||
|
It supports tables of arbitrary dimension and shape.
|
||||||
|
It stores information about each table and subtable's size and children.
|
||||||
|
|
||||||
|
For convenience, all stored information is itself persistent.
|
||||||
|
It would be more efficient to cache stored information in global variables and update it on save/load but this is not yet implemented.
|
||||||
|
Ask expwnent to try this if performance is bad.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
local persistTable = require 'persist-table'
|
||||||
|
persistTable.GlobalTable.doomitude = 'doom!' -- will be stored persistently
|
||||||
|
print(persistTable.GlobalTable.doomitude) --doom!
|
||||||
|
persistTable.GlobalTable.doomitude = nil --delete the persistent record
|
||||||
|
print(persistTable.GlobalTable.doomitude) --nil
|
||||||
|
|
||||||
|
persistTable.GlobalTable.mana = {} --allocate a subtable for mana
|
||||||
|
local mana = persistTable.GlobalTable.mana --setting elements in this table will be persistent too
|
||||||
|
mana['1'] = '3' --slightly faster than persistTable.GlobalTable.mana['1'] = '3'
|
||||||
|
--be aware that if you don't change the local variable mana when the game exits and reloads a different save you will run into mysterious problems so don't do that
|
||||||
|
mana['2'] = '100'
|
||||||
|
mana.maximum = '1000' --tables can be any arbitrary shape
|
||||||
|
local globalTable = persistTable.GlobalTable --this is safe too
|
||||||
|
globalTable.mana = nil --this is safe: it will deallocate all subtables cleanly
|
||||||
|
globalTable.revengeDesire = {}
|
||||||
|
--globalTable.revengeDseire.foo = {} -- error: tables must be allocated first with parentTable.subtableName = {}
|
||||||
|
--you can check if it exists with globalTable.tableName != nil
|
||||||
|
local revengeTable = globalTable.revengeDesire
|
||||||
|
revengeTable['2'] = revengeTable['2'] or {} --this is fine too
|
||||||
|
revengeTable['2']['3'] = 'totally a lot, man'
|
||||||
|
revengeTable['3'] = {}
|
||||||
|
revengeTable['3']['2'] = 'maybe a little bit'
|
||||||
|
revengeTable['2'] = nil
|
||||||
|
-------------
|
||||||
|
And so on.
|
||||||
|
|
||||||
|
Be careful not to name your tables in a way that will conflict with other scripts! The easiest way is to just put all your tables in one giant table named based on your script.
|
||||||
|
|
||||||
|
All stored values MUST be strings. Numbers can be supported later but are not yet supported. Keep in mind there is a significant overhead for each table element so don't go totally crazy storing massive amounts of information or the game will run out of RAM.
|
||||||
|
|
||||||
|
--table._children returns a list of child keys
|
||||||
|
for _,childKey in ipairs(table._children) do
|
||||||
|
local child = table[childKey]
|
||||||
|
--blah
|
||||||
|
end
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local prefix = 'persist-table'
|
||||||
|
|
||||||
|
local function ensure(name)
|
||||||
|
return dfhack.persistent.save({key=name})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gensym()
|
||||||
|
local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
|
||||||
|
local available = nil
|
||||||
|
local smallest = nil
|
||||||
|
for _,candidate in pairs(availables) do
|
||||||
|
--TODO: it would be great if we could iterate over these in order but we can't
|
||||||
|
local score = tonumber(candidate.value)
|
||||||
|
--print('gensym', candidate, score, available, smallest)
|
||||||
|
if (score and (not available or score < smallest)) then
|
||||||
|
smallest = score
|
||||||
|
available = candidate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if available then
|
||||||
|
local value = available.value
|
||||||
|
available:delete()
|
||||||
|
--print('gensym: allocate ' .. value)
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
--none explicitly available, so smallest unused is the next available number
|
||||||
|
local smallestUnused = ensure(prefix .. '$smallest_unused')
|
||||||
|
if smallestUnused.value == '' then
|
||||||
|
smallestUnused.value = '0'
|
||||||
|
end
|
||||||
|
local result = smallestUnused.value
|
||||||
|
smallestUnused.value = tostring(1+tonumber(result))
|
||||||
|
smallestUnused:save()
|
||||||
|
--print('gensym: allocate ' .. result)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function releasesym(symb)
|
||||||
|
local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
|
||||||
|
for _,available in pairs(availables) do
|
||||||
|
--print('releasesym: ', symb, available.value, available)
|
||||||
|
if available.value == symb then
|
||||||
|
print('error: persist-table.releasesym(' .. symb .. '): available.value = ' .. available.value)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dfhack.persistent.save({key=prefix .. '$available', value=symb}, true)
|
||||||
|
--print('releasesym: unallocate ' .. symb)
|
||||||
|
end
|
||||||
|
local intCount = 7
|
||||||
|
local existIndex = intCount-0
|
||||||
|
local existValue = 1
|
||||||
|
local pointerIndex = intCount-1
|
||||||
|
local pointerValue = 1
|
||||||
|
local defaultValue = -1
|
||||||
|
|
||||||
|
local function isEmpty(table)
|
||||||
|
return next(table) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function deletePersistent(name)
|
||||||
|
if name == '' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local children = dfhack.persistent.get_all(prefix .. name) or {}
|
||||||
|
for _,childKey in ipairs(children) do
|
||||||
|
local childEntry = ensure(prefix .. name .. '$$' .. childKey.value)
|
||||||
|
if childEntry.ints[existIndex] == existValue and childEntry.ints[pointerIndex] == pointerValue then
|
||||||
|
deletePersistent(childEntry.value)
|
||||||
|
end
|
||||||
|
childEntry:delete()
|
||||||
|
childKey:delete()
|
||||||
|
end
|
||||||
|
releasesym(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
GlobalTable = GlobalTable or {key = 'mastertable'}
|
||||||
|
GlobalTable.mt = GlobalTable.mt or {}
|
||||||
|
GlobalTable.mt.__index = GlobalTable.mt.__index or function(theTable, key)
|
||||||
|
if key == '_children' then
|
||||||
|
return rawget(theTable,key)
|
||||||
|
end
|
||||||
|
--print(rawget(theTable,'key') .. '[' .. key .. ']')
|
||||||
|
local entry = ensure(prefix .. rawget(theTable,'key') .. '$$' .. key)
|
||||||
|
if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == defaultValue then
|
||||||
|
--print('string: ' .. entry.value)
|
||||||
|
return entry.value
|
||||||
|
end
|
||||||
|
if entry.ints[pointerIndex] == pointerValue then
|
||||||
|
--pre-existing pointer
|
||||||
|
local result = {key = entry.value}
|
||||||
|
result.mt = rawget(GlobalTable,'mt')
|
||||||
|
local childArgs = dfhack.persistent.get_all(prefix .. entry.value)
|
||||||
|
result._children = {}
|
||||||
|
for _,childArg in ipairs(childArgs or {}) do
|
||||||
|
--print(result._children, childArg.value)
|
||||||
|
table.insert(result._children, childArg.value)
|
||||||
|
end
|
||||||
|
setmetatable(result,rawget(GlobalTable,'mt'))
|
||||||
|
--print('theTable: ' .. entry.value)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
entry:delete()
|
||||||
|
--print 'theTable[key] does not exist.'
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
GlobalTable.mt.__newindex = GlobalTable.mt.__newindex or function(theTable, key, value)
|
||||||
|
--print(rawget(theTable,'key') .. '[' .. key .. '] = ' .. tostring(value))
|
||||||
|
local entry = ensure(prefix .. rawget(theTable,'key') .. '$$' .. key)
|
||||||
|
local old = entry.value
|
||||||
|
local isNew = entry.ints[existIndex] == defaultValue
|
||||||
|
if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == pointerValue then
|
||||||
|
if type(value) == 'table' and rawget(value,'mt') == rawget(GlobalTable,mt) and entry.value == rawget(value,'key') then
|
||||||
|
--if setting it to the same table it already is, then don't do anything
|
||||||
|
return
|
||||||
|
end
|
||||||
|
deletePersistent(entry.value)
|
||||||
|
end
|
||||||
|
if not value then
|
||||||
|
--print('__newindesx: delete')
|
||||||
|
--delete
|
||||||
|
for i,child in ipairs(dfhack.persistent.get_all(prefix .. rawget(theTable,'key')) or {}) do
|
||||||
|
if child.value == key then
|
||||||
|
child:delete()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
entry:delete()
|
||||||
|
return
|
||||||
|
elseif type(value) == 'string' then
|
||||||
|
--print('__newindesx: string')
|
||||||
|
entry.value = value
|
||||||
|
entry.ints[pointerIndex] = defaultValue
|
||||||
|
entry.ints[existIndex] = existValue
|
||||||
|
entry:save()
|
||||||
|
if isNew then
|
||||||
|
--print('new child!')
|
||||||
|
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
elseif type(value) == 'table' then
|
||||||
|
--print('__newindesx: table')
|
||||||
|
if rawget(value,'mt') ~= rawget(GlobalTable,'mt') then
|
||||||
|
if not isEmpty(value) then
|
||||||
|
error('setting value to an invalid table')
|
||||||
|
end
|
||||||
|
--print('__newindesx: empty table')
|
||||||
|
--empty table: allocate a thing
|
||||||
|
entry.ints[pointerIndex] = pointerValue
|
||||||
|
entry.ints[existIndex] = existValue
|
||||||
|
entry.value = gensym()
|
||||||
|
entry:save()
|
||||||
|
|
||||||
|
if isNew then
|
||||||
|
--print('new child!')
|
||||||
|
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
--print('__newindesx: table assignment')
|
||||||
|
entry.value = rawget(value,'key')
|
||||||
|
entry.ints[pointerIndex] = pointerValue
|
||||||
|
entry.ints[existIndex] = existValue
|
||||||
|
entry:save()
|
||||||
|
if isNew then
|
||||||
|
--print('new child!')
|
||||||
|
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
else
|
||||||
|
error('type(value) = ' .. type(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
setmetatable(GlobalTable, GlobalTable.mt)
|
||||||
|
|
||||||
|
return _ENV
|
@ -0,0 +1,42 @@
|
|||||||
|
-- lua/plugins/repeatUtil.lua
|
||||||
|
-- author expwnent
|
||||||
|
-- tools for registering callbacks periodically
|
||||||
|
-- vaguely based on a script by Putnam
|
||||||
|
|
||||||
|
local _ENV = mkmodule("repeat-util")
|
||||||
|
|
||||||
|
repeating = repeating or {}
|
||||||
|
|
||||||
|
dfhack.onStateChange.repeatUtilStateChange = function(code)
|
||||||
|
if code == SC_WORLD_UNLOADED then
|
||||||
|
repeating = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cancel(name)
|
||||||
|
if not repeating[name] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
dfhack.timeout_active(repeating[name],nil)
|
||||||
|
repeating[name] = nil
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function scheduleEvery(name,time,timeUnits,func)
|
||||||
|
cancel(name)
|
||||||
|
local function helper()
|
||||||
|
func()
|
||||||
|
repeating[name] = dfhack.timeout(time,timeUnits,helper)
|
||||||
|
end
|
||||||
|
helper()
|
||||||
|
end
|
||||||
|
|
||||||
|
function scheduleUnlessAlreadyScheduled(name,time,timeUnits,func)
|
||||||
|
if repeating[name] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
scheduleEvery(name,time,timeUnits,func)
|
||||||
|
end
|
||||||
|
|
||||||
|
return _ENV
|
||||||
|
|
@ -0,0 +1,175 @@
|
|||||||
|
--lua/syndrome-util.lua
|
||||||
|
--author expwnent
|
||||||
|
--some utilities for adding syndromes to units
|
||||||
|
|
||||||
|
local _ENV = mkmodule("syndrome-util")
|
||||||
|
local utils = require("utils")
|
||||||
|
|
||||||
|
function findUnitSyndrome(unit,syn_id)
|
||||||
|
for index,syndrome in ipairs(unit.syndromes.active) do
|
||||||
|
if syndrome['type'] == syn_id then
|
||||||
|
return syndrome
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--usage: syndromeUtil.ResetPolicy.DoNothing, syndromeUtil.ResetPolicy.ResetDuration, etc
|
||||||
|
ResetPolicy = ResetPolicy or utils.invert({
|
||||||
|
"DoNothing",
|
||||||
|
"ResetDuration",
|
||||||
|
"AddDuration",
|
||||||
|
"NewInstance"
|
||||||
|
})
|
||||||
|
|
||||||
|
function eraseSyndrome(unit,syndromeId,oldestFirst)
|
||||||
|
local i1
|
||||||
|
local iN
|
||||||
|
local d
|
||||||
|
if oldestFirst then
|
||||||
|
i1 = 0
|
||||||
|
iN = #unit.syndromes.active-1
|
||||||
|
d = 1
|
||||||
|
else
|
||||||
|
i1 = #unit.syndromes.active-1
|
||||||
|
iN = 0
|
||||||
|
d = -1
|
||||||
|
end
|
||||||
|
local syndromes = unit.syndromes.active
|
||||||
|
for i=i1,iN,d do
|
||||||
|
if syndromes[i]['type'] == syndromeId then
|
||||||
|
syndromes:erase(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function eraseSyndromeClassHelper(unit,synclass)
|
||||||
|
for i,unitSyndrome in ipairs(unit.syndromes.active) do
|
||||||
|
local syndrome = df.syndrome.find(unitSyndrome.type)
|
||||||
|
for _,class in ipairs(syndrome.syn_class) do
|
||||||
|
if class.value == synclass then
|
||||||
|
unit.syndromes.active:erase(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function eraseSyndromeClass(unit,synclass)
|
||||||
|
local count=0
|
||||||
|
while eraseSyndromeClassHelper(unit,synclass) do
|
||||||
|
count = count+1
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
function eraseSyndromes(unit,syndromeId)
|
||||||
|
local count=0
|
||||||
|
while eraseSyndrome(unit,syndromeId,true) do
|
||||||
|
count = count+1
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--target is a df.unit, syndrome is a df.syndrome, resetPolicy is one of syndromeUtil.ResetPolicy
|
||||||
|
--if the target has an instance of the syndrome already, the reset policy takes effect
|
||||||
|
--returns true if the unit did not have the syndrome before calling and false otherwise
|
||||||
|
function infectWithSyndrome(target,syndrome,resetPolicy)
|
||||||
|
local oldSyndrome = findUnitSyndrome(target,syndrome.id)
|
||||||
|
if oldSyndrome == nil or resetPolicy == nil or resetPolicy == ResetPolicy.NewInstance then
|
||||||
|
local unitSyndrome = df.unit_syndrome:new()
|
||||||
|
unitSyndrome.type = syndrome.id
|
||||||
|
unitSyndrome.year = df.global.cur_year
|
||||||
|
unitSyndrome.year_time = df.global.cur_year_tick
|
||||||
|
unitSyndrome.ticks = 0
|
||||||
|
unitSyndrome.wound_id = -1
|
||||||
|
for k,v in ipairs(syndrome.ce) do
|
||||||
|
local symptom = df.unit_syndrome.T_symptoms:new()
|
||||||
|
symptom.quantity = 0
|
||||||
|
symptom.delay = 0
|
||||||
|
symptom.ticks = 0
|
||||||
|
symptom.flags.active = true
|
||||||
|
unitSyndrome.symptoms:insert("#",symptom)
|
||||||
|
end
|
||||||
|
target.syndromes.active:insert("#",unitSyndrome)
|
||||||
|
elseif resetPolicy == ResetPolicy.DoNothing then
|
||||||
|
elseif resetPolicy == ResetPolicy.ResetDuration then
|
||||||
|
for k,symptom in ipairs(oldSyndrome.symptoms) do
|
||||||
|
symptom.ticks = 0
|
||||||
|
end
|
||||||
|
oldSyndrome.ticks = 0
|
||||||
|
elseif resetPolicy == ResetPolicy.AddDuration then
|
||||||
|
for k,symptom in ipairs(oldSyndrome.symptoms) do
|
||||||
|
--really it's syndrome.ce[k].end, but lua doesn't like that because keywords
|
||||||
|
if syndrome.ce[k]["end"] ~= -1 then
|
||||||
|
symptom.ticks = symptom.ticks - syndrome.ce[k]["end"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else qerror("Bad reset policy: " .. resetPolicy)
|
||||||
|
end
|
||||||
|
return (oldSyndrome == nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function isValidTarget(unit,syndrome)
|
||||||
|
--mostly copied from itemsyndrome, which is based on autoSyndrome
|
||||||
|
if
|
||||||
|
#syndrome.syn_affected_class==0
|
||||||
|
and #syndrome.syn_affected_creature==0
|
||||||
|
and #syndrome.syn_affected_caste==0
|
||||||
|
and #syndrome.syn_immune_class==0
|
||||||
|
and #syndrome.syn_immune_creature==0
|
||||||
|
and #syndrome.syn_immune_caste==0
|
||||||
|
then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local affected = false
|
||||||
|
local unitRaws = df.creature_raw.find(unit.race)
|
||||||
|
local casteRaws = unitRaws.caste[unit.caste]
|
||||||
|
local unitRaceName = unitRaws.creature_id
|
||||||
|
local unitCasteName = casteRaws.caste_id
|
||||||
|
local unitClasses = casteRaws.creature_class
|
||||||
|
for _,unitClass in ipairs(unitClasses) do
|
||||||
|
for _,syndromeClass in ipairs(syndrome.syn_affected_class) do
|
||||||
|
if unitClass.value==syndromeClass.value then
|
||||||
|
affected = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for caste,creature in ipairs(syndrome.syn_affected_creature) do
|
||||||
|
local affectedCreature = creature.value
|
||||||
|
local affectedCaste = syndrome.syn_affected_caste[caste].value
|
||||||
|
if affectedCreature == unitRaceName and (affectedCaste == unitCasteName or affectedCaste == "ALL") then
|
||||||
|
affected = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _,unitClass in ipairs(unitClasses) do
|
||||||
|
for _,syndromeClass in ipairs(syndrome.syn_immune_class) do
|
||||||
|
if unitClass.value == syndromeClass.value then
|
||||||
|
affected = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for caste,creature in ipairs(syndrome.syn_immune_creature) do
|
||||||
|
local immuneCreature = creature.value
|
||||||
|
local immuneCaste = syndrome.syn_immune_caste[caste].value
|
||||||
|
if immuneCreature == unitRaceName and (immuneCaste == unitCasteName or immuneCaste == "ALL") then
|
||||||
|
affected = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return affected
|
||||||
|
end
|
||||||
|
|
||||||
|
function infectWithSyndromeIfValidTarget(target,syndrome,resetPolicy)
|
||||||
|
if isValidTarget(target,syndrome) then
|
||||||
|
infectWithSyndrome(target,syndrome,resetPolicy)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return _ENV
|
||||||
|
|
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/peterix/dfhack
|
||||||
|
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
/* Based on luafilesystem
|
||||||
|
Copyright © 2003-2014 Kepler Project.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "modules/Filesystem.h"
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::chdir (std::string path)
|
||||||
|
{
|
||||||
|
return !(bool)::chdir(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DFHack::Filesystem::getcwd ()
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
char buf[LFS_MAXPATHLEN];
|
||||||
|
std::string result = "";
|
||||||
|
#ifdef _WIN32
|
||||||
|
if ((path = ::_getcwd(buf, LFS_MAXPATHLEN)) != NULL)
|
||||||
|
#else
|
||||||
|
if ((path = ::getcwd(buf, LFS_MAXPATHLEN)) != NULL)
|
||||||
|
#endif
|
||||||
|
result = buf;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::mkdir (std::string path)
|
||||||
|
{
|
||||||
|
int fail;
|
||||||
|
#ifdef _WIN32
|
||||||
|
fail = ::_mkdir(path.c_str());
|
||||||
|
#else
|
||||||
|
fail = ::mkdir(path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
|
||||||
|
S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||||
|
#endif
|
||||||
|
return !(bool)fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::rmdir (std::string path)
|
||||||
|
{
|
||||||
|
int fail;
|
||||||
|
#ifdef _WIN32
|
||||||
|
fail = ::_rmdir(path.c_str());
|
||||||
|
#else
|
||||||
|
fail = ::rmdir(path.c_str());
|
||||||
|
#endif
|
||||||
|
return !(bool)fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
_filetype mode2type (unsigned short mode) {
|
||||||
|
#else
|
||||||
|
_filetype mode2type (mode_t mode) {
|
||||||
|
#endif
|
||||||
|
if (S_ISREG(mode))
|
||||||
|
return FILETYPE_FILE;
|
||||||
|
else if (S_ISDIR(mode))
|
||||||
|
return FILETYPE_DIRECTORY;
|
||||||
|
else if (S_ISLNK(mode))
|
||||||
|
return FILETYPE_LINK;
|
||||||
|
else if (S_ISSOCK(mode))
|
||||||
|
return FILETYPE_SOCKET;
|
||||||
|
else if (S_ISFIFO(mode))
|
||||||
|
return FILETYPE_NAMEDPIPE;
|
||||||
|
else if (S_ISCHR(mode))
|
||||||
|
return FILETYPE_CHAR_DEVICE;
|
||||||
|
else if (S_ISBLK(mode))
|
||||||
|
return FILETYPE_BLOCK_DEVICE;
|
||||||
|
else
|
||||||
|
return FILETYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::stat (std::string path, STAT_STRUCT &info)
|
||||||
|
{
|
||||||
|
return !(bool)(STAT_FUNC(path.c_str(), &info));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::exists (std::string path)
|
||||||
|
{
|
||||||
|
STAT_STRUCT info;
|
||||||
|
return (bool)DFHack::Filesystem::stat(path.c_str(), info);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
_filetype DFHack::Filesystem::filetype (std::string path)
|
||||||
|
{
|
||||||
|
STAT_STRUCT info;
|
||||||
|
DFHack::Filesystem::stat(path, info);
|
||||||
|
std::cout << info.st_mode << std::endl;
|
||||||
|
return mode2type(info.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::isfile (std::string path)
|
||||||
|
{
|
||||||
|
return DFHack::Filesystem::filetype(path) == FILETYPE_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DFHack::Filesystem::isdir (std::string path)
|
||||||
|
{
|
||||||
|
return DFHack::Filesystem::filetype(path) == FILETYPE_DIRECTORY;
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit 499507eac5bdd3abc70e204497248627327cf8de
|
Subproject commit 55b60e3aa99aece7e9a239b041dc4f95a58dcef3
|
@ -0,0 +1,30 @@
|
|||||||
|
Notes by PeridexisErrant, on the needs_porting scripts and plugins:
|
||||||
|
|
||||||
|
I deleted:
|
||||||
|
attachtest.py obsolete
|
||||||
|
digger.cpp less useful than digger2, replaced by autochop
|
||||||
|
digger2.cpp replaced by digfort
|
||||||
|
dfstatus.cpp replaced by dfstatus.lua
|
||||||
|
drawtile.cpp replaced by tiletypes
|
||||||
|
fix-3708.cpp obsolete, bug fixed in vanilla
|
||||||
|
lair.cpp replaced by lair
|
||||||
|
reveal.py replaced by reveal
|
||||||
|
treedump.py replaced by prospect & autochop
|
||||||
|
veinlook.cpp replaced by prospect
|
||||||
|
veinswap.cpp replaced by changevein
|
||||||
|
|
||||||
|
|
||||||
|
To investigate further:
|
||||||
|
creaturemanager.cpp modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere
|
||||||
|
digpattern.cpp allows multi-Z designations. Obsolete, or is there more here?
|
||||||
|
incrementalsearch.cpp linux-only memory stuff; unqualified to judge
|
||||||
|
SegementedFinder.h more memory stuff
|
||||||
|
|
||||||
|
|
||||||
|
To port:
|
||||||
|
copypaste.cpp high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions
|
||||||
|
dfbauxtite.cpp changes material of mechanisms to bauxtite (ie magma-safe)
|
||||||
|
hellhole.cpp instantly creates a hole to the HFS
|
||||||
|
hotkeynotedump.py outputs a list of hotkeys and names; most useful before keybindings were possible. Trival to port but low value.
|
||||||
|
itemdesignator.cpp mostly replaced by Falconne's enhanced stocks, but could port the interesting 'set fire to things' function
|
||||||
|
position.py outputs very detailed time& place info
|
@ -1,53 +0,0 @@
|
|||||||
import time
|
|
||||||
from pydfhack import ContextManager
|
|
||||||
|
|
||||||
df_cm = ContextManager("Memory.xml")
|
|
||||||
df = None
|
|
||||||
|
|
||||||
def test_attach():
|
|
||||||
global df
|
|
||||||
|
|
||||||
if not df:
|
|
||||||
df = df_cm.get_single_context()
|
|
||||||
|
|
||||||
if not df.attach():
|
|
||||||
print "Unable to attach!"
|
|
||||||
return False
|
|
||||||
elif not df.detach():
|
|
||||||
print "Unabled to detach!"
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def suspend_test():
|
|
||||||
global df
|
|
||||||
|
|
||||||
if not df:
|
|
||||||
df = df_cm.get_single_context()
|
|
||||||
|
|
||||||
print "Testing suspend/resume"
|
|
||||||
|
|
||||||
df.attach()
|
|
||||||
|
|
||||||
t1 = time.time()
|
|
||||||
|
|
||||||
for i in xrange(1000):
|
|
||||||
df.suspend()
|
|
||||||
|
|
||||||
if i % 10 == 0:
|
|
||||||
print "%i%%" % (i / 10.0,)
|
|
||||||
|
|
||||||
df.resume()
|
|
||||||
|
|
||||||
t2 = time.time()
|
|
||||||
|
|
||||||
df.detach()
|
|
||||||
|
|
||||||
print "suspend test done in $0.9f seconds" % (t2 - t1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if test_attach():
|
|
||||||
suspend_test()
|
|
||||||
|
|
||||||
print "Done. Press any key to continue"
|
|
||||||
raw_input()
|
|
@ -1,206 +0,0 @@
|
|||||||
/*
|
|
||||||
* dfstatus.cpp
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <curses.h>
|
|
||||||
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
#include <climits>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
//#include <conio.h> //to break on keyboard input
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
using namespace std;
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <DFVector.h>
|
|
||||||
#include <extra/stopwatch.h>
|
|
||||||
|
|
||||||
WINDOW *create_newwin(int height, int width, int starty, int startx);
|
|
||||||
|
|
||||||
int32_t drinkCount = 0;
|
|
||||||
int32_t mealsCount = 0;
|
|
||||||
int32_t plantCount = 0;
|
|
||||||
int32_t fishCount = 0;
|
|
||||||
int32_t meatCount = 0;
|
|
||||||
int32_t logsCount = 0;
|
|
||||||
int32_t barCount = 0;
|
|
||||||
int32_t clothCount = 0;
|
|
||||||
int32_t ironBars = 0;
|
|
||||||
int32_t pigIronBars = 0;
|
|
||||||
int32_t goldBars = 0;
|
|
||||||
int32_t silverBars = 0;
|
|
||||||
int32_t copperBars = 0;
|
|
||||||
int32_t steelBars = 0;
|
|
||||||
int32_t fuel = 0;
|
|
||||||
uint64_t start_time = 0;
|
|
||||||
uint64_t end_time = 0;
|
|
||||||
uint64_t total_time = 0;
|
|
||||||
|
|
||||||
WINDOW *create_newwin(int height, int width, int starty, int startx){
|
|
||||||
WINDOW *local_win;
|
|
||||||
|
|
||||||
local_win = newwin(height, width, starty, startx);
|
|
||||||
box(local_win, 0, 0); /* 0, 0 gives default characters
|
|
||||||
* for the vertical and horizontal
|
|
||||||
* lines */
|
|
||||||
//first row
|
|
||||||
mvwprintw(local_win,2 ,2,"Drinks : %d", drinkCount);
|
|
||||||
mvwprintw(local_win,4 ,2,"Meals : %d", mealsCount);
|
|
||||||
mvwprintw(local_win,6 ,2,"Plants : %d", plantCount);
|
|
||||||
mvwprintw(local_win,7 ,2,"Fish : %d", fishCount);
|
|
||||||
mvwprintw(local_win,8 ,2,"Meat : %d", meatCount);
|
|
||||||
mvwprintw(local_win,10,2,"Logs : %d", logsCount);
|
|
||||||
mvwprintw(local_win,12,2,"Cloth : %d", clothCount);
|
|
||||||
//second row
|
|
||||||
mvwprintw(local_win,2,22,"Iron Bars : %d", ironBars);
|
|
||||||
mvwprintw(local_win,3,22,"Gold Bars : %d", goldBars);
|
|
||||||
mvwprintw(local_win,4,22,"Silver Bars : %d", silverBars);
|
|
||||||
mvwprintw(local_win,5,22,"Copper Bars : %d", copperBars);
|
|
||||||
mvwprintw(local_win,6,22,"Steel Bars : %d", steelBars);
|
|
||||||
mvwprintw(local_win,7,22,"Pig iron Bars : %d", pigIronBars);
|
|
||||||
mvwprintw(local_win,9,22,"Fuel : %d", fuel);
|
|
||||||
total_time += end_time - start_time;
|
|
||||||
mvwprintw(local_win,14,2,"Time: %d ms last update, %d ms total", end_time - start_time, total_time);
|
|
||||||
|
|
||||||
wrefresh(local_win); // paint the screen and all components.
|
|
||||||
|
|
||||||
return local_win;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
WINDOW *my_win;
|
|
||||||
int startx, starty, width, height;
|
|
||||||
|
|
||||||
DFHack::Process * p;
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context * DF;
|
|
||||||
DFHack::Materials * Materials;
|
|
||||||
try{ //is DF running?
|
|
||||||
DF = DFMgr.getSingleContext();
|
|
||||||
DF->Attach();
|
|
||||||
Materials = DF->getMaterials();
|
|
||||||
Materials->ReadAllMaterials();
|
|
||||||
DF->Resume();
|
|
||||||
}
|
|
||||||
catch (exception& e){
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
//init and Attach
|
|
||||||
ofstream file("dfstatus_errors.txt");
|
|
||||||
streambuf* strm_buffer = cerr.rdbuf(); // save cerr's output buffer
|
|
||||||
cerr.rdbuf (file.rdbuf()); // redirect output into the file
|
|
||||||
|
|
||||||
initscr(); //start curses.
|
|
||||||
nonl();
|
|
||||||
intrflush(stdscr, FALSE);
|
|
||||||
keypad(stdscr, TRUE);
|
|
||||||
do{
|
|
||||||
drinkCount = 0;
|
|
||||||
mealsCount = 0;
|
|
||||||
plantCount = 0;
|
|
||||||
fishCount = 0;
|
|
||||||
meatCount = 0;
|
|
||||||
logsCount = 0;
|
|
||||||
barCount = 0;
|
|
||||||
clothCount = 0;
|
|
||||||
ironBars = 0;
|
|
||||||
pigIronBars = 0;
|
|
||||||
goldBars = 0;
|
|
||||||
silverBars = 0;
|
|
||||||
copperBars = 0;
|
|
||||||
steelBars = 0;
|
|
||||||
fuel = 0;
|
|
||||||
|
|
||||||
//FILE * pFile;
|
|
||||||
//pFile = fopen("dump.txt","w");
|
|
||||||
start_time = GetTimeMs64();
|
|
||||||
if(!DF->Suspend())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//DFHack::Gui * Gui = DF->getGui();
|
|
||||||
|
|
||||||
DFHack::Items * Items = DF->getItems();
|
|
||||||
Items->Start();
|
|
||||||
|
|
||||||
DFHack::VersionInfo * mem = DF->getMemoryInfo();
|
|
||||||
p = DF->getProcess();
|
|
||||||
|
|
||||||
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
|
|
||||||
DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
|
|
||||||
uint32_t size = p_items.size();
|
|
||||||
|
|
||||||
DFHack::dfh_item itm; //declare itm
|
|
||||||
//memset(&itm, 0, sizeof(DFHack::dfh_item)); //seems to set every value in itm to 0
|
|
||||||
|
|
||||||
for(unsigned int idx = 0; idx < size; idx++) //fill our item variables with this loop
|
|
||||||
{
|
|
||||||
Items->readItem(p_items[idx], itm);
|
|
||||||
|
|
||||||
if (itm.base.flags.owned) //only count what we actually own.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string s0 = Items->getItemClass(itm.matdesc.itemType).c_str();
|
|
||||||
string s1 = Items->getItemDescription(itm, Materials).c_str();
|
|
||||||
|
|
||||||
if( s0 == "drink" ) {drinkCount += itm.quantity;}
|
|
||||||
else if(s0 == "food"){mealsCount += itm.quantity;}
|
|
||||||
else if(s0 == "plant"){plantCount += itm.quantity;}
|
|
||||||
else if(s0 == "fish"){fishCount += itm.quantity;}
|
|
||||||
else if(s0 == "meat"){meatCount += itm.quantity;}
|
|
||||||
else if(s0 == "wood"){logsCount += itm.quantity;}
|
|
||||||
else if(s0 == "cloth"){clothCount += itm.quantity;}
|
|
||||||
else if(s0 == "bar") //need to break it down by ItemDescription to get the different types of bars.
|
|
||||||
{
|
|
||||||
barCount = barCount + itm.quantity;
|
|
||||||
if(s1.find("PIG_IRON")!=string::npos){pigIronBars++;}
|
|
||||||
else if(s1.find("IRON")!=string::npos){ironBars++;}
|
|
||||||
else if(s1.find("GOLD")!=string::npos){goldBars++;}
|
|
||||||
else if(s1.find("SILVER")!=string::npos){silverBars++;}
|
|
||||||
else if(s1.find("COPPER")!=string::npos){copperBars++;}
|
|
||||||
else if(s1.find("STEEL")!=string::npos){steelBars++;}
|
|
||||||
else if(s1.find("COAL")!=string::npos){fuel++;}
|
|
||||||
}
|
|
||||||
/*if(s0 != "boulder" && s0 != "thread"){
|
|
||||||
fprintf(pFile,"%5d: %12s - %64s - [%d]\n", idx, Items->getItemClass(itm.matdesc.itemType).c_str(), Items->getItemDescription(itm, Materials).c_str(), itm.quantity);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
DF->Resume();
|
|
||||||
end_time = GetTimeMs64();
|
|
||||||
//printf("%d - %d\n", (clock()/CLOCKS_PER_SEC),(clock()/CLOCKS_PER_SEC)%60);
|
|
||||||
height = LINES;
|
|
||||||
width = COLS;
|
|
||||||
starty = (LINES - height) / 2;
|
|
||||||
startx = (COLS - width) / 2;
|
|
||||||
|
|
||||||
my_win = create_newwin(height, width, starty, startx);
|
|
||||||
|
|
||||||
#ifdef LINUX_BUILD
|
|
||||||
sleep(10);
|
|
||||||
#else
|
|
||||||
Sleep(10000);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} while(true);
|
|
||||||
|
|
||||||
endwin(); /* End curses mode */
|
|
||||||
cerr.rdbuf (strm_buffer); // restore old output buffer
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,363 +0,0 @@
|
|||||||
// digger.cpp
|
|
||||||
|
|
||||||
// NOTE currently only works with trees
|
|
||||||
|
|
||||||
// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <list>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <assert.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <DFTileTypes.h>
|
|
||||||
#include <argstream.h>
|
|
||||||
|
|
||||||
// counts the occurances of a certain element in a vector
|
|
||||||
// used to determine of a given tile is a target
|
|
||||||
int vec_count(vector<uint16_t>& vec, uint16_t t)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (uint32_t i = 0; i < vec.size(); ++i)
|
|
||||||
{
|
|
||||||
if (vec[i] == t)
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// splits a string on a certain char
|
|
||||||
//
|
|
||||||
// src is the string to split
|
|
||||||
// delim is the delimiter to split the string around
|
|
||||||
// tokens is filled with every occurance between delims
|
|
||||||
void string_split(vector<string>& tokens, const std::string& src, const std::string& delim)
|
|
||||||
{
|
|
||||||
std::string::size_type start = 0;
|
|
||||||
std::string::size_type end;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
end = src.find(delim, start);
|
|
||||||
tokens.push_back(src.substr(start, end - start));
|
|
||||||
if (end == std::string::npos) // last token handled
|
|
||||||
break;
|
|
||||||
start = end + delim.size(); // skip next delim
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is used to parse the command line options
|
|
||||||
void parse_int_csv(vector<uint16_t>& targets, const std::string& src)
|
|
||||||
{
|
|
||||||
std::string::size_type start = 0;
|
|
||||||
std::string::size_type end;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
end = src.find(",", start);
|
|
||||||
targets.push_back(atoi(src.substr(start, end - start).c_str()));
|
|
||||||
if (end == std::string::npos) // last token handled
|
|
||||||
break;
|
|
||||||
start = end + 1; // skip next delim
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DigTarget
|
|
||||||
{
|
|
||||||
DigTarget() :
|
|
||||||
source_distance(0),
|
|
||||||
grid_x(0), grid_y(0),
|
|
||||||
local_x(0), local_y(0),
|
|
||||||
real_x(0), real_y(0), z(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
DigTarget(
|
|
||||||
int realx, int realy, int _z,
|
|
||||||
int sourcex, int sourcey, int sourcez) :
|
|
||||||
real_x(realx), real_y(realy), z(_z)
|
|
||||||
{
|
|
||||||
grid_x = realx/16;
|
|
||||||
grid_y = realy/16;
|
|
||||||
|
|
||||||
local_x = realx%16;
|
|
||||||
local_y = realy%16;
|
|
||||||
|
|
||||||
source_distance = manhattan_distance(
|
|
||||||
real_x, real_y, z,
|
|
||||||
sourcex, sourcey, sourcez);
|
|
||||||
}
|
|
||||||
|
|
||||||
DigTarget(
|
|
||||||
int gridx, int gridy, int _z,
|
|
||||||
int localx, int localy,
|
|
||||||
int sourcex, int sourcey, int sourcez) :
|
|
||||||
grid_x(gridx), grid_y(gridy),
|
|
||||||
local_x(localx), local_y(localy),
|
|
||||||
z(_z)
|
|
||||||
{
|
|
||||||
real_x = (grid_x*16)+local_x;
|
|
||||||
real_y = (grid_y*16)+local_y;
|
|
||||||
|
|
||||||
source_distance = manhattan_distance(
|
|
||||||
real_x, real_y, z,
|
|
||||||
sourcex, sourcey, sourcez);
|
|
||||||
}
|
|
||||||
|
|
||||||
int source_distance; // the distance to the source coords, used for sorting
|
|
||||||
|
|
||||||
int grid_x, grid_y; // what grid the target is in
|
|
||||||
int local_x, local_y; // on what coord in the grid the target is in (0-16)
|
|
||||||
int real_x, real_y; // real coordinates for target, thats grid*16+local
|
|
||||||
int z; // z position for target, stored plain since there arent z grids
|
|
||||||
|
|
||||||
bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// calculates the manhattan distance between two coords
|
|
||||||
int manhattan_distance(int x, int y, int z, int xx, int yy, int zz)
|
|
||||||
{
|
|
||||||
return abs(x-xx)+abs(y-yy)+abs(z-zz);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int dig(DFHack::Maps* Maps,
|
|
||||||
vector<uint16_t>& targets,
|
|
||||||
int num = -1,
|
|
||||||
const int x_source = 0,
|
|
||||||
const int y_source = 0,
|
|
||||||
const int z_source = 0,
|
|
||||||
bool verbose = false)
|
|
||||||
{
|
|
||||||
if (num == 0)
|
|
||||||
return 0; // max limit of 0, nothing to do
|
|
||||||
|
|
||||||
uint32_t x_max,y_max,z_max;
|
|
||||||
DFHack::designations40d designations;
|
|
||||||
DFHack::tiletypes40d tiles;
|
|
||||||
Maps->getSize(x_max,y_max,z_max);
|
|
||||||
|
|
||||||
// every tile found, will later be sorted by distance to source
|
|
||||||
vector<DigTarget> candidates;
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
cout << "source is " << x_source << " " << y_source << " " << z_source << endl;
|
|
||||||
|
|
||||||
// walk the map
|
|
||||||
for(uint32_t x = 0; x < x_max; x++)
|
|
||||||
{
|
|
||||||
for(uint32_t y = 0; y < y_max; y++)
|
|
||||||
{
|
|
||||||
for(uint32_t z = 0; z < z_max; z++)
|
|
||||||
{
|
|
||||||
if(Maps->isValidBlock(x,y,z))
|
|
||||||
{
|
|
||||||
// read block designations and tiletype
|
|
||||||
Maps->ReadDesignations(x,y,z, &designations);
|
|
||||||
Maps->ReadTileTypes(x,y,z, &tiles);
|
|
||||||
|
|
||||||
// search all tiles for dig targets:
|
|
||||||
// visible, not yet marked for dig and matching tile type
|
|
||||||
for(uint32_t lx = 0; lx < 16; lx++)
|
|
||||||
{
|
|
||||||
for(uint32_t ly = 0; ly < 16; ly++)
|
|
||||||
{
|
|
||||||
if (/*designations[lx][ly].bits.hidden == 0 && */
|
|
||||||
designations[lx][ly].bits.dig == 0 &&
|
|
||||||
vec_count(targets, DFHack::tileShape(tiles[lx][ly])) > 0)
|
|
||||||
{
|
|
||||||
DigTarget dt(
|
|
||||||
x, y, z,
|
|
||||||
lx, ly,
|
|
||||||
x_source, y_source, z_source);
|
|
||||||
candidates.push_back(dt);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
{
|
|
||||||
cout << "target found at " << dt.real_x << " " << dt.real_y << " " << dt.z;
|
|
||||||
cout << ", " << dt.source_distance << " tiles to source" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // local y
|
|
||||||
} // local x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we found more tiles than was requested, sort them by distance to source,
|
|
||||||
// keep the front 'num' elements and drop the rest
|
|
||||||
if (num != -1 && candidates.size() > (unsigned int)num)
|
|
||||||
{
|
|
||||||
sort(candidates.begin(), candidates.end());
|
|
||||||
candidates.resize(num);
|
|
||||||
}
|
|
||||||
num = candidates.size();
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
cout << "=== proceeding to designating targets ===" << endl;
|
|
||||||
|
|
||||||
// mark the tiles for actual digging
|
|
||||||
for (vector<DigTarget>::const_iterator i = candidates.begin(); i != candidates.end(); ++i)
|
|
||||||
{
|
|
||||||
if (verbose)
|
|
||||||
{
|
|
||||||
cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z;
|
|
||||||
cout << ", " << (*i).source_distance << " tiles to source" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO this could probably be made much better, theres a big chance the trees are on the same grid
|
|
||||||
Maps->ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, &designations);
|
|
||||||
designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default;
|
|
||||||
Maps->WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, &designations);
|
|
||||||
|
|
||||||
// Mark as dirty so the jobs are properly picked up by the dwarves
|
|
||||||
Maps->WriteDirtyBit((*i).grid_x, (*i).grid_y, (*i).z, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
void test()
|
|
||||||
{
|
|
||||||
//////////////////////////
|
|
||||||
// DigTarget
|
|
||||||
{
|
|
||||||
DigTarget dt(
|
|
||||||
20, 35, 16,
|
|
||||||
10, 12, 14);
|
|
||||||
|
|
||||||
assert(dt.grid_x == 1);
|
|
||||||
assert(dt.grid_y == 2);
|
|
||||||
|
|
||||||
assert(dt.local_x == 4);
|
|
||||||
assert(dt.local_y == 3);
|
|
||||||
|
|
||||||
assert(dt.real_x == 20);
|
|
||||||
assert(dt.real_y == 35);
|
|
||||||
|
|
||||||
assert(dt.z == 16);
|
|
||||||
assert(dt.source_distance == 35);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
DigTarget dt(
|
|
||||||
2, 4, 16,
|
|
||||||
5, 10,
|
|
||||||
10, 12, 14);
|
|
||||||
|
|
||||||
assert(dt.grid_x == 2);
|
|
||||||
assert(dt.grid_y == 4);
|
|
||||||
|
|
||||||
assert(dt.local_x == 5);
|
|
||||||
assert(dt.local_y == 10);
|
|
||||||
|
|
||||||
assert(dt.real_x == 37);
|
|
||||||
assert(dt.real_y == 74);
|
|
||||||
|
|
||||||
assert(dt.z == 16);
|
|
||||||
assert(dt.source_distance == 91);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// string splitter
|
|
||||||
{
|
|
||||||
vector<string> tokens;
|
|
||||||
string src = "10,9,11";
|
|
||||||
string delim = ",";
|
|
||||||
string_split(tokens, src, delim);
|
|
||||||
|
|
||||||
assert(tokens.size() == 3);
|
|
||||||
assert(tokens[0] == "10");
|
|
||||||
assert(tokens[1] == "9");
|
|
||||||
assert(tokens[2] == "11");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
vector<string> tokens;
|
|
||||||
string src = "10";
|
|
||||||
string delim = ",";
|
|
||||||
string_split(tokens, src, delim);
|
|
||||||
|
|
||||||
assert(tokens.size() == 1);
|
|
||||||
assert(tokens[0] == "10");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
vector<uint16_t> targets;
|
|
||||||
parse_int_csv(targets, "9,10");
|
|
||||||
assert(targets[0] == 9);
|
|
||||||
assert(targets[1] == 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main (int argc, char** argv)
|
|
||||||
{
|
|
||||||
//test();
|
|
||||||
|
|
||||||
// Command line options
|
|
||||||
string s_targets;
|
|
||||||
string s_origin;
|
|
||||||
bool verbose;
|
|
||||||
int max = 10;
|
|
||||||
argstream as(argc,argv);
|
|
||||||
|
|
||||||
as >>option('v',"verbose",verbose,"Active verbose mode")
|
|
||||||
>>parameter('o',"origin",s_origin,"Close to where we should designate targets, format: x,y,z")
|
|
||||||
>>parameter('t',"targets",s_targets,"What kinds of tile we should designate, format: type1,type2")
|
|
||||||
>>parameter('m',"max",max,"The maximum limit of designated targets")
|
|
||||||
>>help();
|
|
||||||
|
|
||||||
// some commands need extra care
|
|
||||||
vector<uint16_t> targets;
|
|
||||||
parse_int_csv(targets, s_targets);
|
|
||||||
|
|
||||||
vector<uint16_t> origin;
|
|
||||||
parse_int_csv(origin, s_origin);
|
|
||||||
|
|
||||||
// sane check
|
|
||||||
if (!as.isOk())
|
|
||||||
{
|
|
||||||
cout << as.errorLog();
|
|
||||||
}
|
|
||||||
else if (targets.size() == 0 || origin.size() != 3)
|
|
||||||
{
|
|
||||||
cout << as.usage();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context *DF = DFMgr.getSingleContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DF->Attach();
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
DFHack::Maps *Maps = DF->getMaps();
|
|
||||||
if (Maps && Maps->Start())
|
|
||||||
{
|
|
||||||
int count = dig(Maps, targets, max, origin[0],origin[1],origin[2], verbose);
|
|
||||||
cout << count << " targets designated" << endl;
|
|
||||||
Maps->Finish();
|
|
||||||
|
|
||||||
if (!DF->Detach())
|
|
||||||
{
|
|
||||||
cerr << "Unable to detach DF process" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cerr << "Unable to init map" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cout << "Done. Press any key to continue" << endl;
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file digger2.cpp
|
|
||||||
* @author rOut
|
|
||||||
*
|
|
||||||
* Improved digger tool.
|
|
||||||
*
|
|
||||||
* Takes a text file as first an only argument.
|
|
||||||
* The text file is read as a grid, and every character represents a designation for a tile.
|
|
||||||
* Allowed characters are 'd' for dig, 'u' for up stairs, 'j' for down stairs, 'i' for up and down stairs, 'h' for channel, 'r' for upward ramp and 'x' to remove designation.
|
|
||||||
* Other characters don't do anything and can be used for padding.
|
|
||||||
* The designation pattern is the wrote in game memory, centered on the current cursor position. Thus, the game needs to be in designation mode or, perhaps, any other mode that have a cursor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <assert.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <DFTileTypes.h>
|
|
||||||
#define BLOCK_SIZE 16
|
|
||||||
|
|
||||||
|
|
||||||
void dig(DFHack::Maps* layers, DFHack::Gui* Gui, ::std::vector< ::std::string >& dig_map, bool verbose = false)
|
|
||||||
{
|
|
||||||
int32_t x_cent;
|
|
||||||
int32_t y_cent;
|
|
||||||
int32_t z_cent;
|
|
||||||
Gui->getCursorCoords(x_cent, y_cent, z_cent);
|
|
||||||
|
|
||||||
// ::std::cout << "x_cent: " << x_cent << " y_cent: " << y_cent << " z_cent: " << z_cent << ::std::endl;
|
|
||||||
|
|
||||||
int32_t z_from = z_cent;
|
|
||||||
int32_t z = 0;
|
|
||||||
|
|
||||||
uint32_t x_max;
|
|
||||||
uint32_t y_max;
|
|
||||||
uint32_t z_max;
|
|
||||||
layers->getSize(x_max, y_max, z_max);
|
|
||||||
|
|
||||||
// ::std::cout << "x_max: " << x_max << " y_max: " << y_max << " z_max: " << z_max << ::std::endl;
|
|
||||||
|
|
||||||
int32_t dig_height = dig_map.size();
|
|
||||||
int32_t y_from = y_cent - (dig_height / 2);
|
|
||||||
// ::std::cout << "dig_height: " << dig_height << ::std::endl;
|
|
||||||
// ::std::cout << "y_from: " << y_from << ::std::endl;
|
|
||||||
|
|
||||||
int32_t y = 0;
|
|
||||||
DFHack::designations40d designations;
|
|
||||||
DFHack::tiletypes40d tiles;
|
|
||||||
::std::vector< ::std::string >::iterator str_it;
|
|
||||||
for (str_it = dig_map.begin(); str_it != dig_map.end(); ++str_it) {
|
|
||||||
int32_t dig_width = str_it->size();
|
|
||||||
int32_t x_from = x_cent - (dig_width / 2);
|
|
||||||
|
|
||||||
// ::std::cout << "x_cent: " << x_cent << " y_cent: " << y_cent << " z_cent: " << z_cent << ::std::endl;
|
|
||||||
// ::std::cout << "dig_width: " << dig_width << ::std::endl;
|
|
||||||
// ::std::cout << "x_from: " << x_from << ::std::endl;
|
|
||||||
|
|
||||||
int32_t x = 0;
|
|
||||||
::std::string::iterator chr_it;
|
|
||||||
for (chr_it = str_it->begin(); chr_it != str_it ->end(); ++chr_it)
|
|
||||||
{
|
|
||||||
int32_t x_grid = (x_from + x) / BLOCK_SIZE;
|
|
||||||
int32_t y_grid = (y_from + y) / BLOCK_SIZE;
|
|
||||||
int32_t z_grid = z_from + z;
|
|
||||||
int32_t x_locl = (x_from + x) - x_grid * BLOCK_SIZE;
|
|
||||||
int32_t y_locl = (y_from + y) - y_grid * BLOCK_SIZE;
|
|
||||||
int32_t z_locl = 0;
|
|
||||||
|
|
||||||
if (x_grid >= 0 && y_grid >= 0 && x_grid < x_max && y_grid < y_max)
|
|
||||||
{
|
|
||||||
// TODO this could probably be made much better, theres a big chance the trees are on the same grid
|
|
||||||
layers->ReadDesignations(x_grid, y_grid, z_grid, &designations);
|
|
||||||
layers->ReadTileTypes(x_grid, y_grid, z_grid, &tiles);
|
|
||||||
|
|
||||||
// ::std::cout << ::std::hex << "designations: " << designations[x_locl][y_locl].bits.dig << ::std::dec << ::std::endl;
|
|
||||||
DFHack::naked_designation & des = designations[x_locl][y_locl].bits;
|
|
||||||
if ( DFHack::tileShape(tiles[x_locl][y_locl]) == DFHack::WALL)
|
|
||||||
{
|
|
||||||
switch ((char) *chr_it)
|
|
||||||
{
|
|
||||||
case 'd':
|
|
||||||
des.dig = DFHack::designation_default;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
des.dig = DFHack::designation_u_stair;
|
|
||||||
break;
|
|
||||||
case 'j':
|
|
||||||
des.dig = DFHack::designation_d_stair;
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
des.dig = DFHack::designation_ud_stair;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
des.dig = DFHack::designation_channel;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
des.dig = DFHack::designation_ramp;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
des.dig = DFHack::designation_no;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
{
|
|
||||||
::std::cout << "designating " << (char) *chr_it << " at " << x_from + x << " " << y_from + y << " " << z_from + z << ::std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
layers->WriteDesignations(x_grid, y_grid, z_grid, &designations);
|
|
||||||
|
|
||||||
// Mark as dirty so the jobs are properly picked up by the dwarves
|
|
||||||
layers->WriteDirtyBit(x_grid, y_grid, z_grid, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++x;
|
|
||||||
}
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
if(argc < 2) {
|
|
||||||
::std::cout << "gimme a file!" << ::std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::std::ifstream map_in(argv[1]);
|
|
||||||
|
|
||||||
::std::vector< ::std::string > dig_map;
|
|
||||||
while (map_in.good() && !map_in.eof() && !map_in.bad()) {
|
|
||||||
::std::string line;
|
|
||||||
map_in >> line;
|
|
||||||
|
|
||||||
dig_map.push_back(line);
|
|
||||||
}
|
|
||||||
dig_map.resize(dig_map.size() - 1);
|
|
||||||
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context * DF = DFMgr.getSingleContext();
|
|
||||||
|
|
||||||
try {
|
|
||||||
DF->Attach();
|
|
||||||
} catch (::std::exception& e) {
|
|
||||||
::std::cerr << e.what() << ::std::endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
::std::cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFHack::Maps *layers = DF->getMaps();
|
|
||||||
if (layers && layers->Start()) {
|
|
||||||
|
|
||||||
dig(layers, DF->getGui(), dig_map, true);
|
|
||||||
|
|
||||||
::std::cout << "Finished digging" << ::std::endl;
|
|
||||||
layers->Finish();
|
|
||||||
|
|
||||||
if (!DF->Detach()) {
|
|
||||||
::std::cerr << "Unable to detach DF process" << ::std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
::std::cerr << "Unable to init map" << ::std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
::std::cout << "Done. Press any key to continue" << ::std::endl;
|
|
||||||
::std::cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,315 +0,0 @@
|
|||||||
//
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <limits>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <conio.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <DFTileTypes.h>
|
|
||||||
|
|
||||||
//Avoid including Windows.h because it causes name clashes
|
|
||||||
extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long milliseconds);
|
|
||||||
|
|
||||||
//Trim
|
|
||||||
#define WHITESPACE " \t\r\n"
|
|
||||||
inline string trimr(const string & s, const string & t = WHITESPACE)
|
|
||||||
{
|
|
||||||
string d (s);
|
|
||||||
string::size_type i (d.find_last_not_of (t));
|
|
||||||
if (i == string::npos)
|
|
||||||
return "";
|
|
||||||
else
|
|
||||||
return d.erase (d.find_last_not_of (t) + 1) ;
|
|
||||||
}
|
|
||||||
inline string triml(const string & s, const string & t = WHITESPACE)
|
|
||||||
{
|
|
||||||
string d (s);
|
|
||||||
return d.erase (0, s.find_first_not_of (t)) ;
|
|
||||||
}
|
|
||||||
inline string trim(const string & s, const string & t = WHITESPACE)
|
|
||||||
{
|
|
||||||
string d (s);
|
|
||||||
return triml(trimr(d, t), t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printtiletype( int i ){
|
|
||||||
printf("%s\n%4i ; %-13s ; %-11s ; %c ; %-12s ; %s\n",
|
|
||||||
( DFHack::tileTypeTable[i].name ? DFHack::tileTypeTable[i].name : "[invalid tile]" ),
|
|
||||||
i,
|
|
||||||
( DFHack::tileTypeTable[i].name ? DFHack::TileShapeString[ DFHack::tileTypeTable[i].shape ] : "" ),
|
|
||||||
( DFHack::tileTypeTable[i].name ? DFHack::TileMaterialString[ DFHack::tileTypeTable[i].material ] : "" ),
|
|
||||||
( DFHack::tileTypeTable[i].variant ? '0'+ DFHack::tileTypeTable[i].variant : ' ' ),
|
|
||||||
( DFHack::tileTypeTable[i].special ? DFHack::TileSpecialString[ DFHack::tileTypeTable[i].special ] : "" ),
|
|
||||||
( DFHack::tileTypeTable[i].direction.whole ? DFHack::tileTypeTable[i].direction.getStr() : "" ),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
int32_t x,y,z,tx,ty;
|
|
||||||
//DFHack::designations40d designations;
|
|
||||||
DFHack::tiletypes40d tiles;
|
|
||||||
//DFHack::t_temperatures temp1,temp2;
|
|
||||||
uint32_t x_max,y_max,z_max;
|
|
||||||
int32_t oldT, newT;
|
|
||||||
int count, dirty;
|
|
||||||
|
|
||||||
//Brush defaults
|
|
||||||
DFHack::TileShape BrushClass = DFHack::WALL;
|
|
||||||
DFHack::TileMaterial BrushMat = DFHack::tilematerial_invalid;
|
|
||||||
int BrushType = -1;
|
|
||||||
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context *DF;
|
|
||||||
DFHack::Maps * Maps;
|
|
||||||
DFHack::Gui * Gui;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DF=DFMgr.getSingleContext();
|
|
||||||
DF->Attach();
|
|
||||||
Maps = DF->getMaps();
|
|
||||||
Maps->Start();
|
|
||||||
Maps->getSize(x_max,y_max,z_max);
|
|
||||||
Gui = DF->getGui();
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
bool end = false;
|
|
||||||
cout << "Welcome to the Tile Drawing tool.\nType 'help' or ? for a list of available commands, 'q' to quit" << endl;
|
|
||||||
string mode = "wall";
|
|
||||||
string command = "";
|
|
||||||
|
|
||||||
while(!end)
|
|
||||||
{
|
|
||||||
DF->Resume();
|
|
||||||
|
|
||||||
cout << endl << ":";
|
|
||||||
getline(cin, command);
|
|
||||||
int ch = command[0];
|
|
||||||
if(command.length()<=0) ch=0;
|
|
||||||
if( ((int)command.find("help")) >=0 ) ch='?'; //under windows, find was casting unsigned!
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
case '?':
|
|
||||||
cout << "Modes:" << endl
|
|
||||||
<< "O - draw Open Space" << endl
|
|
||||||
<< "M - draw material only (shape unchanged)" << endl
|
|
||||||
<< "m number - use Material value entered" << endl
|
|
||||||
<< "r - use Rock/stone material" << endl
|
|
||||||
<< "l - use Soil material" << endl
|
|
||||||
<< "v - use Vein material" << endl
|
|
||||||
<< "H - draw tile shape only (material unchanged)" << endl
|
|
||||||
<< "h number - draw Tile Shape value entered" << endl
|
|
||||||
<< "w - draw Wall tiles" << endl
|
|
||||||
<< "f - draw Floor tiles" << endl
|
|
||||||
<< "t number - draw exact tile type entered" << endl
|
|
||||||
<< "Commands:" << endl
|
|
||||||
<< "p - print tile shapes and materials, and current brush" << endl
|
|
||||||
<< "P - print all tile types" << endl
|
|
||||||
<< "q - quit" << endl
|
|
||||||
<< "help OR ? - print this list of commands" << endl
|
|
||||||
<< "d - being drawing" << endl
|
|
||||||
<< endl
|
|
||||||
<< "Usage:\nChoose a mode (default is walls), then enter 'd' to being drawing.\nMove the cursor in DF wherever you want to draw.\nPress any key to pause drawing." << endl;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
//Classes
|
|
||||||
printf("\nTile Type Classes:\n");
|
|
||||||
for(int i=0;i<DFHack::tileshape_count;++i)
|
|
||||||
{
|
|
||||||
printf("%4i ; %s\n", i, DFHack::TileShapeString[i] ,0 );
|
|
||||||
}
|
|
||||||
//Materials
|
|
||||||
printf("\nTile Type Materials:\n");
|
|
||||||
for(int i=0;i<DFHack::tilematerial_count;++i)
|
|
||||||
{
|
|
||||||
printf("%4i ; %s\n", i, DFHack::TileMaterialString[i] ,0 );
|
|
||||||
}
|
|
||||||
//fall through...
|
|
||||||
case 10:
|
|
||||||
case 13:
|
|
||||||
case 0:
|
|
||||||
//Print current cursor & brush settings.
|
|
||||||
cout << "\nCurrent Brush:\n";
|
|
||||||
cout << "tile = ";
|
|
||||||
if(BrushClass<0) cout<<"(not drawing)"; else cout<<DFHack::TileShapeString[BrushClass]; cout << endl;
|
|
||||||
cout << "mat = ";
|
|
||||||
if(BrushMat<0) cout<<"(not drawing)"; else cout<<DFHack::TileMaterialString[BrushMat]; cout << endl;
|
|
||||||
cout << "type = ";
|
|
||||||
if(BrushType<0){
|
|
||||||
cout<<"(not drawing)";
|
|
||||||
}else{
|
|
||||||
printtiletype(BrushType);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
cout << "\nAll Valid Tile Types:\n";
|
|
||||||
for(int i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
|
|
||||||
{
|
|
||||||
if( DFHack::tileTypeTable[i].name )
|
|
||||||
printtiletype(i);
|
|
||||||
}
|
|
||||||
case 'w':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushClass = DFHack::WALL;
|
|
||||||
cout << "Tile brush shape set to Wall." << endl;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushClass = DFHack::FLOOR;
|
|
||||||
cout << "Tile brush shape set to Floor." << endl;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushClass = (DFHack::TileShape)atol( command.c_str()+1 );
|
|
||||||
cout << "Tile brush shape set to " << BrushClass << endl;
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
BrushClass = DFHack::tileshape_invalid;
|
|
||||||
cout << "Tile brush will not draw tile shape." << endl;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushMat = DFHack::STONE;
|
|
||||||
cout << "Tile brush material set to Rock." << endl;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushMat = DFHack::SOIL;
|
|
||||||
cout << "Tile brush material set to Soil." << endl;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushMat = DFHack::VEIN;
|
|
||||||
cout << "Tile brush material set to Vein." << endl;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushMat = (DFHack::TileMaterial)atol( command.c_str()+1 );
|
|
||||||
cout << "Tile brush material set to " << BrushMat << endl;
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
BrushMat = DFHack::tilematerial_invalid;
|
|
||||||
cout << "Tile brush will not draw material." << endl;
|
|
||||||
break;
|
|
||||||
case 'O':
|
|
||||||
BrushType=-1;
|
|
||||||
BrushClass = DFHack::EMPTY;
|
|
||||||
BrushMat = DFHack::AIR;
|
|
||||||
cout << "Tile brush will draw Open Space." << endl;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
BrushClass = DFHack::tileshape_invalid ;
|
|
||||||
BrushMat = DFHack::tilematerial_invalid;
|
|
||||||
BrushType = atol( command.c_str()+1 );
|
|
||||||
cout << "Tile brush type set to:" << endl;
|
|
||||||
printtiletype(BrushType);
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
end = true;
|
|
||||||
cout << "Bye!" << endl;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
{
|
|
||||||
count=0;
|
|
||||||
cout << "Beginning to draw at cursor." << endl << "Press any key to stop drawing." << endl;
|
|
||||||
//DF->Suspend();
|
|
||||||
kbhit(); //throw away, just to be sure.
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
if(!Maps->Start())
|
|
||||||
{
|
|
||||||
cout << "Can't see any DF map loaded." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!Gui->getCursorCoords(x,y,z))
|
|
||||||
{
|
|
||||||
cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//cout << "cursor coords: " << x << "/" << y << "/" << z << endl;
|
|
||||||
tx=x%16; ty=y%16;
|
|
||||||
|
|
||||||
if(!Maps->isValidBlock(x/16,y/16,z))
|
|
||||||
{
|
|
||||||
cout << "Invalid block." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Read the tiles.
|
|
||||||
dirty=0;
|
|
||||||
Maps->ReadTileTypes((x/16),(y/16),z, &tiles);
|
|
||||||
oldT = tiles[tx][ty];
|
|
||||||
|
|
||||||
newT = -1;
|
|
||||||
if( 0<BrushType ){
|
|
||||||
//Explicit tile type set. Trust the user.
|
|
||||||
newT = BrushType;
|
|
||||||
}else if( 0==BrushMat && 0==BrushClass ){
|
|
||||||
//Special case, Empty Air.
|
|
||||||
newT = 32;
|
|
||||||
}else if( BrushMat>=0 && BrushClass>=0 && ( BrushClass != DFHack::tileTypeTable[oldT].shape || BrushMat != DFHack::tileTypeTable[oldT].material) ){
|
|
||||||
//Set tile material and class
|
|
||||||
newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
|
|
||||||
if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid, DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
|
|
||||||
if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 );
|
|
||||||
}else if( BrushMat<0 && BrushClass>=0 && BrushClass != DFHack::tileTypeTable[oldT].shape ){
|
|
||||||
//Set current tile class only, as accurately as can be expected
|
|
||||||
newT = DFHack::findSimilarTileType(oldT,BrushClass);
|
|
||||||
}else if( BrushClass<0 && BrushMat>=0 && BrushMat != DFHack::tileTypeTable[oldT].material ){
|
|
||||||
//Set current tile material only
|
|
||||||
newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
|
|
||||||
if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
|
|
||||||
if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 );
|
|
||||||
}
|
|
||||||
//If no change, skip it (couldn't find a good tile type, or already what we want)
|
|
||||||
if ( newT > 0 && oldT != newT ){
|
|
||||||
//Set new tile type
|
|
||||||
tiles[tx][ty] = newT;
|
|
||||||
dirty=-1;
|
|
||||||
}
|
|
||||||
//If anything was changed, write it all.
|
|
||||||
if (dirty)
|
|
||||||
{
|
|
||||||
//Maps->WriteDesignations(x/16,y/16,z/16, &designations);
|
|
||||||
Maps->WriteTileTypes(x/16,y/16,z, &tiles);
|
|
||||||
printf("(%4d,%4d,%4d)",x,y,z);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maps->Finish();
|
|
||||||
|
|
||||||
Sleep(10);
|
|
||||||
if( kbhit() ) break;
|
|
||||||
}
|
|
||||||
cin.clear();
|
|
||||||
cout << endl << count << " tiles were drawn." << endl << "Drawing halted. Entering command mode." << endl;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Unknown command: " << command << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
DF->Detach();
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cout << "Done. Press any key to continue" << endl;
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,217 +0,0 @@
|
|||||||
/* Fixes bug 3708 (Ghosts that can't be engraved on a slab).
|
|
||||||
|
|
||||||
Cause of the bug:
|
|
||||||
|
|
||||||
In order to be engraved on a slab, the creature must be
|
|
||||||
a historical figure, i.e. be in the historical figure list
|
|
||||||
of the Legends mode. It seems that caravan guards are not
|
|
||||||
added to that list until they do something notable, e.g.
|
|
||||||
kill a goblin. Unfortunately, their own death doesn't
|
|
||||||
trigger this sometimes.
|
|
||||||
|
|
||||||
Solution:
|
|
||||||
|
|
||||||
Steal a historical figure entry from a dead goblin, by
|
|
||||||
replacing the IDs in the structures; also overwrite his
|
|
||||||
name, race and profession to make the menus make slightly
|
|
||||||
more sense.
|
|
||||||
|
|
||||||
Downsides:
|
|
||||||
|
|
||||||
- Obviously, this is an ugly hack.
|
|
||||||
- The Legends mode still lists the guard as belonging to
|
|
||||||
the goblin civilization, and killed by whoever killed the
|
|
||||||
original goblin. There might be other inconsistencies.
|
|
||||||
|
|
||||||
Positive sides:
|
|
||||||
|
|
||||||
- Avoids messing with tricky creature control code,
|
|
||||||
by allowing the ghost to be removed naturally.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <climits>
|
|
||||||
#include <string.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <list>
|
|
||||||
#include <stdio.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#define DFHACK_WANT_MISCUTILS
|
|
||||||
#include <DFHack.h>
|
|
||||||
|
|
||||||
enum likeType
|
|
||||||
{
|
|
||||||
FAIL = 0,
|
|
||||||
MATERIAL = 1,
|
|
||||||
ITEM = 2,
|
|
||||||
FOOD = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
DFHack::Materials * Materials;
|
|
||||||
DFHack::VersionInfo *mem;
|
|
||||||
DFHack::Creatures * Creatures = NULL;
|
|
||||||
|
|
||||||
void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature)
|
|
||||||
{
|
|
||||||
cout << "Address: " << hex << creature.origin << dec << ", creature race: " << Materials->raceEx[creature.race].rawname
|
|
||||||
<< ", position: " << creature.x << "x " << creature.y << "y "<< creature.z << "z" << endl
|
|
||||||
<< "Name: " << creature.name.first_name;
|
|
||||||
|
|
||||||
if (creature.name.nickname[0])
|
|
||||||
cout << " `" << creature.name.nickname << "'";
|
|
||||||
|
|
||||||
DFHack::Translation * Tran = DF->getTranslation();
|
|
||||||
|
|
||||||
cout << " " << Tran->TranslateName(creature.name,false)
|
|
||||||
<< " (" << Tran->TranslateName(creature.name,true) << ")" << endl;
|
|
||||||
|
|
||||||
cout << "Profession: " << mem->getProfession(creature.profession);
|
|
||||||
|
|
||||||
if(creature.custom_profession[0])
|
|
||||||
cout << ", custom: " << creature.custom_profession;
|
|
||||||
|
|
||||||
uint32_t dayoflife = creature.birth_year*12*28 + creature.birth_time/1200;
|
|
||||||
cout << endl
|
|
||||||
<< "Born on the year " << creature.birth_year
|
|
||||||
<< ", month " << (creature.birth_time/1200/28)
|
|
||||||
<< ", day " << ((creature.birth_time/1200) % 28 + 1)
|
|
||||||
<< ", " << dayoflife << " days lived." << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main (int numargs, char ** args)
|
|
||||||
{
|
|
||||||
DFHack::World * World;
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context* DF;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DF = DFMgr.getSingleContext();
|
|
||||||
DF->Attach();
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Creatures = DF->getCreatures();
|
|
||||||
Materials = DF->getMaterials();
|
|
||||||
World = DF->getWorld();
|
|
||||||
DFHack::Translation * Tran = DF->getTranslation();
|
|
||||||
|
|
||||||
uint32_t numCreatures;
|
|
||||||
if(!Creatures->Start(numCreatures))
|
|
||||||
{
|
|
||||||
cerr << "Can't get creatures" << endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Materials->ReadCreatureTypes();
|
|
||||||
Materials->ReadCreatureTypesEx();
|
|
||||||
|
|
||||||
mem = DF->getMemoryInfo();
|
|
||||||
DFHack::Process *p = DF->getProcess();
|
|
||||||
|
|
||||||
if(!Tran->Start())
|
|
||||||
{
|
|
||||||
cerr << "Can't get name tables" << endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFHack::OffsetGroup *ogc = mem->getGroup("Creatures")->getGroup("creature");
|
|
||||||
uint32_t o_flags3 = ogc->getOffset("flags3");
|
|
||||||
uint32_t o_c_hfid = ogc->getGroup("advanced")->getOffset("hist_figure_id");
|
|
||||||
|
|
||||||
std::list<uint32_t> goblins;
|
|
||||||
std::list<uint32_t> ghosts;
|
|
||||||
|
|
||||||
for(uint32_t i = 0; i < numCreatures; i++)
|
|
||||||
{
|
|
||||||
DFHack::t_creature temp;
|
|
||||||
Creatures->ReadCreature(i,temp);
|
|
||||||
|
|
||||||
int32_t hfid = p->readDWord(temp.origin + o_c_hfid);
|
|
||||||
|
|
||||||
if (hfid > 0) {
|
|
||||||
if (temp.flags1.bits.dead) {
|
|
||||||
std::string name = Materials->raceEx[temp.race].rawname;
|
|
||||||
if (name == "GOBLIN")
|
|
||||||
goblins.push_back(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t flags3 = p->readDWord(temp.origin + o_flags3);
|
|
||||||
if (!(flags3 & 0x1000))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ghosts.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (goblins.size() >= ghosts.size() && ghosts.size() > 0)
|
|
||||||
{
|
|
||||||
DFHack::OffsetGroup *grp_figures = mem->getGroup("Legends")->getGroup("figures");
|
|
||||||
uint32_t f_vector = p->readDWord(grp_figures->getAddress("vector"));
|
|
||||||
uint32_t f_id = grp_figures->getOffset("figure_id");
|
|
||||||
uint32_t f_unit = grp_figures->getOffset("unit_id");
|
|
||||||
uint32_t f_name = grp_figures->getOffset("name");
|
|
||||||
uint32_t f_race = grp_figures->getOffset("race");
|
|
||||||
uint32_t f_profession = grp_figures->getOffset("profession");
|
|
||||||
|
|
||||||
for (std::list<uint32_t>::iterator it = ghosts.begin(); it != ghosts.end(); ++it)
|
|
||||||
{
|
|
||||||
int i = *it;
|
|
||||||
DFHack::t_creature ghost;
|
|
||||||
Creatures->ReadCreature(i,ghost);
|
|
||||||
|
|
||||||
printCreature(DF,ghost);
|
|
||||||
|
|
||||||
int igoblin = goblins.front();
|
|
||||||
goblins.pop_front();
|
|
||||||
DFHack::t_creature goblin;
|
|
||||||
Creatures->ReadCreature(igoblin,goblin);
|
|
||||||
|
|
||||||
printCreature(DF,goblin);
|
|
||||||
|
|
||||||
int32_t hfid = p->readDWord(goblin.origin + o_c_hfid);
|
|
||||||
uint32_t fptr = p->readDWord(f_vector + 4*hfid);
|
|
||||||
|
|
||||||
if (p->readDWord(fptr + f_id) != hfid ||
|
|
||||||
p->readDWord(fptr + f_unit) != goblin.id ||
|
|
||||||
p->readWord(fptr + f_race) != goblin.race)
|
|
||||||
{
|
|
||||||
cout << "Data structure inconsistency detected, aborting.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (1) {
|
|
||||||
p->writeDWord(goblin.origin + o_c_hfid, -1);
|
|
||||||
p->writeDWord(ghost.origin + o_c_hfid, hfid);
|
|
||||||
p->writeDWord(fptr + f_unit, ghost.id);
|
|
||||||
p->writeWord(fptr + f_race, ghost.race);
|
|
||||||
p->writeWord(fptr + f_profession, ghost.profession);
|
|
||||||
Creatures->CopyNameTo(ghost, fptr + f_name);
|
|
||||||
cout << "Pair succesfully patched." << endl << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cout << "No suitable ghosts, or not enough goblins." << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Creatures->Finish();
|
|
||||||
DF->Detach();
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cout << "Done. Press any key to continue" << endl;
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
// This is a simple bit writer... it marks the whole map as a creature lair, preventing item scatter.
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
using namespace std;
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <extra/termutil.h>
|
|
||||||
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
bool temporary_terminal = TemporaryTerminal();
|
|
||||||
uint32_t x_max,y_max,z_max;
|
|
||||||
DFHack::occupancies40d occupancies;
|
|
||||||
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
DFHack::Context *DF;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DF = DFMgr.getSingleContext();
|
|
||||||
DF->Attach();
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
if(temporary_terminal)
|
|
||||||
cin.ignore();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFHack::Maps *Maps =DF->getMaps();
|
|
||||||
|
|
||||||
// init the map
|
|
||||||
if(!Maps->Start())
|
|
||||||
{
|
|
||||||
cerr << "Can't init map." << endl;
|
|
||||||
if(temporary_terminal)
|
|
||||||
cin.ignore();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Designating, please wait..." << endl;
|
|
||||||
|
|
||||||
Maps->getSize(x_max,y_max,z_max);
|
|
||||||
for(uint32_t x = 0; x< x_max;x++)
|
|
||||||
{
|
|
||||||
for(uint32_t y = 0; y< y_max;y++)
|
|
||||||
{
|
|
||||||
for(uint32_t z = 0; z< z_max;z++)
|
|
||||||
{
|
|
||||||
if(Maps->isValidBlock(x,y,z))
|
|
||||||
{
|
|
||||||
// read block designations
|
|
||||||
Maps->ReadOccupancy(x,y,z, &occupancies);
|
|
||||||
//Maps->ReadTileTypes(x,y,z, &tiles);
|
|
||||||
// change the monster_lair flag to 1
|
|
||||||
for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++)
|
|
||||||
{
|
|
||||||
// add tile type chack here
|
|
||||||
occupancies[i][j].bits.monster_lair = 1;
|
|
||||||
}
|
|
||||||
// write the designations back
|
|
||||||
Maps->WriteOccupancy(x,y,z, &occupancies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(temporary_terminal)
|
|
||||||
{
|
|
||||||
cout << "The map has been marked as a creature lair. Items shouldn't scatter." << endl;
|
|
||||||
cin.ignore();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
import time
|
|
||||||
from context import ContextManager
|
|
||||||
|
|
||||||
class HideBlock(object):
|
|
||||||
__slots__ = [ "x", "y", "z", "hiddens" ]
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.x = 0
|
|
||||||
self.y = 0
|
|
||||||
self.z = 0
|
|
||||||
self.hiddens = [[0 for i in xrange(16)] for j in xrange(16)]
|
|
||||||
|
|
||||||
df_cm = ContextManager("Memory.xml")
|
|
||||||
df = df_cm.get_single_context()
|
|
||||||
|
|
||||||
df.attach()
|
|
||||||
|
|
||||||
m = df.maps
|
|
||||||
w = df.world
|
|
||||||
|
|
||||||
print "Pausing..."
|
|
||||||
|
|
||||||
w.start()
|
|
||||||
|
|
||||||
#this mimics the hack in the C++ reveal tool that attempts to ensure that DF isn't in the middle of
|
|
||||||
#a frame update
|
|
||||||
w.set_pause_state(True)
|
|
||||||
df.resume()
|
|
||||||
time.sleep(1)
|
|
||||||
df.suspend()
|
|
||||||
|
|
||||||
w.finish()
|
|
||||||
|
|
||||||
m.start()
|
|
||||||
|
|
||||||
print "Revealing, please wait..."
|
|
||||||
|
|
||||||
m_x, m_y, m_z = m.size
|
|
||||||
hide_blocks = []
|
|
||||||
|
|
||||||
for x in xrange(m_x):
|
|
||||||
for y in xrange(m_y):
|
|
||||||
for z in xrange(m_z):
|
|
||||||
if m.is_valid_block(x, y, z):
|
|
||||||
hb = HideBlock()
|
|
||||||
|
|
||||||
hb.x = x
|
|
||||||
hb.y = y
|
|
||||||
hb.z = z
|
|
||||||
|
|
||||||
d = m.read_designations(x, y, z)
|
|
||||||
|
|
||||||
for k_i, i in enumerate(d):
|
|
||||||
for k_j, j in enumerate(i):
|
|
||||||
hb.hiddens[k_i][k_j] = j.bits.hidden
|
|
||||||
|
|
||||||
j.bits.hidden = 0
|
|
||||||
|
|
||||||
hide_blocks.append(hb)
|
|
||||||
|
|
||||||
m.write_designations(x, y, z, d)
|
|
||||||
|
|
||||||
m.finish()
|
|
||||||
df.detach()
|
|
||||||
|
|
||||||
print "Map revealed. The game has been paused for you."
|
|
||||||
print "Unpausing can unleash the forces of hell!"
|
|
||||||
print "Press any key to unreveal."
|
|
||||||
print "Close to keep the map revealed !!FOREVER!!"
|
|
||||||
|
|
||||||
raw_input()
|
|
||||||
|
|
||||||
print "Unrevealing...please wait"
|
|
||||||
|
|
||||||
df.attach()
|
|
||||||
m = df.maps
|
|
||||||
m.start()
|
|
||||||
|
|
||||||
for h in hide_blocks:
|
|
||||||
d = m.read_designations(h.x, h.y, h.z)
|
|
||||||
|
|
||||||
for k_i, i in enumerate(h.hiddens):
|
|
||||||
for k_j, j in enumerate(i):
|
|
||||||
d[k_i][k_j].bits.hidden = j
|
|
||||||
|
|
||||||
m.write_designations(h.x, h.y, h.z, d)
|
|
||||||
|
|
||||||
m.finish()
|
|
||||||
|
|
||||||
print "Done. Press any key to continue"
|
|
||||||
raw_input()
|
|
||||||
|
|
||||||
df.detach()
|
|
@ -1,52 +0,0 @@
|
|||||||
from context import Context, ContextManager
|
|
||||||
|
|
||||||
cm = ContextManager("Memory.xml")
|
|
||||||
df = cm.get_single_context()
|
|
||||||
|
|
||||||
df.attach()
|
|
||||||
|
|
||||||
gui = df.gui
|
|
||||||
veg = df.vegetation
|
|
||||||
mps = df.maps
|
|
||||||
mat = df.materials
|
|
||||||
|
|
||||||
x, y, z = gui.get_cursor_coords()
|
|
||||||
|
|
||||||
num_veg = veg.start()
|
|
||||||
|
|
||||||
if x == -30000:
|
|
||||||
print "----==== Trees ====----"
|
|
||||||
|
|
||||||
for i in xrange(num_veg):
|
|
||||||
t = veg.read(i)
|
|
||||||
|
|
||||||
print "%d/%d/%d, %d:%d" % (t.x, t.y, t.z, t.type, t.material)
|
|
||||||
else:
|
|
||||||
#new method, gets the list of trees in a block. can show farm plants
|
|
||||||
if mps.start():
|
|
||||||
pos_tuple = (x, y, z)
|
|
||||||
trees = mps.read_vegetation(x / 16, y / 16, z)
|
|
||||||
|
|
||||||
if trees is not None:
|
|
||||||
for t in trees:
|
|
||||||
if (t.x, t.y, t.z) == pos_tuple:
|
|
||||||
print "----==== Tree at %d/%d/%d ====----" % pos_tuple
|
|
||||||
print str(t)
|
|
||||||
break
|
|
||||||
mps.finish()
|
|
||||||
|
|
||||||
#old method, get the tree from the global vegetation vector. can't show farm plants
|
|
||||||
for i in xrange(num_veg):
|
|
||||||
t = veg.read(i)
|
|
||||||
|
|
||||||
if (t.x, t.y, t.z) == pos_tuple:
|
|
||||||
print "----==== Tree at %d/%d/%d ====----" % pos_tuple
|
|
||||||
print str(t)
|
|
||||||
break
|
|
||||||
|
|
||||||
veg.finish()
|
|
||||||
|
|
||||||
df.detach()
|
|
||||||
|
|
||||||
print "Done. Press any key to continue"
|
|
||||||
raw_input()
|
|
@ -1,229 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <limits>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <conio.h>
|
|
||||||
|
|
||||||
#include <DFHack.h>
|
|
||||||
#include <DFTileTypes.h>
|
|
||||||
#include <extra/MapExtras.h>
|
|
||||||
|
|
||||||
|
|
||||||
//Globals
|
|
||||||
DFHack::Context *DF;
|
|
||||||
DFHack::Maps *maps;
|
|
||||||
DFHack::Gui *gui;
|
|
||||||
DFHack::Materials *mats;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
int32_t
|
|
||||||
cx,cy,z, //cursor coords
|
|
||||||
tx,ty, //tile coords within block
|
|
||||||
bx,by; //block coords
|
|
||||||
//DFHack::designations40d designations;
|
|
||||||
//DFHack::tiletypes40d tiles;
|
|
||||||
//DFHack::t_temperatures temp1,temp2;
|
|
||||||
uint32_t x_max,y_max,z_max;
|
|
||||||
|
|
||||||
DFHack::ContextManager DFMgr("Memory.xml");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
DF=DFMgr.getSingleContext();
|
|
||||||
DF->Attach();
|
|
||||||
maps = DF->getMaps();
|
|
||||||
maps->Start();
|
|
||||||
maps->getSize(x_max,y_max,z_max);
|
|
||||||
gui = DF->getGui();
|
|
||||||
mats = DF->getMaterials();
|
|
||||||
mats->ReadAllMaterials();
|
|
||||||
if(!mats->ReadInorganicMaterials())
|
|
||||||
{
|
|
||||||
printf("Error: Could not load materials!\n");
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
#ifndef LINUX_BUILD
|
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool end = false;
|
|
||||||
cout << "Welcome to the Vein Swap tool.\nType 'help' or ? for a list of available commands, 'q' to quit" << endl;
|
|
||||||
string mode = "";
|
|
||||||
string command = "";
|
|
||||||
|
|
||||||
while(!end)
|
|
||||||
{
|
|
||||||
DF->Resume();
|
|
||||||
|
|
||||||
cout << endl << ":";
|
|
||||||
getline(cin, command);
|
|
||||||
int ch = command[0];
|
|
||||||
if(command.length()<=0) ch=0;
|
|
||||||
if( ((int)command.find("help")) >=0 ) ch='?'; //under windows, find was casting unsigned!
|
|
||||||
|
|
||||||
//Process user command.
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
case 'h':
|
|
||||||
case '?':
|
|
||||||
cout << "" << endl
|
|
||||||
<< "Commands:" << endl
|
|
||||||
<< "p - print vein at cursor" << endl
|
|
||||||
<< "m - print all inorganic material types" << endl
|
|
||||||
<< "r MatTo - replace the vein at cursor with MatTo" << endl
|
|
||||||
<< "R Percent MatFrom MatTo - replace Percent of MatFrom veins with MatTo veins" << endl
|
|
||||||
<< "help OR ? - print this list of commands" << endl
|
|
||||||
<< "q - quit" << endl
|
|
||||||
<< endl
|
|
||||||
<< "Usage:\n\t" << endl;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
case 10:
|
|
||||||
case 13:
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
//Print current cursor
|
|
||||||
mats->ReadAllMaterials();
|
|
||||||
|
|
||||||
if(!maps->Start())
|
|
||||||
{
|
|
||||||
cout << "Can't see any DF map loaded." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!gui->getCursorCoords(cx,cy,z))
|
|
||||||
{
|
|
||||||
cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//cout << "cursor coords: " << x << "/" << y << "/" << z << endl;
|
|
||||||
tx=cx%16; ty=cy%16;
|
|
||||||
bx=cx/16; by=cy/16;
|
|
||||||
DFHack::DFCoord xyz(cx,cy,z);
|
|
||||||
|
|
||||||
printf("Cursor[%d,%d,%d] Block(%d,%d) Tile(%d,%d)\n", cx,cy,z, bx,by, tx,ty );
|
|
||||||
|
|
||||||
if(!maps->isValidBlock(bx,by,z))
|
|
||||||
{
|
|
||||||
cout << "Invalid block." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<DFHack::t_vein> veinVector;
|
|
||||||
int found=0;
|
|
||||||
maps->ReadVeins(bx,by,z,&veinVector);
|
|
||||||
printf("Veins in block (%d):\n",veinVector.size());
|
|
||||||
for(unsigned long i=0;i<veinVector.size();++i){
|
|
||||||
found = veinVector[i].getassignment(tx,ty);
|
|
||||||
printf("\t%c %4d %s\n",
|
|
||||||
(found ? '*' : ' '),
|
|
||||||
veinVector[i].type,
|
|
||||||
mats->inorganic[veinVector[i].type].id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
printf("Cursor is%s in vein.\n", (found?"":" not") );
|
|
||||||
|
|
||||||
maps->Finish();
|
|
||||||
DF->Resume();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
end = true;
|
|
||||||
cout << "Bye!" << endl;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
DF->Suspend();
|
|
||||||
do{
|
|
||||||
//Process parameters
|
|
||||||
long matto = atol( command.c_str()+1 );
|
|
||||||
if( matto < 0 || matto >= (long)mats->inorganic.size() ){
|
|
||||||
cout << "Invalid material: " << matto << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!maps->Start())
|
|
||||||
{
|
|
||||||
cout << "Can't see any DF map loaded." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!gui->getCursorCoords(cx,cy,z))
|
|
||||||
{
|
|
||||||
cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tx=cx%16; ty=cy%16;
|
|
||||||
bx=cx/16; by=cy/16;
|
|
||||||
printf("Cursor[%d,%d,%d] Block(%d,%d) Tile(%d,%d)\n", cx,cy,z, bx,by, tx,ty );
|
|
||||||
|
|
||||||
if(!maps->isValidBlock(bx,by,z))
|
|
||||||
{
|
|
||||||
cout << "Invalid block." << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//MapExtras::MapCache MC(maps);
|
|
||||||
//MapExtras::Block B(maps,DFHack::DFCoord(bx,by,z));
|
|
||||||
|
|
||||||
vector<DFHack::t_vein> veinVector;
|
|
||||||
int v=-1; //the vector pointed to by the cursor
|
|
||||||
|
|
||||||
mats->ReadAllMaterials();
|
|
||||||
|
|
||||||
maps->ReadVeins(bx,by,z,&veinVector);
|
|
||||||
for(unsigned long i=0 ; v<0 && i<veinVector.size() ; ++i){
|
|
||||||
if( veinVector[i].getassignment(tx,ty) )
|
|
||||||
v=i;
|
|
||||||
}
|
|
||||||
printf("Replacing %d %s with %d %s...\n", veinVector[v].type, mats->inorganic[veinVector[v].type].id, matto, mats->inorganic[matto].id );
|
|
||||||
printf("%X\n",veinVector[v].vtable);
|
|
||||||
vector<DFHack::t_vein> veinTable;
|
|
||||||
|
|
||||||
veinVector[v].type = matto;
|
|
||||||
maps->WriteVein( &veinVector[v] );
|
|
||||||
|
|
||||||
|
|
||||||
maps->Finish();
|
|
||||||
|
|
||||||
cout << endl << "Finished." << endl;
|
|
||||||
}while(0);
|
|
||||||
DF->Resume();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Unknown command: " << command << endl;
|
|
||||||
}//end switch
|
|
||||||
|
|
||||||
}//end while
|
|
||||||
|
|
||||||
DF->Detach();
|
|
||||||
//#ifndef LINUX_BUILD
|
|
||||||
//cout << "Done. Press any key to continue" << endl;
|
|
||||||
//cin.ignore();
|
|
||||||
//#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445
|
|
||||||
|
|
||||||
0x2ac6b
|
|
||||||
CC CC CC CC CC
|
|
||||||
66 39 E8 EB 53
|
|
||||||
|
|
||||||
.text:0042B86B loc_42B86B:
|
|
||||||
.text:0042B86B cmp ax, bp
|
|
||||||
.text:0042B86E jmp short loc_42B8C3
|
|
||||||
|
|
||||||
0x2ac7b
|
|
||||||
CC CC CC CC CC
|
|
||||||
E9 96 A2 00 00
|
|
||||||
|
|
||||||
.text:0042B87B loc_42B87B:
|
|
||||||
.text:0042B87B jmp loc_435B16
|
|
||||||
|
|
||||||
0x2acc3
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
75 0A 66 FF 4C 24 16 79 03 58 EB AC C3
|
|
||||||
|
|
||||||
.text:0042B8C3 loc_42B8C3:
|
|
||||||
.text:0042B8C3 jnz short locret_42B8CF
|
|
||||||
.text:0042B8C5 dec word ptr [esp+16h] ; 4+8+8+2
|
|
||||||
.text:0042B8CA jns short locret_42B8CF
|
|
||||||
.text:0042B8CC pop eax
|
|
||||||
.text:0042B8CD jmp short loc_42B87B
|
|
||||||
.text:0042B8CF locret_42B8CF:
|
|
||||||
.text:0042B8CF retn
|
|
||||||
|
|
||||||
0x2b2a1
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
66 C7 44 24 0E 01 00 8B 90 44 01 00 00 C3 CC
|
|
||||||
|
|
||||||
.text:0042BEA1 loc_42BEA1:
|
|
||||||
.text:0042BEA1 mov word ptr [esp+0Eh], 1 ; 4+8+2
|
|
||||||
.text:0042BEA8 mov edx, [eax+144h]
|
|
||||||
.text:0042BEAE retn
|
|
||||||
|
|
||||||
0x34d91
|
|
||||||
8B 90 44 01 00 00
|
|
||||||
E8 0B 65 FF FF 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00435991 mov edx, [eax+144h]
|
|
||||||
====
|
|
||||||
.text:00435991 call loc_42BEA1
|
|
||||||
.text:00435996 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x34e53
|
|
||||||
0F 84 BD 00 00 00
|
|
||||||
E8 6B 5E FF FF 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00435A53 jz loc_435B16
|
|
||||||
====
|
|
||||||
.text:00435A53 call loc_42B8C3
|
|
||||||
.text:00435A58 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x34ef3
|
|
||||||
66 3B C5 74 1E
|
|
||||||
E8 73 5D FF FF
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00435AF3 cmp ax, bp
|
|
||||||
.text:00435AF6 jz short loc_435B16
|
|
||||||
====
|
|
||||||
.text:00435AF3 call loc_42B86B
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
|
|
||||||
basically:
|
|
||||||
|
|
||||||
+ int allowed_count = 1; // to mean 2
|
|
||||||
...
|
|
||||||
- if (type(item) == new_type)
|
|
||||||
+ if (type(item) == new_type && --allowed_count < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
to allow up to two items of the same type at the same time
|
|
||||||
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
0002AC6B: CC 66
|
|
||||||
0002AC6C: CC 39
|
|
||||||
0002AC6D: CC E8
|
|
||||||
0002AC6E: CC EB
|
|
||||||
0002AC6F: CC 53
|
|
||||||
0002AC7B: CC E9
|
|
||||||
0002AC7C: CC 96
|
|
||||||
0002AC7D: CC A2
|
|
||||||
0002AC7E: CC 00
|
|
||||||
0002AC7F: CC 00
|
|
||||||
0002ACC3: CC 75
|
|
||||||
0002ACC4: CC 0A
|
|
||||||
0002ACC5: CC 66
|
|
||||||
0002ACC6: CC FF
|
|
||||||
0002ACC7: CC 4C
|
|
||||||
0002ACC8: CC 24
|
|
||||||
0002ACC9: CC 16
|
|
||||||
0002ACCA: CC 79
|
|
||||||
0002ACCB: CC 03
|
|
||||||
0002ACCC: CC 58
|
|
||||||
0002ACCD: CC EB
|
|
||||||
0002ACCE: CC AC
|
|
||||||
0002ACCF: CC C3
|
|
||||||
0002B2A1: CC 66
|
|
||||||
0002B2A2: CC C7
|
|
||||||
0002B2A3: CC 44
|
|
||||||
0002B2A4: CC 24
|
|
||||||
0002B2A5: CC 0E
|
|
||||||
0002B2A6: CC 01
|
|
||||||
0002B2A7: CC 00
|
|
||||||
0002B2A8: CC 8B
|
|
||||||
0002B2A9: CC 90
|
|
||||||
0002B2AA: CC 44
|
|
||||||
0002B2AB: CC 01
|
|
||||||
0002B2AC: CC 00
|
|
||||||
0002B2AD: CC 00
|
|
||||||
0002B2AE: CC C3
|
|
||||||
00034D91: 8B E8
|
|
||||||
00034D92: 90 0B
|
|
||||||
00034D93: 44 65
|
|
||||||
00034D94: 01 FF
|
|
||||||
00034D95: 00 FF
|
|
||||||
00034D96: 00 90
|
|
||||||
00034E53: 0F E8
|
|
||||||
00034E54: 84 6B
|
|
||||||
00034E55: BD 5E
|
|
||||||
00034E56: 00 FF
|
|
||||||
00034E57: 00 FF
|
|
||||||
00034E58: 00 90
|
|
||||||
00034EF3: 66 E8
|
|
||||||
00034EF4: 3B 73
|
|
||||||
00034EF5: C5 5D
|
|
||||||
00034EF6: 74 FF
|
|
||||||
00034EF7: 1E FF
|
|
@ -1,91 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=808
|
|
||||||
|
|
||||||
Original code:
|
|
||||||
|
|
||||||
.text:00916BCE mov edi, ebp
|
|
||||||
.text:00916BD0 call eax
|
|
||||||
.text:00916BD2 test eax, eax
|
|
||||||
.text:00916BD4 jnz short loc_916C1C
|
|
||||||
|
|
||||||
.text:00916C0A mov edi, ebp
|
|
||||||
|
|
||||||
.text:00916C14 mov edi, ebp
|
|
||||||
|
|
||||||
Patch:
|
|
||||||
|
|
||||||
0x2ac34:
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
8B 7C 24 78 8B 3C B7 FF D0 EB 25 CC
|
|
||||||
|
|
||||||
.text:0042B834 loc_42B834:
|
|
||||||
.text:0042B834 mov edi, [esp+78h]
|
|
||||||
.text:0042B838 mov edi, [edi+esi*4]
|
|
||||||
.text:0042B83B call eax
|
|
||||||
.text:0042B83D jmp short unk_42B864
|
|
||||||
|
|
||||||
0x2ac64
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
85 C0 E9 69 B3 4E 00 CC CC CC CC CC
|
|
||||||
|
|
||||||
.text:0042B864 loc_42B864:
|
|
||||||
.text:0042B864 test eax, eax
|
|
||||||
.text:0042B866 jmp loc_916BD4
|
|
||||||
|
|
||||||
0x515fce
|
|
||||||
8B FD FF D0 85 C0
|
|
||||||
E9 61 4C B1 FF 90
|
|
||||||
|
|
||||||
.text:00916BCE jmp loc_42B834
|
|
||||||
.text:00916BD3 nop
|
|
||||||
.text:00916BD4 loc_916BD4:
|
|
||||||
|
|
||||||
0x51600a
|
|
||||||
8B FD
|
|
||||||
90 90
|
|
||||||
|
|
||||||
.text:00916C0A nop
|
|
||||||
.text:00916C0B nop
|
|
||||||
|
|
||||||
0x516014
|
|
||||||
8B FD
|
|
||||||
90 90
|
|
||||||
|
|
||||||
.text:00916C14 nop
|
|
||||||
.text:00916C15 nop
|
|
||||||
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
0002AC34: CC 8B
|
|
||||||
0002AC35: CC 7C
|
|
||||||
0002AC36: CC 24
|
|
||||||
0002AC37: CC 78
|
|
||||||
0002AC38: CC 8B
|
|
||||||
0002AC39: CC 3C
|
|
||||||
0002AC3A: CC B7
|
|
||||||
0002AC3B: CC FF
|
|
||||||
0002AC3C: CC D0
|
|
||||||
0002AC3D: CC EB
|
|
||||||
0002AC3E: CC 25
|
|
||||||
0002AC64: CC 85
|
|
||||||
0002AC65: CC C0
|
|
||||||
0002AC66: CC E9
|
|
||||||
0002AC67: CC 69
|
|
||||||
0002AC68: CC B3
|
|
||||||
0002AC69: CC 4E
|
|
||||||
0002AC6A: CC 00
|
|
||||||
00515FCE: 8B E9
|
|
||||||
00515FCF: FD 61
|
|
||||||
00515FD0: FF 4C
|
|
||||||
00515FD1: D0 B1
|
|
||||||
00515FD2: 85 FF
|
|
||||||
00515FD3: C0 90
|
|
||||||
0051600A: 8B 90
|
|
||||||
0051600B: FD 90
|
|
||||||
00516014: 8B 90
|
|
||||||
00516015: FD 90
|
|
@ -1,61 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=5994
|
|
||||||
|
|
||||||
Original code:
|
|
||||||
|
|
||||||
.text:008629BD mov edi, [eax+38h]
|
|
||||||
.text:008629C0 mov eax, [eax+3Ch]
|
|
||||||
.text:008629C3 mov [esp+1Ch], eax
|
|
||||||
.text:008629C7 cmp edi, eax
|
|
||||||
.text:008629C9 jnb short loc_862A22
|
|
||||||
.text:008629CB jmp short loc_8629D0
|
|
||||||
.text:008629CD lea ecx, [ecx+0]
|
|
||||||
...
|
|
||||||
.text:00862A19 add edi, 4
|
|
||||||
.text:00862A1C cmp edi, [esp+1Ch]
|
|
||||||
.text:00862A20 jb short loc_8629D0
|
|
||||||
|
|
||||||
Patch:
|
|
||||||
|
|
||||||
0x461dbd
|
|
||||||
8B 78 38 8B 40 3C 89 44 24 1C 3B F8
|
|
||||||
8B 78 3C 8B 40 38 89 44 24 1C 39 F8
|
|
||||||
|
|
||||||
.text:008629BD mov edi, [eax+3Ch]
|
|
||||||
.text:008629C0 mov eax, [eax+38h]
|
|
||||||
.text:008629C3 mov [esp+1Ch], eax
|
|
||||||
.text:008629C7 cmp eax, edi
|
|
||||||
|
|
||||||
0x461dcb
|
|
||||||
EB 03 8D 49 00
|
|
||||||
83 EF 04 90 90
|
|
||||||
|
|
||||||
.text:008629CB sub edi, 4
|
|
||||||
.text:008629CE nop
|
|
||||||
.text:008629CF nop
|
|
||||||
|
|
||||||
0x461e19
|
|
||||||
83 C7 04 3B 7C 24 1C 72 AE
|
|
||||||
83 EF 04 3B 7C 24 1C 73 AE
|
|
||||||
|
|
||||||
.text:00862A19 sub edi, 4
|
|
||||||
.text:00862A1C cmp edi, [esp+1Ch]
|
|
||||||
.text:00862A20 jnb short loc_8629D0
|
|
||||||
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
00461DBF: 38 3C
|
|
||||||
00461DC2: 3C 38
|
|
||||||
00461DC7: 3B 39
|
|
||||||
00461DCB: EB 83
|
|
||||||
00461DCC: 03 EF
|
|
||||||
00461DCD: 8D 04
|
|
||||||
00461DCE: 49 90
|
|
||||||
00461DCF: 00 90
|
|
||||||
00461E1A: C7 EF
|
|
||||||
00461E20: 72 73
|
|
@ -1,104 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=5994
|
|
||||||
|
|
||||||
0x461de2
|
|
||||||
F6 46 0C 01 74 31
|
|
||||||
E9 0A 8E BC FF 90
|
|
||||||
|
|
||||||
.text:008629E2 jmp near ptr loc_42B7F1 ; << CAVE
|
|
||||||
.text:008629E7 nop
|
|
||||||
.text:008629E8 loc_8629E8:
|
|
||||||
|
|
||||||
0x2abf1
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
8B 4C 24 2C F6 46 0C 01 75 08 E9 19 72 43 00
|
|
||||||
|
|
||||||
.text:0042B7F1 loc_42B7F1:
|
|
||||||
.text:0042B7F1 mov ecx, [esp+2Ch] ; job
|
|
||||||
.text:0042B7F5 test byte ptr [esi+0Ch], 1
|
|
||||||
.text:0042B7F9 jnz short near ptr loc_42B803
|
|
||||||
.text:0042B7FB coord_test_jfail:
|
|
||||||
.text:0042B7FB jmp loc_862A19
|
|
||||||
|
|
||||||
0x2ac03
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
8B 41 10 3B 46 04 75 F0 EB 06 CC CC CC
|
|
||||||
|
|
||||||
.text:0042B803 loc_42B803:
|
|
||||||
.text:0042B803 mov eax, [ecx+10h] ; job->pos.(x,y)
|
|
||||||
.text:0042B806 cmp eax, [esi+4] ; item->pos.(x,y)
|
|
||||||
.text:0042B809 jnz short coord_test_jfail
|
|
||||||
.text:0042B80B jmp short near ptr loc_42B813
|
|
||||||
|
|
||||||
0x2ac13
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
66 8B 41 14 66 3B 46 08 75 DE EB 06 CC
|
|
||||||
|
|
||||||
text:0042B813 loc_42B813:
|
|
||||||
.text:0042B813 mov ax, [ecx+14h] ; job->pos.z
|
|
||||||
.text:0042B817 cmp ax, [esi+8] ; item->pos.z
|
|
||||||
.text:0042B81B jnz short coord_test_jfail
|
|
||||||
.text:0042B81D jmp short near ptr loc_42B825
|
|
||||||
|
|
||||||
0x2ac25
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
E9 BE 71 43 00 CC CC CC CC CC CC
|
|
||||||
|
|
||||||
.text:0042B825 loc_42B825:
|
|
||||||
.text:0042B825 jmp loc_8629E8
|
|
||||||
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
0002ABF1: CC 8B
|
|
||||||
0002ABF2: CC 4C
|
|
||||||
0002ABF3: CC 24
|
|
||||||
0002ABF4: CC 2C
|
|
||||||
0002ABF5: CC F6
|
|
||||||
0002ABF6: CC 46
|
|
||||||
0002ABF7: CC 0C
|
|
||||||
0002ABF8: CC 01
|
|
||||||
0002ABF9: CC 75
|
|
||||||
0002ABFA: CC 08
|
|
||||||
0002ABFB: CC E9
|
|
||||||
0002ABFC: CC 19
|
|
||||||
0002ABFD: CC 72
|
|
||||||
0002ABFE: CC 43
|
|
||||||
0002ABFF: CC 00
|
|
||||||
0002AC03: CC 8B
|
|
||||||
0002AC04: CC 41
|
|
||||||
0002AC05: CC 10
|
|
||||||
0002AC06: CC 3B
|
|
||||||
0002AC07: CC 46
|
|
||||||
0002AC08: CC 04
|
|
||||||
0002AC09: CC 75
|
|
||||||
0002AC0A: CC F0
|
|
||||||
0002AC0B: CC EB
|
|
||||||
0002AC0C: CC 06
|
|
||||||
0002AC13: CC 66
|
|
||||||
0002AC14: CC 8B
|
|
||||||
0002AC15: CC 41
|
|
||||||
0002AC16: CC 14
|
|
||||||
0002AC17: CC 66
|
|
||||||
0002AC18: CC 3B
|
|
||||||
0002AC19: CC 46
|
|
||||||
0002AC1A: CC 08
|
|
||||||
0002AC1B: CC 75
|
|
||||||
0002AC1C: CC DE
|
|
||||||
0002AC1D: CC EB
|
|
||||||
0002AC1E: CC 06
|
|
||||||
0002AC25: CC E9
|
|
||||||
0002AC26: CC BE
|
|
||||||
0002AC27: CC 71
|
|
||||||
0002AC28: CC 43
|
|
||||||
0002AC29: CC 00
|
|
||||||
00461DE2: F6 E9
|
|
||||||
00461DE3: 46 0A
|
|
||||||
00461DE4: 0C 8E
|
|
||||||
00461DE5: 01 BC
|
|
||||||
00461DE6: 74 FF
|
|
||||||
00461DE7: 31 90
|
|
@ -1,62 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=4406
|
|
||||||
|
|
||||||
1. Include store in hospital jobs when recomputing counters
|
|
||||||
|
|
||||||
0x68a63
|
|
||||||
0F 85 58 01 00 00
|
|
||||||
90 90 90 90 90 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00469663 jnz loc_4697C1
|
|
||||||
====
|
|
||||||
.text:00469663 nop
|
|
||||||
.text:00469664 nop
|
|
||||||
.text:00469665 nop
|
|
||||||
.text:00469666 nop
|
|
||||||
.text:00469667 nop
|
|
||||||
.text:00469668 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
- if (job->getBuildingRef(BUILDING_DESTINATION) != this) continue;
|
|
||||||
+ // NOP
|
|
||||||
|
|
||||||
This reference points to the containers, not the hospital civzone.
|
|
||||||
Since fixing this properly is too hard for a patch, just remove the
|
|
||||||
check. Most people have only one hospital anyway, and it is better
|
|
||||||
to err on the side of caution here.
|
|
||||||
|
|
||||||
|
|
||||||
2. Make the stockpiling code increment the right stock counters
|
|
||||||
|
|
||||||
0x3dcbf9
|
|
||||||
8B 0C 90 8B 81 80 00 00 00
|
|
||||||
8B 3C 90 8B 87 80 00 00 00
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:007DD7F9 mov ecx, [eax+edx*4]
|
|
||||||
.text:007DD7FC mov eax, [ecx+80h]
|
|
||||||
====
|
|
||||||
.text:007DD7F9 mov edi, [eax+edx*4]
|
|
||||||
.text:007DD7FC mov eax, [edi+80h]
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
- id = civzones[i]->children[child_idx[i]]->id
|
|
||||||
+ cur_civzone = civzones[i] // existing var from previous loop
|
|
||||||
+ id = cur_civzone->children[child_idx[i]]->id
|
|
||||||
|
|
||||||
The reason being, later code uses that var (at this point containing
|
|
||||||
useless data) to increment counters and amounts in the hospital.
|
|
||||||
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
00068A63: 0F 90
|
|
||||||
00068A64: 85 90
|
|
||||||
00068A65: 58 90
|
|
||||||
00068A66: 01 90
|
|
||||||
00068A67: 00 90
|
|
||||||
00068A68: 00 90
|
|
||||||
003DCBFA: 0C 3C
|
|
||||||
003DCBFD: 81 87
|
|
@ -1,83 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=4530
|
|
||||||
|
|
||||||
0x2ac85
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
29 44 24 24 8B 9D 28 01 00 00 C3
|
|
||||||
|
|
||||||
.text:0042B885 loc_42B885:
|
|
||||||
.text:0042B885 sub [esp+24h], eax
|
|
||||||
.text:0042B889 mov ebx, [ebp+128h]
|
|
||||||
.text:0042B88F retn
|
|
||||||
|
|
||||||
0x2ac94
|
|
||||||
CC CC CC CC CC CC CC CC CC CC CC CC
|
|
||||||
89 C1 8B 00 FF 90 34 02 00 00 EB E5
|
|
||||||
|
|
||||||
.text:0042B894 loc_42B894:
|
|
||||||
.text:0042B894 mov ecx, eax
|
|
||||||
.text:0042B896 mov eax, [eax]
|
|
||||||
.text:0042B898 call dword ptr [eax+234h]
|
|
||||||
.text:0042B89E jmp short loc_42B885
|
|
||||||
|
|
||||||
0x6e28ff
|
|
||||||
29 44 24 20
|
|
||||||
90 90 90 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00AE34FF sub [esp+20h], eax
|
|
||||||
====
|
|
||||||
.text:00AE34FF nop
|
|
||||||
.text:00AE3500 nop
|
|
||||||
.text:00AE3501 nop
|
|
||||||
.text:00AE3502 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x6e2999
|
|
||||||
8B 9D 28 01 00 00
|
|
||||||
E8 F6 82 94 FF 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:00AE3599 mov ebx, [ebp+128h]
|
|
||||||
====
|
|
||||||
.text:00AE3599 call loc_42B894
|
|
||||||
.text:00AE359E nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
0002AC85: CC 29
|
|
||||||
0002AC86: CC 44
|
|
||||||
0002AC87: CC 24
|
|
||||||
0002AC88: CC 24
|
|
||||||
0002AC89: CC 8B
|
|
||||||
0002AC8A: CC 9D
|
|
||||||
0002AC8B: CC 28
|
|
||||||
0002AC8C: CC 01
|
|
||||||
0002AC8D: CC 00
|
|
||||||
0002AC8E: CC 00
|
|
||||||
0002AC8F: CC C3
|
|
||||||
0002AC94: CC 89
|
|
||||||
0002AC95: CC C1
|
|
||||||
0002AC96: CC 8B
|
|
||||||
0002AC97: CC 00
|
|
||||||
0002AC98: CC FF
|
|
||||||
0002AC99: CC 90
|
|
||||||
0002AC9A: CC 34
|
|
||||||
0002AC9B: CC 02
|
|
||||||
0002AC9C: CC 00
|
|
||||||
0002AC9D: CC 00
|
|
||||||
0002AC9E: CC EB
|
|
||||||
0002AC9F: CC E5
|
|
||||||
006E28FF: 29 90
|
|
||||||
006E2900: 44 90
|
|
||||||
006E2901: 24 90
|
|
||||||
006E2902: 20 90
|
|
||||||
006E2999: 8B E8
|
|
||||||
006E299A: 9D F6
|
|
||||||
006E299B: 28 82
|
|
||||||
006E299C: 01 94
|
|
||||||
006E299D: 00 FF
|
|
||||||
006E299E: 00 90
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445
|
|
||||||
|
|
||||||
0x4c05c4
|
|
||||||
8B 8C 24 80 00 00 00
|
|
||||||
89 C1 90 90 90 90 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:008C11C4 mov ecx, [esp+98h+var_18]
|
|
||||||
====
|
|
||||||
.text:008C11C4 mov ecx, eax
|
|
||||||
.text:008C11C6 nop
|
|
||||||
.text:008C11C7 nop
|
|
||||||
.text:008C11C8 nop
|
|
||||||
.text:008C11C9 nop
|
|
||||||
.text:008C11CA nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x4c06a1
|
|
||||||
8B 8C 24 80 00 00 00
|
|
||||||
89 C1 90 90 90 90 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:008C12A1 mov ecx, [esp+98h+var_18]
|
|
||||||
====
|
|
||||||
.text:008C12A1 mov ecx, eax
|
|
||||||
.text:008C12A3 nop
|
|
||||||
.text:008C12A4 nop
|
|
||||||
.text:008C12A5 nop
|
|
||||||
.text:008C12A6 nop
|
|
||||||
.text:008C12A7 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
|
|
||||||
basically:
|
|
||||||
|
|
||||||
b_squad_id = building->getSpecificSquad();
|
|
||||||
- if (b_squad_id != squad->id || !building->canUse(some_squad_id, 4))
|
|
||||||
+ if (b_squad_id != squad->id || !building->canUse(b_squad_id, 4))
|
|
||||||
unassign(building);
|
|
||||||
|
|
||||||
the reason being, some_other_squad_id contains irrelevant garbage at this point
|
|
||||||
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf Fortress.exe
|
|
||||||
004C05C4: 8B 89
|
|
||||||
004C05C5: 8C C1
|
|
||||||
004C05C6: 24 90
|
|
||||||
004C05C7: 80 90
|
|
||||||
004C05C8: 00 90
|
|
||||||
004C05C9: 00 90
|
|
||||||
004C05CA: 00 90
|
|
||||||
004C06A1: 8B 89
|
|
||||||
004C06A2: 8C C1
|
|
||||||
004C06A3: 24 90
|
|
||||||
004C06A4: 80 90
|
|
||||||
004C06A5: 00 90
|
|
||||||
004C06A6: 00 90
|
|
||||||
004C06A7: 00 90
|
|
@ -1,147 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445
|
|
||||||
|
|
||||||
0x9461
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
C7 44 24 18 01 00 00 00 FF A0 44 01 00 00
|
|
||||||
|
|
||||||
.text:08051461 sub_8051461 proc near
|
|
||||||
.text:08051461 mov dword ptr [esp+18h], 1
|
|
||||||
.text:08051469 jmp dword ptr [eax+144h]
|
|
||||||
.text:08051469 sub_8051461 endp
|
|
||||||
|
|
||||||
0x9548
|
|
||||||
90 90 90 90 90 90 90 90
|
|
||||||
FF 4C 24 14 78 08 EB 0B
|
|
||||||
|
|
||||||
.text:08051548 loc_8051548:
|
|
||||||
.text:08051548 dec dword ptr [esp+14h]
|
|
||||||
.text:0805154C js short loc_8051556
|
|
||||||
.text:0805154E jmp short loc_805155B
|
|
||||||
|
|
||||||
0x9556
|
|
||||||
90 90 90 90 90 90 90 90 90 90
|
|
||||||
E9 F6 8C 05 00 E9 D0 8D 05 00
|
|
||||||
|
|
||||||
.text:08051556 loc_8051556:
|
|
||||||
.text:08051556 jmp loc_80AA251
|
|
||||||
.text:0805155B loc_805155B:
|
|
||||||
.text:0805155B jmp loc_80AA330
|
|
||||||
|
|
||||||
0x9568
|
|
||||||
90 90 90 90 90 90 90 90
|
|
||||||
FF 4C 24 14 78 E8 EB 06
|
|
||||||
|
|
||||||
.text:08051568 loc_8051568:
|
|
||||||
.text:08051568 dec [esp+14h]
|
|
||||||
.text:0805156C js short loc_8051556
|
|
||||||
.text:0805156E jmp short loc_8051576
|
|
||||||
|
|
||||||
0x9576
|
|
||||||
90 90 90 90 90
|
|
||||||
E9 4D 8E 05 00
|
|
||||||
|
|
||||||
.text:08051576 loc_8051576:
|
|
||||||
.text:08051576 jmp loc_80AA3C8
|
|
||||||
|
|
||||||
0x62243
|
|
||||||
FF 90 44 01 00 00
|
|
||||||
E8 19 72 FA FF 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:080AA243 call dword ptr [eax+144h]
|
|
||||||
====
|
|
||||||
.text:080AA243 call sub_8051461
|
|
||||||
.text:080AA248 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x62369
|
|
||||||
E9 E3 FE FF FF
|
|
||||||
E9 DA 71 FA FF
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:080AA369 jmp loc_80AA251
|
|
||||||
====
|
|
||||||
.text:080AA369 jmp loc_8051548
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
0x623f6
|
|
||||||
E9 56 FE FF FF
|
|
||||||
E9 6D 71 FA FF
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:080AA3F6 jmp loc_80AA251
|
|
||||||
====
|
|
||||||
.text:080AA3F6 jmp loc_8051568
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
basically:
|
|
||||||
|
|
||||||
+ int allowed_count = 1; // to mean 2
|
|
||||||
...
|
|
||||||
- if (type(item) == new_type)
|
|
||||||
+ if (type(item) == new_type && --allowed_count < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
to allow up to two items of the same type at the same time
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
00009461: 90 C7
|
|
||||||
00009462: 90 44
|
|
||||||
00009463: 90 24
|
|
||||||
00009464: 90 18
|
|
||||||
00009465: 90 01
|
|
||||||
00009466: 90 00
|
|
||||||
00009467: 90 00
|
|
||||||
00009468: 90 00
|
|
||||||
00009469: 90 FF
|
|
||||||
0000946A: 90 A0
|
|
||||||
0000946B: 90 44
|
|
||||||
0000946C: 90 01
|
|
||||||
0000946D: 90 00
|
|
||||||
0000946E: 90 00
|
|
||||||
00009548: 90 FF
|
|
||||||
00009549: 90 4C
|
|
||||||
0000954A: 90 24
|
|
||||||
0000954B: 90 14
|
|
||||||
0000954C: 90 78
|
|
||||||
0000954D: 90 08
|
|
||||||
0000954E: 90 EB
|
|
||||||
0000954F: 90 0B
|
|
||||||
00009556: 90 E9
|
|
||||||
00009557: 90 F6
|
|
||||||
00009558: 90 8C
|
|
||||||
00009559: 90 05
|
|
||||||
0000955A: 90 00
|
|
||||||
0000955B: 90 E9
|
|
||||||
0000955C: 90 D0
|
|
||||||
0000955D: 90 8D
|
|
||||||
0000955E: 90 05
|
|
||||||
0000955F: 90 00
|
|
||||||
00009568: 90 FF
|
|
||||||
00009569: 90 4C
|
|
||||||
0000956A: 90 24
|
|
||||||
0000956B: 90 14
|
|
||||||
0000956C: 90 78
|
|
||||||
0000956D: 90 E8
|
|
||||||
0000956E: 90 EB
|
|
||||||
0000956F: 90 06
|
|
||||||
00009576: 90 E9
|
|
||||||
00009577: 90 4D
|
|
||||||
00009578: 90 8E
|
|
||||||
00009579: 90 05
|
|
||||||
0000957A: 90 00
|
|
||||||
00062243: FF E8
|
|
||||||
00062244: 90 19
|
|
||||||
00062245: 44 72
|
|
||||||
00062246: 01 FA
|
|
||||||
00062247: 00 FF
|
|
||||||
00062248: 00 90
|
|
||||||
0006236A: E3 DA
|
|
||||||
0006236B: FE 71
|
|
||||||
0006236C: FF FA
|
|
||||||
000623F7: 56 6D
|
|
||||||
000623F8: FE 71
|
|
||||||
000623F9: FF FA
|
|
@ -1,40 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=808
|
|
||||||
|
|
||||||
for (i = 0; i < num_items; i++)
|
|
||||||
{
|
|
||||||
ridx = reagent_idx[i];
|
|
||||||
sz = reagent_quantity[ridx]; // used quantity
|
|
||||||
if (sz <= 0) continue;
|
|
||||||
reag = reagent[ridx];
|
|
||||||
if (reag->flags.PRESERVE_REAGENT) continue;
|
|
||||||
rsz = items[i]->getTotalDimension();
|
|
||||||
<<<<<<<<
|
|
||||||
if (reag->flags3.ANY_RAW_MATERIAL)
|
|
||||||
rsz *= BASE_SIZE(items[i]->getType());
|
|
||||||
if (items[i]->subtractDimension(rsz))
|
|
||||||
========
|
|
||||||
/* Not in patch, but necessary for full correctness:
|
|
||||||
if (reag->flags3.ANY_RAW_MATERIAL)
|
|
||||||
rsz /= BASE_SIZE(items[i]->getType());
|
|
||||||
*/
|
|
||||||
if (reag->flags3.ANY_RAW_MATERIAL)
|
|
||||||
sz *= BASE_SIZE(items[i]->getType());
|
|
||||||
if (items[i]->subtractDimension(sz))
|
|
||||||
>>>>>>>>
|
|
||||||
destroy_item(items[i]);
|
|
||||||
reagent_quantity[ridx] -= rsz
|
|
||||||
if (reagent_quantity[ridx] < 0)
|
|
||||||
reagent_quantity[ridx] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
0087F7EF: F8 D8
|
|
||||||
0087F86F: F8 D8
|
|
||||||
0087F9AD: C7 C3
|
|
||||||
0087F9ED: C7 C3
|
|
@ -1,83 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=5994
|
|
||||||
|
|
||||||
Original code:
|
|
||||||
|
|
||||||
.text:087AC378 cmp edx, eax
|
|
||||||
.text:087AC37A mov [esp+4Ch], eax
|
|
||||||
.text:087AC37E jnb loc_87A7034
|
|
||||||
.text:087AC384 mov [esp+48h], edx
|
|
||||||
.text:087AC388 mov [esp+54h], ebx
|
|
||||||
...
|
|
||||||
.text:087AC440 add dword ptr [esp+48h], 4
|
|
||||||
.text:087AC445 mov ebp, [esp+48h]
|
|
||||||
.text:087AC449 cmp [esp+4Ch], ebp
|
|
||||||
.text:087AC44D ja loc_87AC38C
|
|
||||||
|
|
||||||
Patch:
|
|
||||||
|
|
||||||
0x76437a
|
|
||||||
89 44 24 4C
|
|
||||||
89 54 24 4C
|
|
||||||
|
|
||||||
.text:087AC37A mov [esp+4Ch], edx
|
|
||||||
|
|
||||||
0x764384
|
|
||||||
89 54 24 48 89 5C 24 54
|
|
||||||
E8 8A 51 8A FF 90 90 90
|
|
||||||
|
|
||||||
.text:087AC384 call sub_8051513
|
|
||||||
.text:087AC389 nop
|
|
||||||
.text:087AC38A nop
|
|
||||||
.text:087AC38B nop
|
|
||||||
|
|
||||||
0x764440
|
|
||||||
83 44 24 48 04 8B 6C 24 48 39 6C 24 4C 0F 87 39 FF FF FF
|
|
||||||
83 6C 24 48 04 8B 6C 24 48 39 6C 24 4C 0F 86 39 FF FF FF
|
|
||||||
|
|
||||||
.text:087AC440 sub dword ptr [esp+48h], 4
|
|
||||||
.text:087AC445 mov ebp, [esp+48h]
|
|
||||||
.text:087AC449 cmp [esp+4Ch], ebp
|
|
||||||
.text:087AC44D jbe loc_87AC38C
|
|
||||||
|
|
||||||
0x9513
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
83 E8 04 89 44 24 4C 89 5C 24 58 C3 90
|
|
||||||
|
|
||||||
.text:08051513 sub_8051513 proc near
|
|
||||||
.text:08051513 sub eax, 4
|
|
||||||
.text:08051516 mov [esp+4Ch], eax ; 48h
|
|
||||||
.text:0805151A mov [esp+58h], ebx ; 54h
|
|
||||||
.text:0805151E retn
|
|
||||||
.text:0805151E sub_8051513 endp
|
|
||||||
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
00009513: 90 83
|
|
||||||
00009514: 90 E8
|
|
||||||
00009515: 90 04
|
|
||||||
00009516: 90 89
|
|
||||||
00009517: 90 44
|
|
||||||
00009518: 90 24
|
|
||||||
00009519: 90 4C
|
|
||||||
0000951A: 90 89
|
|
||||||
0000951B: 90 5C
|
|
||||||
0000951C: 90 24
|
|
||||||
0000951D: 90 58
|
|
||||||
0000951E: 90 C3
|
|
||||||
0076437B: 44 54
|
|
||||||
00764384: 89 E8
|
|
||||||
00764385: 54 8A
|
|
||||||
00764386: 24 51
|
|
||||||
00764387: 48 8A
|
|
||||||
00764388: 89 FF
|
|
||||||
00764389: 5C 90
|
|
||||||
0076438A: 24 90
|
|
||||||
0076438B: 54 90
|
|
||||||
00764441: 44 6C
|
|
||||||
0076444E: 87 86
|
|
@ -1,139 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=5994
|
|
||||||
|
|
||||||
0x7643f8
|
|
||||||
F6 46 0C 01 74 42
|
|
||||||
E9 B6 50 8A FF 90
|
|
||||||
|
|
||||||
.text:087AC3F8 jmp loc_80514B3 ; << CAVE
|
|
||||||
.text:087AC3FD nop
|
|
||||||
.text:087AC3FE loc_87AC3FE:
|
|
||||||
|
|
||||||
0x94b3
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
F6 46 0C 01 75 0A E9 82 AF 75 00 90 90
|
|
||||||
|
|
||||||
.text:080514B3 loc_80514B3:
|
|
||||||
.text:080514B3 test byte ptr [esi+0Ch], 1
|
|
||||||
.text:080514B7 jnz short loc_80514C3
|
|
||||||
.text:080514B9 coord_test_jfail:
|
|
||||||
.text:080514B9 jmp loc_87AC440
|
|
||||||
|
|
||||||
0x94c3
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
8D 9C 24 60 03 00 00 0F BF 03 EB 07 90
|
|
||||||
|
|
||||||
.text:080514C3 loc_80514C3:
|
|
||||||
.text:080514C3 lea ebx, [esp+360h]
|
|
||||||
.text:080514CA movsx eax, word ptr [ebx] ; job_z
|
|
||||||
.text:080514CD jmp short loc_80514D6
|
|
||||||
|
|
||||||
0x94d6
|
|
||||||
90 90 90 90 90 90 90 90 90 90
|
|
||||||
66 3B 46 08 75 DD EB 05 90 90
|
|
||||||
|
|
||||||
.text:080514D6 loc_80514D6:
|
|
||||||
.text:080514D6 cmp ax, [esi+8] ; item->pos.z
|
|
||||||
.text:080514DA jnz short coord_test_jfail
|
|
||||||
.text:080514DC jmp short loc_80514E3
|
|
||||||
|
|
||||||
0x94e3
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
0F BF 43 10 66 3B 46 04 75 CC EB 04 90
|
|
||||||
|
|
||||||
.text:080514E3 loc_80514E3:
|
|
||||||
.text:080514E3 movsx eax, word ptr [ebx+10h] ; job_x
|
|
||||||
.text:080514E7 cmp ax, [esi+4] ; item->pos.x
|
|
||||||
.text:080514EB jnz short coord_test_jfail
|
|
||||||
.text:080514ED jmp short loc_80514F3
|
|
||||||
|
|
||||||
0x94f3
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
0F BF 43 20 66 3B 46 06 75 BC EB 04 90
|
|
||||||
|
|
||||||
.text:080514F3 loc_80514F3:
|
|
||||||
.text:080514F3 movsx eax, word ptr [ebx+20h] ; job_y
|
|
||||||
.text:080514F7 cmp ax, [esi+6] ; item->pos.y
|
|
||||||
.text:080514FB jnz short coord_test_jfail
|
|
||||||
.text:080514FD jmp short loc_8051503
|
|
||||||
|
|
||||||
0x9503
|
|
||||||
90 90 90 90 90 90 90 90 90 90 90 90 90
|
|
||||||
E9 F6 AE 75 00 90 90 90 90 90 90 90 90
|
|
||||||
|
|
||||||
.text:08051503 loc_8051503:
|
|
||||||
.text:08051503 jmp loc_87AC3FE
|
|
||||||
|
|
||||||
|
|
||||||
You can use this script to apply the generated patch below:
|
|
||||||
http://stalkr.net/files/ida/idadif.py
|
|
||||||
|
|
||||||
----8<----
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
000094B3: 90 F6
|
|
||||||
000094B4: 90 46
|
|
||||||
000094B5: 90 0C
|
|
||||||
000094B6: 90 01
|
|
||||||
000094B7: 90 75
|
|
||||||
000094B8: 90 0A
|
|
||||||
000094B9: 90 E9
|
|
||||||
000094BA: 90 82
|
|
||||||
000094BB: 90 AF
|
|
||||||
000094BC: 90 75
|
|
||||||
000094BD: 90 00
|
|
||||||
000094C3: 90 8D
|
|
||||||
000094C4: 90 9C
|
|
||||||
000094C5: 90 24
|
|
||||||
000094C6: 90 60
|
|
||||||
000094C7: 90 03
|
|
||||||
000094C8: 90 00
|
|
||||||
000094C9: 90 00
|
|
||||||
000094CA: 90 0F
|
|
||||||
000094CB: 90 BF
|
|
||||||
000094CC: 90 03
|
|
||||||
000094CD: 90 EB
|
|
||||||
000094CE: 90 07
|
|
||||||
000094D6: 90 66
|
|
||||||
000094D7: 90 3B
|
|
||||||
000094D8: 90 46
|
|
||||||
000094D9: 90 08
|
|
||||||
000094DA: 90 75
|
|
||||||
000094DB: 90 DD
|
|
||||||
000094DC: 90 EB
|
|
||||||
000094DD: 90 05
|
|
||||||
000094E3: 90 0F
|
|
||||||
000094E4: 90 BF
|
|
||||||
000094E5: 90 43
|
|
||||||
000094E6: 90 10
|
|
||||||
000094E7: 90 66
|
|
||||||
000094E8: 90 3B
|
|
||||||
000094E9: 90 46
|
|
||||||
000094EA: 90 04
|
|
||||||
000094EB: 90 75
|
|
||||||
000094EC: 90 CC
|
|
||||||
000094ED: 90 EB
|
|
||||||
000094EE: 90 04
|
|
||||||
000094F3: 90 0F
|
|
||||||
000094F4: 90 BF
|
|
||||||
000094F5: 90 43
|
|
||||||
000094F6: 90 20
|
|
||||||
000094F7: 90 66
|
|
||||||
000094F8: 90 3B
|
|
||||||
000094F9: 90 46
|
|
||||||
000094FA: 90 06
|
|
||||||
000094FB: 90 75
|
|
||||||
000094FC: 90 BC
|
|
||||||
000094FD: 90 EB
|
|
||||||
000094FE: 90 04
|
|
||||||
00009503: 90 E9
|
|
||||||
00009504: 90 F6
|
|
||||||
00009505: 90 AE
|
|
||||||
00009506: 90 75
|
|
||||||
00009507: 90 00
|
|
||||||
007643F8: F6 E9
|
|
||||||
007643F9: 46 B6
|
|
||||||
007643FA: 0C 50
|
|
||||||
007643FB: 01 8A
|
|
||||||
007643FC: 74 FF
|
|
||||||
007643FD: 42 90
|
|
@ -1,60 +0,0 @@
|
|||||||
http://www.bay12games.com/dwarves/mantisbt/view.php?id=4406
|
|
||||||
|
|
||||||
1. Include store in hospital jobs when recomputing counters
|
|
||||||
|
|
||||||
0x746d7
|
|
||||||
75 D7
|
|
||||||
90 90
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:080BC6D7 jnz short loc_80BC6B0
|
|
||||||
====
|
|
||||||
.text:080BC6D7 nop
|
|
||||||
.text:080BC6D8 nop
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
- if (job->getBuildingRef(BUILDING_DESTINATION) != this) continue;
|
|
||||||
+ // NOP
|
|
||||||
|
|
||||||
This reference points to the containers, not the hospital civzone.
|
|
||||||
Since fixing this properly is too hard for a patch, just remove the
|
|
||||||
check. Most people have only one hospital anyway, and it is better
|
|
||||||
to err on the side of caution here.
|
|
||||||
|
|
||||||
|
|
||||||
2. Make the stockpiling code increment the right stock counters
|
|
||||||
|
|
||||||
0x67cb0e
|
|
||||||
0B 04 90
|
|
||||||
8B 1C 90
|
|
||||||
|
|
||||||
0x67cb18
|
|
||||||
8B 40 74
|
|
||||||
8B 43 74
|
|
||||||
|
|
||||||
<<<<
|
|
||||||
.text:086C4B0E mov eax, [eax+edx*4]
|
|
||||||
.text:086C4B11 mov edx, [esp+ecx*4+39Ch+var_2B4]
|
|
||||||
.text:086C4B18 mov eax, [eax+74h]
|
|
||||||
====
|
|
||||||
.text:086C4B0E mov ebx, [eax+edx*4]
|
|
||||||
.text:086C4B11 mov edx, [esp+ecx*4+39Ch+var_2B4]
|
|
||||||
.text:086C4B18 mov eax, [ebx+74h]
|
|
||||||
>>>>
|
|
||||||
|
|
||||||
- id = civzones[i]->children[child_idx[i]]->id
|
|
||||||
+ cur_civzone = civzones[i] // existing var from previous loop
|
|
||||||
+ id = cur_civzone->children[child_idx[i]]->id
|
|
||||||
|
|
||||||
The reason being, later code uses that var (at this point containing
|
|
||||||
useless data) to increment counters and amounts in the hospital.
|
|
||||||
|
|
||||||
|
|
||||||
---8<---
|
|
||||||
This difference file is created by The Interactive Disassembler
|
|
||||||
|
|
||||||
Dwarf_Fortress
|
|
||||||
000746D7: 75 90
|
|
||||||
000746D8: D7 90
|
|
||||||
0067CB0F: 04 1C
|
|
||||||
0067CB19: 40 43
|
|