diff options
| author | Petr Mrázek | 2012-03-01 00:01:24 +0100 |
|---|---|---|
| committer | Petr Mrázek | 2012-03-01 00:01:24 +0100 |
| commit | 07b4044336176e8277f3adaa2e03c406e77b6b76 (patch) | |
| tree | 9019b2ea3ff92b8c77dc464c46d8026d63bbd7ac /needs_porting/fix-3708.cpp | |
| parent | 1f2782d5b86ee62d821ec0c7e33833048fc06b20 (diff) | |
| download | dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.gz dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.bz2 dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.xz | |
Nuke more!
Diffstat (limited to 'needs_porting/fix-3708.cpp')
| -rw-r--r-- | needs_porting/fix-3708.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/needs_porting/fix-3708.cpp b/needs_porting/fix-3708.cpp new file mode 100644 index 00000000..2cfaed91 --- /dev/null +++ b/needs_porting/fix-3708.cpp @@ -0,0 +1,217 @@ +/* Fixes bug 3708 (Ghosts that can't be engraved on a slab). + + Cause of the bug: + + In order to be engraved on a slab, the creature must be + a historical figure, i.e. be in the historical figure list + of the Legends mode. It seems that caravan guards are not + added to that list until they do something notable, e.g. + kill a goblin. Unfortunately, their own death doesn't + trigger this sometimes. + + Solution: + + Steal a historical figure entry from a dead goblin, by + replacing the IDs in the structures; also overwrite his + name, race and profession to make the menus make slightly + more sense. + + Downsides: + + - Obviously, this is an ugly hack. + - The Legends mode still lists the guard as belonging to + the goblin civilization, and killed by whoever killed the + original goblin. There might be other inconsistencies. + + Positive sides: + + - Avoids messing with tricky creature control code, + by allowing the ghost to be removed naturally. + */ + +#include <iostream> +#include <climits> +#include <string.h> +#include <vector> +#include <list> +#include <stdio.h> +using namespace std; + +#define DFHACK_WANT_MISCUTILS +#include <DFHack.h> + +enum likeType +{ + FAIL = 0, + MATERIAL = 1, + ITEM = 2, + FOOD = 3 +}; + +DFHack::Materials * Materials; +DFHack::VersionInfo *mem; +DFHack::Creatures * Creatures = NULL; + +void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature) +{ + cout << "Address: " << hex << creature.origin << dec << ", creature race: " << Materials->raceEx[creature.race].rawname + << ", position: " << creature.x << "x " << creature.y << "y "<< creature.z << "z" << endl + << "Name: " << creature.name.first_name; + + if (creature.name.nickname[0]) + cout << " `" << creature.name.nickname << "'"; + + DFHack::Translation * Tran = DF->getTranslation(); + + cout << " " << Tran->TranslateName(creature.name,false) + << " (" << Tran->TranslateName(creature.name,true) << ")" << endl; + + cout << "Profession: " << mem->getProfession(creature.profession); + + if(creature.custom_profession[0]) + cout << ", custom: " << creature.custom_profession; + + uint32_t dayoflife = creature.birth_year*12*28 + creature.birth_time/1200; + cout << endl + << "Born on the year " << creature.birth_year + << ", month " << (creature.birth_time/1200/28) + << ", day " << ((creature.birth_time/1200) % 28 + 1) + << ", " << dayoflife << " days lived." << endl << endl; +} + + +int main (int numargs, char ** args) +{ + DFHack::World * World; + DFHack::ContextManager DFMgr("Memory.xml"); + DFHack::Context* DF; + try + { + DF = DFMgr.getSingleContext(); + DF->Attach(); + } + catch (exception& e) + { + cerr << e.what() << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + Creatures = DF->getCreatures(); + Materials = DF->getMaterials(); + World = DF->getWorld(); + DFHack::Translation * Tran = DF->getTranslation(); + + uint32_t numCreatures; + if(!Creatures->Start(numCreatures)) + { + cerr << "Can't get creatures" << endl; + #ifndef LINUX_BUILD + cin.ignore(); + #endif + return 1; + } + + Materials->ReadCreatureTypes(); + Materials->ReadCreatureTypesEx(); + + mem = DF->getMemoryInfo(); + DFHack::Process *p = DF->getProcess(); + + if(!Tran->Start()) + { + cerr << "Can't get name tables" << endl; + return 1; + } + + DFHack::OffsetGroup *ogc = mem->getGroup("Creatures")->getGroup("creature"); + uint32_t o_flags3 = ogc->getOffset("flags3"); + uint32_t o_c_hfid = ogc->getGroup("advanced")->getOffset("hist_figure_id"); + + std::list<uint32_t> goblins; + std::list<uint32_t> ghosts; + + for(uint32_t i = 0; i < numCreatures; i++) + { + DFHack::t_creature temp; + Creatures->ReadCreature(i,temp); + + int32_t hfid = p->readDWord(temp.origin + o_c_hfid); + + if (hfid > 0) { + if (temp.flags1.bits.dead) { + std::string name = Materials->raceEx[temp.race].rawname; + if (name == "GOBLIN") + goblins.push_back(i); + } + } else { + uint32_t flags3 = p->readDWord(temp.origin + o_flags3); + if (!(flags3 & 0x1000)) + continue; + + ghosts.push_back(i); + } + } + + if (goblins.size() >= ghosts.size() && ghosts.size() > 0) + { + DFHack::OffsetGroup *grp_figures = mem->getGroup("Legends")->getGroup("figures"); + uint32_t f_vector = p->readDWord(grp_figures->getAddress("vector")); + uint32_t f_id = grp_figures->getOffset("figure_id"); + uint32_t f_unit = grp_figures->getOffset("unit_id"); + uint32_t f_name = grp_figures->getOffset("name"); + uint32_t f_race = grp_figures->getOffset("race"); + uint32_t f_profession = grp_figures->getOffset("profession"); + + for (std::list<uint32_t>::iterator it = ghosts.begin(); it != ghosts.end(); ++it) + { + int i = *it; + DFHack::t_creature ghost; + Creatures->ReadCreature(i,ghost); + + printCreature(DF,ghost); + + int igoblin = goblins.front(); + goblins.pop_front(); + DFHack::t_creature goblin; + Creatures->ReadCreature(igoblin,goblin); + + printCreature(DF,goblin); + + int32_t hfid = p->readDWord(goblin.origin + o_c_hfid); + uint32_t fptr = p->readDWord(f_vector + 4*hfid); + + if (p->readDWord(fptr + f_id) != hfid || + p->readDWord(fptr + f_unit) != goblin.id || + p->readWord(fptr + f_race) != goblin.race) + { + cout << "Data structure inconsistency detected, aborting."; + break; + } + + if (1) { + p->writeDWord(goblin.origin + o_c_hfid, -1); + p->writeDWord(ghost.origin + o_c_hfid, hfid); + p->writeDWord(fptr + f_unit, ghost.id); + p->writeWord(fptr + f_race, ghost.race); + p->writeWord(fptr + f_profession, ghost.profession); + Creatures->CopyNameTo(ghost, fptr + f_name); + cout << "Pair succesfully patched." << endl << endl; + } + } + } + else + { + cout << "No suitable ghosts, or not enough goblins." << endl; + } + + Creatures->Finish(); + DF->Detach(); + #ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); + #endif + return 0; +} |
