// Creature dump #include #include #include #include #include using namespace std; #include #include #include template void print_bits ( T val, std::ostream& out ) { T n_bits = sizeof ( val ) * CHAR_BIT; for ( unsigned i = 0; i < n_bits; ++i ) { out<< !!( val & 1 ) << " "; val >>= 1; } } vector buildingtypes; map > names; uint32_t numCreatures; vector creaturestypes; void printDwarves(DFHack::API & DF) { int dwarfCounter = 0; for(uint32_t i = 0; i < numCreatures; i++) { DFHack::t_creature temp; DF.ReadCreature(i, temp); string type = creaturestypes[temp.type].id; if(type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed){ cout << i << ":"; if(temp.nick_name[0]) { cout << temp.nick_name; } else{ cout << temp.first_name; } string transName = DF.TranslateName(temp.last_name,names,creaturestypes[temp.type].id); cout << " " << temp.custom_profession; //transName; if(dwarfCounter%3 != 2){ cout << '\t'; } else{ cout << endl; } dwarfCounter++; } } } bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string & changeString, string & commandString,int & eraseAmount,int &dwarfNum,bool &isName) { static string lastText; bool dwarfSuccess = false; while(!dwarfSuccess) { string input; cout << "\nSelect Dwarf to Change or q to Quit" << endl; DF.Resume(); getline (cin, input); DF.Suspend(); if(input == "q") { return false; } else if(input == "r") { printDwarves(DF); } else if(!input.empty()) { int num; stringstream(input) >> num;//= atol(input.c_str()); dwarfSuccess = DF.ReadCreature(num,toChange); string type = creaturestypes[toChange.type].id; if(type != "DWARF") { dwarfSuccess = false; } else { dwarfNum = num; } } } bool changeType = false; while(!changeType) { string input; cout << "\n(n)ickname or (p)rofession?" << endl; getline(cin, input); if(input == "q"){ return false; } if(input == "n"){ commandString = "pzyn"; eraseAmount = string(toChange.nick_name).length(); changeType = true; isName = true; } else if(input == "p"){ commandString = "pzyp"; eraseAmount = string(toChange.custom_profession).length(); changeType = true; isName = false; } } bool changeValue = false; while(!changeValue) { string input; cout << "value to change to?" << endl; getline(cin, input); if(input == "q"){ return false; } if(!lastText.empty() && input.empty()){ changeValue = true; } else if( !input.empty()){ lastText = input; changeValue = true; } } changeString = lastText; return true; } bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, bool isName) { DFHack::DFWindow * w = DF.getWindow(); DF.Suspend(); DFHack::t_creature testCre; DF.ReadCreature(creatureToCheck,testCre); int tryCount = 0; if(isName) { while(testCre.nick_name != changeValue && tryCount <50) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadCreature(creatureToCheck,testCre); tryCount++; } } else { while(testCre.custom_profession != changeValue && tryCount < 50) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadCreature(creatureToCheck,testCre); tryCount++; } } if(tryCount >= 50){ cerr << "Something went wrong, make sure that DF is at the correct screen"; return false; } DF.Resume(); return true; } bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true) { DFHack::DFWindow * w = DF.getWindow(); DFHack::t_viewscreen current; DF.Suspend(); DF.ReadViewScreen(current); int tryCount = 0; while(((EqualTo && buildingtypes[current.type] != screenState) || (!EqualTo && buildingtypes[current.type] == screenState)) && tryCount < 50) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadViewScreen(current); tryCount++; } if(tryCount >= 50){ cerr << "Something went wrong, DF at " << buildingtypes[current.type] << endl; return false; } DF.Resume(); return true; } bool waitTillCursorState(DFHack::API &DF, bool On) { DFHack::DFWindow * w = DF.getWindow(); int32_t x,y,z; int tryCount = 0; DF.Suspend(); bool cursorResult = DF.getCursorCoords(x,y,z); while(tryCount < 50 && On && !cursorResult || !On && cursorResult) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); tryCount++; DF.Suspend(); cursorResult = DF.getCursorCoords(x,y,z); } if(tryCount >= 50) { cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl; return false; } DF.Resume(); return true; } bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true) { int tryCount = 0; DFHack::DFWindow * w = DF.getWindow(); DF.Suspend(); uint32_t testState = DF.ReadMenuState(); while(tryCount < 50 && ((EqualTo && menuState != testState) || (!EqualTo && menuState == testState))) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); tryCount++; DF.Suspend(); testState = DF.ReadMenuState(); } if(tryCount >= 50) { cerr << "Something went wrong, menuState: "<TypeSpecial(DFHack::F9); // cancel out of text input in names // DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys w->TypeSpecial(DFHack::SPACE); // should move up a level if(!waitTillScreenState(DF,buildingtypes[current.type],false)) return false; // wait until screen changes from current DF.ReadViewScreen(current); } if(DF.ReadMenuState() != 0){// if menu state != 0 then there is a menu, so escape it w->TypeSpecial(DFHack::F9);w->TypeSpecial(DFHack::ENTER); // exit out of any text prompts w->TypeSpecial(DFHack::SPACE); // go back to base state if(!waitTillMenuState(DF,0))return false; } DF.Resume(); return true; } bool setCursorToCreature(DFHack::API &DF) { DFHack::DFWindow * w = DF.getWindow(); int32_t x,y,z; DF.Suspend(); DF.getCursorCoords(x,y,z); DF.Resume(); if(x == -30000){ w->TypeStr("v"); if(!waitTillCursorState(DF,true)) return false; } else{ // reset the cursor to be the creature cursor w->TypeSpecial(DFHack::SPACE); if(!waitTillCursorState(DF,false)) return false; w->TypeStr("v"); if(!waitTillCursorState(DF,true)) return false; } return true; } int main (void) { DFHack::API DF("Memory.xml"); if(!DF.Attach()) { cerr << "DF not found" << endl; return 1; } DF.Suspend(); //Need buildingtypes for the viewscreen vtables, this really should not be just buildings, as viewscreen and items both use the same interface uint32_t numBuildings = DF.InitReadBuildings(buildingtypes); DFHack::memory_info mem = DF.getMemoryInfo(); // get stone matgloss mapping if(!DF.ReadCreatureMatgloss(creaturestypes)) { cerr << "Can't get the creature types." << endl; return 1; } DF.InitReadNameTables(names); numCreatures = DF.InitReadCreatures(); DF.InitViewAndCursor(); printDwarves(DF); DFHack::t_creature toChange; string changeString,commandString; int eraseAmount; int toChangeNum; bool isName; DFHack::DFWindow * w = DF.getWindow(); while(getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName)) { // limit length, DF doesn't accept input after this point if(changeString.size() > 39) { changeString.resize(39); } start: bool completed = false; if(moveToBaseWindow(DF) && setCursorToCreature(DF)) { DF.Suspend(); DF.setCursorCoords(toChange.x, toChange.y,toChange.z); vector underCursor; while(!DF.getCurrentCursorCreatures(underCursor)) { DF.Resume(); w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.setCursorCoords(toChange.x, toChange.y,toChange.z); DF.ReadCreature(toChangeNum,toChange); } //CurrentCursorCreatures gives the creatures in the order that you see them with the 'k' cursor. //The 'v' cursor displays them in the order of last, then first,second,third and so on //Pretty weird, but it works //The only place that seems to display which creature is currently selected is on the stack, whose location is likely not static, so not usable if(underCursor[underCursor.size()-1] != toChange.origin) { for(int i = 0;iTypeStr("v",100); if(underCursor[i] == toChange.origin) { break; } } } DF.Resume(); w->TypeStr(commandString.c_str()); if(waitTillScreenState(DF,"viewscreen_customize_unit")) { DF.Resume(); w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount); if(waitTillChanged(DF,toChangeNum,"",isName)) { DF.Resume(); w->TypeStr(changeString.c_str()); if(waitTillChanged(DF,toChangeNum,changeString,isName)) { DF.Resume(); w->TypeSpecial(DFHack::ENTER); w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked if(waitTillScreenState(DF,"viewscreen_unit")) { DF.Resume(); w->TypeSpecial(DFHack::SPACE); if(waitTillScreenState(DF,"viewscreen_dwarfmode")) { DF.Resume(); w->TypeSpecial(DFHack::SPACE); if(waitTillCursorState(DF,false)) { completed = true; } } } } } } } if(!completed){ cerr << "Something went wrong, please reset DF to its original state, then press any key to continue" << endl; goto start; } DF.Suspend(); printDwarves(DF); } return 0; }