From 45ae2ed67f9aba4d635a7565253bd9098a87bbde Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
dfhack.units.setNickname(unit,nick)
+Sets the unit's nickname properly.
+dfhack.units.getVisibleName(unit)
-Returns the name visible in game, accounting for false identities.
+Returns the language_name object visible in game, accounting for false identities.
+dfhack.units.getNemesis(unit)
+Returns the nemesis record of the unit if it has one, or nil.
dfhack.units.isDead(unit)
The unit is completely dead and passive.
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index f1d86580a..5e55460d7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -55,6 +55,7 @@ distribution. #include "df/unit.h" #include "df/item.h" #include "df/material.h" +#include "df/nemesis_record.h" #include "df/historical_figure.h" #include "df/plant_raw.h" #include "df/creature_raw.h" @@ -555,7 +556,9 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = { }; static const LuaWrapper::FunctionReg dfhack_units_module[] = { + WRAPM(Units, setNickname), WRAPM(Units, getVisibleName), + WRAPM(Units, getNemesis), WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), diff --git a/library/include/modules/Translation.h b/library/include/modules/Translation.h index 19a3ed9a6..6d74431e3 100644 --- a/library/include/modules/Translation.h +++ b/library/include/modules/Translation.h @@ -50,6 +50,8 @@ DFHACK_EXPORT bool IsValid (); DFHACK_EXPORT bool readName(t_name & name, df::language_name * address); DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * target); +DFHACK_EXPORT void setNickname(df::language_name *name, std::string nick); + // translate a name using the loaded dictionaries DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true, bool onlyLastPart = false); diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index b966a39be..838d1d596 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -33,6 +33,11 @@ distribution. #include "DataDefs.h" #include "df/unit.h" +namespace df +{ + struct nemesis_record; +} + /** * \defgroup grp_units Unit module parts * @ingroup grp_modules @@ -193,8 +198,11 @@ DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target); DFHACK_EXPORT bool RemoveOwnedItemByIdx(const uint32_t index, int32_t id); DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id); +DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick); DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit); +DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit); + DFHACK_EXPORT bool isDead(df::unit *unit); DFHACK_EXPORT bool isAlive(df::unit *unit); DFHACK_EXPORT bool isSane(df::unit *unit); diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index aae2a90b9..592f27c0b 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -46,6 +46,7 @@ using namespace DFHack; #include "df/global_objects.h" #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_dungeonmodest.h" +#include "df/viewscreen_dungeon_monsterstatusst.h" #include "df/viewscreen_joblistst.h" #include "df/viewscreen_unitlistst.h" #include "df/viewscreen_itemst.h" @@ -284,6 +285,9 @@ static df::unit *getAnyUnit(df::viewscreen *top) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitlistst, top)) return vector_get(screen->units[screen->page], screen->cursor_pos[screen->page]); + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_dungeon_monsterstatusst, top)) + return screen->unit; + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top)) { df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos); diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index bc0724707..6b055a4ac 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -92,6 +92,21 @@ void addNameWord (string &out, const string &word) out.append(upper); } +void Translation::setNickname(df::language_name *name, std::string nick) +{ + CHECK_NULL_POINTER(name); + + if (!name->has_name) + { + *name = df::language_name(); + + name->language = 0; + name->has_name = true; + } + + name->nickname = nick; +} + string Translation::TranslateName(const df::language_name * name, bool inEnglish, bool onlyLastPart) { CHECK_NULL_POINTER(name); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 3dc5d1b04..e210a9028 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -48,6 +48,8 @@ using namespace std; #include "df/world.h" #include "df/ui.h" #include "df/unit_inventory_item.h" +#include "df/unit_soul.h" +#include "df/nemesis_record.h" #include "df/historical_entity.h" #include "df/historical_figure.h" #include "df/historical_figure_info.h" @@ -527,6 +529,47 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target) Translation::copyName(&creature->name, target); } +void Units::setNickname(df::unit *unit, std::string nick) +{ + CHECK_NULL_POINTER(unit); + + // There are >=3 copies of the name, and the one + // in the unit is not the authoritative one. + // This is the reason why military units often + // lose nicknames set from Dwarf Therapist. + Translation::setNickname(&unit->name, nick); + + if (unit->status.current_soul) + Translation::setNickname(&unit->status.current_soul->name, nick); + + df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id); + if (figure) + { + Translation::setNickname(&figure->name, nick); + + // v0.34.01: added the vampire's assumed identity + if (figure->info && figure->info->reputation) + { + auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity); + + if (identity) + { + auto id_hfig = df::historical_figure::find(identity->histfig_id); + + if (id_hfig) + { + // Even DF doesn't do this bit, because it's apparently + // only used for demons masquerading as gods, so you + // can't ever change their nickname in-game. + Translation::setNickname(&id_hfig->name, nick); + } + else + Translation::setNickname(&identity->name, nick); + } + } + } +} + df::language_name *Units::getVisibleName(df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -555,6 +598,22 @@ df::language_name *Units::getVisibleName(df::unit *unit) return &unit->name; } +df::nemesis_record *Units::getNemesis(df::unit *unit) +{ + if (!unit) + return NULL; + + for (unsigned i = 0; i < unit->refs.size(); i++) + { + df::nemesis_record *rv = unit->refs[i]->getNemesis(); + if (rv && rv->unit == unit) + return rv; + } + + return NULL; +} + + bool DFHack::Units::isDead(df::unit *unit) { CHECK_NULL_POINTER(unit); diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 4fc1b4e5d..ffb428fd8 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -8,6 +8,8 @@ #include "modules/Materials.h" #include "modules/Maps.h" #include "modules/Items.h" +#include "modules/Gui.h" +#include "modules/Units.h" #include "DataDefs.h" #include "df/world.h" @@ -159,31 +161,6 @@ static bool bodyswap_hotkey(df::viewscreen *top) !!virtual_cast