From 0f8ce360ac2e16541c6cdd47f9b162a6b6f8a2a4 Mon Sep 17 00:00:00 2001 From: Tachytaenius Date: Mon, 7 Nov 2022 23:01:00 +0000 Subject: [PATCH] Make first pass of action timer API --- docs/api/Units.rst | 0 library/LuaApi.cpp | 6 + library/include/modules/Units.h | 8 ++ library/modules/Units.cpp | 190 ++++++++++++++++++++++++++++++++ plugins/fastdwarf.cpp | 69 +----------- 5 files changed, 205 insertions(+), 68 deletions(-) create mode 100644 docs/api/Units.rst diff --git a/docs/api/Units.rst b/docs/api/Units.rst new file mode 100644 index 000000000..e69de29bb diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 36d132124..c918cdedb 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1779,6 +1779,12 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getMainSocialEvent), WRAPM(Units, getStressCategory), WRAPM(Units, getStressCategoryRaw), + WRAPM(Units, subtractActionTimer), + WRAPM(Units, subtractActionTimerCategory), + WRAPM(Units, multiplyActionTimer), + WRAPM(Units, multiplyActionTimerCategory), + WRAPM(Units, setActionTimer), + WRAPM(Units, setActionTimerCategory), { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index be630b802..ffbeaac67 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -224,5 +224,13 @@ DFHACK_EXPORT extern const std::vector stress_cutoffs; DFHACK_EXPORT int getStressCategory(df::unit *unit); DFHACK_EXPORT int getStressCategoryRaw(int32_t stress_level); +enum ActionTypeGroup {All, Movement, MovementFeet, Offensive, Work}; +DFHACK_EXPORT void subtractActionTimer(df::unit *unit, int amount, int affectedActionType); +DFHACK_EXPORT void subtractActionTimerCategory(df::unit *unit, int amount, int affectedActionTypes); +DFHACK_EXPORT void multiplyActionTimer(df::unit *unit, float amount, int affectedActionType); +DFHACK_EXPORT void multiplyActionTimerCategory(df::unit *unit, float amount, int affectedActionTypes); +DFHACK_EXPORT void setActionTimer(df::unit *unit, int amount, int affectedActionType); +DFHACK_EXPORT void setActionTimerCategory(df::unit *unit, int amount, int affectedActionTypes); + } } diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 777c3239b..468c0dc40 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -80,6 +80,7 @@ using namespace std; #include "df/unit_soul.h" #include "df/unit_wound.h" #include "df/world.h" +#include "df/unit_action.h" using namespace DFHack; using namespace df::enums; @@ -1949,3 +1950,192 @@ int Units::getStressCategoryRaw(int32_t stress_level) } return level; } + +struct AffectedActionTypesGroupContainer +{ + std::vector> groups; + + AffectedActionTypesGroupContainer() + { + // "All" category + std::vector & allVector = groups[Units::ActionTypeGroup::All]; + // reinitialise allVector to the length of the df::unit_action_type enum + allVector[df::unit_action_type::Move] = true; + allVector[df::unit_action_type::Attack] = true; + allVector[df::unit_action_type::HoldTerrain] = true; + allVector[df::unit_action_type::Climb] = true; + allVector[df::unit_action_type::Job] = true; + allVector[df::unit_action_type::Talk] = true; + allVector[df::unit_action_type::Unsteady] = true; + allVector[df::unit_action_type::Dodge] = true; + allVector[df::unit_action_type::Recover] = true; + allVector[df::unit_action_type::StandUp] = true; + allVector[df::unit_action_type::LieDown] = true; + allVector[df::unit_action_type::Job2] = true; + allVector[df::unit_action_type::PushObject] = true; + allVector[df::unit_action_type::SuckBlood] = true; + + // "Movement" category + std::vector & movementVector = groups[Units::ActionTypeGroup::Movement]; + // reinitialise movementVector to falses with the length of the df::unit_action_type enum + movementVector[df::unit_action_type::Move] = true; + movementVector[df::unit_action_type::HoldTerrain] = true; + movementVector[df::unit_action_type::Climb] = true; + // Include Unsteady? + movementVector[df::unit_action_type::Dodge] = true; + movementVector[df::unit_action_type::Recover] = true; + movementVector[df::unit_action_type::StandUp] = true; + movementVector[df::unit_action_type::LieDown] = true; + movementVector[df::unit_action_type::PushObject] = true; + + // "MovementFeet" category + std::vector & movementFeetVector = groups[Units::ActionTypeGroup::MovementFeet]; + // reinitialise movementFeetVector to falses with the length of the df::unit_action_type enum + movementFeetVector[df::unit_action_type::Move] = true; + // Include Unsteady? + movementFeetVector[df::unit_action_type::Dodge] = true; + movementFeetVector[df::unit_action_type::Recover] = true; + movementFeetVector[df::unit_action_type::PushObject] = true; + + // "Offensive" category + std::vector & offensiveVector = groups[Units::ActionTypeGroup::Offensive]; + // reinitialise offensiveVector to falses with the length of the df::unit_action_type enum + offensiveVector[df::unit_action_type::Attack] = true; + offensiveVector[df::unit_action_type::SuckBlood] = true; + + // "Work" category + std::vector & workVector = groups[Units::ActionTypeGroup::Work]; + // reinitialise workVector to falses with the length of the df::unit_action_type enum + workVector[df::unit_action_type::Job] = true; + workVector[df::unit_action_type::Job2] = true; + workVector[df::unit_action_type::PushObject] = true; + } +}; + +int *getActionTimerPointer(df::unit_action *action) { + switch (action->type) + { + case unit_action_type::None: + break; + case unit_action_type::Move: + return &action->data.move.timer; + case unit_action_type::Attack: + if (action->data.attack.timer1 != 0) { + // Wind-up timer is still active, work on it + return &action->data.attack.timer1; + } else { + // Wind-up timer is finished, work on recovery timer + return &action->data.attack.timer2; + } + case unit_action_type::HoldTerrain: + return &action->data.holdterrain.timer; + case unit_action_type::Climb: + return &action->data.climb.timer; + case unit_action_type::Job: + return &action->data.job.timer; + // could also patch the unit->job.current_job->completion_timer + case unit_action_type::Talk: + return &action->data.talk.timer; + case unit_action_type::Unsteady: + return &action->data.unsteady.timer; + case unit_action_type::Dodge: + return &action->data.dodge.timer; + case unit_action_type::Recover: + return &action->data.recover.timer; + case unit_action_type::StandUp: + return &action->data.standup.timer; + case unit_action_type::LieDown: + return &action->data.liedown.timer; + case unit_action_type::Job2: + return &action->data.job2.timer; + // could also patch the unit->job.current_job->completion_timer + case unit_action_type::PushObject: + return &action->data.pushobject.timer; + case unit_action_type::SuckBlood: + return &action->data.suckblood.timer; + case unit_action_type::Jump: + case unit_action_type::ReleaseTerrain: + case unit_action_type::Parry: + case unit_action_type::Block: + case unit_action_type::HoldItem: + case unit_action_type::ReleaseItem: + default: + break; + } + return nullptr; +} + +void Units::subtractActionTimer(df::unit *unit, int amount, int affectedActionType) +{ + CHECK_NULL_POINTER(unit); + for (auto action : unit->actions) { + if (affectedActionType != action->type) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = max(*timer - amount, 1); + } + } +} + +void Units::subtractActionTimerCategory(df::unit *unit, int amount, int affectedActionTypes) +{ + CHECK_NULL_POINTER(unit); + static AffectedActionTypesGroupContainer groupContainer; + for (auto action : unit->actions) { + if (!groupContainer.groups[affectedActionTypes][action->type]) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = max(*timer - amount, 1); + } + } +} + +void Units::multiplyActionTimer(df::unit *unit, float amount, int affectedActionType) +{ + CHECK_NULL_POINTER(unit); + for (auto action : unit->actions) { + if (affectedActionType != action->type) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = max(int(*timer * amount), 1); + } + } +} + +void Units::multiplyActionTimerCategory(df::unit *unit, float amount, int affectedActionTypes) +{ + CHECK_NULL_POINTER(unit); + static AffectedActionTypesGroupContainer groupContainer; + for (auto action : unit->actions) { + if (!groupContainer.groups[affectedActionTypes][action->type]) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = max(int(*timer * amount), 1); + } + } +} + +void Units::setActionTimer(df::unit *unit, int amount, int affectedActionType) +{ + CHECK_NULL_POINTER(unit); + for (auto action : unit->actions) { + if (affectedActionType != action->type) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = amount; + } + } +} + +void Units::setActionTimerCategory(df::unit *unit, int amount, int affectedActionTypes) +{ + CHECK_NULL_POINTER(unit); + static AffectedActionTypesGroupContainer groupContainer; + for (auto action : unit->actions) { + if (!groupContainer.groups[affectedActionTypes][action->type]) continue; + int *timer = getActionTimerPointer(action); + if (timer != nullptr && *timer != 0) { + *timer = amount; + } + } +} diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index 787f85c5d..cb6a3e310 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -82,74 +82,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) if (enable_fastdwarf) { - for (size_t i = 0; i < unit->actions.size(); i++) - { - df::unit_action *action = unit->actions[i]; - switch (action->type) - { - case unit_action_type::None: - break; - case unit_action_type::Move: - action->data.move.timer = 1; - break; - case unit_action_type::Attack: - // Attacks are executed when timer1 reaches zero, which will be - // on the following tick. - if (action->data.attack.timer1 > 1) - action->data.attack.timer1 = 1; - // Attack actions are completed, and new ones generated, when - // timer2 reaches zero. - if (action->data.attack.timer2 > 1) - action->data.attack.timer2 = 1; - break; - case unit_action_type::HoldTerrain: - action->data.holdterrain.timer = 1; - break; - case unit_action_type::Climb: - action->data.climb.timer = 1; - break; - case unit_action_type::Job: - action->data.job.timer = 1; - // could also patch the unit->job.current_job->completion_timer - break; - case unit_action_type::Talk: - action->data.talk.timer = 1; - break; - case unit_action_type::Unsteady: - action->data.unsteady.timer = 1; - break; - case unit_action_type::Dodge: - action->data.dodge.timer = 1; - break; - case unit_action_type::Recover: - action->data.recover.timer = 1; - break; - case unit_action_type::StandUp: - action->data.standup.timer = 1; - break; - case unit_action_type::LieDown: - action->data.liedown.timer = 1; - break; - case unit_action_type::Job2: - action->data.job2.timer = 1; - // could also patch the unit->job.current_job->completion_timer - break; - case unit_action_type::PushObject: - action->data.pushobject.timer = 1; - break; - case unit_action_type::SuckBlood: - action->data.suckblood.timer = 1; - break; - case unit_action_type::Jump: - case unit_action_type::ReleaseTerrain: - case unit_action_type::Parry: - case unit_action_type::Block: - case unit_action_type::HoldItem: - case unit_action_type::ReleaseItem: - default: - break; - } - } + Units::setActionTimerCategory(unit, 1, Units::ActionTypeGroup::All); } } return CR_OK;