Deal with third flag group in creatures

Added support for reading and writing the third creature flag group,
t_creaturflags3 (the offest already exists in Memory.xml).  So far I've
only figured out three of the flags (out of an apparent 13):

1) announce_titan, which causes the creature to be announced as if
   it was a titan or FB which had just arrived.

2) scuttle, which causes the creature to be die like it had been
   killed in the game.  That is, it leaves behind a corpse, and
   will generate unhappy thoughts in dwarves if approriate.

3) ghostly, for creatures which are the ghosts of dead dwarves.

I updated creaturemanager to use scuttle for --kill, and added the
action --erase to kill in the old way which doesn't leave a corpse or
creatre unhappy thoughts.
develop
Matthew Cline 2011-07-10 04:00:52 -07:00
parent bc9911212e
commit cb9c9aae7c
5 changed files with 114 additions and 2 deletions

@ -54,6 +54,7 @@ DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr);
DFHACK_EXPORT int Creatures_WriteLabors(DFHackObject* cPtr, const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); DFHACK_EXPORT int Creatures_WriteLabors(DFHackObject* cPtr, const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);
DFHACK_EXPORT int Creatures_WriteHappiness(DFHackObject* cPtr, const uint32_t index, const uint32_t happiness_value); DFHACK_EXPORT int Creatures_WriteHappiness(DFHackObject* cPtr, const uint32_t index, const uint32_t happiness_value);
DFHACK_EXPORT int Creatures_WriteFlags(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2); DFHACK_EXPORT int Creatures_WriteFlags(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2);
DFHACK_EXPORT int Creatures_WriteFlags3(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2, const uint32_t flags3);
DFHACK_EXPORT int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul); DFHACK_EXPORT int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul);
DFHACK_EXPORT int Creatures_WriteAttributes(DFHackObject* cPtr, const uint32_t index, const t_creature* creature); DFHACK_EXPORT int Creatures_WriteAttributes(DFHackObject* cPtr, const uint32_t index, const t_creature* creature);
DFHACK_EXPORT int Creatures_WriteSex(DFHackObject* cPtr, const uint32_t index, const uint8_t sex); DFHACK_EXPORT int Creatures_WriteSex(DFHackObject* cPtr, const uint32_t index, const uint8_t sex);

