diff --git a/Memory.xml b/Memory.xml index 84fff9b27..29efd1857 100644 --- a/Memory.xml +++ b/Memory.xml @@ -285,10 +285,10 @@ - + - + @@ -299,21 +299,23 @@ - + - + + + - + @@ -329,23 +331,23 @@ - - - + + + - - - - - - + + + + + + - + @@ -353,7 +355,7 @@ - + @@ -423,7 +425,7 @@ - + diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index 21dbbe6c7..14db195b8 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -80,11 +80,13 @@ DFHACK_TOOL(dfprinttiletypes printtiletypes.cpp) # Will have many options in the future. DFHACK_TOOL(dfhellhole hellhole.cpp) -# skillmodify +# dfcreature # Author: raoulxq -# Lets modify skills and labors of dwarfs and other creatures -# Allows mass-modify, esp. for all immigrants -DFHACK_TOOL(dfskillmodify skillmodify.cpp) +# - Display creatures +# - Modify skills and labors of creatures +# - Kill creatures +# - Etc. +DFHACK_TOOL(dfcreature creature.cpp) # digpattern # Author: raoulxq diff --git a/tools/playground/skillmodify.cpp b/tools/playground/creature.cpp similarity index 51% rename from tools/playground/skillmodify.cpp rename to tools/playground/creature.cpp index c53ead8c8..1aa49797e 100644 --- a/tools/playground/skillmodify.cpp +++ b/tools/playground/creature.cpp @@ -1,13 +1,14 @@ /********************************************* - * skillmodify.cpp - * * Purpose: * * - Display creatures * - Modify skills and labors of creatures + * - Kill creatures + * - Etc. * * Version: 0.1.1 * Date: 2011-04-07 + * Author: raoulxq (based on creaturedump.cpp from peterix) * Todo: * - Option to add/remove single skills @@ -17,12 +18,27 @@ * - Filter by last name with -ln * - Add pattern matching (or at least matching) to -n/-fn/-ln * - Set nickname with --setnick (only if -i is given) - * - Kill/revive creature(s) with --kill/--revive + * - Revive creature(s) with --revive * - Show skills/labors only when -ss/-sl/-v is given or a skill/labor is changed - * - Allow multiple -i switches - * - Display current job + * - Make -1 the default for everything but -i + * - Imply -i if first argument is a number + * - Search for nick/profession if first argument is a string without - (i.e. no switch) + * - Switch --showhappy + * - Switch --makefriendly + * - Switch --listskills, showing first 3 important skills * Done: + * - Allow comma separated list of IDs for -i + * - '-c all' shows all creatures + * - Rename from skillmodify.cpp to creature.cpp + * - Kill creature(s) with --kill + * - Hide skills with level 0 and 0 experience points + * - Add --showallflags flag to display all flags (default: display a few important ones) + * - Add --showdead flag to also display dead creatures + * - Display more creature flags + * - Show creature type (again) + * - Add switch -1/--summary to only display one line for every creature. Good for an overview. + * - Display current job (has been there all the time, but not shown in Windows due to missing memory offsets) * - Remove magic numbers * - Show social skills only when -ss is given * - Hide hauler labors when +sh is given @@ -67,25 +83,33 @@ using namespace std; #define SKILL_FLATTERY 82 #define SKILL_CONSOLING 83 #define SKILL_PACIFICATION 84 -#define LABOR_STONE_HAULING 1 -#define LABOR_WOOD_HAULING 2 -#define LABOR_BURIAL 3 -#define LABOR_FOOD_HAULING 4 -#define LABOR_REFUSE_HAULING 5 -#define LABOR_ITEM_HAULING 6 -#define LABOR_FURNITURE_HAULING 7 -#define LABOR_ANIMAL_HAULING 8 -#define LABOR_CLEANING 9 + +#define LABOR_STONE_HAULING 1 +#define LABOR_WOOD_HAULING 2 +#define LABOR_BURIAL 3 +#define LABOR_FOOD_HAULING 4 +#define LABOR_REFUSE_HAULING 5 +#define LABOR_ITEM_HAULING 6 +#define LABOR_FURNITURE_HAULING 7 +#define LABOR_ANIMAL_HAULING 8 +#define LABOR_CLEANING 9 #define LABOR_FEED_PATIENTS_PRISONERS 22 -#define LABOR_RECOVERING_WOUNDED 23 +#define LABOR_RECOVERING_WOUNDED 23 #define NOT_SET INT_MIN #define MAX_MOOD 4 #define NO_MOOD -1 -bool quiet; +#define PROFESSION_CHILD 96 +#define PROFESSION_BABY 97 + +bool quiet=true; bool verbose = false; bool showhauler = true; bool showsocial = false; +bool showfirstlineonly = false; +bool showdead = false; +bool showallflags = false; + int hauler_labors[] = { LABOR_STONE_HAULING ,LABOR_WOOD_HAULING @@ -117,23 +141,32 @@ void usage(int argc, const char * argv[]) cout << "Usage:" << endl << argv[0] << " [option 1] [option 2] [...]" << endl - << "-q : Suppress \"Press any key to continue\" at program termination" << endl - << "-v : Increase verbosity" << endl - << "-c creature : Only show/modify this creature type instead of dwarfes" << endl - << "-i id : Only show/modify creature with this id" << endl - << "-nn : Only show/modify creatures with no custom nickname (migrants)" << endl - << "--nicks : Only show/modify creatures with custom nickname" << endl - << "-ll : List available labors" << endl - << "-al : Add labor to creature" << endl - << "-rl : Remove labor from creature" << endl - << "-ras : Remove all skills from creature" << endl - << "-ral : Remove all labors from creature" << endl - << "-ah : Add hauler labors (stone hauling, etc.) to creature" << endl - << "-rh : Remove hauler labors (stone hauling, etc.) from creature" << endl - << "--setmood : Set mood to n (-1 = no mood, max=4)" << endl - // Doesn't work, because hapiness is recalculated + << endl + << "Display options:" << endl + << "-q : Suppress \"Press any key to continue\" at program termination" << endl + << "-v : Increase verbosity" << endl + << "-c creature : Show/modify this creature type instead of dwarfes ('all' to show all creatures)" << endl + << "-1/--summary : Only display one line per creature" << endl + << "-i id1[,id2,...]: Only show/modify creature with this id" << endl + << "-nn/--nonicks : Only show/modify creatures with no custom nickname (migrants)" << endl + << "--nicks : Only show/modify creatures with custom nickname" << endl + << "-ll/--listlabors: List available labors" << endl + << "--showdead : Also show/modify dead creatures" << endl + << "--showallflags : Show all flags of a creature" << endl + << endl + << "Modifying options:" << endl + << "-al : Add labor to creature" << endl + << "-rl : Remove labor from creature" << endl + << "-ras : Remove all skills from creature" << endl + << "-ral : Remove all labors from creature" << endl + << "-ah : Add hauler labors (stone hauling, etc.) to creature" << endl + << "-rh : Remove hauler labors (stone hauling, etc.) from creature" << endl + // Disabling mood doesn't work as intented + << "--setmood : Set mood to n (-1 = no mood, max=4, buggy!)" << endl + << "--kill : Kill creature(s) (may need to be called multiple times)" << endl + // Setting happiness doesn't work, because hapiness is recalculated //<< "--sethappiness : Set happiness to n" << endl - << "-f : Force an action" << endl + << "-f : Force an action" << endl << endl << "Example 1: Show all dwarfs" << endl << argv[0] << " -c Dwarf" << endl @@ -141,8 +174,8 @@ void usage(int argc, const char * argv[]) << "Example 2: Show all Yaks" << endl << argv[0] << " -c Yak" << endl << endl - << "Example 3: Remove all skills from dwarf with id 32" << endl - << argv[0] << " -i 32 -ras" << endl + << "Example 3: Remove all skills from dwarfs 15 and 32" << endl + << argv[0] << " -i 15,32 -ras" << endl << endl << "Example 4: Remove all skills and labors from dwarfs with no custom nickname" << endl << argv[0] << " -c DWARF -nn -ras -ral" << endl @@ -171,13 +204,26 @@ DFHack::Creatures * Creatures = NULL; std::string toCaps(std::string s) { const int length = s.length(); + bool caps=true; if (length == 0) { return s; } - s[0] = std::toupper(s[0]); - for(int i=1; i!=length ; ++i) + for(int i=0; i!=length ; ++i) { - s[i] = std::tolower(s[i]); + if (caps) + { + s[i] = std::toupper(s[i]); + caps = false; + } + else if (s[i] == '_' || s[i] == ' ') + { + s[i] = ' '; + caps = true; + } + else + { + s[i] = std::tolower(s[i]); + } } return s; } @@ -201,53 +247,107 @@ bool is_in(int m, int set[], int set_size) return false; } +int * find_int(std::vector v, int comp) +{ + for (int i=0; iraceEx[creature.race].rawname); + DFHack::Translation *Tran = DF->getTranslation(); DFHack::VersionInfo *mem = DF->getMemoryInfo(); + string type="(no type)"; + if (Materials->raceEx[creature.race].rawname[0]) + { + type = toCaps(Materials->raceEx[creature.race].rawname); + } + + string name="(no name)"; if(creature.name.nickname[0]) { - cout << ", " << creature.name.nickname; + name = creature.name.nickname; } else { if(creature.name.first_name[0]) { - cout << ", " << toCaps(creature.name.first_name); - } + name = toCaps(creature.name.first_name); - string transName = Tran->TranslateName(creature.name,false); - if(!transName.empty()) - { - cout << " " << toCaps(transName); + string transName = Tran->TranslateName(creature.name,false); + if(!transName.empty()) + { + name += " " + toCaps(transName); + } } } - string prof_string=""; + string profession=""; try { - prof_string = mem->getProfession(creature.profession); + profession = mem->getProfession(creature.profession); } catch (exception& e) { cout << "Error retrieving creature profession: " << e.what() << endl; } - cout << ", " << toCaps(prof_string) << "(" << int(creature.profession) << ")"; - if(creature.custom_profession[0]) { - cout << "/" << creature.custom_profession; + profession = creature.custom_profession; } + + string job="No Job"; if(creature.current_job.active) { - cout << ", current job: " << mem->getJob(creature.current_job.jobId); + job=mem->getJob(creature.current_job.jobId); + int p=job.size(); + while (p>0 && (job[p]==' ' || job[p]=='\t')) + p--; + if (p <= 1) + { + stringstream ss; + ss << creature.current_job.jobId; + job = ss.str(); + } } - cout << ", Happy = " << creature.happiness; - cout << endl; + if (showfirstlineonly) + { + printf("%3d", index); + printf(" %-17s", type.c_str()); + printf(" %-32s", name.c_str()); + printf(" %-16s", toCaps(profession).c_str()); + printf(" %-30s", job.c_str()); + printf(" %5d", creature.happiness); + if (showdead) + { + printf(" %-5s", creature.flags1.bits.dead ? "Dead" : "Alive"); + } + + printf("\n"); + + return; + } + else + { + printf("ID: %d", index); + printf(", %s", type.c_str()); + printf(", %s", name.c_str()); + printf(", %s", toCaps(profession).c_str()); + printf(", Job: %s", job.c_str()); + printf(", Happiness: %d", creature.happiness); + printf("\n"); + } if((creature.mood != NO_MOOD) && (creature.mood<=MAX_MOOD)) { @@ -289,8 +389,11 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in skillname = "Unknown skill"; cout << e.what() << endl; } - cout << "(Skill " << int(skillid) << ") " << setw(16) << skillname << ": " - << skillrating << "/" << skillexperience << endl; + if (skillrating > 0 || skillexperience > 0) + { + cout << "(Skill " << int(skillid) << ") " << setw(16) << skillname << ": " + << skillrating << "/" << skillexperience << endl; + } } } @@ -312,26 +415,97 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in cout << "(Labor " << i << ") " << setw(16) << laborname << endl; } } - /* FLAGS 1 */ - if(creature.flags1.bits.dead) { cout << "Flag: Dead" << endl; } - if(creature.flags1.bits.on_ground) { cout << "Flag: On the ground" << endl; } - if(creature.flags1.bits.skeleton) { cout << "Flag: Skeletal" << endl; } - if(creature.flags1.bits.zombie) { cout << "Flag: Zombie" << endl; } - if(creature.flags1.bits.tame) { cout << "Flag: Tame" << endl; } - if(creature.flags1.bits.royal_guard){ cout << "Flag: Royal_guard" << endl; } - if(creature.flags1.bits.fortress_guard){cout<<"Flag: Fortress_guard" << endl; } - /* FLAGS 2 */ - if(creature.flags2.bits.killed) { cout << "Flag: Killed by kill function" << endl; } - if(creature.flags2.bits.resident) { cout << "Flag: Resident" << endl; } - if(creature.flags2.bits.gutted) { cout << "Flag: Gutted" << endl; } - if(creature.flags2.bits.slaughter) { cout << "Flag: Marked for slaughter" << endl; } - if(creature.flags2.bits.underworld) { cout << "Flag: From the underworld" << endl; } - - if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) ) + if (showallflags) + { + DFHack::t_creaturflags1 f1 = creature.flags1; + DFHack::t_creaturflags2 f2 = creature.flags2; + + if(f1.bits.had_mood){cout<TranslateName(creature.artifact_name,false); - cout << "Artifact: " << artifact_name << endl; + /* FLAGS 1 */ + if(creature.flags1.bits.dead) { cout << "Flag: Dead" << endl; } + if(creature.flags1.bits.on_ground) { cout << "Flag: On the ground" << endl; } + if(creature.flags1.bits.tame) { cout << "Flag: Tame" << endl; } + if(creature.flags1.bits.royal_guard) { cout << "Flag: Royal guard" << endl; } + if(creature.flags1.bits.fortress_guard) { cout << "Flag: Fortress guard" << endl; } + + /* FLAGS 2 */ + if(creature.flags2.bits.killed) { cout << "Flag: Killed by kill function" << endl; } + if(creature.flags2.bits.resident) { cout << "Flag: Resident" << endl; } + if(creature.flags2.bits.gutted) { cout << "Flag: Gutted" << endl; } + if(creature.flags2.bits.slaughter) { cout << "Flag: Marked for slaughter" << endl; } + if(creature.flags2.bits.underworld) { cout << "Flag: From the underworld" << endl; } + + if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) ) + { + string artifact_name = Tran->TranslateName(creature.artifact_name,false); + cout << "Artifact: " << artifact_name << endl; + } } + cout << endl; } int main (int argc, const char* argv[]) @@ -342,12 +516,12 @@ int main (int argc, const char* argv[]) #endif string creature_type = "Dwarf"; - string creature_id = ""; - int creature_id_int = 0; + std::vector creature_id; bool find_nonicks = false; bool find_nicks = false; bool remove_skills = false; bool remove_labors = false; + bool kill_creature = false; bool make_hauler = false; bool remove_hauler = false; bool add_labor = false; @@ -392,6 +566,10 @@ int main (int argc, const char* argv[]) { verbose = true; } + else if(arg_cur == "-1" || arg_cur == "--summary") + { + showfirstlineonly = true; + } else if(arg_cur == "-ss" || arg_cur == "--showsocial") { showsocial = true; @@ -400,6 +578,14 @@ int main (int argc, const char* argv[]) { showhauler = false; } + else if(arg_cur == "--showdead") + { + showdead = true; + } + else if(arg_cur == "--showallflags") + { + showallflags = true; + } else if(arg_cur == "-ras") { remove_skills = true; @@ -409,7 +595,7 @@ int main (int argc, const char* argv[]) force_massdesignation = true; } // list labors - else if(arg_cur == "-ll") + else if(arg_cur == "-ll" || arg_cur == "--listlabors") { list_labors = true; } @@ -455,6 +641,12 @@ int main (int argc, const char* argv[]) set_happiness_n = arg_next_int; i++; } + else if(arg_cur == "--kill") + { + kill_creature = true; + showallflags = true; + showdead = true; + } else if(arg_cur == "-ral") { remove_labors = true; @@ -467,7 +659,7 @@ int main (int argc, const char* argv[]) { remove_hauler = true; } - else if(arg_cur == "-nn") + else if(arg_cur == "-nn" || arg_cur == "--nonicks") { find_nonicks = true; } @@ -482,8 +674,15 @@ int main (int argc, const char* argv[]) } else if(arg_cur == "-i" && i < argc-1) { - creature_id = argv[i+1]; - sscanf(argv[i+1], "%d", &creature_id_int); + std::stringstream ss(argv[i+1]); + int num; + while (ss >> num) { + creature_id.push_back(num); + ss.ignore(1); + } + + creature_type = ""; // if -i is given, match all creatures + showdead = true; i++; } else @@ -572,6 +771,12 @@ int main (int argc, const char* argv[]) } else { + if (showfirstlineonly) + { + printf("ID Type Name/nickname Job title Current job Happy%s\n", showdead?" Dead ":""); + printf("--- ----------------- -------------------------------- ---------------- ------------------------------ -----%s\n", showdead?" -----":""); + } + vector addrs; for(uint32_t creature_idx = 0; creature_idx < numCreatures; creature_idx++) { @@ -581,16 +786,16 @@ int main (int argc, const char* argv[]) bool hasnick = (creature.name.nickname[0] != '\0'); if ( - // Check for -i - (creature_id.empty() || creature_idx == creature_id_int) - // Check for -c - && (creature_type.empty() || toCaps(string(Materials->raceEx[creature.race].rawname)) == toCaps(creature_type)) + // Check for -i and -c + (NULL != find_int(creature_id, creature_idx) + || toCaps(string(Materials->raceEx[creature.race].rawname)) == toCaps(creature_type) + || "All" == toCaps(creature_type)) // Check for -nn && ((find_nonicks == true && hasnick == false) || (find_nicks == true && hasnick == true) || (find_nicks == false && find_nonicks == false)) && (find_nonicks == false || creature.name.nickname[0] == '\0') - && (!creature.flags1.bits.dead) + && (showdead == true || !creature.flags1.bits.dead) ) { printCreature(DF,creature,creature_idx); @@ -600,23 +805,24 @@ int main (int argc, const char* argv[]) remove_skills || remove_labors || add_labor || remove_labor || make_hauler || remove_hauler + || kill_creature || set_happiness || set_mood ); - // 96=Child, 97=Baby - if (creature.profession == 96 || creature.profession == 97) + if (toCaps(creature_type) == "Dwarf" + && (creature.profession == PROFESSION_CHILD || creature.profession == PROFESSION_BABY)) { dochange = false; } bool allow_massdesignation = - !creature_id.empty() || toCaps(creature_type) != "Dwarf" || find_nonicks == true || force_massdesignation; + creature_id.size()==0 || toCaps(creature_type) != "Dwarf" || find_nonicks == true || force_massdesignation; if (dochange == true && allow_massdesignation == false) { cout << "Not changing creature because none of -c (other than dwarf), -i or -nn was" << endl - << "selected. Add -f to still do mass designation." << endl; + << "selected. Add -f (force) to override this safety measure." << endl; dochange = false; } @@ -624,10 +830,74 @@ int main (int argc, const char* argv[]) { if(creature.has_default_soul) { + if (kill_creature) + { + /* + [quote author=Eldrick Tobin link=topic=58809.msg2178545#msg2178545 date=1302638055] + + After extensive testing that just ate itself -.-; + + Runesmith does not unset the following: + - Active Invader (sets if they are just about the invade, as Currently + Invading removes this one) + - Hidden Ambusher (Just in Case, however it is still set when an Active Invader) + - Hidden in Ambush (Just in Case, however it is still set when an Active Invader, + until discovery) + - Incoming (Sets if something is here yet... wave X of a siege here) + - Invader -Fleeing/Leaving + - Currently Invading + + When it nukes something it basically just sets them to 'dead'. It does not also + set them to 'killed'. Show dead will show everything (short of 'vanished'/'deleted' + I'd suspect) so one CAN go through the intensive process to revive a broken siege. These + particular flags are not visible at the same exact time so multiple passes -even through + a narrow segment- are advised. + + Problem I ran into (last thing before I mention something more DFHack related): + I set the Killed Flag (but not dead), and I got mortally wounded siegers that refused to + just pift in Magma. [color=purple]Likely missing upper torsoes on examination[/color]. + + */ + DFHack::t_creaturflags1 f1 = creature.flags1; + DFHack::t_creaturflags2 f2 = creature.flags2; + + f1.bits.dead = 1; + f2.bits.killed = 1; + f1.bits.active_invader = 0; /*!< 17: Active invader (for organized ones) */ + f1.bits.hidden_ambusher = 0; /*!< 21: Active marauder/invader moving inward? */ + f1.bits.hidden_in_ambush = 0; + f1.bits.invades = 0; /*!< 22: Marauder resident/invader moving in all the way */ + + cout << "Setting f1.bits.dead = 1" << endl; + cout << "Setting f2.bits.killed = 1" << endl; + cout << "Setting f1.bits.active_invader = 0" << endl; + cout << "Setting f1.bits.hidden_ambusher = 0" << endl; + cout << "Setting f1.bits.hidden_in_ambush = 0" << endl; + cout << "Setting f1.bits.invades = 0" << endl; + cout << "Writing flags..." << endl; + if (!Creatures->WriteFlags(creature_idx, f1.whole, f2.whole)) + { + cout << "Error writing creature flags!" << endl; + } + // We want the flags to be shown after our modification, but they are not read back + creature.flags1 = f1; + creature.flags2 = f2; + } + if (set_mood) { + /* Doesn't really work to disable a mood */ cout << "Setting mood to " << set_mood_n << "..." << endl; Creatures->WriteMood(creature_idx, set_mood_n); + DFHack::t_creaturflags1 f1 = creature.flags1; + DFHack::t_creaturflags2 f2 = creature.flags2; + f1.bits.has_mood = (set_mood_n == NO_MOOD ? 0 : 1); + if (!Creatures->WriteFlags(creature_idx, f1.whole, f2.whole)) + { + cout << "Error writing creature flags!" << endl; + } + creature.flags1 = f1; + creature.flags2 = f2; } if (set_happiness) @@ -705,7 +975,6 @@ int main (int argc, const char* argv[]) } printCreature(DF,creature,creature_idx); } /* End remove skills/labors */ - cout << endl; } /* if (print creature) */ } /* End for(all creatures) */ } /* End if (we need to walk creatures) */