From 81c87d09214f7297ffdee4274f2bf55aff6c5e0a Mon Sep 17 00:00:00 2001 From: expwnent Date: Thu, 3 Jul 2014 04:55:12 -0400 Subject: [PATCH] EventManager: INTERACTION event for unit interactions. --- library/include/modules/EventManager.h | 9 ++ library/modules/EventManager.cpp | 112 ++++++++++++++++++++++++- plugins/eventful.cpp | 8 ++ plugins/lua/eventful.lua | 1 + 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index 750851f24..c7aacf4bb 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -80,6 +80,15 @@ namespace DFHack { int32_t defender; int32_t wound; }; + + struct InteractionData { + std::string attackVerb; + std::string defendVerb; + int32_t attackReport; + int32_t defendReport; + int32_t attacker; + int32_t defender; + }; 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); diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 828a46496..1d434f42d 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -6,6 +6,7 @@ #include "modules/EventManager.h" #include "modules/Once.h" #include "modules/Job.h" +#include "modules/Units.h" #include "modules/World.h" #include "df/announcement_type.h" @@ -33,7 +34,9 @@ #include "df/world.h" #include +#include #include +#include #include #include @@ -129,7 +132,7 @@ static void manageEquipmentEvent(color_ostream& out); 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 manageInteractionEvent(color_ostream& out); typedef void (*eventManager_t)(color_ostream&); @@ -897,7 +900,112 @@ static void manageUnitAttackEvent(color_ostream& out) { } } +static std::string getVerb(df::unit* unit, std::string reportStr) { + std::string result(reportStr); + std::string name = unit->name.first_name + " "; + bool useName = strncmp(result.c_str(), name.c_str(), name.length()) == 0; + if ( useName ) { + result = result.substr(name.length()); + result = result.substr(0,result.length()-1); + return result; + } + //use profession name + std::string profession = "The " + Units::getProfessionName(unit) + " "; + bool match = strncmp(result.c_str(), profession.c_str(), profession.length()) == 0; + if ( !match ) + return ""; + result = result.substr(profession.length()); + result = result.substr(0,result.length()-1); + //TODO: special case for the player in adventure mode + return result; +} + static void manageInteractionEvent(color_ostream& out) { - + multimap copy(handlers[EventType::INTERACTION].begin(), handlers[EventType::INTERACTION].end()); + std::vector& reports = df::global::world->status.reports; + size_t a = df::report::binsearch_index(reports, lastReportInteraction, false); + while (a < reports.size() && reports[a]->id <= lastReportInteraction) { + a++; + } + if ( a < reports.size() ) + updateReportToRelevantUnits(); + + int32_t attackerId = -1; + int32_t lastTime = -1; + std::string attackVerb; + int32_t attackReport = -1; + for ( ; a < reports.size(); a++ ) { + df::report* report = reports[a]; + lastReportInteraction = report->id; + if ( report->flags.bits.continuation ) + continue; + df::announcement_type type = report->type; + if ( type != df::announcement_type::INTERACTION_ACTOR && type != df::announcement_type::INTERACTION_TARGET ) + continue; + int32_t unitId = -1; + int32_t validCount = 0; + std::string verb; + //find relevant unit + for ( auto b = reportToRelevantUnits[report->id].begin(); b != reportToRelevantUnits[report->id].end(); b++ ) { + int32_t candidateId = *b; + df::unit* candidate = df::unit::find(candidateId); + if ( !candidate ) { + //TODO: error + continue; + } + if ( candidate->pos != report->pos ) + continue; + std::string verbC = getVerb(candidate, report->text); + if ( verbC.length() == 0 ) + continue; + verb = verbC; + validCount++; + unitId = candidateId; + } + if ( validCount > 1 ) { + if ( Once::doOnce("EventManager interaction too many actors") ) { + out.print("%s:%d: too many actors for report %d\n", __FILE__, __LINE__, report->id); + out.print("reportStr = \"%s\", pos = %d,%d,%d\n", report->text.c_str(), report->pos.x, report->pos.y, report->pos.z); + } + attackerId = -1; + continue; + } + if ( validCount == 0 ) { + if ( Once::doOnce("EventManager interaction too few actors") ) { + out.print("%s:%d: too few actors for report %d\n", __FILE__, __LINE__, report->id); + out.print("reportStr = \"%s\", pos = %d,%d,%d\n", report->text.c_str(), report->pos.x, report->pos.y, report->pos.z); + } + attackerId = -1; + continue; + } + //int32_t unitId = reportToRelevantUnits[report->id][0]; + bool isActor = type == df::announcement_type::INTERACTION_ACTOR; + + if ( isActor ) { + attackReport = report->id; + attackerId = unitId; + lastTime = report->year*ticksPerYear + report->time; + attackVerb = verb; + continue; + } + + if ( attackerId == -1 ) + continue; + if ( report->year*ticksPerYear + report->time != lastTime ) { + attackerId = -1; + continue; + } + InteractionData data; + data.attacker = attackerId; + data.defender = unitId; + data.attackReport = attackReport; + data.defendReport = report->id; + data.attackVerb = attackVerb; + data.defendVerb = verb; + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler handle = (*b).second; + handle.eventHandler(out, (void*)&data); + } + } } diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index bb1b4c319..6a264ab95 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -123,6 +123,7 @@ static void handle_inventory_change(color_ostream& out,int32_t,int32_t,df::unit_ static void handle_report(color_ostream& out,int32_t){}; static void handle_unitAttack(color_ostream& out,int32_t,int32_t,int32_t){}; static void handle_unload(color_ostream& out){}; +static void handle_interaction(color_ostream& out, std::string, std::string, int32_t, int32_t, int32_t, int32_t){}; DEFINE_LUA_EVENT_1(onBuildingCreatedDestroyed, handle_int32t, int32_t); DEFINE_LUA_EVENT_1(onJobInitiated,handle_job_init,df::job*); DEFINE_LUA_EVENT_1(onJobCompleted,handle_job_complete,df::job*); @@ -135,6 +136,7 @@ DEFINE_LUA_EVENT_4(onInventoryChange,handle_inventory_change,int32_t,int32_t,df: DEFINE_LUA_EVENT_1(onReport,handle_report,int32_t); DEFINE_LUA_EVENT_3(onUnitAttack,handle_unitAttack,int32_t,int32_t,int32_t); DEFINE_LUA_EVENT_0(onUnload,handle_unload); +DEFINE_LUA_EVENT_6(onInteraction,handle_interaction, std::string, std::string, int32_t, int32_t, int32_t, int32_t); DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onWorkshopFillSidebarMenu), DFHACK_LUA_EVENT(postWorkshopFillSidebarMenu), @@ -157,6 +159,7 @@ DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_EVENT(onReport), DFHACK_LUA_EVENT(onUnitAttack), DFHACK_LUA_EVENT(onUnload), + DFHACK_LUA_EVENT(onInteraction), DFHACK_LUA_END }; @@ -227,6 +230,10 @@ static void ev_mng_unitAttack(color_ostream& out, void* ptr) { static void ev_mng_unload(color_ostream& out, void* ptr) { onUnload(out); } +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); +} std::vector enabledEventManagerEvents(EventManager::EventType::EVENT_MAX,-1); typedef void (*handler_t) (color_ostream&,void*); static const handler_t eventHandlers[] = { @@ -243,6 +250,7 @@ static const handler_t eventHandlers[] = { ev_mng_report, ev_mng_unitAttack, ev_mng_unload, + ev_mng_interaction, }; static void enableEvent(int evType,int freq) { diff --git a/plugins/lua/eventful.lua b/plugins/lua/eventful.lua index 34c5182ce..6e41271ad 100644 --- a/plugins/lua/eventful.lua +++ b/plugins/lua/eventful.lua @@ -146,6 +146,7 @@ eventType=invertTable{ "REPORT", "UNIT_ATTACK", "UNLOAD", + "INTERACTION", "EVENT_MAX" } return _ENV