@ -111,6 +111,40 @@ namespace DFHack
} bits; } bits;
}; };
union t_creaturflags3
{
uint32_t whole; /*!< Access all flags as a single 32bit number. */
struct
{
unsigned int unk0 : 1; /*!< Is 1 for new and dead creatures,
periodicaly set to 0 for non-dead creatures.
*/
unsigned int unk1 : 1; /*!< Is 1 for new creatures, periodically set
to 0 for non-dead creatures. */
unsigned int unk2 : 1; /*!< Is set to 1 every tick for non-dead
creatures. */
unsigned int unk3 : 1; /*!< Is periodically set to 0 for non-dead
creatures. */
unsigned int announce_titan : 1; /*!< Announces creature like an
FB or titan. */
unsigned int unk5 : 1;
unsigned int unk6 : 1;
unsigned int unk7 : 1;
unsigned int unk8 : 1; /*!< Is set to 1 every tick for non-dead
creatures. */
unsigned int unk9 : 1; /*!< Is set to 0 every tick for non-dead
creatures. */
unsigned int scuttle : 1; /*!< Scuttle creature: causes creature
to be killed, leaving a behind corpse
and generating negative thoughts like
a real kill. */
unsigned int unk11 : 1;
unsigned int ghostly : 1; /*!< Creature is a ghost. */
unsigned int unk13_31 : 19;
} bits;
};
// FIXME: WTF IS THIS SHIT? // FIXME: WTF IS THIS SHIT?
/* /*
struct t_labor struct t_labor
@ -261,6 +295,7 @@ namespace DFHack
t_creaturflags1 flags1; t_creaturflags1 flags1;
t_creaturflags2 flags2; t_creaturflags2 flags2;
t_creaturflags3 flags3;
t_name name; t_name name;
@ -335,6 +370,7 @@ namespace DFHack
bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]); bool WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);
bool WriteHappiness(const uint32_t index, const uint32_t happinessValue); bool WriteHappiness(const uint32_t index, const uint32_t happinessValue);
bool WriteFlags(const uint32_t index, const uint32_t flags1, const uint32_t flags2); bool WriteFlags(const uint32_t index, const uint32_t flags1, const uint32_t flags2);
bool WriteFlags(const uint32_t index, const uint32_t flags1, const uint32_t flags2, uint32_t flags3);
bool WriteSkills(const uint32_t index, const t_soul &soul); bool WriteSkills(const uint32_t index, const t_soul &soul);
bool WriteAttributes(const uint32_t index, const t_creature &creature); bool WriteAttributes(const uint32_t index, const t_creature &creature);
bool WriteSex(const uint32_t index, const uint8_t sex); bool WriteSex(const uint32_t index, const uint8_t sex);

@ -68,6 +68,7 @@ struct Creatures::Private
int32_t civ_offset; int32_t civ_offset;
uint32_t flags1_offset; uint32_t flags1_offset;
uint32_t flags2_offset; uint32_t flags2_offset;
uint32_t flags3_offset;
uint32_t name_offset; uint32_t name_offset;
uint32_t sex_offset; uint32_t sex_offset;
uint32_t caste_offset; uint32_t caste_offset;
@ -156,6 +157,7 @@ Creatures::Creatures(DFContextShared* _d)
creatures.pos_offset = OG_creature->getOffset ("position"); creatures.pos_offset = OG_creature->getOffset ("position");
creatures.flags1_offset = OG_creature->getOffset ("flags1"); creatures.flags1_offset = OG_creature->getOffset ("flags1");
creatures.flags2_offset = OG_creature->getOffset ("flags2"); creatures.flags2_offset = OG_creature->getOffset ("flags2");
creatures.flags3_offset = OG_creature->getOffset ("flags3");
creatures.sex_offset = OG_creature->getOffset ("sex"); creatures.sex_offset = OG_creature->getOffset ("sex");
creatures.caste_offset = OG_creature->getOffset ("caste"); creatures.caste_offset = OG_creature->getOffset ("caste");
creatures.id_offset = OG_creature->getOffset ("id"); creatures.id_offset = OG_creature->getOffset ("id");
@ -284,6 +286,7 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball)
p->readWord (addr_cr + offs.caste_offset, furball.caste); p->readWord (addr_cr + offs.caste_offset, furball.caste);
p->readDWord (addr_cr + offs.flags1_offset, furball.flags1.whole); p->readDWord (addr_cr + offs.flags1_offset, furball.flags1.whole);
p->readDWord (addr_cr + offs.flags2_offset, furball.flags2.whole); p->readDWord (addr_cr + offs.flags2_offset, furball.flags2.whole);
p->readDWord (addr_cr + offs.flags3_offset, furball.flags3.whole);
// custom profession // custom profession
p->readSTLString(addr_cr + offs.custom_profession_offset, furball.custom_profession, sizeof(furball.custom_profession)); p->readSTLString(addr_cr + offs.custom_profession_offset, furball.custom_profession, sizeof(furball.custom_profession));
// profession // profession
@ -491,6 +494,21 @@ bool Creatures::WriteFlags(const uint32_t index,
return true; return true;
} }
bool Creatures::WriteFlags(const uint32_t index,
const uint32_t flags1,
const uint32_t flags2,
const uint32_t flags3)
{
if(!d->Started || !d->Ft_basic) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord (temp + d->creatures.flags1_offset, flags1);
p->writeDWord (temp + d->creatures.flags2_offset, flags2);
p->writeDWord (temp + d->creatures.flags3_offset, flags3);
return true;
}
bool Creatures::WriteSkills(const uint32_t index, const t_soul &soul) bool Creatures::WriteSkills(const uint32_t index, const t_soul &soul)
{ {
if(!d->Started || !d->Ft_soul) return false; if(!d->Started || !d->Ft_soul) return false;

@ -212,6 +212,17 @@ int Creatures_WriteFlags(DFHackObject* cPtr, const uint32_t index, const uint32_
return -1; return -1;
} }
int Creatures_WriteFlags3(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2, const uint32_t flags3)
{
if(cPtr != NULL)
{
return ((DFHack::Creatures*)cPtr)->WriteFlags(index, flags1, flags2,
flags3);
}
return -1;
}
int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul) int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul)
{ {
if(cPtr != NULL && soul != NULL) if(cPtr != NULL && soul != NULL)

@ -208,6 +208,7 @@ void usage(int argc, const char * argv[])
<< " * diplomat: all diplomats" << endl << " * diplomat: all diplomats" << endl
<< " * FB: all forgotten beasts" << endl << " * FB: all forgotten beasts" << endl
<< " * female: all female creatures" << endl << " * female: all female creatures" << endl
<< " * ghost: all ghosts" << endl
<< " * male: all male creatures" << endl << " * male: all male creatures" << endl
<< " * merchants: all merchants (including pack animals)" << endl << " * merchants: all merchants (including pack animals)" << endl
<< " * neuter: all neuter creatuers" << endl << " * neuter: all neuter creatuers" << endl
@ -238,7 +239,8 @@ void usage(int argc, const char * argv[])
<< "-rh : Remove hauler labors (stone hauling, etc.) from creature" << endl << "-rh : Remove hauler labors (stone hauling, etc.) from creature" << endl
// Disabling mood doesn't work as intented // Disabling mood doesn't work as intented
<< "--setmood <n> : Set mood to n (-1 = no mood, max=4, buggy!)" << endl << "--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 << "--kill : Kill creature(s) (leaves behind corpses)" << endl
<< "--erase : Remove creature(s) from game without killing" << endl
<< "--tame : Tames animals, recruits intelligent creatures." << endl << "--tame : Tames animals, recruits intelligent creatures." << endl
<< "--slaugher : Mark a creature for slaughter, even sentients" << endl << "--slaugher : Mark a creature for slaughter, even sentients" << endl
<< "--butcher : Same as --slaugher" << endl << "--butcher : Same as --slaugher" << endl
@ -520,6 +522,7 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
{ {
DFHack::t_creaturflags1 f1 = creature.flags1; DFHack::t_creaturflags1 f1 = creature.flags1;
DFHack::t_creaturflags2 f2 = creature.flags2; DFHack::t_creaturflags2 f2 = creature.flags2;
DFHack::t_creaturflags3 f3 = creature.flags3;
if(f1.bits.dead){cout << "Flag: dead" << endl; } if(f1.bits.dead){cout << "Flag: dead" << endl; }
if(f1.bits.had_mood){cout<<toCaps("Flag: had_mood") << endl; } if(f1.bits.had_mood){cout<<toCaps("Flag: had_mood") << endl; }
@ -584,6 +587,10 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
if(f2.bits.breathing_problem){cout<<toCaps("Flag: breathing_problem") << endl; } if(f2.bits.breathing_problem){cout<<toCaps("Flag: breathing_problem") << endl; }
if(f2.bits.roaming_wilderness_population_source){cout<<toCaps("Flag: roaming_wilderness_population_source") << endl; } if(f2.bits.roaming_wilderness_population_source){cout<<toCaps("Flag: roaming_wilderness_population_source") << endl; }
if(f2.bits.roaming_wilderness_population_source_not_a_map_feature){cout<<toCaps("Flag: roaming_wilderness_population_source_not_a_map_feature") << endl; } if(f2.bits.roaming_wilderness_population_source_not_a_map_feature){cout<<toCaps("Flag: roaming_wilderness_population_source_not_a_map_feature") << endl; }
if(f3.bits.announce_titan){cout<<toCaps("Flag: announce_titan") << endl; }
if(f3.bits.scuttle){cout<<toCaps("Flag: scuttle") << endl; }
if(f3.bits.ghostly){cout<<toCaps("Flag: ghostly") << endl; }
} }
else else
{ {
@ -601,6 +608,9 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, in
if(creature.flags2.bits.slaughter) { cout << "Flag: Marked for slaughter" << 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.flags2.bits.underworld) { cout << "Flag: From the underworld" << endl; }
/* FLAGS 3 */
if(creature.flags3.bits.ghostly) { cout << "Flag: Ghost" << endl; }
if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) ) if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) )
{ {
string artifact_name = Tran->TranslateName(creature.artifact_name,false); string artifact_name = Tran->TranslateName(creature.artifact_name,false);
@ -628,6 +638,7 @@ public:
bool find_nonicks; bool find_nonicks;
bool find_nicks; bool find_nicks;
bool forgotten_beast; bool forgotten_beast;
bool ghost;
bool merchant; bool merchant;
bool pregnant; bool pregnant;
bool tame; bool tame;
@ -654,6 +665,7 @@ public:
find_nonicks = false; find_nonicks = false;
find_nicks = false; find_nicks = false;
forgotten_beast = false; forgotten_beast = false;
ghost = false;
merchant = false; merchant = false;
pregnant = false; pregnant = false;
sex = SEX_ANY; sex = SEX_ANY;
@ -696,6 +708,8 @@ public:
diplomat = true; diplomat = true;
else if (type == "Fb" || type == "Beast") else if (type == "Fb" || type == "Beast")
forgotten_beast = true; forgotten_beast = true;
else if (type == "Ghost")
ghost = true;
else if (type == "Merchant") else if (type == "Merchant")
merchant = true; merchant = true;
else if (type == "Pregnant") else if (type == "Pregnant")
@ -735,6 +749,7 @@ public:
const DFHack::t_creaturflags1 &f1 = creature.flags1; const DFHack::t_creaturflags1 &f1 = creature.flags1;
const DFHack::t_creaturflags2 &f2 = creature.flags2; const DFHack::t_creaturflags2 &f2 = creature.flags2;
const DFHack::t_creaturflags3 &f3 = creature.flags3;
if(f1.bits.dead && !showdead) if(f1.bits.dead && !showdead)
return false; return false;
@ -758,6 +773,8 @@ public:
return false; return false;
if(forgotten_beast && !f2.bits.visitor_uninvited) if(forgotten_beast && !f2.bits.visitor_uninvited)
return false; return false;
if(ghost && !f3.bits.ghostly)
return false;
if(merchant && !f1.bits.merchant) if(merchant && !f1.bits.merchant)
return false; return false;
if(pregnant && creature.pregnancy_timer == 0) if(pregnant && creature.pregnancy_timer == 0)
@ -790,6 +807,7 @@ int main (int argc, const char* argv[])
bool remove_military_skills = false; bool remove_military_skills = false;
bool remove_labors = false; bool remove_labors = false;
bool kill_creature = false; bool kill_creature = false;
bool erase_creature = false;
bool revive_creature = false; bool revive_creature = false;
bool make_hauler = false; bool make_hauler = false;
bool remove_hauler = false; bool remove_hauler = false;
@ -926,6 +944,12 @@ int main (int argc, const char* argv[])
showallflags = true; showallflags = true;
showdead = true; showdead = true;
} }
else if(arg_cur == "--erase")
{
erase_creature = true;
showallflags = true;
showdead = true;
}
else if(arg_cur == "--revive") else if(arg_cur == "--revive")
{ {
revive_creature = true; revive_creature = true;
@ -1088,7 +1112,7 @@ int main (int argc, const char* argv[])
remove_skills || remove_civil_skills || remove_military_skills remove_skills || remove_civil_skills || remove_military_skills
|| remove_labors || add_labor || remove_labor || remove_labors || add_labor || remove_labor
|| make_hauler || remove_hauler || make_hauler || remove_hauler
|| kill_creature || kill_creature || erase_creature
|| revive_creature || revive_creature
|| set_happiness || set_happiness
|| set_mood || set_mood
@ -1119,6 +1143,27 @@ int main (int argc, const char* argv[])
if(creature.has_default_soul) if(creature.has_default_soul)
{ {
if (kill_creature && !creature.flags1.bits.dead) if (kill_creature && !creature.flags1.bits.dead)
{
DFHack::t_creaturflags1 f1 = creature.flags1;
DFHack::t_creaturflags2 f2 = creature.flags2;
DFHack::t_creaturflags3 f3 = creature.flags3;
f3.bits.scuttle = true;
cout << "Writing flags..." << endl;
if (!Creatures->WriteFlags(creature_idx, f1.whole,
f2.whole, f3.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;
creature.flags3 = f3;
}
if (erase_creature && !creature.flags1.bits.dead)
{ {
/* /*
[quote author=Eldrick Tobin link=topic=58809.msg2178545#msg2178545 date=1302638055] [quote author=Eldrick Tobin link=topic=58809.msg2178545#msg2178545 date=1302638055]
@ -1185,6 +1230,7 @@ int main (int argc, const char* argv[])
creature.flags2 = f2; creature.flags2 = f2;
} }
if (revive_creature && creature.flags1.bits.dead) if (revive_creature && creature.flags1.bits.dead)
{ {
DFHack::t_creaturflags1 f1 = creature.flags1; DFHack::t_creaturflags1 f1 = creature.flags1;