Merge pull request #87 from matthew-cline/master

creaturemanager.cpp: Additional actions and creature filters, and misc changes
develop
Petr Mrázek 2011-07-09 20:32:20 -07:00
commit 488322cb0d
1 changed files with 290 additions and 30 deletions

@ -189,18 +189,45 @@ void usage(int argc, const char * argv[])
<< "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
<< endl
<< "Choosing which creatures to display and/or modify "
<< "(note that all criteria" << endl << "must match, so adding "
<< " more narrows things down):" << endl
<< "-i id1[,id2,...]: Only show/modify creature with this id" << endl
<< "-c creature : Show/modify this creature type instead of dwarves" << endl
<< " ('all' to show all creatures)" << 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
<< "--type : Show/modify all creatures of given type" << endl
<< " : Can be used multiple times" << endl
<< " types:" << endl
<< " * dead: all dead creatures" << endl
<< " * demon: all demons" << endl
<< " * diplomat: all diplomats" << endl
<< " * FB: all forgotten beasts" << endl
<< " * female: all female creatures" << endl
<< " * male: all male creatures" << endl
<< " * merchants: all merchants (including pack animals)" << endl
<< " * neuter: all neuter creatuers" << endl
<< " * pregnant: all pregnant creatures" << endl
<< " * tame: all tame creatues" << endl
<< " * wild: all wild creatures" << endl
<< endl
<< "What information to display:" << endl
<< "-saf : Show all flags of a creature" << endl
<< "--showallflags : Show all flags of a creature" << endl
<< "-ll/--listlabors: List available labors" << endl
<< "-ss : Show social skills" << endl
<< "+sh : Hide hauler labors" << endl
<< "-1/--summary : Only display one line per creature" << endl
<< endl
<< "Modifying options:" << endl
<< "Options to modify selected creatures:" << endl
<< "-al <n> : Add labor <n> to creature" << endl
<< "-rl <n> : Remove labor <n> from creature" << endl
<< "-ras : Remove all skills from creature (i.e. set them to zero)" << endl
@ -212,6 +239,9 @@ void usage(int argc, const char * argv[])
// Disabling mood doesn't work as intented
<< "--setmood <n> : Set mood to n (-1 = no mood, max=4, buggy!)" << endl
<< "--kill : Kill creature(s) (may need to be called multiple times)" << endl
<< "--tame : Tames animals, recruits intelligent creatures." << endl
<< "--slaugher : Mark a creature for slaughter, even sentients" << endl
<< "--butcher : Same as --slaugher" << endl
// Doesn't seem to work
//<< "--revive : Attempt to revive creature(s) (remove dead and killed flag)" << endl
// Setting happiness doesn't work really, because hapiness is recalculated
@ -249,6 +279,9 @@ void usage(int argc, const char * argv[])
<< endl
<< "Make Urist, Stodir and Ingish miners:" << endl
<< argv[0] << " -i 31,42,77 -al 0" << endl
<< endl
<< "Make all demons friendly:" << endl
<< argv[0] << " --type demon --tame" << endl
;
if (quiet == false) {
cout << "Press any key to continue" << endl;
@ -413,6 +446,8 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
printf(", Job: %s", job.c_str());
printf(", Happiness: %d", creature.happiness);
printf("\n");
printf("Origin: %p\n", creature.origin);
printf("Civ #: %d\n", creature.civ);
}
if((creature.mood != NO_MOOD) && (creature.mood<=MAX_MOOD))
@ -486,6 +521,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
DFHack::t_creaturflags1 f1 = creature.flags1;
DFHack::t_creaturflags2 f2 = creature.flags2;
if(f1.bits.dead){cout << "Flag: dead" << endl; }
if(f1.bits.had_mood){cout<<toCaps("Flag: had_mood") << endl; }
if(f1.bits.marauder){cout<<toCaps("Flag: marauder") << endl; }
if(f1.bits.drowning){cout<<toCaps("Flag: drowning") << endl; }
@ -574,17 +610,181 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
cout << endl;
}
class creature_filter
{
public:
enum sex_filter
{
SEX_FEMALE = 0,
SEX_MALE = 1,
SEX_ANY = 254, // Our magin number for ignoring sex.
SEX_NEUTER = 255
};
bool dead;
bool demon;
bool diplomat;
bool find_nonicks;
bool find_nicks;
bool forgotten_beast;
bool merchant;
bool pregnant;
bool tame;
bool wild;
sex_filter sex;
string creature_type;
std::vector<int> creature_id;
#define DEFAULT_CREATURE_STR "Default"
creature_filter()
{
// By default we only select dwarves, except that if we use the
// --type option we want to default to everyone. So we start out
// with a special string, and if remains unchanged after all
// the options have been processed we turn it to DWARF.
creature_type = DEFAULT_CREATURE_STR;
dead = false;
demon = false;
diplomat = false;
find_nonicks = false;
find_nicks = false;
forgotten_beast = false;
merchant = false;
pregnant = false;
sex = SEX_ANY;
tame = false;
wild = false;
}
// If the creature type is still the default, then change it to allow
// for all creatures. If the creature type has been explicitly set,
// then don't alter it.
void defaultTypeToAll()
{
if (creature_type == DEFAULT_CREATURE_STR)
creature_type = "";
}
// If the creature type is still the default, change it to DWARF
void defaultTypeToDwarf()
{
if (creature_type == DEFAULT_CREATURE_STR)
creature_type = "Dwarf";
}
void process_type(string type)
{
type = toCaps(type);
// If we're going by type, then by default all species are
// permitted.
defaultTypeToAll();
if (type == "Dead")
{
dead = true;
showdead = true;
}
else if (type == "Demon")
demon = true;
else if (type == "Diplomat")
diplomat = true;
else if (type == "Fb" || type == "Beast")
forgotten_beast = true;
else if (type == "Merchant")
merchant = true;
else if (type == "Pregnant")
pregnant = true;
else if (type == "Tame")
tame = true;
else if (type == "Wild")
wild = true;
else if (type == "Male")
sex = SEX_MALE;
else if (type == "Female")
sex = SEX_FEMALE;
else if (type == "Neuter")
sex = SEX_NEUTER;
else
{
cerr << "ERROR: Unknown type '" << type << "'" << endl;
}
}
void doneProcessingOptions()
{
string temp = toCaps(creature_type);
creature_type = temp;
defaultTypeToDwarf();
}
bool creatureMatches(const DFHack::t_creature & creature,
uint32_t creature_idx)
{
// A list of ids overrides everything else.
if (creature_id.size() > 0)
return (find_int(creature_id, creature_idx));
// If it's not a list of ids, it has not match all given criteria.
const DFHack::t_creaturflags1 &f1 = creature.flags1;
const DFHack::t_creaturflags2 &f2 = creature.flags2;
if(f1.bits.dead && !showdead)
return false;
bool hasnick = (creature.name.nickname[0] != '\0');
if(hasnick && find_nonicks)
return false;
if(!hasnick && find_nicks)
return false;
string race_name = string(Materials->raceEx[creature.race].rawname);
if(!creature_type.empty() && creature_type != toCaps(race_name))
return false;
if(dead && !f1.bits.dead)
return false;
if(demon && !f2.bits.underworld)
return false;
if(diplomat && !f1.bits.diplomat)
return false;
if(forgotten_beast && !f2.bits.visitor_uninvited)
return false;
if(merchant && !f1.bits.merchant)
return false;
if(pregnant && creature.pregnancy_timer == 0)
return false;
if (sex != SEX_ANY && creature.sex != (uint8_t) sex)
return false;
if(tame && !f1.bits.tame)
return false;
if(wild && !f2.bits.roaming_wilderness_population_source &&
!f2.bits.roaming_wilderness_population_source_not_a_map_feature)
{
return false;
}
return true;
}
};
int main (int argc, const char* argv[])
{
// let's be more useful when double-clicked on windows
#ifndef LINUX_BUILD
quiet = false;
#endif
creature_filter filter;
string creature_type = "Dwarf";
std::vector<int> creature_id;
bool find_nonicks = false;
bool find_nicks = false;
bool remove_skills = false;
bool remove_civil_skills = false;
bool remove_military_skills = false;
@ -603,6 +803,8 @@ int main (int argc, const char* argv[])
int set_mood_n = NOT_SET;
bool list_labors = false;
bool force_massdesignation = false;
bool tame_creature = false;
bool slaughter_creature = false;
if (argc == 1) {
usage(argc, argv);
@ -651,7 +853,7 @@ int main (int argc, const char* argv[])
{
showdead = true;
}
else if(arg_cur == "--showallflags")
else if(arg_cur == "--showallflags" || arg_cur == "-saf")
{
showallflags = true;
}
@ -744,15 +946,15 @@ int main (int argc, const char* argv[])
}
else if(arg_cur == "-nn" || arg_cur == "--nonicks")
{
find_nonicks = true;
filter.find_nonicks = true;
}
else if(arg_cur == "--nicks")
{
find_nicks = true;
filter.find_nicks = true;
}
else if(arg_cur == "-c" && i < argc-1)
{
creature_type = argv[i+1];
filter.creature_type = argv[i+1];
i++;
}
else if(arg_cur == "-i" && i < argc-1)
@ -760,14 +962,23 @@ int main (int argc, const char* argv[])
std::stringstream ss(argv[i+1]);
int num;
while (ss >> num) {
creature_id.push_back(num);
filter.creature_id.push_back(num);
ss.ignore(1);
}
creature_type = ""; // if -i is given, match all creatures
filter.creature_type = ""; // if -i is given, match all creatures
showdead = true;
i++;
}
else if(arg_cur == "--type" && i < argc-1)
{
filter.process_type(arg_next);
i++;
}
else if (arg_cur == "--tame")
tame_creature = true;
else if (arg_cur == "--slaugher" || arg_cur == "--butcher")
slaughter_creature = true;
else
{
if (arg_cur != "-h") {
@ -779,6 +990,8 @@ int main (int argc, const char* argv[])
}
}
filter.doneProcessingOptions();
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context* DF;
try
@ -866,20 +1079,7 @@ int main (int argc, const char* argv[])
DFHack::t_creature creature;
Creatures->ReadCreature(creature_idx,creature);
/* Check if we want to display/change this creature or skip it */
bool hasnick = (creature.name.nickname[0] != '\0');
if (
// Check for -i <num> and -c <type>
(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')
&& (showdead == true || !creature.flags1.bits.dead)
)
if(filter.creatureMatches(creature, creature_idx))
{
printCreature(DF,creature,creature_idx);
addrs.push_back(creature.origin);
@ -892,16 +1092,20 @@ int main (int argc, const char* argv[])
|| revive_creature
|| set_happiness
|| set_mood
|| tame_creature || slaughter_creature
);
if (toCaps(creature_type) == "Dwarf"
if (toCaps(filter.creature_type) == "Dwarf"
&& (creature.profession == PROFESSION_CHILD || creature.profession == PROFESSION_BABY))
{
dochange = false;
}
bool allow_massdesignation =
creature_id.size()==0 || toCaps(creature_type) != "Dwarf" || find_nonicks == true || force_massdesignation;
filter.creature_id.size()==0 ||
toCaps(filter.creature_type) != "Dwarf" ||
filter.find_nonicks == true ||
force_massdesignation;
if (dochange == true && allow_massdesignation == false)
{
cout
@ -1095,6 +1299,62 @@ int main (int argc, const char* argv[])
cout << "Error writing labors." << endl;
}
}
if (tame_creature)
{
bool tame = true;
DFHack::t_creaturflags1 f1 = creature.flags1;
DFHack::t_creaturflags2 f2 = creature.flags2;
// Site residents are intelligent, so don't
// tame them.
if (f2.bits.resident)
tame = false;
f1.bits.diplomat = false;
f1.bits.merchant = false;
f2.bits.resident = false;
f2.bits.underworld = false;
f2.bits.visitor_uninvited = false;
f2.bits.roaming_wilderness_population_source = false;
f2.bits.roaming_wilderness_population_source_not_a_map_feature = false;
// Creatures which already belong to a civ might
// be intelligent, so don't tame them.
if (creature.civ == -1)
f1.bits.tame = tame;
if (!Creatures->WriteFlags(creature_idx,
f1.whole, f2.whole))
{
cout << "Error writing creature flags!" << endl;
}
int32_t civ = Creatures->GetDwarfCivId();
if (!Creatures->WriteCiv(creature_idx, civ))
{
cout << "Error writing creature civ!" << endl;
}
creature.flags1 = f1;
creature.flags2 = f2;
}
if (slaughter_creature)
{
DFHack::t_creaturflags1 f1 = creature.flags1;
DFHack::t_creaturflags2 f2 = creature.flags2;
f2.bits.slaughter = true;
if (!Creatures->WriteFlags(creature_idx,
f1.whole, f2.whole))
{
cout << "Error writing creature flags!" << endl;
}
creature.flags1 = f1;
creature.flags2 = f2;
}
}
else
{