Merge branch 'cleanup-needs-porting' into develop

develop
Alexander Gavrilov 2014-05-12 21:56:23 +04:00
commit e4a6f13347
17 changed files with 160 additions and 2899 deletions

@ -61,6 +61,7 @@ The following is a list of people who have contributed to **DFHack**.
- Caldfir <caldfir@hotmail.com>
- Antalia <tamarakorr@gmail.com>
- Angus Mezick <amezick@gmail.com>
- PeridexisErrant <PeridexisErrant@gmail.com>
And those are the cool people who made **stonesense**.

@ -15,6 +15,7 @@ DFHack future
- undump-buildings: removes dump designation from materials used in buildings.
- exportlegends: exports data from legends mode, allowing a set-and-forget export of large worlds.
- log-region: each time a fort is loaded identifying information will be written to the gamelog.
- dfstatus: show an overview of critical stock quantities, including food, drinks, wood, and bars.
New commands:
- move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands

@ -2463,6 +2463,10 @@ dfhack commands. Useful for hotkeys.
Example::
multicmd locate-ore iron ; digv
dfstatus
========
Show a quick overview of critical stock quantities, including food, dirnks, wood, and various bars.
=======================
In-game interface tools
=======================

@ -56,6 +56,9 @@ keybinding add Ctrl-D@legends "exportlegends maps"
# Stocks plugin
keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show"
# open an overview window summarising some stocks (dfstatus)
keybinding add Ctrl-Shift-I@dwarfmode/Default dfstatus
# Workflow
keybinding add Ctrl-W@dwarfmode/QueryBuilding/Some "gui/workflow"
keybinding add Ctrl-I "gui/workflow status"

@ -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()

File diff suppressed because it is too large Load Diff

@ -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;
}

@ -0,0 +1,121 @@
-- dfstatus 1.5 - a quick access status screen.
-- written by enjia2000@gmail.com, fixed by Lethosor and PeridexisErrant
local gui = require 'gui'
function draw()
screen2 = gui.FramedScreen{
frame_style = gui.GREY_LINE_FRAME,
frame_title = 'dfstatus',
frame_width = 16,
frame_height = 17,
frame_inset = 1,
}
end
if (not shown) then
draw()
screen2:show()
shown = true
else
shown = nil
screen2:dismiss()
end
function screen2:onRenderBody(dc)
local drink = 0
local wood = 0
--local meat = 0
--local raw_fish = 0
--local plants = 0
local prepared_meals = 0
local fuel = 0
local pigiron = 0
local iron = 0
local steel = 0
local silver = 0
local copper = 0
local gold = 0
local tannedhides = 0
local cloth = 0
--print("------------------------------")
for _,item in ipairs(df.global.world.items.all) do
if(not item.flags.rotten and not item.flags.dump and not item.flags.forbid) then
if(item:getType() ~= df.item_type.THREAD and item:getType() ~= df.item_type.REMAINS and item:getType() ~= df.item_type.ARMOR and item:getType() ~= df.item_type.SHOES and item:getType() ~= df.item_type.SHIELD and item:getType() ~= df.item_type.HELM and item:getType() ~= df.item_type.GOVES) then
--print(item:getType() .. ":" .. dfhack.items.getDescription(item,0))
end
if(item:getType() == df.item_type.DRINK)then
--print(item:getType() .. ":" .. dfhack.items.getDescription(item,0))
end
if (item:getType() == df.item_type.WOOD) then wood = wood + item:getStackSize()
elseif (item:getType() == df.item_type.DRINK) then drink = drink + item:getStackSize()
elseif (item:getType() == df.item_type.SKIN_TANNED) then tannedhides = tannedhides + item:getStackSize()
elseif (item:getType() == df.item_type.CLOTH) then cloth = cloth + item:getStackSize()
--elseif (item:getType() == df.item_type.MEAT) then meat = meat + item:getStackSize()
--elseif (item:getType() == df.item_type.FISH_RAW) then raw_fish = raw_fish + item:getStackSize()
--elseif (item:getType() == df.item_type.PLANT) then plants = plants + item:getStackSize()
elseif (item:getType() == df.item_type.FOOD) then prepared_meals = prepared_meals + item:getStackSize()
elseif (item:getType() == df.item_type.BAR) then
for token in string.gmatch(dfhack.items.getDescription(item,0),"[^%s]+") do
if (token == "silver") then silver = silver + item:getStackSize()
elseif (token == "charcoal" or token == "coke") then fuel = fuel + item:getStackSize()
elseif (token == "iron") then iron = iron + item:getStackSize()
elseif (token == "pig") then pigiron = pigiron + item:getStackSize()
elseif (token == "copper") then copper = copper + item:getStackSize()
elseif (token == "gold") then gold = gold + item:getStackSize()
elseif (token == "steel") then steel = steel + item:getStackSize()
end
break -- only need to look at the 1st token of each item.
end
end
end
end
--print("------------------------------")
dc:string("Drinks: ".. drink, COLOR_LIGHTGREEN)
dc:newline(0)
dc:string("Meals: ".. prepared_meals, COLOR_LIGHTGREEN)
dc:newline(0)
dc:newline(0)
dc:string("Wood: ".. wood, COLOR_LIGHTGREEN)
dc:newline(0)
dc:newline(0)
dc:string("Hides: ".. tannedhides, COLOR_LIGHTGREEN)
dc:newline(0)
dc:string("Cloth: ".. cloth, COLOR_LIGHTGREEN)
dc:newline(0)
-- dc:string("Raw Fish: ".. raw_fish, COLOR_LIGHTGREEN)
-- dc:newline(0)
-- dc:string("Plants: ".. plants, COLOR_LIGHTGREEN)
-- dc:newline(0)
dc:newline(0)
dc:string("Bars:", COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Fuel: ".. fuel, COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Pig Iron: ".. pigiron, COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Steel: ".. steel, COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Iron: ".. iron, COLOR_LIGHTGREEN)
dc:newline(1)
dc:newline(1)
dc:string("Copper: ".. copper, COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Silver: ".. silver, COLOR_LIGHTGREEN)
dc:newline(1)
dc:string("Gold: ".. gold, COLOR_LIGHTGREEN)
end
function screen2:onInput(keys)
if keys.LEAVESCREEN or keys.SELECT then
shown = nil
self:dismiss()
end
end