Make first pass of action timer API

develop
Tachytaenius 2022-11-07 23:01:00 +00:00
parent ab8632cb7e
commit 0f8ce360ac
5 changed files with 205 additions and 68 deletions

@ -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 }
};

@ -224,5 +224,13 @@ DFHACK_EXPORT extern const std::vector<int32_t> 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);
}
}

@ -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<std::vector<bool>> groups;
AffectedActionTypesGroupContainer()
{
// "All" category
std::vector<bool> & 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<bool> & 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<bool> & 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<bool> & 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<bool> & 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;
}
}
}

@ -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;