diff --git a/docs/Lua API.rst b/docs/Lua API.rst index c0dec4b6ed..776304325c 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -4627,6 +4627,10 @@ These events are straight from EventManager module. Each of them first needs to Called when a unit uses an interaction on another. +14. ``onUnitAction(unit_id, action)`` + + Called when a unit does an action (movement, attacking, talking and so on). + Functions --------- diff --git a/docs/changelog.txt b/docs/changelog.txt index 80c52e046e..08065e7c61 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,6 +40,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- `EventManager`: add new event type ``UNIT_ACTION``, triggered when a unit starts an action ## Documentation diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index 7808f6d8c6..9bbaa64b3f 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -38,6 +38,7 @@ namespace DFHack { UNIT_ATTACK, UNLOAD, INTERACTION, + UNIT_ACTION, EVENT_MAX }; } @@ -117,6 +118,11 @@ namespace DFHack { } }; + struct ActionData { + int32_t unitId; + df::unit_action* action; + }; + DFHACK_EXPORT void registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin); DFHACK_EXPORT int32_t registerTick(EventHandler handler, int32_t when, Plugin* plugin, bool absolute=false); DFHACK_EXPORT void unregister(EventType::EventType e, EventHandler handler, Plugin* plugin); diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 70908aada4..f5123be603 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -28,6 +28,7 @@ #include "df/report.h" #include "df/ui.h" #include "df/unit.h" +#include "df/unit_action.h" #include "df/unit_flags1.h" #include "df/unit_inventory_item.h" #include "df/unit_report_type.h" @@ -137,6 +138,7 @@ static void manageReportEvent(color_ostream& out); static void manageUnitAttackEvent(color_ostream& out); static void manageUnloadEvent(color_ostream& out){}; static void manageInteractionEvent(color_ostream& out); +static void manageActionEvent(color_ostream& out); typedef void (*eventManager_t)(color_ostream&); @@ -175,6 +177,8 @@ eventManager_t getManager(EventType::EventType t) { return manageUnloadEvent; case EventType::INTERACTION: return manageInteractionEvent; + case EventType::UNIT_ACTION: + return manageActionEvent; case EventType::EVENT_MAX: return nullptr; //default: @@ -234,6 +238,9 @@ static int32_t reportToRelevantUnitsTime = -1; //interaction static int32_t lastReportInteraction; +//unit action +static std::unordered_map > unitToKnownActions; + void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event event) { static bool doOnce = false; // const string eventNames[] = {"world loaded", "world unloaded", "map loaded", "map unloaded", "viewscreen changed", "core initialized", "begin unload", "paused", "unpaused"}; @@ -256,6 +263,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event buildings.clear(); constructions.clear(); equipmentLog.clear(); + unitToKnownActions.clear(); Buildings::clearBuildings(out); lastReport = -1; @@ -1277,3 +1285,30 @@ static void manageInteractionEvent(color_ostream& out) { //TODO: deduce attacker from latest defend event first } } + +static void manageActionEvent(color_ostream& out) { + if (!df::global::world) + return; + multimap copy(handlers[EventType::UNIT_ACTION].begin(), handlers[EventType::UNIT_ACTION].end()); + for ( df::unit* unit : df::global::world->units.all ) { + if ( !Units::isActive(unit) ) { + unitToKnownActions.erase(unit->id); + continue; + } + auto& knownActions = unitToKnownActions[unit->id]; + for ( df::unit_action* action : unit->actions ) { + if ( action->type != df::unit_action_type::None) { + if ( std::find(knownActions.begin(), knownActions.end(), action->id) == knownActions.end() ) { + knownActions.push_back(action->id); + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler handle = (*b).second; + ActionData data = {unit->id, action}; + handle.eventHandler(out, (void*)&data); + } + } + } else { + knownActions.erase(std::remove(knownActions.begin(), knownActions.end(), action->id), knownActions.end()); + } + } + } +} diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 980b2db9c6..0bb482e4c8 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -20,6 +20,7 @@ #include "df/reaction_reagent_itemst.h" #include "df/reaction_product_itemst.h" #include "df/unit.h" +#include "df/unit_action.h" #include "df/unit_inventory_item.h" #include "df/unit_wound.h" #include "df/world.h" @@ -110,6 +111,7 @@ DEFINE_LUA_EVENT_NH_1(onReport, int32_t); DEFINE_LUA_EVENT_NH_3(onUnitAttack, int32_t, int32_t, int32_t); DEFINE_LUA_EVENT_NH_0(onUnload); DEFINE_LUA_EVENT_NH_6(onInteraction, std::string, std::string, int32_t, int32_t, int32_t, int32_t); +DEFINE_LUA_EVENT_NH_2(onUnitAction, int32_t, df::unit_action*); DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onWorkshopFillSidebarMenu), @@ -137,6 +139,7 @@ DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onUnitAttack), DFHACK_LUA_EVENT(onUnload), DFHACK_LUA_EVENT(onInteraction), + DFHACK_LUA_EVENT(onUnitAction), DFHACK_LUA_END }; @@ -221,6 +224,10 @@ static void ev_mng_interaction(color_ostream& out, void* ptr) { EventManager::InteractionData* data = (EventManager::InteractionData*)ptr; onInteraction(out, data->attackVerb, data->defendVerb, data->attacker, data->defender, data->attackReport, data->defendReport); } +static void ev_mng_unitAction(color_ostream& out, void* ptr) { + EventManager::ActionData* data = (EventManager::ActionData*)ptr; + onUnitAction(out, data->unitId, data->action); +} std::vector enabledEventManagerEvents(EventManager::EventType::EVENT_MAX,-1); typedef void (*handler_t) (color_ostream&,void*); @@ -260,6 +267,8 @@ handler_t getManager(EventType t) { return ev_mng_unload; case INTERACTION: return ev_mng_interaction; + case UNIT_ACTION: + return ev_mng_unitAction; case EVENT_MAX: return nullptr; //default: diff --git a/plugins/lua/eventful.lua b/plugins/lua/eventful.lua index 2938743937..b912c629a4 100644 --- a/plugins/lua/eventful.lua +++ b/plugins/lua/eventful.lua @@ -166,6 +166,7 @@ eventType=invertTable{ "UNIT_ATTACK", "UNLOAD", "INTERACTION", + "UNIT_ACTION", "EVENT_MAX" } return _ENV