EventManager: INTERACTION event for unit interactions.

develop
expwnent 2014-07-03 04:55:12 -04:00
parent 8f43b97284
commit 81c87d0921
4 changed files with 128 additions and 2 deletions

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

@ -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 <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
@ -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<Plugin*,EventHandler> copy(handlers[EventType::INTERACTION].begin(), handlers[EventType::INTERACTION].end());
std::vector<df::report*>& 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);
}
}
}

@ -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<int> 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)
{

@ -146,6 +146,7 @@ eventType=invertTable{
"REPORT",
"UNIT_ATTACK",
"UNLOAD",
"INTERACTION",
"EVENT_MAX"
}
return _ENV