diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..10760875f --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# linux backup files +*~ + +# compiled binaries +output/* + +# this one is important, track it +!output/Memory.xml + +# a file generated by cmake +library/config.h + +# any build folders +build*/ + +#except for the real one +!build/ + +#ignore Kdevelop stuff +.kdev4 diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 000000000..474fe987c --- /dev/null +++ b/build/.gitignore @@ -0,0 +1 @@ +build-real \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9aa1cec5f..058d5014c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -37,11 +37,6 @@ TARGET_LINK_LIBRARIES(dfsuspend dfhack) ADD_EXECUTABLE(dfitemdump dfitemdump.cpp) TARGET_LINK_LIBRARIES(dfitemdump dfhack) -# digger - designate for digging by tile class -# Author: mizipzor -ADD_EXECUTABLE(dfdigger digger.cpp) -TARGET_LINK_LIBRARIES(dfdigger dfhack) - # hotkeynotedump - dumps the hotkeys and notes for the loaded map # Author: belal ADD_EXECUTABLE(dfhotkeynotedump hotkeynotedump.cpp) @@ -63,7 +58,6 @@ dfattachtest dfbuildingsdump dfcreaturedump dfitemdump -dfdigger dfexpbench dfmaterialtest dfposition diff --git a/examples/digger.cpp b/examples/digger.cpp deleted file mode 100644 index 1a4e8f556..000000000 --- a/examples/digger.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// digger.cpp - -// Usage: Call with a list of TileClass ids separated by a space, -// every (visible) tile on the map with that id will be designated for digging. - -// NOTE currently only works with trees - -// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well -// TODO add proper cli -// TODO add interactive text based menu - -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include - -int vec_count(vector& vec, uint16_t t) -{ - int count = 0; - for (uint32_t i = 0; i < vec.size(); ++i) - { - if (vec[i] == t) - ++count; - } - return count; -} - -int dig(DFHack::API& DF, vector& targets) -{ - uint32_t x_max,y_max,z_max; - DFHack::t_designation designations[256]; - uint16_t tiles[256]; - uint32_t count = 0; - DF.getSize(x_max,y_max,z_max); - - // 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(DF.isValidBlock(x,y,z)) - { - // read block designations and tiletype - DF.ReadDesignations(x,y,z, (uint32_t *) designations); - DF.ReadTileTypes(x,y,z, (uint16_t *) tiles); - - // check all tiles, if type is in target list and its visible: designate for dig - for (uint32_t i = 0; i < 256; i++) - { - if (designations[i].bits.hidden == 0 && - vec_count(targets, DFHack::tileTypeTable[tiles[i]].c) > 0) - { - //cout << "target found at: "; - //cout << x << "," << y << "," << z << "," << i << endl; - designations[i].bits.dig = DFHack::designation_default; - ++count; - } - } - - // write the designations back - // could probably be optimized in the cases where we dont changed anything - DF.WriteDesignations(x,y,z, (uint32_t *) designations); - } - } - } - } - return count; -} - -int main (int argc, const char* argv[]) -{ - vector targets; - for (int i = 1; i < argc; ++i) - { - targets.push_back(atoi(argv[i])); - } - if (targets.size() == 0) - { - cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; - cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; - } - else - { - DFHack::API DF("Memory.xml"); - if(!DF.Attach()) - { - cerr << "DF not found" << endl; - return 1; - } - DF.InitMap(); - - int count = dig(DF, targets); // <-- important part - cout << count << " targets designated" << endl; - - DF.Detach(); - } - #ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; - cin.ignore(); - #endif - return 0; -} \ No newline at end of file diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index a77f284c1..5e81803c4 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -272,11 +272,12 @@ main(int argc, char *argv[]) finish(0); } + // FIXME: could fail on small forts int cursorX = x_max/2 - 1; int cursorY = y_max/2 - 1; int cursorZ = z_max/2 - 1; - // FIXME: could fail on small forts + int vein = 0; // walk the map! @@ -318,13 +319,15 @@ main(int argc, char *argv[]) cursorY = max(cursorY, 0); cursorZ = max(cursorZ, 0); - cursorX = min(cursorX, x_max - 3); - cursorY = min(cursorY, y_max - 3); - cursorZ = min(cursorZ, z_max - 3); + cursorX = min(cursorX, x_max - 1); + cursorY = min(cursorY, y_max - 1); + cursorZ = min(cursorZ, z_max - 1); DF.Suspend(); - for(int i = 0; i < 3; i++) - for(int j = 0; j < 3; j++) + for(int i = -1; i <= 1; i++) + { + for(int j = -1; j <= 1; j++) + { if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ)) { // read data @@ -338,22 +341,24 @@ main(int argc, char *argv[]) color = pickColor(tiletypes[x][y]); if(designations[x][y].bits.hidden) { - puttile(x+i*16,y+j*16,tiletypes[x][y], color); + puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); } else { attron(A_STANDOUT); - puttile(x+i*16,y+j*16,tiletypes[x][y], color); + puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); attroff(A_STANDOUT); } } } - if(i == 1 && j == 1) + if(i == 0 && j == 0) { veinVector.clear(); DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector); } } + } + } gotoxy(0,48); cprintf("arrow keys, PGUP, PGDN = navigate"); gotoxy(0,49); @@ -361,7 +366,7 @@ main(int argc, char *argv[]) gotoxy(0,50); if(vein == veinVector.size()) vein = veinVector.size() - 1; if(vein < -1) vein = -1; - cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX + 1,x_max,cursorY + 1,y_max,cursorZ + 1,z_max,vein+1,veinVector.size()); + cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,veinVector.size()); if(!veinVector.empty()) { if(vein != -1 && vein < veinVector.size()) @@ -402,6 +407,8 @@ main(int argc, char *argv[]) } } } + gotoxy(0,52); + cprintf("%s",stonetypes[veinVector[vein].type].name); } gotoxy(0,51); cprintf("%s, address 0x%x",str.c_str(),veinVector[vein].address_of); diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 12de11fbd..4eae87b63 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -19,6 +19,8 @@ md5/md5wrapper.h tinyxml/tinystr.h tinyxml/tinyxml.h +gopt/gopt.h + ../shmserver/shms.h ) @@ -33,6 +35,7 @@ tinyxml/tinystr.cpp tinyxml/tinyxml.cpp tinyxml/tinyxmlerror.cpp tinyxml/tinyxmlparser.cpp +gopt/gopt.c ) SET(PROJECT_HDRS_LINUX diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 602f90e60..18334c2db 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -83,14 +83,14 @@ public: uint32_t item_material_offset; - uint32_t note_foreground_offset; - uint32_t note_background_offset; - uint32_t note_name_offset; - uint32_t note_xyz_offset; - uint32_t hotkey_start; - uint32_t hotkey_mode_offset; - uint32_t hotkey_xyz_offset; - uint32_t hotkey_size; + uint32_t note_foreground_offset; + uint32_t note_background_offset; + uint32_t note_name_offset; + uint32_t note_xyz_offset; + uint32_t hotkey_start; + uint32_t hotkey_mode_offset; + uint32_t hotkey_xyz_offset; + uint32_t hotkey_size; uint32_t dwarf_lang_table_offset; @@ -107,8 +107,8 @@ public: bool cursorWindowInited; bool viewSizeInited; bool itemsInited; - bool notesInited; - bool hotkeyInited; + bool notesInited; + bool hotkeyInited; bool nameTablesInited; @@ -118,7 +118,7 @@ public: DfVector *p_bld; DfVector *p_veg; DfVector *p_itm; - DfVector *p_notes; + DfVector *p_notes; }; API::API (const string path_to_xml) @@ -134,8 +134,8 @@ API::API (const string path_to_xml) d->cursorWindowInited = false; d->viewSizeInited = false; d->itemsInited = false; - d->notesInited = false; - d->hotkeyInited = false; + d->notesInited = false; + d->hotkeyInited = false; d->pm = NULL; } @@ -221,9 +221,18 @@ bool API::DestroyMap() bool API::isValidBlock (uint32_t x, uint32_t y, uint32_t z) { + if (x < 0 || x >= d->x_block_count || y < 0 || y >= d->y_block_count || z < 0 || z >= d->z_block_count) + return false; return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z] != 0; } +uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) +{ + if (x < 0 || x >= d->x_block_count || y < 0 || y >= d->y_block_count || z < 0 || z >= d->z_block_count) + return 0; + return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; +} + // 256 * sizeof(uint16_t) bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer) { @@ -851,7 +860,7 @@ bool API::InitReadCreatures( uint32_t &numcreatures ) && d->creature_labors_offset && d->creature_happiness_offset && d->creature_traits_offset - // && d->creature_likes_offset + // && d->creature_likes_offset ) { d->p_cre = new DfVector (d->p->readVector (creatures, 4)); @@ -872,9 +881,9 @@ bool API::InitReadNotes( uint32_t &numnotes ) memory_info * minfo = d->offset_descriptor; int notes = d->offset_descriptor->getAddress ("notes"); d->note_foreground_offset = minfo->getOffset ("note_foreground"); - d->note_background_offset = minfo->getOffset ("note_background"); - d->note_name_offset = minfo->getOffset ("note_name"); - d->note_xyz_offset = minfo->getOffset ("note_xyz"); + d->note_background_offset = minfo->getOffset ("note_background"); + d->note_name_offset = minfo->getOffset ("note_name"); + d->note_xyz_offset = minfo->getOffset ("note_xyz"); if (notes && d->note_foreground_offset @@ -901,25 +910,25 @@ bool API::ReadNote (const int32_t &index, t_note & note) assert (d->notesInited); // read pointer from vector at position uint32_t temp = * (uint32_t *) d->p_notes->at (index); - note.symbol = g_pProcess->readByte(temp); - note.foreground = g_pProcess->readWord(temp + d->note_foreground_offset); - note.background = g_pProcess->readWord(temp + d->note_background_offset); - d->p->readSTLString (temp + d->note_name_offset, note.name, 128); - g_pProcess->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) ¬e.x); - return true; + note.symbol = g_pProcess->readByte(temp); + note.foreground = g_pProcess->readWord(temp + d->note_foreground_offset); + note.background = g_pProcess->readWord(temp + d->note_background_offset); + d->p->readSTLString (temp + d->note_name_offset, note.name, 128); + g_pProcess->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) ¬e.x); + return true; } bool API::InitReadHotkeys( ) { memory_info * minfo = d->offset_descriptor; - d->hotkey_start = minfo->getAddress("hotkey_start"); + d->hotkey_start = minfo->getAddress("hotkey_start"); d->hotkey_mode_offset = minfo->getOffset ("hotkey_mode"); - d->hotkey_xyz_offset = minfo->getOffset("hotkey_xyz"); - d->hotkey_size = minfo->getHexValue("hotkey_size"); - + d->hotkey_xyz_offset = minfo->getOffset("hotkey_xyz"); + d->hotkey_size = minfo->getHexValue("hotkey_size"); + if (d->hotkey_start && d->hotkey_mode_offset && d->hotkey_size) { - d->hotkeyInited = true; - return true; + d->hotkeyInited = true; + return true; } else { @@ -930,15 +939,15 @@ bool API::InitReadHotkeys( ) bool API::ReadHotkeys(t_hotkey hotkeys[]) { assert (d->hotkeyInited); - uint32_t currHotkey = d->hotkey_start; - for(uint32_t i = 0 ; i < NUM_HOTKEYS ;i++) - { - d->p->readSTLString(currHotkey,hotkeys[i].name,10); - hotkeys[i].mode = g_pProcess->readWord(currHotkey+d->hotkey_mode_offset); - g_pProcess->read (currHotkey + d->hotkey_xyz_offset, 3*sizeof (int32_t), (uint8_t *) &hotkeys[i].x); - currHotkey+=d->hotkey_size; - } - return true; + uint32_t currHotkey = d->hotkey_start; + for(uint32_t i = 0 ; i < NUM_HOTKEYS ;i++) + { + d->p->readSTLString(currHotkey,hotkeys[i].name,10); + hotkeys[i].mode = g_pProcess->readWord(currHotkey+d->hotkey_mode_offset); + g_pProcess->read (currHotkey + d->hotkey_xyz_offset, 3*sizeof (int32_t), (uint8_t *) &hotkeys[i].x); + currHotkey+=d->hotkey_size; + } + return true; } // returns index of creature actually read or -1 if no creature can be found int32_t API::ReadCreatureInBox (int32_t index, t_creature & furball, diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h index ce7ef8dac..f41647261 100644 --- a/library/DFHackAPI.h +++ b/library/DFHackAPI.h @@ -128,6 +128,10 @@ namespace DFHack * Return false/0 on failure, buffer allocated by client app, 256 items long */ bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz); + /** + * Get the address of a block or 0 if block is not valid + */ + uint32_t getBlockPtr (uint32_t x, uint32_t y, uint32_t z); bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) @@ -172,12 +176,12 @@ namespace DFHack bool InitViewAndCursor(); - bool InitReadNotes( uint32_t & numnotes ); - bool ReadNote(const int32_t &index, t_note & note); - void FinishReadNotes(); + bool InitReadNotes( uint32_t & numnotes ); + bool ReadNote(const int32_t &index, t_note & note); + void FinishReadNotes(); - bool InitReadHotkeys( ); - bool ReadHotkeys(t_hotkey hotkeys[]); + bool InitReadHotkeys( ); + bool ReadHotkeys(t_hotkey hotkeys[]); bool getViewCoords (int32_t &x, int32_t &y, int32_t &z); bool setViewCoords (const int32_t &x, const int32_t &y, const int32_t &z); diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index 19491c279..f08aec558 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -73,7 +73,7 @@ bool ProcessEnumerator::findProcessess() if(p->isIdentified()) { d->processes.push_back(p); - return true; + return true; } else { @@ -103,7 +103,7 @@ bool ProcessEnumerator::findProcessess() else { //FIXME delete q; - q = 0; + q = 0; } } if(d->processes.size()) diff --git a/library/DFTypes.h b/library/DFTypes.h index 717c82180..50e36d898 100644 --- a/library/DFTypes.h +++ b/library/DFTypes.h @@ -756,22 +756,22 @@ struct t_viewscreen struct t_note { char symbol; - uint16_t foreground; - uint16_t background; - char name[128]; - uint16_t x; - uint16_t y; - uint16_t z; + uint16_t foreground; + uint16_t background; + char name[128]; + uint16_t x; + uint16_t y; + uint16_t z; }; #define NUM_HOTKEYS 16 struct t_hotkey { - char name[10]; - int16_t mode; - int32_t x; - int32_t y; - int32_t z; + char name[10]; + int16_t mode; + int32_t x; + int32_t y; + int32_t z; }; }// namespace DFHack diff --git a/library/gopt/gopt.c b/library/gopt/gopt.c new file mode 100644 index 000000000..ee4564abf --- /dev/null +++ b/library/gopt/gopt.c @@ -0,0 +1,265 @@ +/* gopt.c version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ +/* +I, Tom Vajzovic, am the author of this software and its documentation and +permanently abandon all copyright and other intellectual property rights in +them, including the right to be identified as the author. + +I am fairly certain that this software does what the documentation says it +does, but I cannot guarantee that it does, or that it does what you think it +should, and I cannot guarantee that it will not have undesirable side effects. + +You are free to use, modify and distribute this software as you please, but +you do so at your own risk. If you remove or hide this warning then you are +responsible for any problems encountered by people that you make the software +available to. + +Before modifying or distributing this software I ask that you would please +read http://www.purposeful.co.uk/tfl/ +*/ + +#include +#include +#include +#include "gopt.h" + +#ifdef USE_SYSEXITS +#include +#else +#define EX_OSERR EXIT_FAILURE +#define EX_USAGE EXIT_FAILURE +#endif + +struct opt_spec_s { + int key; + int flags; + const char *shorts; + const char* const *longs; +}; +typedef struct opt_spec_s opt_spec_t; + +struct opt_s { + int key; + const char *arg; +}; +typedef struct opt_s opt_t; + +void *gopt_sort( int *argc, const char **argv, const void *opt_specs ){ + void *opts; + {{{ + const char* const *arg_p= argv + 1; + size_t opt_count= 1; + for( ; *arg_p; ++arg_p ) + if( '-' == (*arg_p)[0] && (*arg_p)[1] ) + if( '-' == (*arg_p)[1] ) + if( (*arg_p)[2] ) + ++opt_count; + else + break; + else { + const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; + for( ; opt_spec_p-> key; ++opt_spec_p ) + if( strchr( opt_spec_p-> shorts, (*arg_p)[1] )){ + opt_count+= opt_spec_p-> flags & GOPT_ARG ? 1 : strlen( (*arg_p) + 1 ); + break; + } + } + opts= malloc( opt_count * sizeof(opt_t) ); + }}} + { + const char **arg_p= argv + 1; + const char **next_operand= arg_p; + opt_t *next_option= (opt_t*)opts; + + if( ! opts ){ + perror( argv[0] ); + exit( EX_OSERR ); + } + for( ; *arg_p; ++arg_p ) + if( '-' == (*arg_p)[0] && (*arg_p)[1] ) + if( '-' == (*arg_p)[1] ) + if( (*arg_p)[2] ) + {{{ + const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; + const char* const *longs= opt_spec_p-> longs; + next_option-> key= 0; + while( *longs ){ + const char *option_cp= (*arg_p) + 2; + const char *name_cp= *longs; + while( *option_cp && *option_cp == *name_cp ){ + ++option_cp; + ++name_cp; + } + if( '=' == *option_cp || !*option_cp ){ + if( *name_cp ){ + if( next_option-> key ){ + fprintf( stderr, "%s: --%.*s: abbreviated option is ambiguous\n", argv[0], (int)( option_cp -( (*arg_p) + 2 )), (*arg_p) + 2 ); + free( opts ); + exit( EX_USAGE ); + } + next_option-> key= opt_spec_p-> key; + } + else { + next_option-> key= opt_spec_p-> key; + goto found_long; + } + } + if( !*++longs ){ + ++opt_spec_p; + if( opt_spec_p-> key ) + longs= opt_spec_p-> longs; + } + } + if( ! next_option-> key ){ + fprintf( stderr, "%s: --%.*s: unknown option\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); + free( opts ); + exit( EX_USAGE ); + } + for( opt_spec_p= (const opt_spec_t*)opt_specs; opt_spec_p-> key != next_option-> key; ++opt_spec_p ); + found_long: + + if( !( opt_spec_p-> flags & GOPT_REPEAT )){ + const opt_t *opt_p= (const opt_t*)opts; + for( ; opt_p != next_option; ++opt_p ) + if( opt_p-> key == opt_spec_p-> key ){ + fprintf( stderr, "%s: --%.*s: option may not be repeated (in any long or short form)\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); + free( opts ); + exit( EX_USAGE ); + } + } + if( opt_spec_p-> flags & GOPT_ARG ){ + next_option-> arg= strchr( (*arg_p) + 2, '=' ) + 1; + if( (char*)0 + 1 == next_option-> arg ){ + ++arg_p; + if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ + fprintf( stderr, "%s: --%s: option requires an option argument\n", argv[0], (*(arg_p-1)) + 2 ); + free( opts ); + exit( EX_USAGE ); + } + next_option-> arg= *arg_p; + } + } + else { + if( strchr( (*arg_p) + 2, '=' )){ + fprintf( stderr, "%s: --%.*s: option may not take an option argument\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); + free( opts ); + exit( EX_USAGE ); + } + next_option-> arg= NULL; + } + ++next_option; + }}} + else { + for( ++arg_p; *arg_p; ++arg_p ) + *next_operand++= *arg_p; + break; + } + else + {{{ + const char *short_opt= (*arg_p) + 1; + for( ;*short_opt; ++short_opt ){ + const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; + + for( ; opt_spec_p-> key; ++opt_spec_p ) + if( strchr( opt_spec_p-> shorts, *short_opt )){ + if( !( opt_spec_p-> flags & GOPT_REPEAT )){ + const opt_t *opt_p= (const opt_t*)opts; + for( ; opt_p != next_option; ++opt_p ) + if( opt_p-> key == opt_spec_p-> key ){ + fprintf( stderr, "%s: -%c: option may not be repeated (in any long or short form)\n", argv[0], *short_opt ); + free( opts ); + exit( EX_USAGE ); + } + } + next_option-> key= opt_spec_p-> key; + + if( opt_spec_p-> flags & GOPT_ARG ){ + if( short_opt[1] ) + next_option-> arg= short_opt + 1; + + else { + ++arg_p; + if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ + fprintf( stderr, "%s: -%c: option requires an option argument\n", argv[0], *short_opt ); + free( opts ); + exit( EX_USAGE ); + } + next_option-> arg= *arg_p; + } + ++next_option; + goto break_2; + } + next_option-> arg= NULL; + ++next_option; + goto continue_2; + } + fprintf( stderr, "%s: -%c: unknown option\n", argv[0], *short_opt ); + free( opts ); + exit( EX_USAGE ); + continue_2: 0; + } + break_2: 0; + }}} + else + *next_operand++= *arg_p; + + next_option-> key= 0; + *next_operand= NULL; + *argc= next_operand - argv; + } + return opts; +} + +size_t gopt( const void *vptr_opts, int key ){ + const opt_t *opts= (const opt_t*)vptr_opts; + size_t count= 0; + for( ; opts-> key; ++opts ) + count+= opts-> key == key; + + return count; +} + +size_t gopt_arg( const void *vptr_opts, int key, const char **arg ){ + const opt_t *opts= (const opt_t*)vptr_opts; + size_t count= 0; + + for( ; opts-> key; ++opts ) + if( opts-> key == key ){ + if( ! count ) + *arg= opts-> arg; + ++count; + } + return count; +} + +const char *gopt_arg_i( const void *vptr_opts, int key, size_t i ){ + const opt_t *opts= (const opt_t*)vptr_opts; + + for( ; opts-> key; ++opts ) + if( opts-> key == key ){ + if( ! i ) + return opts-> arg; + --i; + } + return NULL; +} + +size_t gopt_args( const void *vptr_opts, int key, const char **args, size_t args_len ){ + const char **args_stop= args + args_len; + const char **args_ptr= args; + const opt_t *opts= (const opt_t*)vptr_opts; + + for( ; opts-> key; ++opts ) + if( opts-> key == key ){ + if( args_stop == args_ptr ) + return args_len + gopt( opts, key ); + + *args_ptr++= opts-> arg; + } + if( args_stop != args_ptr ) + *args_ptr= NULL; + return args_ptr - args; +} + +void gopt_free( void *vptr_opts ){ + free( vptr_opts ); +} diff --git a/library/gopt/gopt.h b/library/gopt/gopt.h new file mode 100644 index 000000000..27ef648d5 --- /dev/null +++ b/library/gopt/gopt.h @@ -0,0 +1,60 @@ +/* gopt.h version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ +/* +I, Tom Vajzovic, am the author of this software and its documentation and +permanently abandon all copyright and other intellectual property rights in +them, including the right to be identified as the author. + +I am fairly certain that this software does what the documentation says it +does, but I cannot guarantee that it does, or that it does what you think it +should, and I cannot guarantee that it will not have undesirable side effects. + +You are free to use, modify and distribute this software as you please, but +you do so at your own risk. If you remove or hide this warning then you are +responsible for any problems encountered by people that you make the software +available to. + +Before modifying or distributing this software I ask that you would please +read http://www.purposeful.co.uk/tfl/ +*/ + +#ifndef GOPT_H_INCLUDED +#define GOPT_H_INCLUDED + +#define GOPT_ONCE 0 +#define GOPT_REPEAT 1 +#define GOPT_NOARG 0 +#define GOPT_ARG 2 + +#define gopt_start(...) (const void*)( const struct { int k; int f; const char *s; const char*const*l; }[]){ __VA_ARGS__, {0}} +#define gopt_option(k,f,s,l) { k, f, s, l } +#define gopt_shorts( ... ) (const char*)(const char[]){ __VA_ARGS__, 0 } +#define gopt_longs( ... ) (const char**)(const char*[]){ __VA_ARGS__, NULL } + + +void *gopt_sort( int *argc, const char **argv, const void *opt_specs ); +/* returns a pointer for use in the following calls + * prints to stderr and call exit() on error + */ +size_t gopt( const void *opts, int key ); +/* returns the number of times the option was specified + * which will be 0 or 1 unless GOPT_REPEAT was used + */ +size_t gopt_arg( const void *opts, int key, const char **arg ); +/* returns the number of times the option was specified + * writes a pointer to the option argument from the first (or only) occurance to *arg + */ +const char *gopt_arg_i( const void *opts, int key, size_t i ); +/* returns a pointer to the ith (starting at zero) occurance + * of the option, or NULL if it was not specified that many times + */ +size_t gopt_args( const void *opts, int key, const char **args, size_t args_len ); +/* returns the number of times the option was specified + * writes pointers to the option arguments in the order of occurance to args[]. + * writes at most args_len pointers + * if the return value is less than args_len, also writes a null pointer + */ +void gopt_free( void *opts ); +/* releases memory allocated in the corresponding call to gopt_sort() + * opts can no longer be used + */ +#endif /* GOPT_H_INCLUDED */ diff --git a/output/.gitignore b/output/.gitignore new file mode 100644 index 000000000..e2502ac16 --- /dev/null +++ b/output/.gitignore @@ -0,0 +1,3 @@ +Debug +Release +RelWithDebInfo \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6a6fa9f95..ab93a9660 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -26,10 +26,19 @@ TARGET_LINK_LIBRARIES(dfincremental dfhack) ADD_EXECUTABLE(dfbauxite dfbauxite.cpp) TARGET_LINK_LIBRARIES(dfbauxite dfhack) +# digger - designate for digging by tile class +# Author: mizipzor +ADD_EXECUTABLE(dfdigger digger.cpp) +TARGET_LINK_LIBRARIES(dfdigger dfhack) + + # itemdesignator - change some item designations (dump, forbid, on-fire) for all items of a given type and material ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp) TARGET_LINK_LIBRARIES(dfitemdesignator dfhack) +ADD_EXECUTABLE(dffindnameindexes findnameindexes.cpp) +TARGET_LINK_LIBRARIES(dffindnameindexes dfhack) + IF(UNIX) install(TARGETS dfreveal diff --git a/tools/digger.cpp b/tools/digger.cpp new file mode 100644 index 000000000..3b875afa6 --- /dev/null +++ b/tools/digger.cpp @@ -0,0 +1,354 @@ +// digger.cpp + +// Usage: Call with a list of TileClass ids separated by a space, +// every (visible) tile on the map with that id will be designated for digging. + +// NOTE currently only works with trees + +// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well +// TODO add proper cli +// TODO add interactive text based menu +// TODO add ability to mark num closest to cursor + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include + +int vec_count(vector& vec, uint16_t t) +{ + int count = 0; + for (uint32_t i = 0; i < vec.size(); ++i) + { + if (vec[i] == t) + ++count; + } + return count; +} + +//// manhattan distance +//int source_distance(int sx, int sy, int sz, +// int x, int y, int z, int i) +//{ +// // TODO changing x and y seems to be optimized away (?) +// cout << x << " " << i << " " << i%16 << " " << x+(i%16) << endl; +// +// // handle the fact that x,y,z refers to a 16x16 grid +// //x += i%16; +// //y += i/16; +// int dx = i%16; +// int dy = i/16; +// //x *= 16; +// //y *= 16; +// //x += dx; +// //y += dy; +// return abs(sx-(x+(i%16)))+abs(sy-(y+(i/16)))+abs(sz-z); +//} + +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); +} + +struct DigTarget +{ +//public: + 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) : + //grid_x(realx/16), grid_y(realy/16), + //local_x(realx%16), local_y(realy%16), + 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) : + //source_distance(manhattan_distance( + // realx, realy, realz, + // sourcex, sourcey, sourcez)), + grid_x(gridx), grid_y(gridy), + local_x(localx), local_y(localy), + z(_z) + //real_x(realx), real_y(realy), real_z(realz) + { + 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 source_distance() const { return _source_distance; } + + int grid_x, grid_y; + int local_x, local_y; + int real_x, real_y; + int z; + //int index; + + //const bool valid; + + bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; } + +//private: +// int source_x, source_y, source_z; +// int _source_distance; +}; + +int dig(DFHack::API& DF, + vector& targets, + int num = -1, + const int x_source = 0, + const int y_source = 0, + const int z_source = 0) +{ + if (num == 0) + return 0; // max limit of 0, nothing to do + + uint32_t x_max,y_max,z_max; + DFHack::t_designation designations[16][16]; + uint16_t tiles[16][16]; + //uint32_t count = 0; + DF.getSize(x_max,y_max,z_max); + + // every tile found, will later be sorted by distance to source + vector candidates; + + cout << "============================" << endl; + cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + + //int debugmaxx = 0; + //int debugmaxy = 0; + + // 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 (z != z_source) + continue; // hack to cut down on targets + + if(DF.isValidBlock(x,y,z)) + { + // read block designations and tiletype + DF.ReadDesignations(x,y,z, (uint32_t *) designations); + DF.ReadTileTypes(x,y,z, (uint16_t *) 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::tileTypeTable[tiles[lx][ly]].c) > 0) + { + //cout << "target found at: "; + //cout << x << "," << y << "," << z << "," << i << endl; + + //designations[i].bits.dig = DFHack::designation_default; + //++count; + + //int realx = (x*16)+lx; + //int realy = (y*16)+ly; + + candidates.push_back(DigTarget( + x, y, z, + lx, ly, + x_source, y_source, z_source)); + + //cout << "target found at " << world_x << " " << world_y << " " << z; + //cout << ", " << dt->source_distance << " tiles to source" << endl; + + //if (world_x > debugmaxx) + // debugmaxx = world_x; + //if (world_y > debugmaxy) + // debugmaxy = world_y; + } + } // local y + } // local x + } + } + } + } + + // TODO the following routine doesnt check if the tile is already marked for digging + + // 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(); + + cout << "============================" << endl; + cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + + // mark the tiles for actual digging + for (vector::const_iterator i = candidates.begin(); i != candidates.end(); ++i) + { + //int grid_x = (*i).x/16; + //int grid_y = (*i).y/16; + //int z = (*i).z; + + //int local_x = (*i).x%grid_x; + //int local_y = (*i).y%grid_y; + + 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 + // TODO move into function in DigTarget + DF.ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default; + DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + } + + //cout << debugmaxx << " " << debugmaxy << endl; + + return num; +} + +void test() +{ + { + DigTarget dt; + //assert(!dt.valid); + } + + { + 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); + //assert(dt.valid); + } + + { + 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); + //assert(dt.valid); + } + + //{ // sorting + // DigTarget a( + // 20, 35, 16, + // 10, 12, 14); + + // DigTarget b( + // 2, 4, 16, + // 5, 10, + // 10, 12, 14); + + // vector v; + // v.push_back(b); + // v.push_back(a); + // sort(v.begin(), v.end()); + // assert(*(v.begin()) == a); + //} +} + +int main (int argc, const char* argv[]) +{ + test(); + + vector targets; + for (int i = 1; i < argc; ++i) + { + targets.push_back(atoi(argv[i])); + } + if (targets.size() == 0) + { + cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; + cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; + } + else + { + DFHack::API DF("Memory.xml"); + if(!DF.Attach()) + { + cerr << "DF not found" << endl; + return 1; + } + DF.InitMap(); + + // TODO hack until we have a proper cli to specify origin + int x_source = 134, y_source = 134, z_source = 16; // my wagon starts here; cut trees close to wagon + //DF.InitViewAndCursor(); + //if (!DF.getViewCoords(x_source, y_source, z_source)) + //{ + // cerr << "Enable cursor" << endl; + // return 1; + //} + + int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part + cout << count << " targets designated" << endl; + + DF.Detach(); + } + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} \ No newline at end of file diff --git a/tools/findnameindexes.cpp b/tools/findnameindexes.cpp new file mode 100644 index 000000000..c584ae23c --- /dev/null +++ b/tools/findnameindexes.cpp @@ -0,0 +1,84 @@ +// Map cleaner. Removes all the snow, mud spills, blood and vomit from map tiles. + +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + +// returns a lower case version of the string +string tolower (const string & s) +{ + string d (s); + + transform (d.begin (), d.end (), d.begin (), (int(*)(int)) tolower); + return d; +} +string groupBy2(const string & s) +{ + string d; + for(int i =2;i>24) | + ((x<<8) & 0x00FF0000) | + ((x>>8) & 0x0000FF00) | + (x<<24); + return x; +} + + +int main (void) +{ + DFHack::API DF ("Memory.xml"); + if(!DF.Attach()) + { + cerr << "DF not found" << endl; + return 1; + } + map< string, vector > names; + if(!DF.InitReadNameTables(names)) + { + cerr << "Could not get Names" << endl; + return 1; + } + string input; + DF.ForceResume(); + cout << "\nSelect Name to search or q to Quit" << endl; + getline (cin, input); + while(input != "q"){ + for( map< string, vector >::iterator it = names.begin();it != names.end(); it++){ + for(uint32_t i = 0; i < it->second.size(); i++){ + uint32_t found = input.find(tolower(it->second[i])); + if(found != string::npos){ + stringstream value; + value << setfill('0') << setw(8) << hex << endian_swap(i); + cout << it->first << " " << it->second[i] << " " << groupBy2(value.str()) << endl; + } + } + } + DF.Resume(); + getline(cin,input); + } + DF.Detach(); + DF.FinishReadNameTables(); + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +}