diff --git a/NEWS b/NEWS index c6a470fd3..38e307bc4 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,36 @@ DFHack Future Lua scripts can set environment variables of each other with dfhack.run_script_with_env. eventful Lua reactions no longer require LUA_HOOK as a prefix: you can register a callback for the completion of any reaction with a name Filesystem module now provides file access/modification times and can list directories (normally and recursively) + Units Module: New functions: + isWar + isHunter + isAvailableForAdoption + isOwnCiv + isOwnRace + getRaceName + getRaceNamePlural + getRaceBabyName + getRaceChildName + isBaby + isChild + isAdult + isEggLayer + isGrazer + isMilkable + isTrainableWar + isTrainableHunting + isTamable + isMale + isFemale + isMerchant + isForest + isMarkedForSlaughter + Buildings Module: New Functions: + isActivityZone + isPenPasture + isPitPond + isActive + findPenPitAt Fixes dfhack.run_script should correctly find save-specific scripts now. Updated add-thought to properly affect stress. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 7832ce513..64d27038c 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1401,6 +1401,29 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getCasteProfessionName), WRAPM(Units, getProfessionColor), WRAPM(Units, getCasteProfessionColor), + WRAPM(Units, isWar), + WRAPM(Units, isHunter), + WRAPM(Units, isAvailableForAdoption), + WRAPM(Units, isOwnCiv), + WRAPM(Units, isOwnRace), + WRAPM(Units, getRaceName), + WRAPM(Units, getRaceNamePlural), + WRAPM(Units, getRaceBabyName), + WRAPM(Units, getRaceChildName), + WRAPM(Units, isBaby), + WRAPM(Units, isChild), + WRAPM(Units, isAdult), + WRAPM(Units, isEggLayer), + WRAPM(Units, isGrazer), + WRAPM(Units, isMilkable), + WRAPM(Units, isTrainableWar), + WRAPM(Units, isTrainableHunting), + WRAPM(Units, isTamable), + WRAPM(Units, isMale), + WRAPM(Units, isFemale), + WRAPM(Units, isMerchant), + WRAPM(Units, isForest), + WRAPM(Units, isMarkedForSlaughter), { NULL, NULL } }; @@ -1678,6 +1701,10 @@ static const LuaWrapper::FunctionReg dfhack_buildings_module[] = { WRAPM(Buildings, constructWithItems), WRAPM(Buildings, constructWithFilters), WRAPM(Buildings, deconstruct), + WRAPM(Buildings, isActivityZone), + WRAPM(Buildings, isPenPasture), + WRAPM(Buildings, isPitPond), + WRAPM(Buildings, isActive), { NULL, NULL } }; @@ -1699,6 +1726,13 @@ static int buildings_findCivzonesAt(lua_State *L) return 1; } +static int buildings_findPenPitAt(lua_State *L) +{ + auto pos = CheckCoordXYZ(L, 1, true); + Lua::PushDFObject(L, Buildings::findPenPitAt(pos)); + return 1; +} + static int buildings_getCorrectSize(lua_State *state) { df::coord2d size(luaL_optint(state, 1, 1), luaL_optint(state, 2, 1)); @@ -1758,6 +1792,7 @@ static const luaL_Reg dfhack_buildings_funcs[] = { { "getCorrectSize", buildings_getCorrectSize }, { "setSize", &Lua::CallWithCatchWrapper }, { "getStockpileContents", buildings_getStockpileContents}, + { "findPenPitAt", buildings_findPenPitAt}, { NULL, NULL } }; diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index db12bb73e..5d0005963 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -288,6 +288,11 @@ public: * Collects items stored on a stockpile into a vector. */ DFHACK_EXPORT void getStockpileContents(df::building_stockpilest *stockpile, std::vector *items); +DFHACK_EXPORT bool isActivityZone(df::building * building); +DFHACK_EXPORT bool isPenPasture(df::building * building); +DFHACK_EXPORT bool isPitPond(df::building * building); +DFHACK_EXPORT bool isActive(df::building * building); +DFHACK_EXPORT df::building* findPenPitAt(df::coord coord); } } diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 6462b166c..655f13b5a 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -233,6 +233,35 @@ DFHACK_EXPORT bool isAlive(df::unit *unit); DFHACK_EXPORT bool isSane(df::unit *unit); DFHACK_EXPORT bool isCitizen(df::unit *unit); DFHACK_EXPORT bool isDwarf(df::unit *unit); +DFHACK_EXPORT bool isWar(df::unit* unit); +DFHACK_EXPORT bool isHunter(df::unit* unit); +DFHACK_EXPORT bool isAvailableForAdoption(df::unit* unit); +DFHACK_EXPORT bool isOwnCiv(df::unit* unit); +DFHACK_EXPORT bool isOwnRace(df::unit* unit); + +DFHACK_EXPORT std::string getRaceNameById(int32_t race_id); +DFHACK_EXPORT std::string getRaceName(df::unit* unit); +DFHACK_EXPORT std::string getRaceNamePluralById(int32_t race_id); +DFHACK_EXPORT std::string getRaceNamePlural(df::unit* unit); +DFHACK_EXPORT std::string getRaceBabyNameById(int32_t race_id); +DFHACK_EXPORT std::string getRaceBabyName(df::unit* unit); +DFHACK_EXPORT std::string getRaceChildNameById(int32_t race_id); +DFHACK_EXPORT std::string getRaceChildName(df::unit* unit); + +DFHACK_EXPORT bool isBaby(df::unit* unit); +DFHACK_EXPORT bool isChild(df::unit* unit); +DFHACK_EXPORT bool isAdult(df::unit* unit); +DFHACK_EXPORT bool isEggLayer(df::unit* unit); +DFHACK_EXPORT bool isGrazer(df::unit* unit); +DFHACK_EXPORT bool isMilkable(df::unit* unit); +DFHACK_EXPORT bool isTrainableWar(df::unit* unit); +DFHACK_EXPORT bool isTrainableHunting(df::unit* unit); +DFHACK_EXPORT bool isTamable(df::unit* unit); +DFHACK_EXPORT bool isMale(df::unit* unit); +DFHACK_EXPORT bool isFemale(df::unit* unit); +DFHACK_EXPORT bool isMerchant(df::unit* unit); +DFHACK_EXPORT bool isForest(df::unit* unit); +DFHACK_EXPORT bool isMarkedForSlaughter(df::unit* unit); DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 885edfa02..0ceaeb819 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1176,3 +1176,45 @@ void Buildings::getStockpileContents(df::building_stockpilest *stockpile, std::v items->push_back(item); } } + +bool Buildings::isActivityZone(df::building * building) +{ + CHECK_NULL_POINTER(building); + return building->getType() == building_type::Civzone + && building->getSubtype() == (short)civzone_type::ActivityZone; +} + +bool Buildings::isPenPasture(df::building * building) +{ + if (!isActivityZone(building)) + return false; + + return ((df::building_civzonest*) building)->zone_flags.bits.pen_pasture != 0; +} + +bool Buildings::isPitPond(df::building * building) +{ + if (!isActivityZone(building)) + return false; + return ((df::building_civzonest*) building)->zone_flags.bits.pit_pond != 0; +} + +bool Buildings::isActive(df::building * building) +{ + if (!isActivityZone(building)) + return false; + return ((df::building_civzonest*) building)->zone_flags.bits.active != 0; +} + +// returns building of pen/pit at cursor position (NULL if nothing found) +df::building* Buildings::findPenPitAt(df::coord coord) +{ + vector zones; + Buildings::findCivzonesAt(&zones, coord); + for (auto zone = zones.begin(); zone != zones.end(); ++zone) + { + if (isPenPasture(*zone) || isPitPond(*zone)) + return (*zone); + } + return NULL; +} diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 463cea227..a040521bd 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -765,7 +765,7 @@ df::unit_misc_trait *Units::getMiscTrait(df::unit *unit, df::misc_trait_type typ return NULL; } -bool DFHack::Units::isDead(df::unit *unit) +bool Units::isDead(df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -773,7 +773,7 @@ bool DFHack::Units::isDead(df::unit *unit) unit->flags3.bits.ghostly; } -bool DFHack::Units::isAlive(df::unit *unit) +bool Units::isAlive(df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -782,12 +782,11 @@ bool DFHack::Units::isAlive(df::unit *unit) !unit->curse.add_tags1.bits.NOT_LIVING; } -bool DFHack::Units::isSane(df::unit *unit) +bool Units::isSane(df::unit *unit) { CHECK_NULL_POINTER(unit); - if (unit->flags1.bits.dead || - unit->flags3.bits.ghostly || + if (isDead(unit) || isOpposedToLife(unit) || unit->enemy.undead) return false; @@ -808,7 +807,7 @@ bool DFHack::Units::isSane(df::unit *unit) return true; } -bool DFHack::Units::isCitizen(df::unit *unit) +bool Units::isCitizen(df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -838,7 +837,7 @@ bool DFHack::Units::isCitizen(df::unit *unit) !unit->flags2.bits.visitor; } -bool DFHack::Units::isDwarf(df::unit *unit) +bool Units::isDwarf(df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -846,7 +845,220 @@ bool DFHack::Units::isDwarf(df::unit *unit) unit->enemy.normal_race == ui->race_id; } -double DFHack::Units::getAge(df::unit *unit, bool true_age) +// check for profession "war creature" +bool Units::isWar(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->profession == df::profession::TRAINED_WAR + || unit->profession2 == df::profession::TRAINED_WAR; +} + +// check for profession "hunting creature" +bool Units::isHunter(df::unit* unit) +{ + CHECK_NULL_POINTER(unit) + return unit->profession == df::profession::TRAINED_HUNTER + || unit->profession2 == df::profession::TRAINED_HUNTER; +} + +// check if unit is marked as available for adoption +bool Units::isAvailableForAdoption(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + auto refs = unit->specific_refs; + for(size_t i=0; itype; + if( reftype == df::specific_ref_type::PETINFO_PET ) + { + //df::pet_info* pet = ref->pet; + return true; + } + } + + return false; +} + +// check if creature belongs to the player's civilization +// (don't try to pasture/slaughter random untame animals) +bool Units::isOwnCiv(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->civ_id == ui->civ_id; +} + +// check if creature belongs to the player's race +// (in combination with check for civ helps to filter out own dwarves) +bool Units::isOwnRace(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->race == ui->race_id; +} + +// get race name by id or unit pointer +string Units::getRaceNameById(int32_t id) +{ + df::creature_raw *raw = world->raws.creatures.all[id]; + if (raw) + return raw->creature_id; + return ""; +} +string Units::getRaceName(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return getRaceNameById(unit->race); +} + +// get plural of race name (used for display in autobutcher UI and for sorting the watchlist) +string Units::getRaceNamePluralById(int32_t id) +{ + df::creature_raw *raw = world->raws.creatures.all[id]; + if (raw) + return raw->name[1]; // second field is plural of race name + return ""; +} + +string Units::getRaceNamePlural(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return getRaceNamePluralById(unit->race); +} + +string Units::getRaceBabyNameById(int32_t id) +{ + df::creature_raw *raw = world->raws.creatures.all[id]; + if (raw) + return raw->general_baby_name[0]; + return ""; +} + +string Units::getRaceBabyName(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return getRaceBabyNameById(unit->race); +} + +string Units::getRaceChildNameById(int32_t id) +{ + df::creature_raw *raw = world->raws.creatures.all[id]; + if (raw) + return raw->general_child_name[0]; + return ""; +} + +string Units::getRaceChildName(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return getRaceChildNameById(unit->race); +} + +bool Units::isBaby(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->profession == df::profession::BABY; +} + +bool Units::isChild(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->profession == df::profession::CHILD; +} + +bool Units::isAdult(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return !isBaby(unit) && !isChild(unit); +} + +bool Units::isEggLayer(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if ((*caste)->flags.is_set(caste_raw_flags::LAYS_EGGS) + || (*caste)->flags.is_set(caste_raw_flags::LAYS_UNUSUAL_EGGS)) + return true; + } + return false; +} + +bool Units::isGrazer(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if((*caste)->flags.is_set(caste_raw_flags::GRAZER)) + return true; + } + return false; +} + +bool Units::isMilkable(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if((*caste)->flags.is_set(caste_raw_flags::MILKABLE)) + return true; + } + return false; +} + +bool Units::isTrainableWar(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if((*caste)->flags.is_set(caste_raw_flags::TRAINABLE_WAR)) + return true; + } + return false; +} + +bool Units::isTrainableHunting(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if((*caste)->flags.is_set(caste_raw_flags::TRAINABLE_HUNTING)) + return true; + } + return false; +} + +bool Units::isTamable(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto caste = raw->caste.begin(); caste != raw->caste.end(); ++caste) + { + if((*caste)->flags.is_set(caste_raw_flags::PET) || + (*caste)->flags.is_set(caste_raw_flags::PET_EXOTIC)) + return true; + } + return false; +} + +bool Units::isMale(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->sex == 1; +} + +bool Units::isFemale(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->sex == 0; +} + + +double Units::getAge(df::unit *unit, bool true_age) { using df::global::cur_year; using df::global::cur_year_tick; @@ -1126,7 +1338,7 @@ int Units::computeMovementSpeed(df::unit *unit) // General counters and flags - if (unit->profession == profession::BABY) + if (isBaby(unit)) speed += 3000; if (unit->flags3.bits.unk15) @@ -1326,7 +1538,7 @@ static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NobleP return a.position->id < b.position->id; } -bool DFHack::Units::getNoblePositions(std::vector *pvec, df::unit *unit) +bool Units::getNoblePositions(std::vector *pvec, df::unit *unit) { CHECK_NULL_POINTER(unit); @@ -1367,7 +1579,7 @@ bool DFHack::Units::getNoblePositions(std::vector *pvec, df::unit return true; } -std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural) +std::string Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural) { CHECK_NULL_POINTER(unit); @@ -1400,7 +1612,7 @@ std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, return getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); } -std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural) +std::string Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural) { std::string prof, race_prefix; @@ -1517,7 +1729,7 @@ std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::pro return Translation::capitalize(prof, true); } -int8_t DFHack::Units::getProfessionColor(df::unit *unit, bool ignore_noble) +int8_t Units::getProfessionColor(df::unit *unit, bool ignore_noble) { CHECK_NULL_POINTER(unit); @@ -1532,7 +1744,7 @@ int8_t DFHack::Units::getProfessionColor(df::unit *unit, bool ignore_noble) return getCasteProfessionColor(unit->race, unit->caste, unit->profession); } -int8_t DFHack::Units::getCasteProfessionColor(int race, int casteid, df::profession pid) +int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid) { // make sure it's an actual profession if (pid < 0 || !is_valid_enum_item(pid)) @@ -1556,7 +1768,7 @@ int8_t DFHack::Units::getCasteProfessionColor(int race, int casteid, df::profess return 3; } -std::string DFHack::Units::getSquadName(df::unit *unit) +std::string Units::getSquadName(df::unit *unit) { if (unit->military.squad_id == -1) return ""; @@ -1567,3 +1779,22 @@ std::string DFHack::Units::getSquadName(df::unit *unit) return squad->alias; return Translation::TranslateName(&squad->name, true); } + +bool Units::isMerchant(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + + return unit->flags1.bits.merchant == 1; +} + +bool Units::isForest(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->flags1.bits.forest == 1; +} + +bool Units::isMarkedForSlaughter(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return unit->flags2.bits.slaughter == 1; +} diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index e359eb0b4..ae666e5e4 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -38,6 +38,7 @@ #include "modules/MapCache.h" #include "modules/Items.h" +#include "modules/Units.h" using std::string; using std::endl; @@ -1158,8 +1159,8 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) is_on_break = true; } - if (dwarfs[dwarf]->profession == profession::BABY || - dwarfs[dwarf]->profession == profession::CHILD || + if (Units::isBaby(dwarfs[dwarf]) || + Units::isChild(dwarfs[dwarf]) || dwarfs[dwarf]->profession == profession::DRUNK) { dwarf_info[dwarf].state = CHILD; diff --git a/plugins/catsplosion.cpp b/plugins/catsplosion.cpp index 725aaf492..a714a47a5 100644 --- a/plugins/catsplosion.cpp +++ b/plugins/catsplosion.cpp @@ -81,7 +81,7 @@ command_result catsplosion (color_ostream &out, std::vector & para { df::unit * creature = Units::GetCreature(i); df::creature_raw *raw = world->raws.creatures.all[creature->race]; - if(creature->sex == 0) // female + if(Units::isFemale(creature)) { female_counts[raw->creature_id].push_back(creature); male_counts[raw->creature_id].size(); diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 98e593542..9a7d1f30c 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1109,18 +1109,14 @@ struct preference_map case (T_type::LikeCreature): { label = "Creature :"; - auto creature = df::creature_raw::find(pref.creature_id); - if (creature) - label += creature->name[1]; + Units::getRaceNamePluralById(pref.creature_id); break; } case (T_type::HateCreature): { label = "Hates :"; - auto creature = df::creature_raw::find(pref.creature_id); - if (creature) - label += creature->name[1]; + Units::getRaceNamePluralById(pref.creature_id); break; } @@ -1619,8 +1615,8 @@ static void update_dwarf_stats(bool is_paused) if (!monitor_jobs || is_paused) continue; - if (unit->profession == profession::BABY || - unit->profession == profession::CHILD || + if (Units::isBaby(unit) || + Units::isChild(unit) || unit->profession == profession::DRUNK) { continue; diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 450bbd78a..56c1f8894 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -445,10 +445,10 @@ viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector &src, int cur cur->allowEdit = true; cur->active_index = active_idx[unit]; - if (unit->race != ui->race_id) + if (!Units::isOwnRace(unit)) cur->allowEdit = false; - if (unit->civ_id != ui->civ_id) + if (!Units::isOwnCiv(unit)) cur->allowEdit = false; if (unit->flags1.bits.dead) diff --git a/plugins/petcapRemover.cpp b/plugins/petcapRemover.cpp index 7eaa3b1e2..6c0724024 100644 --- a/plugins/petcapRemover.cpp +++ b/plugins/petcapRemover.cpp @@ -5,6 +5,7 @@ #include "Export.h" #include "PluginManager.h" #include "modules/EventManager.h" +#include "modules/Units.h" #include "modules/Maps.h" #include "df/caste_raw.h" @@ -79,12 +80,12 @@ void impregnateMany() { df::creature_raw* creatureRaw = world->raws.creatures.all[race]; df::caste_raw* casteRaw = creatureRaw->caste[caste]; //must have PET or PET_EXOTIC - if ( !(casteRaw->flags.is_set(df::enums::caste_raw_flags::PET) || casteRaw->flags.is_set(df::enums::caste_raw_flags::PET_EXOTIC) ) ) + if ( !Units::isTamable(unit)) continue; //check for adulthood - if ( unit->profession == df::enums::profession::CHILD || unit->profession == df::enums::profession::BABY ) + if ( Units::isBaby(unit) || Units::isChild(unit)) continue; - if ( unit->sex == 1 ) + if ( Units::isMale(unit)) males[unit->race].push_back(a); else females[unit->race].push_back(a); diff --git a/plugins/search.cpp b/plugins/search.cpp index b4428f049..ead49a3a8 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -960,8 +960,8 @@ private: } } - if (unit->profession == profession::BABY || - unit->profession == profession::CHILD || + if (Units::isBaby(unit) || + Units::isChild(unit) || unit->profession == profession::DRUNK) { return ""; diff --git a/plugins/showmood.cpp b/plugins/showmood.cpp index 34b2c8f44..c1e4ff019 100644 --- a/plugins/showmood.cpp +++ b/plugins/showmood.cpp @@ -7,6 +7,7 @@ #include "modules/Materials.h" #include "modules/Translation.h" #include "modules/Items.h" +#include "modules/Units.h" #include "DataDefs.h" #include "df/world.h" @@ -153,7 +154,7 @@ command_result df_showmood (color_ostream &out, vector & parameters) break; } out.print(".\n"); - if (unit->sex) + if (Units::isMale(unit)) out.print("He has "); else out.print("She has "); diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 72ecdeed6..a80e54180 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -707,7 +707,7 @@ static command_result tweak(color_ostream &out, vector ¶meters) if (!unit) return CR_FAILURE; - if(unit->race != ui->race_id) + if(!Units::isOwnRace(unit)) { out << "Selected unit does not belong to your race!" << endl; return CR_FAILURE; @@ -720,14 +720,14 @@ static command_result tweak(color_ostream &out, vector ¶meters) // case #2: migrants who have the merchant flag // happens on almost all maps after a few migrant waves - if(unit->flags1.bits.merchant) + if(Units::isMerchant(unit)) unit->flags1.bits.merchant = 0; // this one is a cheat, but bugged migrants usually have the same civ_id // so it should not be triggered in most cases // if it happens that the player has 'foreign' units of the same race // (vanilla df: dwarves not from mountainhome) on his map, just grab them - if(unit->civ_id != ui->civ_id) + if(!Units::isOwnCiv(unit)) unit->civ_id = ui->civ_id; return fix_clothing_ownership(out, unit); @@ -742,11 +742,11 @@ static command_result tweak(color_ostream &out, vector ¶meters) if (unit->flags2.bits.resident) unit->flags2.bits.resident = 0; - if(unit->flags1.bits.merchant) + if(Units::isMerchant(unit)) unit->flags1.bits.merchant = 0; - if(unit->flags1.bits.forest) + if(Units::isForest(unit)) unit->flags1.bits.forest = 0; - if(unit->civ_id != ui->civ_id) + if(!Units::isOwnCiv(unit)) unit->civ_id = ui->civ_id; if(unit->profession == df::profession::MERCHANT) unit->profession = df::profession::TRADER; diff --git a/plugins/zone.cpp b/plugins/zone.cpp index be4404b7f..a8635c013 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -75,6 +75,8 @@ using namespace std; using std::vector; using std::string; using namespace DFHack; +using namespace DFHack::Units; +using namespace DFHack::Buildings; using namespace df::enums; DFHACK_PLUGIN("zone"); @@ -339,26 +341,12 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) // Various small tool functions // probably many of these should be moved to Unit.h and Building.h sometime later... -int32_t getUnitAge(df::unit* unit); bool isTame(df::unit* unit); bool isTrained(df::unit* unit); -bool isWar(df::unit* unit); -bool isHunter(df::unit* unit); -bool isOwnCiv(df::unit* unit); -bool isMerchant(df::unit* unit); -bool isForest(df::unit* unit); bool isGay(df::unit* unit); -bool isGelded(df::unit* unit); -bool isActivityZone(df::building * building); -bool isPenPasture(df::building * building); -bool isPitPond(df::building * building); -bool isActive(df::building * building); - -int32_t findBuildingIndexById(int32_t id); -int32_t findPenPitAtCursor(); -int32_t findCageAtCursor(); -int32_t findChainAtCursor(); +df::building* findCageAtCursor(); +df::building* findChainAtCursor(); df::general_ref_building_civzone_assignedst * createCivzoneRef(); bool unassignUnitFromBuilding(df::unit* unit); @@ -370,22 +358,6 @@ void chainInfo(color_ostream & out, df::building* building, bool verbose); bool isBuiltCageAtPos(df::coord pos); bool isInBuiltCageRoom(df::unit*); bool isNaked(df::unit *); -bool isTamable(df::unit *); - -int32_t getUnitAge(df::unit* unit) -{ - // If the birthday this year has not yet passed, subtract one year. - // ASSUMPTION: birth_time is on the same scale as cur_year_tick - int32_t yearDifference = *cur_year - unit->relations.birth_year; - if (unit->relations.birth_time >= *cur_year_tick) - yearDifference--; - return yearDifference; -} - -bool isDead(df::unit* unit) -{ - return unit->flags1.bits.dead; -} // ignore vampires, they should be treated like normal dwarves bool isUndead(df::unit* unit) @@ -395,21 +367,6 @@ bool isUndead(df::unit* unit) && !unit->curse.add_tags1.bits.BLOODSUCKER )); } -bool isMerchant(df::unit* unit) -{ - return unit->flags1.bits.merchant; -} - -bool isForest(df::unit* unit) -{ - return unit->flags1.bits.forest; -} - -bool isMarkedForSlaughter(df::unit* unit) -{ - return unit->flags2.bits.slaughter; -} - void doMarkForSlaughter(df::unit* unit) { unit->flags2.bits.slaughter = 1; @@ -489,195 +446,6 @@ bool isTrained(df::unit* unit) return trained; } -// check for profession "war creature" -bool isWar(df::unit* unit) -{ - if( unit->profession == df::profession::TRAINED_WAR - || unit->profession2 == df::profession::TRAINED_WAR) - return true; - else - return false; -} - -// check for profession "hunting creature" -bool isHunter(df::unit* unit) -{ - if( unit->profession == df::profession::TRAINED_HUNTER - || unit->profession2 == df::profession::TRAINED_HUNTER) - return true; - else - return false; -} - -// check if unit is marked as available for adoption -bool isAvailableForAdoption(df::unit* unit) -{ - auto refs = unit->specific_refs; - for(int i=0; itype; - if( reftype == df::specific_ref_type::PETINFO_PET ) - { - //df::pet_info* pet = ref->pet; - return true; - } - } - - return false; -} - -// check if creature belongs to the player's civilization -// (don't try to pasture/slaughter random untame animals) -bool isOwnCiv(df::unit* unit) -{ - return unit->civ_id == ui->civ_id; -} - -// check if creature belongs to the player's race -// (in combination with check for civ helps to filter out own dwarves) -bool isOwnRace(df::unit* unit) -{ - return unit->race == ui->race_id; -} - -// get race name by id or unit pointer -// todo: rename these two functions to "getRaceToken" since the output is more of a token -string getRaceName(int32_t id) -{ - df::creature_raw *raw = world->raws.creatures.all[id]; - return raw->creature_id; -} -string getRaceName(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - return raw->creature_id; -} - -// get plural of race name (used for display in autobutcher UI and for sorting the watchlist) -string getRaceNamePlural(int32_t id) -{ - //WatchedRace * w = watched_races[idx]; - df::creature_raw *raw = world->raws.creatures.all[id]; - return raw->name[1]; // second field is plural of race name -} - -string getRaceBabyName(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - return raw->general_baby_name[0]; -} -string getRaceChildName(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - return raw->general_child_name[0]; -} - -bool isBaby(df::unit* unit) -{ - return unit->profession == df::profession::BABY; -} - -bool isChild(df::unit* unit) -{ - return unit->profession == df::profession::CHILD; -} - -bool isAdult(df::unit* unit) -{ - return !isBaby(unit) && !isChild(unit); -} - -bool isEggLayer(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if( caste->flags.is_set(caste_raw_flags::LAYS_EGGS) - || caste->flags.is_set(caste_raw_flags::LAYS_UNUSUAL_EGGS)) - return true; - } - return false; -} - -bool isGrazer(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if(caste->flags.is_set(caste_raw_flags::GRAZER)) - return true; - } - return false; -} - -bool isMilkable(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if(caste->flags.is_set(caste_raw_flags::MILKABLE)) - return true; - } - return false; -} - -bool isTrainableWar(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if(caste->flags.is_set(caste_raw_flags::TRAINABLE_WAR)) - return true; - } - return false; -} - -bool isTrainableHunting(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if(caste->flags.is_set(caste_raw_flags::TRAINABLE_HUNTING)) - return true; - } - return false; -} - -bool isTamable(df::unit* unit) -{ - df::creature_raw *raw = world->raws.creatures.all[unit->race]; - size_t sizecas = raw->caste.size(); - for (size_t j = 0; j < sizecas;j++) - { - df::caste_raw *caste = raw->caste[j]; - if(caste->flags.is_set(caste_raw_flags::PET) || - caste->flags.is_set(caste_raw_flags::PET_EXOTIC)) - return true; - } - return false; -} - -bool isMale(df::unit* unit) -{ - return unit->sex == 1; -} - -bool isFemale(df::unit* unit) -{ - return unit->sex == 0; -} - // found a unit with weird position values on one of my maps (negative and in the thousands) // it didn't appear in the animal stocks screen, but looked completely fine otherwise (alive, tame, own, etc) // maybe a rare bug, but better avoid assigning such units to zones or slaughter etc. @@ -697,23 +465,11 @@ bool isNaked(df::unit* unit) return (unit->inventory.empty()); } - -int getUnitIndexFromId(df::unit* unit_) -{ - for (size_t i=0; i < world->units.all.size(); i++) - { - df::unit* unit = world->units.all[i]; - if(unit->id == unit_->id) - return i; - } - return -1; -} - bool isGay(df::unit* unit) { df::orientation_flags orientation = unit->status.current_soul->orientation_flags; - return isFemale(unit) && ! (orientation.whole & (orientation.mask_marry_male | orientation.mask_romance_male)) - || ! isFemale(unit) && ! (orientation.whole & (orientation.mask_marry_female | orientation.mask_romance_female)); + return (isFemale(unit) && ! (orientation.whole & (orientation.mask_marry_male | orientation.mask_romance_male))) + || (! isFemale(unit) && ! (orientation.whole & (orientation.mask_marry_female | orientation.mask_romance_female))); } bool isGelded(df::unit* unit) @@ -776,7 +532,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) break; } out << ")"; - out << ", age: " << getUnitAge(unit); + out << ", age: " << getAge(unit, true); if(isTame(unit)) out << ", tame"; @@ -800,7 +556,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) if(verbose) { out << ". Pos: ("<pos.x << "/"<< unit->pos.y << "/" << unit->pos.z << ") " << endl; - out << "index in units vector: " << getUnitIndexFromId(unit) << endl; + out << "index in units vector: " << FindIndexById(unit->id) << endl; } out << endl; @@ -843,41 +599,6 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) } } -bool isActivityZone(df::building * building) -{ - if( building->getType() == building_type::Civzone - && building->getSubtype() == (short)civzone_type::ActivityZone) - return true; - else - return false; -} - -bool isPenPasture(df::building * building) -{ - if(!isActivityZone(building)) - return false; - - df::building_civzonest * civ = (df::building_civzonest *) building; - - if(civ->zone_flags.bits.pen_pasture) - return true; - else - return false; -} - -bool isPitPond(df::building * building) -{ - if(!isActivityZone(building)) - return false; - - df::building_civzonest * civ = (df::building_civzonest *) building; - - if(civ->zone_flags.bits.pit_pond) // && civ->pit_flags==0) - return true; - else - return false; -} - bool isCage(df::building * building) { return building->getType() == building_type::Cage; @@ -888,128 +609,21 @@ bool isChain(df::building * building) return building->getType() == building_type::Chain; } -bool isActive(df::building * building) -{ - if(!isActivityZone(building)) - return false; - - df::building_civzonest * civ = (df::building_civzonest *) building; - if(civ->zone_flags.bits.active) - return true; - else - return false; -} - -int32_t findBuildingIndexById(int32_t id) +// returns building of cage at cursor position (NULL if nothing found) +df::building* findCageAtCursor() { - for (size_t b = 0; b < world->buildings.all.size(); b++) - { - if(world->buildings.all.at(b)->id == id) - return b; - } - return -1; -} - -int32_t findUnitIndexById(int32_t id) -{ - for (size_t i = 0; i < world->units.all.size(); i++) - { - if(world->units.all.at(i)->id == id) - return i; - } - return -1; + df::building* building = Buildings::findAtTile(Gui::getCursorPos()); + if (isCage(building)) + return building; + return NULL; } -df::unit* findUnitById(int32_t id) +df::building* findChainAtCursor() { - int32_t index = findUnitIndexById(id); - if(index != -1) - return world->units.all[index]; - else - return NULL; -} - -// returns id of pen/pit at cursor position (-1 if nothing found) -int32_t findPenPitAtCursor() -{ - int32_t foundID = -1; - - if(cursor->x == -30000) - return -1; - - for (size_t b = 0; b < world->buildings.all.size(); b++) - { - df::building* building = world->buildings.all[b]; - - // find zone under cursor - if (!(building->x1 <= cursor->x && cursor->x <= building->x2 && - building->y1 <= cursor->y && cursor->y <= building->y2 && - building->z == cursor->z)) - continue; - - if(isPenPasture(building) || isPitPond(building)) - { - foundID = building->id; - break; - } - } - return foundID; -} - -// returns id of cage at cursor position (-1 if nothing found) -int32_t findCageAtCursor() -{ - int32_t foundID = -1; - - if(cursor->x == -30000) - return -1; - - for (size_t b = 0; b < world->buildings.all.size(); b++) - { - df::building* building = world->buildings.all[b]; - - if (!(building->x1 <= cursor->x && cursor->x <= building->x2 && - building->y1 <= cursor->y && cursor->y <= building->y2 && - building->z == cursor->z)) - continue; - - // don't set id if cage is not constructed yet - if(building->getBuildStage()!=building->getMaxBuildStage()) - break; - - if(isCage(building)) - { - foundID = building->id; - break; - } - } - return foundID; -} - -int32_t findChainAtCursor() -{ - int32_t foundID = -1; - - if(cursor->x == -30000) - return -1; - - for (size_t b = 0; b < world->buildings.all.size(); b++) - { - df::building* building = world->buildings.all[b]; - - // find zone under cursor - if (!(building->x1 <= cursor->x && cursor->x <= building->x2 && - building->y1 <= cursor->y && cursor->y <= building->y2 && - building->z == cursor->z)) - continue; - - if(isChain(building)) - { - foundID = building->id; - break; - } - } - return foundID; + df::building* building = Buildings::findAtTile(Gui::getCursorPos()); + if (isChain(building)) + return building; + return NULL; } df::general_ref_building_civzone_assignedst * createCivzoneRef() @@ -1283,7 +897,6 @@ bool isEmptyPasture(df::building* building) df::building* findFreeNestboxZone() { df::building * free_building = NULL; - bool cage = false; for (size_t b=0; b < world->buildings.all.size(); b++) { df::building* building = world->buildings.all[b]; @@ -1544,8 +1157,6 @@ command_result assignUnitToBuilding(color_ostream& out, df::unit* unit, df::buil command_result assignUnitsToCagezone(color_ostream& out, vector units, df::building* building, bool verbose) { - command_result result = CR_WRONG_USAGE; - if(!isPenPasture(building)) { out << "A cage zone needs to be a pen/pasture containing at least one cage!" << endl; @@ -1615,7 +1226,7 @@ command_result nickUnitsInZone(color_ostream& out, df::building* building, strin df::building_civzonest * civz = (df::building_civzonest *) building; for(size_t i = 0; i < civz->assigned_units.size(); i++) { - df::unit* unit = findUnitById(civz->assigned_units[i]); + df::unit* unit = df::unit::find(civz->assigned_units[i]); if(unit) Units::setNickname(unit, nick); } @@ -1635,7 +1246,7 @@ command_result nickUnitsInCage(color_ostream& out, df::building* building, strin df::building_cagest* cage = (df::building_cagest*) building; for(size_t i=0; iassigned_units.size(); i++) { - df::unit* unit = findUnitById(cage->assigned_units[i]); + df::unit* unit = df::unit::find(cage->assigned_units[i]); if(unit) Units::setNickname(unit, nick); } @@ -1670,10 +1281,7 @@ command_result nickUnitsInBuilding(color_ostream& out, df::building* building, s // dump some zone info void zoneInfo(color_ostream & out, df::building* building, bool verbose) { - if(building->getType()!= building_type::Civzone) - return; - - if(building->getSubtype() != (short)civzone_type::ActivityZone) + if(!isActivityZone(building)) return; string name; @@ -1689,7 +1297,7 @@ void zoneInfo(color_ostream & out, df::building* building, bool verbose) out.print("\n"); df::building_civzonest * civ = (df::building_civzonest *) building; - if(civ->zone_flags.bits.active) + if(isActive(civ)) out << "active"; else out << "not active"; @@ -1712,7 +1320,7 @@ void zoneInfo(color_ostream & out, df::building* building, bool verbose) << " z:" <z << endl; - int32_t creaturecount = civ->assigned_units.size(); + size_t creaturecount = civ->assigned_units.size(); out << "Creatures in this zone: " << creaturecount << endl; for(size_t c = 0; c < creaturecount; c++) { @@ -1752,7 +1360,7 @@ void cageInfo(color_ostream & out, df::building* building, bool verbose) df::building_cagest * cage = (df::building_cagest*) building; - int32_t creaturecount = cage->assigned_units.size(); + size_t creaturecount = cage->assigned_units.size(); out << "Creatures in this cage: " << creaturecount << endl; for(size_t c = 0; c < creaturecount; c++) { @@ -1827,7 +1435,6 @@ command_result df_zone (color_ostream &out, vector & parameters) bool find_tame = false; bool find_not_tame = false; bool find_merchant = false; - bool find_not_merchant = false; bool find_male = false; bool find_not_male = false; bool find_female = false; @@ -1864,7 +1471,7 @@ command_result df_zone (color_ostream &out, vector & parameters) bool verbose = false; bool all = false; bool unit_slaughter = false; - static int target_building = -1; + static df::building* target_building = NULL; bool nick_set = false; string target_nick = ""; @@ -1935,19 +1542,19 @@ command_result df_zone (color_ostream &out, vector & parameters) if(new_building != -1) { i++; - target_building = new_building; - out << "Assign selected unit(s) to building #" << target_building <id << endl; building_assign = true; } } @@ -1968,18 +1575,18 @@ command_result df_zone (color_ostream &out, vector & parameters) if(new_building != -1) { i++; - target_building = new_building; - out << "Assign selected unit(s) to cagezone #" << target_building <id << endl; cagezone_assign = true; } } @@ -2260,7 +1867,6 @@ command_result df_zone (color_ostream &out, vector & parameters) else if(p == "merchant" && invert_filter) { // actually 'not merchant' is pointless since merchant units are ignored by default - find_not_merchant = true; invert_filter=false; } else if(p == "milkable" && !invert_filter) @@ -2382,21 +1988,13 @@ command_result df_zone (color_ostream &out, vector & parameters) // (doesn't use the findXyzAtCursor() methods because zones might overlap and contain a cage or chain) if(zone_info) // || chain_info || cage_info) { - for (size_t b = 0; b < world->buildings.all.size(); b++) - { - df::building * building = world->buildings.all[b]; - - // find building under cursor - if (!all && - !(building->x1 <= cursor->x && cursor->x <= building->x2 && - building->y1 <= cursor->y && cursor->y <= building->y2 && - building->z == cursor->z)) - continue; - - zoneInfo(out, building, verbose); - chainInfo(out, building, verbose); - cageInfo(out, building, verbose); - } + vector zones; + Buildings::findCivzonesAt(&zones, Gui::getCursorPos()); + for (auto zone = zones.begin(); zone != zones.end(); ++zone) + zoneInfo(out, *zone, verbose); + df::building* building = Buildings::findAtTile(Gui::getCursorPos()); + chainInfo(out, building, verbose); + cageInfo(out, building, verbose); return CR_OK; } @@ -2406,14 +2004,14 @@ command_result df_zone (color_ostream &out, vector & parameters) // cagezone wants a pen/pit as starting point if(!cagezone_assign) target_building = findCageAtCursor(); - if(target_building != -1) + if(!target_building) { out << "Target building type: cage." << endl; } else { - target_building = findPenPitAtCursor(); - if(target_building == -1) + target_building = findPenPitAt(Gui::getCursorPos()); + if(!target_building) { out << "No pen/pasture or pit under cursor!" << endl; return CR_WRONG_USAGE; @@ -2423,29 +2021,23 @@ command_result df_zone (color_ostream &out, vector & parameters) out << "Target building type: pen/pasture or pit." << endl; } } - out << "Current building set to #" << target_building << endl; + out << "Current building set to #" << target_building->id << endl; return CR_OK; } if(building_assign || cagezone_assign || unit_info || unit_slaughter || nick_set) { - df::building * building; if(building_assign || cagezone_assign || (nick_set && !all && !find_count)) { - // try to get building index from the id - int32_t index = findBuildingIndexById(target_building); - if(index == -1) + if (!target_building) { out << "Invalid building id." << endl; - target_building = -1; return CR_WRONG_USAGE; } - building = world->buildings.all.at(index); - if(nick_set && !building_assign) { out << "Renaming all units in target building." << endl; - return nickUnitsInBuilding(out, building, target_nick); + return nickUnitsInBuilding(out, target_building, target_nick); } } @@ -2497,8 +2089,8 @@ command_result df_zone (color_ostream &out, vector & parameters) || (find_not_war && isWar(unit)) || (find_hunter && !isHunter(unit)) || (find_not_hunter && isHunter(unit)) - || (find_agemin && getUnitAge(unit)target_agemax) + || (find_agemin && (int) getAge(unit, true)target_agemax) || (find_grazer && !isGrazer(unit)) || (find_not_grazer && isGrazer(unit)) || (find_egglayer && !isEggLayer(unit)) @@ -2553,7 +2145,7 @@ command_result df_zone (color_ostream &out, vector & parameters) } else if(building_assign) { - command_result result = assignUnitToBuilding(out, unit, building, verbose); + command_result result = assignUnitToBuilding(out, unit, target_building, verbose); if(result != CR_OK) return result; } @@ -2571,7 +2163,7 @@ command_result df_zone (color_ostream &out, vector & parameters) } if(cagezone_assign) { - command_result result = assignUnitsToCagezone(out, units_for_cagezone, building, verbose); + command_result result = assignUnitsToCagezone(out, units_for_cagezone, target_building, verbose); if(result != CR_OK) return result; } @@ -2592,7 +2184,7 @@ command_result df_zone (color_ostream &out, vector & parameters) } else if(building_assign) { - return assignUnitToBuilding(out, unit, building, verbose); + return assignUnitToBuilding(out, unit, target_building, verbose); } else if(unit_slaughter) { @@ -2771,8 +2363,8 @@ command_result autoNestbox( color_ostream &out, bool verbose = false ) // (assuming that the value from there indicates in which tick of the current year the unit was born) bool compareUnitAgesYounger(df::unit* i, df::unit* j) { - int32_t age_i = getUnitAge(i); - int32_t age_j = getUnitAge(j); + int32_t age_i = (int32_t) getAge(i, true); + int32_t age_j = (int32_t) getAge(j, true); if(age_i == 0 && age_j == 0) { age_i = i->relations.birth_time; @@ -2782,8 +2374,8 @@ bool compareUnitAgesYounger(df::unit* i, df::unit* j) } bool compareUnitAgesOlder(df::unit* i, df::unit* j) { - int32_t age_i = getUnitAge(i); - int32_t age_j = getUnitAge(j); + int32_t age_i = (int32_t) getAge(i, true); + int32_t age_j = (int32_t) getAge(j, true); if(age_i == 0 && age_j == 0) { age_i = i->relations.birth_time; @@ -2811,30 +2403,32 @@ public: int raceId; // target amounts - int fk; // max female kids - int mk; // max male kids - int fa; // max female adults - int ma; // max male adults + unsigned fk; // max female kids + unsigned mk; // max male kids + unsigned fa; // max female adults + unsigned ma; // max male adults // amounts of protected (not butcherable) units - int fk_prot; - int fa_prot; - int mk_prot; - int ma_prot; + unsigned fk_prot; + unsigned fa_prot; + unsigned mk_prot; + unsigned ma_prot; // butcherable units - vector fk_ptr; - vector mk_ptr; - vector fa_ptr; - vector ma_ptr; + vector unit_ptr[4]; + vector fk_ptr = unit_ptr[0]; + vector mk_ptr = unit_ptr[1]; + vector fa_ptr = unit_ptr[2]; + vector ma_ptr = unit_ptr[3]; // priority butcherable units - vector fk_pri_ptr; - vector mk_pri_ptr; - vector fa_pri_ptr; - vector ma_pri_ptr; + vector prot_ptr[4]; + vector fk_pri_ptr = prot_ptr[0]; + vector mk_pri_ptr = prot_ptr[1]; + vector fa_pri_ptr = prot_ptr[2]; + vector ma_pri_ptr = prot_ptr[3]; - WatchedRace(bool watch, int id, int _fk, int _mk, int _fa, int _ma) + WatchedRace(bool watch, int id, unsigned _fk, unsigned _mk, unsigned _fa, unsigned _ma) { isWatched = watch; raceId = id; @@ -2854,7 +2448,7 @@ public: { if(!rconfig.isValid()) { - string keyname = "autobutcher/watchlist/" + getRaceName(raceId); + string keyname = "autobutcher/watchlist/" + getRaceNameById(raceId); rconfig = World::GetPersistentData(keyname, NULL); } if(rconfig.isValid()) @@ -2869,7 +2463,7 @@ public: else { // this should never happen - string keyname = "autobutcher/watchlist/" + getRaceName(raceId); + string keyname = "autobutcher/watchlist/" + getRaceNameById(raceId); out << "Something failed, could not find/create config key " << keyname << "!" << endl; } } @@ -2950,17 +2544,14 @@ public: void ClearUnits() { fk_prot = fa_prot = mk_prot = ma_prot = 0; - fk_ptr.clear(); - mk_ptr.clear(); - fa_ptr.clear(); - ma_ptr.clear(); - fk_pri_ptr.clear(); - mk_pri_ptr.clear(); - fa_pri_ptr.clear(); - ma_pri_ptr.clear(); + for (size_t i = 0; i < 4; i++) + { + unit_ptr[i].clear(); + prot_ptr[i].clear(); + } } - int ProcessUnits(vector& unit_ptr, vector& unit_pri_ptr, int prot, int goal) + int ProcessUnits(vector& unit_ptr, vector& unit_pri_ptr, unsigned prot, unsigned goal) { int subcount = 0; while(unit_pri_ptr.size() && (unit_ptr.size() + unit_pri_ptr.size() + prot > goal) ) @@ -3000,8 +2591,8 @@ std::vector watched_races; // helper for sorting the watchlist alphabetically bool compareRaceNames(WatchedRace* i, WatchedRace* j) { - string name_i = getRaceNamePlural(i->raceId); - string name_j = getRaceNamePlural(j->raceId); + string name_i = getRaceNamePluralById(i->raceId); + string name_j = getRaceNamePluralById(j->raceId); return (name_i < name_j); } @@ -3009,10 +2600,10 @@ bool compareRaceNames(WatchedRace* i, WatchedRace* j) static void autobutcher_sortWatchList(color_ostream &out); // default target values for autobutcher -static int default_fk = 5; -static int default_mk = 1; -static int default_fa = 5; -static int default_ma = 1; +static unsigned default_fk = 5; +static unsigned default_mk = 1; +static unsigned default_fa = 5; +static unsigned default_ma = 1; command_result df_autobutcher(color_ostream &out, vector & parameters) { @@ -3028,12 +2619,10 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) vector target_racenames; vector target_raceids; - int target_fk = default_fk; - int target_mk = default_mk; - int target_fa = default_fa; - int target_ma = default_ma; - - int32_t target_raceid = -1; + unsigned target_fk = default_fk; + unsigned target_mk = default_mk; + unsigned target_fa = default_fa; + unsigned target_ma = default_ma; if(!parameters.size()) { @@ -3343,7 +2932,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) bool found_race = false; for(size_t i=0; iraceId); + announce = "New race added to autobutcher watchlist: " + getRaceNamePluralById(w->raceId); Gui::showAnnouncement(announce, 2, false); autobutcher_sortWatchList(out); } @@ -3517,7 +3106,7 @@ command_result autoButcher( color_ostream &out, bool verbose = false ) stringstream ss; ss << slaughter_subcount; string announce; - announce = getRaceNamePlural(w->raceId) + " marked for slaughter: " + ss.str(); + announce = getRaceNamePluralById(w->raceId) + " marked for slaughter: " + ss.str(); Gui::showAnnouncement(announce, 2, false); } } @@ -3845,7 +3434,7 @@ void butcherRace(int race) if(!isContainedInItem(unit) && !hasValidMapPos(unit)) continue; - unit->flags2.bits.slaughter = true; + doMarkForSlaughter(unit); } } @@ -3868,7 +3457,7 @@ void unbutcherRace(int race) if(!isContainedInItem(unit) && !hasValidMapPos(unit)) continue; - unit->flags2.bits.slaughter = false; + unit->flags2.bits.slaughter = 0; } } @@ -3954,7 +3543,7 @@ static void autobutcher_setWatchListRace(color_ostream &out, unsigned id, unsign watched_races.push_back(w); string announce; - announce = "New race added to autobutcher watchlist: " + getRaceNamePlural(w->raceId); + announce = "New race added to autobutcher watchlist: " + getRaceNamePluralById(w->raceId); Gui::showAnnouncement(announce, 2, false); autobutcher_sortWatchList(out); } @@ -4049,7 +3638,7 @@ static int autobutcher_getWatchList(lua_State *L) WatchedRace * w = watched_races[i]; Lua::SetField(L, w->raceId, ctable, "id"); Lua::SetField(L, w->isWatched, ctable, "watched"); - Lua::SetField(L, getRaceNamePlural(w->raceId), ctable, "name"); + Lua::SetField(L, getRaceNamePluralById(w->raceId), ctable, "name"); Lua::SetField(L, w->fk, ctable, "fk"); Lua::SetField(L, w->mk, ctable, "mk"); Lua::SetField(L, w->fa, ctable, "fa"); @@ -4178,7 +3767,7 @@ public: int adjusted_item_index = i; if (list_has_been_sorted) { - for (int j = 0; j < ui_building_assign_units->size(); j++) + for (size_t j = 0; j < ui_building_assign_units->size(); j++) { if (ui_building_assign_units->at(j) == reference_list[i]) {