From 9adf310d7f162ba58da764bed2c918487c692f6b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 22 May 2012 12:31:37 +0400 Subject: [PATCH] Update Units::isCitizen after looking at game-over detection code. --- LUA_API.rst | 13 +++++-- Lua API.html | 11 ++++-- library/LuaApi.cpp | 2 ++ library/modules/Units.cpp | 71 ++++++++++++++++++++++++++++++++++----- library/xml | 2 +- 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index b0f1a9f31..9fb37375d 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -726,7 +726,7 @@ Units module * ``dfhack.units.isDead(unit)`` - The unit is completely dead and passive. + The unit is completely dead and passive, or a ghost. * ``dfhack.units.isAlive(unit)`` @@ -734,7 +734,16 @@ Units module * ``dfhack.units.isSane(unit)`` - The unit is capable of rational action, i.e. not dead, insane or zombie. + The unit is capable of rational action, i.e. not dead, insane, zombie, or active werewolf. + +* ``dfhack.units.isDwarf(unit)`` + + The unit is of the correct race of the fortress. + +* ``dfhack.units.isCitizen(unit)`` + + The unit is an alive sane citizen of the fortress; wraps the + same checks the game uses to decide game-over by extinction. * ``dfhack.units.getAge(unit[,true_age])`` diff --git a/Lua API.html b/Lua API.html index 4b763af25..1576652d6 100644 --- a/Lua API.html +++ b/Lua API.html @@ -960,13 +960,20 @@ a lua list containing them.

Returns the nemesis record of the unit if it has one, or nil.

  • dfhack.units.isDead(unit)

    -

    The unit is completely dead and passive.

    +

    The unit is completely dead and passive, or a ghost.

  • dfhack.units.isAlive(unit)

    The unit isn't dead or undead.

  • dfhack.units.isSane(unit)

    -

    The unit is capable of rational action, i.e. not dead, insane or zombie.

    +

    The unit is capable of rational action, i.e. not dead, insane, zombie, or active werewolf.

    +
  • +
  • dfhack.units.isDwarf(unit)

    +

    The unit is of the correct race of the fortress.

    +
  • +
  • dfhack.units.isCitizen(unit)

    +

    The unit is an alive sane citizen of the fortress; wraps the +same checks the game uses to decide game-over by extinction.

  • dfhack.units.getAge(unit[,true_age])

    Returns the age of the unit in years as a floating-point value. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 6a550db87..8e8a3c4e3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -715,6 +715,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), + WRAPM(Units, isDwarf), + WRAPM(Units, isCitizen), WRAPM(Units, getAge), WRAPM(Units, getProfessionName), WRAPM(Units, getCasteProfessionName), diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index dd26109e7..ee383cc07 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -613,12 +613,45 @@ df::nemesis_record *Units::getNemesis(df::unit *unit) return NULL; } +static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag) +{ + auto creature = df::creature_raw::find(race); + if (!creature) + return false; + + auto craw = vector_get(creature->caste, caste); + if (!craw) + return false; + + return craw->flags.is_set(flag); +} + +static bool isCrazed(df::unit *unit) +{ + if (unit->flags3.bits.scuttle) + return false; + if (unit->curse.rem_tags1.bits.CRAZED) + return false; + if (unit->curse.add_tags1.bits.CRAZED) + return true; + return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CRAZED); +} + +static bool isOpposedToLife(df::unit *unit) +{ + if (unit->curse.rem_tags1.bits.OPPOSED_TO_LIFE) + return false; + if (unit->curse.add_tags1.bits.OPPOSED_TO_LIFE) + return true; + return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CANNOT_UNDEAD); +} bool DFHack::Units::isDead(df::unit *unit) { CHECK_NULL_POINTER(unit); - return unit->flags1.bits.dead; + return unit->flags1.bits.dead || + unit->flags3.bits.ghostly; } bool DFHack::Units::isAlive(df::unit *unit) @@ -636,8 +669,11 @@ bool DFHack::Units::isSane(df::unit *unit) if (unit->flags1.bits.dead || unit->flags3.bits.ghostly || - unit->curse.add_tags1.bits.OPPOSED_TO_LIFE || - unit->curse.add_tags1.bits.CRAZED) + isOpposedToLife(unit) || + unit->unknown8.unk2) + return false; + + if (unit->unknown8.normal_race == unit->unknown8.were_race && isCrazed(unit)) return false; switch (unit->mood) @@ -657,19 +693,38 @@ bool DFHack::Units::isCitizen(df::unit *unit) { CHECK_NULL_POINTER(unit); + // Copied from the conditions used to decide game over, + // except that the game appears to let melancholy/raving + // dwarves count as citizens. + + if (!isDwarf(unit) || !isSane(unit)) + return false; + + if (unit->flags1.bits.marauder || + unit->flags1.bits.invader_origin || + unit->flags1.bits.active_invader || + unit->flags1.bits.forest || + unit->flags1.bits.merchant || + unit->flags1.bits.diplomat) + return false; + + if (unit->flags1.bits.tame) + return true; + return unit->civ_id == ui->civ_id && - !unit->flags1.bits.merchant && - !unit->flags1.bits.diplomat && + unit->civ_id != -1 && + !unit->flags2.bits.underworld && !unit->flags2.bits.resident && - !unit->flags1.bits.dead && - !unit->flags3.bits.ghostly; + !unit->flags2.bits.visitor_uninvited && + !unit->flags2.bits.visitor; } bool DFHack::Units::isDwarf(df::unit *unit) { CHECK_NULL_POINTER(unit); - return unit->race == ui->race_id; + return unit->race == ui->race_id || + unit->unknown8.normal_race == ui->race_id; } double DFHack::Units::getAge(df::unit *unit, bool true_age) diff --git a/library/xml b/library/xml index 234d0f57a..d991d47b0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 234d0f57a927f306f2052fc2f45d38b3201ddee6 +Subproject commit d991d47b0f6709205c4e333bb86edb3dcf656429