2012-12-14 21:29:28 -07:00
# include "Core.h"
2012-12-15 16:08:59 -07:00
# include "Console.h"
2022-12-19 14:43:57 -07:00
# include "Debug.h"
2014-06-28 00:31:34 -06:00
# include "VTableInterpose.h"
2012-12-18 18:28:30 -07:00
# include "modules/Buildings.h"
# include "modules/Constructions.h"
2012-12-14 21:29:28 -07:00
# include "modules/EventManager.h"
2013-10-20 18:02:52 -06:00
# include "modules/Once.h"
2012-12-14 21:29:28 -07:00
# include "modules/Job.h"
2014-07-03 02:55:12 -06:00
# include "modules/Units.h"
2012-12-14 21:29:28 -07:00
# include "modules/World.h"
2014-06-23 07:15:46 -06:00
# include "df/announcement_type.h"
2012-12-18 16:34:38 -07:00
# include "df/building.h"
# include "df/construction.h"
2013-05-25 07:44:17 -06:00
# include "df/general_ref.h"
# include "df/general_ref_type.h"
# include "df/general_ref_unit_workerst.h"
2012-12-14 21:29:28 -07:00
# include "df/global_objects.h"
2016-03-10 06:38:55 -07:00
# include "df/historical_figure.h"
2014-11-09 16:36:21 -07:00
# include "df/interaction.h"
2012-12-15 14:49:13 -07:00
# include "df/item.h"
2014-06-28 00:31:34 -06:00
# include "df/item_actual.h"
# include "df/item_constructed.h"
# include "df/item_crafted.h"
# include "df/item_weaponst.h"
2012-12-15 14:49:13 -07:00
# include "df/job.h"
2012-12-14 21:29:28 -07:00
# include "df/job_list_link.h"
2014-06-23 07:15:46 -06:00
# include "df/report.h"
2023-01-05 18:11:01 -07:00
# include "df/plotinfost.h"
2012-12-15 12:40:11 -07:00
# include "df/unit.h"
2013-10-20 12:37:34 -06:00
# include "df/unit_flags1.h"
2013-06-15 15:59:55 -06:00
# include "df/unit_inventory_item.h"
2014-06-28 00:31:34 -06:00
# include "df/unit_report_type.h"
2013-01-02 16:30:15 -07:00
# include "df/unit_syndrome.h"
2014-06-28 00:31:34 -06:00
# include "df/unit_wound.h"
2012-12-14 21:29:28 -07:00
# include "df/world.h"
2014-07-01 06:58:48 -06:00
# include <algorithm>
2014-07-03 02:55:12 -06:00
# include <cstring>
2012-12-14 21:29:28 -07:00
# include <map>
2014-07-03 02:55:12 -06:00
# include <string>
2012-12-18 16:34:38 -07:00
# include <unordered_map>
# include <unordered_set>
2022-04-14 22:47:25 -06:00
# include <array>
2023-09-27 13:32:46 -06:00
# include <utility>
2012-12-18 16:34:38 -07:00
2022-12-19 14:43:57 -07:00
namespace DFHack {
DBG_DECLARE ( eventmanager , log , DebugCategory : : LINFO ) ;
}
2012-12-14 21:29:28 -07:00
using namespace std ;
using namespace DFHack ;
using namespace EventManager ;
2014-04-23 07:23:34 -06:00
using namespace df : : enums ;
2012-12-14 21:29:28 -07:00
/*
* TODO :
* error checking
2012-12-18 16:34:38 -07:00
* consider a typedef instead of a struct for EventHandler
2012-12-14 21:29:28 -07:00
* */
2013-10-20 19:48:28 -06:00
static multimap < int32_t , EventHandler > tickQueue ;
2012-12-14 21:29:28 -07:00
2012-12-18 16:34:38 -07:00
//TODO: consider unordered_map of pairs, or unordered_map of unordered_set, or whatever
2013-05-11 14:42:00 -06:00
static multimap < Plugin * , EventHandler > handlers [ EventType : : EVENT_MAX ] ;
2022-03-29 10:42:24 -06:00
static int32_t eventLastTick [ EventType : : EVENT_MAX ] ;
2012-12-14 21:29:28 -07:00
2013-10-20 19:48:28 -06:00
static const int32_t ticksPerYear = 403200 ;
2012-12-14 21:29:28 -07:00
2013-01-03 17:31:29 -07:00
void DFHack : : EventManager : : registerListener ( EventType : : EventType e , EventHandler handler , Plugin * plugin ) {
2022-12-19 17:44:44 -07:00
DEBUG ( log ) . print ( " registering handler %p from plugin %s for event %d \n " , handler . eventHandler , plugin - > getName ( ) . c_str ( ) , e ) ;
2012-12-14 21:29:28 -07:00
handlers [ e ] . insert ( pair < Plugin * , EventHandler > ( plugin , handler ) ) ;
}
2013-10-20 20:49:22 -06:00
int32_t DFHack : : EventManager : : registerTick ( EventHandler handler , int32_t when , Plugin * plugin , bool absolute ) {
2013-10-20 19:48:28 -06:00
if ( ! absolute ) {
df : : world * world = df : : global : : world ;
if ( world ) {
when + = world - > frame_counter ;
} else {
if ( Once : : doOnce ( " EventManager registerTick unhonored absolute=false " ) )
Core : : getInstance ( ) . getConsole ( ) . print ( " EventManager::registerTick: warning! absolute flag=false not honored. \n " ) ;
2012-12-15 16:08:59 -07:00
}
}
2022-03-29 10:42:24 -06:00
handler . freq = when ;
tickQueue . insert ( pair < int32_t , EventHandler > ( handler . freq , handler ) ) ;
2022-12-19 17:44:44 -07:00
DEBUG ( log ) . print ( " registering handler %p from plugin %s for event TICK \n " , handler . eventHandler , plugin - > getName ( ) . c_str ( ) ) ;
2022-03-29 10:42:24 -06:00
handlers [ EventType : : TICK ] . insert ( pair < Plugin * , EventHandler > ( plugin , handler ) ) ;
2013-10-20 20:49:22 -06:00
return when ;
}
static void removeFromTickQueue ( EventHandler getRidOf ) {
2013-10-20 21:16:21 -06:00
for ( auto j = tickQueue . find ( getRidOf . freq ) ; j ! = tickQueue . end ( ) ; ) {
if ( ( * j ) . first > getRidOf . freq )
2013-10-20 20:49:22 -06:00
break ;
2013-10-20 21:16:21 -06:00
if ( ( * j ) . second ! = getRidOf ) {
j + + ;
continue ;
2013-10-20 20:49:22 -06:00
}
2013-10-20 21:16:21 -06:00
j = tickQueue . erase ( j ) ;
}
2012-12-14 21:29:28 -07:00
}
2013-01-03 17:31:29 -07:00
void DFHack : : EventManager : : unregister ( EventType : : EventType e , EventHandler handler , Plugin * plugin ) {
2013-10-20 20:49:22 -06:00
for ( auto i = handlers [ e ] . find ( plugin ) ; i ! = handlers [ e ] . end ( ) ; ) {
2012-12-14 21:29:28 -07:00
if ( ( * i ) . first ! = plugin )
break ;
2022-04-18 20:27:15 -06:00
EventHandler & handle = ( * i ) . second ;
2013-10-20 20:49:22 -06:00
if ( handle ! = handler ) {
i + + ;
continue ;
2012-12-14 21:29:28 -07:00
}
2022-12-19 17:44:44 -07:00
DEBUG ( log ) . print ( " unregistering handler %p from plugin %s for event %d \n " , handler . eventHandler , plugin - > getName ( ) . c_str ( ) , e ) ;
2013-10-20 21:16:21 -06:00
i = handlers [ e ] . erase ( i ) ;
2013-10-20 20:49:22 -06:00
if ( e = = EventType : : TICK )
removeFromTickQueue ( handler ) ;
2012-12-14 21:29:28 -07:00
}
}
void DFHack : : EventManager : : unregisterAll ( Plugin * plugin ) {
2022-12-19 17:44:44 -07:00
DEBUG ( log ) . print ( " unregistering all handlers for plugin %s \n " , plugin - > getName ( ) . c_str ( ) ) ;
2022-03-29 10:42:24 -06:00
for ( auto i = handlers [ EventType : : TICK ] . find ( plugin ) ; i ! = handlers [ EventType : : TICK ] . end ( ) ; i + + ) {
2012-12-14 21:29:28 -07:00
if ( ( * i ) . first ! = plugin )
break ;
2015-02-14 20:53:06 -07:00
2013-10-20 20:49:22 -06:00
removeFromTickQueue ( ( * i ) . second ) ;
2012-12-14 21:29:28 -07:00
}
2022-04-18 20:27:15 -06:00
for ( auto & handler : handlers ) {
handler . erase ( plugin ) ;
2012-12-14 21:29:28 -07:00
}
}
static void manageTickEvent ( color_ostream & out ) ;
static void manageJobInitiatedEvent ( color_ostream & out ) ;
2021-08-06 07:02:23 -06:00
static void manageJobStartedEvent ( color_ostream & out ) ;
2012-12-14 21:29:28 -07:00
static void manageJobCompletedEvent ( color_ostream & out ) ;
2022-01-26 10:41:09 -07:00
static void manageNewUnitActiveEvent ( color_ostream & out ) ;
2012-12-15 12:40:11 -07:00
static void manageUnitDeathEvent ( color_ostream & out ) ;
2012-12-15 14:49:13 -07:00
static void manageItemCreationEvent ( color_ostream & out ) ;
2012-12-18 16:34:38 -07:00
static void manageBuildingEvent ( color_ostream & out ) ;
static void manageConstructionEvent ( color_ostream & out ) ;
2013-01-02 16:30:15 -07:00
static void manageSyndromeEvent ( color_ostream & out ) ;
2013-01-03 13:52:56 -07:00
static void manageInvasionEvent ( color_ostream & out ) ;
2013-10-24 17:32:52 -06:00
static void manageEquipmentEvent ( color_ostream & out ) ;
2014-06-23 07:15:46 -06:00
static void manageReportEvent ( color_ostream & out ) ;
2014-06-28 00:31:34 -06:00
static void manageUnitAttackEvent ( color_ostream & out ) ;
2014-06-29 08:03:55 -06:00
static void manageUnloadEvent ( color_ostream & out ) { } ;
2014-07-03 02:55:12 -06:00
static void manageInteractionEvent ( color_ostream & out ) ;
2012-12-14 21:29:28 -07:00
2013-10-20 18:02:52 -06:00
typedef void ( * eventManager_t ) ( color_ostream & ) ;
2022-04-14 22:47:25 -06:00
// integrate new events into this function, and no longer worry about syncing the enum list with the `eventManager` array
eventManager_t getManager ( EventType : : EventType t ) {
switch ( t ) {
case EventType : : TICK :
return manageTickEvent ;
case EventType : : JOB_INITIATED :
return manageJobInitiatedEvent ;
case EventType : : JOB_STARTED :
return manageJobStartedEvent ;
case EventType : : JOB_COMPLETED :
return manageJobCompletedEvent ;
case EventType : : UNIT_NEW_ACTIVE :
return manageNewUnitActiveEvent ;
case EventType : : UNIT_DEATH :
return manageUnitDeathEvent ;
case EventType : : ITEM_CREATED :
return manageItemCreationEvent ;
case EventType : : BUILDING :
return manageBuildingEvent ;
case EventType : : CONSTRUCTION :
return manageConstructionEvent ;
case EventType : : SYNDROME :
return manageSyndromeEvent ;
case EventType : : INVASION :
return manageInvasionEvent ;
case EventType : : INVENTORY_CHANGE :
return manageEquipmentEvent ;
case EventType : : REPORT :
return manageReportEvent ;
case EventType : : UNIT_ATTACK :
return manageUnitAttackEvent ;
case EventType : : UNLOAD :
return manageUnloadEvent ;
case EventType : : INTERACTION :
return manageInteractionEvent ;
case EventType : : EVENT_MAX :
return nullptr ;
//default:
//we don't do this... because then the compiler wouldn't error for missing cases in the enum
}
return nullptr ;
}
std : : array < eventManager_t , EventType : : EVENT_MAX > compileManagerArray ( ) {
std : : array < eventManager_t , EventType : : EVENT_MAX > managers { } ;
auto t = ( EventType : : EventType ) 0 ;
while ( t < EventType : : EVENT_MAX ) {
managers [ t ] = getManager ( t ) ;
t = ( EventType : : EventType ) int ( t + 1 ) ;
}
return managers ;
}
2013-05-25 10:19:54 -06:00
2012-12-18 16:34:38 -07:00
//job initiated
2012-12-15 12:40:11 -07:00
static int32_t lastJobId = - 1 ;
2012-12-18 16:34:38 -07:00
//job completed
static unordered_map < int32_t , df : : job * > prevJobs ;
2022-06-17 10:34:41 -06:00
//active units
static unordered_set < int32_t > activeUnits ;
2012-12-18 16:34:38 -07:00
//unit death
static unordered_set < int32_t > livingUnits ;
//item creation
2012-12-15 14:49:13 -07:00
static int32_t nextItem ;
2022-03-29 10:42:24 -06:00
2012-12-18 16:34:38 -07:00
//building
static int32_t nextBuilding ;
static unordered_set < int32_t > buildings ;
//construction
2022-04-18 14:40:22 -06:00
static unordered_set < df : : construction > constructions ;
2013-01-02 17:23:40 -07:00
static bool gameLoaded ;
2012-12-18 16:34:38 -07:00
2013-10-20 18:02:52 -06:00
//syndrome
static int32_t lastSyndromeTime ;
2013-01-03 13:52:56 -07:00
//invasion
static int32_t nextInvasion ;
2013-06-15 15:59:55 -06:00
//equipment change
//static unordered_map<int32_t, vector<df::unit_inventory_item> > equipmentLog;
2013-10-24 17:32:52 -06:00
static unordered_map < int32_t , vector < InventoryItem > > equipmentLog ;
2013-06-15 15:59:55 -06:00
2014-06-23 07:15:46 -06:00
//report
static int32_t lastReport ;
2014-06-28 00:31:34 -06:00
//unit attack
static int32_t lastReportUnitAttack ;
2014-07-01 06:58:48 -06:00
static std : : map < int32_t , std : : vector < int32_t > > reportToRelevantUnits ;
static int32_t reportToRelevantUnitsTime = - 1 ;
//interaction
static int32_t lastReportInteraction ;
2014-06-28 00:31:34 -06:00
2023-09-27 13:32:46 -06:00
struct hash_pair {
template < typename A , typename B >
size_t operator ( ) ( const std : : pair < A , B > & p ) const {
auto h1 = std : : hash < A > { } ( p . first ) ;
auto h2 = std : : hash < B > { } ( p . second ) ;
return h1 ^ ( h2 < < 1 ) ;
}
} ;
2012-12-14 21:29:28 -07:00
void DFHack : : EventManager : : onStateChange ( color_ostream & out , state_change_event event ) {
2012-12-18 18:28:30 -07:00
static bool doOnce = false ;
2013-10-20 19:48:28 -06:00
// const string eventNames[] = {"world loaded", "world unloaded", "map loaded", "map unloaded", "viewscreen changed", "core initialized", "begin unload", "paused", "unpaused"};
// out.print("%s,%d: onStateChange %d: \"%s\"\n", __FILE__, __LINE__, (int32_t)event, eventNames[event].c_str());
2012-12-18 18:28:30 -07:00
if ( ! doOnce ) {
//TODO: put this somewhere else
doOnce = true ;
2013-01-03 17:31:29 -07:00
EventHandler buildingHandler ( Buildings : : updateBuildings , 100 ) ;
2022-04-18 20:27:15 -06:00
DFHack : : EventManager : : registerListener ( EventType : : BUILDING , buildingHandler , nullptr ) ;
2013-01-01 20:22:31 -07:00
//out.print("Registered listeners.\n %d", __LINE__);
2012-12-18 18:28:30 -07:00
}
2013-10-20 19:48:28 -06:00
if ( event = = DFHack : : SC_MAP_UNLOADED ) {
2012-12-14 21:29:28 -07:00
lastJobId = - 1 ;
2022-04-18 20:27:15 -06:00
for ( auto & prevJob : prevJobs ) {
Job : : deleteJobStruct ( prevJob . second , true ) ;
2012-12-14 21:29:28 -07:00
}
prevJobs . clear ( ) ;
tickQueue . clear ( ) ;
2012-12-15 12:40:11 -07:00
livingUnits . clear ( ) ;
2012-12-18 16:34:38 -07:00
buildings . clear ( ) ;
constructions . clear ( ) ;
2013-10-24 17:32:52 -06:00
equipmentLog . clear ( ) ;
2022-06-17 10:34:41 -06:00
activeUnits . clear ( ) ;
2013-01-01 20:22:31 -07:00
Buildings : : clearBuildings ( out ) ;
2014-06-23 07:15:46 -06:00
lastReport = - 1 ;
2014-06-28 00:31:34 -06:00
lastReportUnitAttack = - 1 ;
2013-01-02 17:23:40 -07:00
gameLoaded = false ;
2014-06-29 08:03:55 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : UNLOAD ] . begin ( ) , handlers [ EventType : : UNLOAD ] . end ( ) ) ;
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for map unloaded state change event \n " ) ;
2023-09-27 13:32:46 -06:00
handle . eventHandler ( out , nullptr ) ;
2014-06-29 08:03:55 -06:00
}
2013-10-20 19:48:28 -06:00
} else if ( event = = DFHack : : SC_MAP_LOADED ) {
2013-10-20 20:49:22 -06:00
/*
2013-10-20 19:48:28 -06:00
int32_t tick = df : : global : : world - > frame_counter ;
multimap < int32_t , EventHandler > newTickQueue ;
for ( auto i = tickQueue . begin ( ) ; i ! = tickQueue . end ( ) ; i + + )
newTickQueue . insert ( pair < int32_t , EventHandler > ( tick + ( * i ) . first , ( * i ) . second ) ) ;
2012-12-14 21:29:28 -07:00
tickQueue . clear ( ) ;
tickQueue . insert ( newTickQueue . begin ( ) , newTickQueue . end ( ) ) ;
2013-10-20 19:48:28 -06:00
//out.print("%s,%d: on load, frame_counter = %d\n", __FILE__, __LINE__, tick);
2013-10-20 20:49:22 -06:00
*/
//tickQueue.clear();
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : item_next_id )
return ;
if ( ! df : : global : : building_next_id )
return ;
if ( ! df : : global : : job_next_id )
return ;
2023-01-05 18:11:01 -07:00
if ( ! df : : global : : plotinfo )
2014-07-21 18:14:43 -06:00
return ;
if ( ! df : : global : : world )
return ;
2015-02-14 20:53:06 -07:00
2013-10-20 15:39:54 -06:00
nextItem = * df : : global : : item_next_id ;
2013-10-20 18:02:52 -06:00
nextBuilding = * df : : global : : building_next_id ;
2023-01-05 18:11:01 -07:00
nextInvasion = df : : global : : plotinfo - > invasions . next_id ;
2013-10-20 18:02:52 -06:00
lastJobId = - 1 + * df : : global : : job_next_id ;
2015-02-14 20:53:06 -07:00
2013-10-20 18:02:52 -06:00
constructions . clear ( ) ;
2022-04-18 20:27:15 -06:00
for ( auto c : df : : global : : world - > constructions ) {
if ( ! c ) {
2013-10-20 18:02:52 -06:00
if ( Once : : doOnce ( " EventManager.onLoad null constr " ) ) {
out . print ( " EventManager.onLoad: null construction. \n " ) ;
}
continue ;
}
2022-04-18 20:27:15 -06:00
if ( c - > pos = = df : : coord ( ) ) {
2013-10-20 18:02:52 -06:00
if ( Once : : doOnce ( " EventManager.onLoad null position of construction. \n " ) )
out . print ( " EventManager.onLoad null position of construction. \n " ) ;
continue ;
}
2022-04-18 14:40:22 -06:00
constructions . emplace ( * c ) ;
2013-10-20 12:37:34 -06:00
}
2022-04-18 20:27:15 -06:00
for ( auto b : df : : global : : world - > buildings . all ) {
2019-10-05 18:26:31 -06:00
Buildings : : updateBuildings ( out , ( void * ) intptr_t ( b - > id ) ) ;
2013-10-20 18:02:52 -06:00
buildings . insert ( b - > id ) ;
}
lastSyndromeTime = - 1 ;
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > units . all ) {
2022-06-17 10:34:41 -06:00
if ( Units : : isActive ( unit ) ) {
activeUnits . emplace ( unit - > id ) ;
}
2022-04-18 20:27:15 -06:00
for ( auto syndrome : unit - > syndromes . active ) {
2013-10-20 18:02:52 -06:00
int32_t startTime = syndrome - > year * ticksPerYear + syndrome - > year_time ;
if ( startTime > lastSyndromeTime )
lastSyndromeTime = startTime ;
}
}
2014-06-23 07:15:46 -06:00
lastReport = - 1 ;
2022-04-18 20:27:15 -06:00
if ( ! df : : global : : world - > status . reports . empty ( ) ) {
2014-11-14 20:07:48 -07:00
lastReport = df : : global : : world - > status . reports [ df : : global : : world - > status . reports . size ( ) - 1 ] - > id ;
}
2014-06-28 00:31:34 -06:00
lastReportUnitAttack = - 1 ;
2014-07-01 06:58:48 -06:00
lastReportInteraction = - 1 ;
reportToRelevantUnitsTime = - 1 ;
reportToRelevantUnits . clear ( ) ;
2022-04-18 20:27:15 -06:00
for ( int & last_tick : eventLastTick ) {
last_tick = - 1 ; //-1000000;
2022-03-29 10:42:24 -06:00
}
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > history . figures ) {
2016-03-10 06:50:03 -07:00
if ( unit - > id < 0 & & unit - > name . language < 0 )
2016-03-10 06:38:55 -07:00
unit - > name . language = 0 ;
}
2015-02-14 20:53:06 -07:00
2013-10-20 15:39:54 -06:00
gameLoaded = true ;
2012-12-14 21:29:28 -07:00
}
}
void DFHack : : EventManager : : manageEvents ( color_ostream & out ) {
2022-04-14 22:47:25 -06:00
static const std : : array < eventManager_t , EventType : : EVENT_MAX > eventManager = compileManagerArray ( ) ;
2013-01-02 17:23:40 -07:00
if ( ! gameLoaded ) {
2012-12-14 21:29:28 -07:00
return ;
}
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2013-05-25 09:50:43 -06:00
CoreSuspender suspender ;
2015-02-14 20:53:06 -07:00
2013-10-20 12:37:34 -06:00
int32_t tick = df : : global : : world - > frame_counter ;
2022-12-19 14:43:57 -07:00
TRACE ( log , out ) . print ( " processing events at tick %d \n " , tick ) ;
2013-01-03 17:31:29 -07:00
2022-03-29 10:42:24 -06:00
for ( size_t a = 0 ; a < EventType : : EVENT_MAX ; a + + ) {
if ( handlers [ a ] . empty ( ) )
2013-05-25 10:19:54 -06:00
continue ;
2022-03-29 10:42:24 -06:00
int32_t eventFrequency = - 100 ;
if ( a ! = EventType : : TICK )
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : handlers [ a ] ) {
2022-04-18 20:27:15 -06:00
if ( handle . freq < eventFrequency | | eventFrequency = = - 100 )
eventFrequency = handle . freq ;
2013-10-20 20:49:22 -06:00
}
2022-03-29 10:42:24 -06:00
else eventFrequency = 1 ;
if ( tick > = eventLastTick [ a ] & & tick - eventLastTick [ a ] < eventFrequency )
continue ;
eventManager [ a ] ( out ) ;
eventLastTick [ a ] = tick ;
2013-01-03 17:31:29 -07:00
}
2012-12-14 21:29:28 -07:00
}
static void manageTickEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2013-10-20 20:49:22 -06:00
unordered_set < EventHandler > toRemove ;
2013-10-20 19:48:28 -06:00
int32_t tick = df : : global : : world - > frame_counter ;
2012-12-14 21:29:28 -07:00
while ( ! tickQueue . empty ( ) ) {
if ( tick < ( * tickQueue . begin ( ) ) . first )
break ;
2022-04-18 20:27:15 -06:00
EventHandler & handle = ( * tickQueue . begin ( ) ) . second ;
2012-12-14 21:29:28 -07:00
tickQueue . erase ( tickQueue . begin ( ) ) ;
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for tick event \n " ) ;
2016-07-28 09:00:52 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( tick ) ) ;
2013-10-20 20:49:22 -06:00
toRemove . insert ( handle ) ;
}
if ( toRemove . empty ( ) )
return ;
2022-03-29 10:42:24 -06:00
for ( auto a = handlers [ EventType : : TICK ] . begin ( ) ; a ! = handlers [ EventType : : TICK ] . end ( ) ; ) {
2022-04-18 20:27:15 -06:00
EventHandler & handle = ( * a ) . second ;
2013-10-20 21:16:21 -06:00
if ( toRemove . find ( handle ) = = toRemove . end ( ) ) {
2022-03-29 10:42:24 -06:00
a + + ;
2013-10-20 20:49:22 -06:00
continue ;
}
2022-03-29 10:42:24 -06:00
a = handlers [ EventType : : TICK ] . erase ( a ) ;
2013-10-20 21:16:21 -06:00
toRemove . erase ( handle ) ;
if ( toRemove . empty ( ) )
break ;
2012-12-14 21:29:28 -07:00
}
}
static void manageJobInitiatedEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
if ( ! df : : global : : job_next_id )
return ;
2012-12-14 21:29:28 -07:00
if ( lastJobId = = - 1 ) {
lastJobId = * df : : global : : job_next_id - 1 ;
return ;
}
2015-02-14 20:53:06 -07:00
2012-12-14 21:29:28 -07:00
if ( lastJobId + 1 = = * df : : global : : job_next_id ) {
return ; //no new jobs
}
2012-12-16 13:39:39 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : JOB_INITIATED ] . begin ( ) , handlers [ EventType : : JOB_INITIATED ] . end ( ) ) ;
2021-06-18 16:06:14 -06:00
2022-04-18 20:27:15 -06:00
for ( df : : job_list_link * link = & df : : global : : world - > jobs . list ; link ! = nullptr ; link = link - > next ) {
if ( link - > item = = nullptr )
2022-03-29 10:42:24 -06:00
continue ;
if ( link - > item - > id < = lastJobId )
continue ;
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for job initiated event \n " ) ;
2022-04-18 20:27:15 -06:00
handle . eventHandler ( out , ( void * ) link - > item ) ;
2012-12-14 21:29:28 -07:00
}
}
2015-02-14 20:53:06 -07:00
2012-12-14 21:29:28 -07:00
lastJobId = * df : : global : : job_next_id - 1 ;
}
2022-03-29 10:42:24 -06:00
static void manageJobStartedEvent ( color_ostream & out ) {
2021-08-06 07:02:23 -06:00
if ( ! df : : global : : world )
return ;
2022-03-29 10:42:24 -06:00
static unordered_set < int32_t > startedJobs ;
2023-09-27 13:32:46 -06:00
vector < df : : job * > new_started_jobs ;
2022-03-29 10:42:24 -06:00
// iterate event handler callbacks
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : JOB_STARTED ] . begin ( ) , handlers [ EventType : : JOB_STARTED ] . end ( ) ) ;
2023-09-28 09:19:32 -06:00
for ( df : : job_list_link * link = & df : : global : : world - > jobs . list ; link - > next ! = nullptr ; link = link - > next ) {
df : : job * job = link - > next - > item ;
int32_t j_id = job - > id ;
2022-11-09 17:49:35 -07:00
if ( job & & Job : : getWorker ( job ) & & ! startedJobs . count ( job - > id ) ) {
startedJobs . emplace ( job - > id ) ;
2023-09-28 09:19:32 -06:00
for ( auto & [ _ , handle ] : copy ) {
// the jobs must have a worker to start
DEBUG ( log , out ) . print ( " calling handler for job started event \n " ) ;
handle . eventHandler ( out , job ) ;
}
2023-09-27 13:32:46 -06:00
}
2023-09-28 09:19:32 -06:00
if ( link - > next = = nullptr | | link - > next - > item - > id ! = j_id ) {
if ( Once : : doOnce ( " EventManager jobstarted job removed " ) ) {
out . print ( " %s,%d: job %u removed from jobs linked list \n " , __FILE__ , __LINE__ , j_id ) ;
}
2021-08-06 07:02:23 -06:00
}
}
}
2022-03-29 10:42:24 -06:00
2013-05-25 07:44:17 -06:00
//helper function for manageJobCompletedEvent
2018-04-05 15:48:11 -06:00
//static int32_t getWorkerID(df::job* job) {
// auto ref = findRef(job->general_refs, general_ref_type::UNIT_WORKER);
// return ref ? ref->getID() : -1;
//}
2013-05-25 07:44:17 -06:00
2013-05-25 10:19:54 -06:00
/*
TODO : consider checking item creation / experience gain just in case
*/
2012-12-14 21:29:28 -07:00
static void manageJobCompletedEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2022-03-29 10:42:24 -06:00
int32_t tick0 = eventLastTick [ EventType : : JOB_COMPLETED ] ;
int32_t tick1 = df : : global : : world - > frame_counter ;
2015-02-14 20:53:06 -07:00
2012-12-16 13:39:39 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : JOB_COMPLETED ] . begin ( ) , handlers [ EventType : : JOB_COMPLETED ] . end ( ) ) ;
2023-09-28 09:19:32 -06:00
unordered_map < int32_t , df : : job * > nowJobs ;
2022-04-18 20:27:15 -06:00
for ( df : : job_list_link * link = & df : : global : : world - > jobs . list ; link ! = nullptr ; link = link - > next ) {
if ( link - > item = = nullptr )
2012-12-14 21:29:28 -07:00
continue ;
2023-09-28 09:19:32 -06:00
nowJobs . emplace ( link - > item - > id , link - > item ) ;
2012-12-14 21:29:28 -07:00
}
2015-02-14 20:53:06 -07:00
2013-05-25 07:44:17 -06:00
#if 0
//testing info on job initiation/completion
//newly allocated jobs
for ( auto j = nowJobs . begin ( ) ; j ! = nowJobs . end ( ) ; j + + ) {
if ( prevJobs . find ( ( * j ) . first ) ! = prevJobs . end ( ) )
continue ;
2015-02-14 20:53:06 -07:00
2013-05-25 07:44:17 -06:00
df : : job & job1 = * ( * j ) . second ;
out . print ( " new job \n "
" location : 0x%X \n "
" id : %d \n "
" type : %d %s \n "
" working : %d \n "
" completion_timer : %d \n "
" workerID : %d \n "
" time : %d -> %d \n "
2022-03-29 10:42:24 -06:00
" \n " , job1 . list_link - > item , job1 . id , job1 . job_type , ENUM_ATTR ( job_type , caption , job1 . job_type ) , job1 . flags . bits . working , job1 . completion_timer , getWorkerID ( & job1 ) , tick0 , tick1 ) ;
2013-05-25 07:44:17 -06:00
}
2012-12-18 16:34:38 -07:00
for ( auto i = prevJobs . begin ( ) ; i ! = prevJobs . end ( ) ; i + + ) {
2013-05-25 07:44:17 -06:00
df : : job & job0 = * ( * i ) . second ;
auto j = nowJobs . find ( ( * i ) . first ) ;
if ( j = = nowJobs . end ( ) ) {
out . print ( " job deallocated \n "
" location : 0x%X \n "
" id : %d \n "
" type : %d %s \n "
" working : %d \n "
" completion_timer : %d \n "
" workerID : %d \n "
" time : %d -> %d \n "
2022-03-29 10:42:24 -06:00
, job0 . list_link = = NULL ? 0 : job0 . list_link - > item , job0 . id , job0 . job_type , ENUM_ATTR ( job_type , caption , job0 . job_type ) , job0 . flags . bits . working , job0 . completion_timer , getWorkerID ( & job0 ) , tick0 , tick1 ) ;
2012-12-14 21:29:28 -07:00
continue ;
2013-05-25 07:44:17 -06:00
}
df : : job & job1 = * ( * j ) . second ;
2015-02-14 20:53:06 -07:00
2013-05-25 07:44:17 -06:00
if ( job0 . flags . bits . working = = job1 . flags . bits . working & &
( job0 . completion_timer = = job1 . completion_timer | | ( job1 . completion_timer > 0 & & job0 . completion_timer - 1 = = job1 . completion_timer ) ) & &
getWorkerID ( & job0 ) = = getWorkerID ( & job1 ) )
continue ;
2015-02-14 20:53:06 -07:00
2013-05-25 07:44:17 -06:00
out . print ( " job change \n "
" location : 0x%X -> 0x%X \n "
" id : %d -> %d \n "
" type : %d -> %d \n "
" type : %s -> %s \n "
" working : %d -> %d \n "
" completion timer : %d -> %d \n "
" workerID : %d -> %d \n "
" time : %d -> %d \n "
" \n " ,
job0 . list_link - > item , job1 . list_link - > item ,
job0 . id , job1 . id ,
job0 . job_type , job1 . job_type ,
ENUM_ATTR ( job_type , caption , job0 . job_type ) , ENUM_ATTR ( job_type , caption , job1 . job_type ) ,
job0 . flags . bits . working , job1 . flags . bits . working ,
job0 . completion_timer , job1 . completion_timer ,
getWorkerID ( & job0 ) , getWorkerID ( & job1 ) ,
2022-03-29 10:42:24 -06:00
tick0 , tick1
2013-05-25 07:44:17 -06:00
) ;
}
# endif
2015-02-14 20:53:06 -07:00
2022-04-18 20:27:15 -06:00
for ( auto & prevJob : prevJobs ) {
2022-03-29 10:42:24 -06:00
//if it happened within a tick, must have been cancelled by the user or a plugin: not completed
if ( tick1 < = tick0 )
continue ;
2022-04-18 20:27:15 -06:00
if ( nowJobs . find ( prevJob . first ) ! = nowJobs . end ( ) ) {
2022-03-29 10:42:24 -06:00
//could have just finished if it's a repeat job
2022-04-18 20:27:15 -06:00
df : : job & job0 = * prevJob . second ;
2022-03-29 10:42:24 -06:00
if ( ! job0 . flags . bits . repeat )
continue ;
2022-04-18 20:27:15 -06:00
df : : job & job1 = * nowJobs [ prevJob . first ] ;
2022-03-29 10:42:24 -06:00
if ( job0 . completion_timer ! = 0 )
continue ;
if ( job1 . completion_timer ! = - 1 )
continue ;
//still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen
2023-09-28 09:19:32 -06:00
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for repeated job completed event \n " ) ;
handle . eventHandler ( out , ( void * ) & job0 ) ;
}
2022-03-29 10:42:24 -06:00
continue ;
}
//recently finished or cancelled job
2022-04-18 20:27:15 -06:00
df : : job & job0 = * prevJob . second ;
2022-03-29 10:42:24 -06:00
if ( job0 . flags . bits . repeat | | job0 . completion_timer ! = 0 )
continue ;
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for job completed event \n " ) ;
2023-09-28 09:19:32 -06:00
handle . eventHandler ( out , ( void * ) & job0 ) ;
2012-12-14 21:29:28 -07:00
}
}
//erase old jobs, copy over possibly altered jobs
2023-09-28 09:19:32 -06:00
for ( auto & [ _ , prev_job ] : prevJobs ) {
Job : : deleteJobStruct ( prev_job , true ) ;
2012-12-14 21:29:28 -07:00
}
prevJobs . clear ( ) ;
2015-02-14 20:53:06 -07:00
2012-12-14 21:29:28 -07:00
//create new jobs
2023-09-28 09:19:32 -06:00
for ( auto & [ _ , now_job ] : nowJobs ) {
2022-03-29 10:42:24 -06:00
/*map<int32_t, df::job*>::iterator i = prevJobs.find((*j).first);
2012-12-14 21:29:28 -07:00
if ( i ! = prevJobs . end ( ) ) {
continue ;
} */
2023-09-28 09:19:32 -06:00
df : : job * newJob = Job : : cloneJobStruct ( now_job , true ) ;
prevJobs . emplace ( newJob - > id , newJob ) ;
2012-12-14 21:29:28 -07:00
}
}
2022-01-26 10:41:09 -07:00
static void manageNewUnitActiveEvent ( color_ostream & out ) {
if ( ! df : : global : : world )
return ;
2022-03-29 10:42:24 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : UNIT_NEW_ACTIVE ] . begin ( ) , handlers [ EventType : : UNIT_NEW_ACTIVE ] . end ( ) ) ;
// iterate event handler callbacks
2023-09-27 13:32:46 -06:00
vector < int32_t > new_active_unit_ids ;
for ( df : : unit * unit : df : : global : : world - > units . active ) {
if ( ! activeUnits . count ( unit - > id ) ) {
activeUnits . emplace ( unit - > id ) ;
new_active_unit_ids . emplace_back ( unit - > id ) ;
}
}
for ( int32_t unit_id : new_active_unit_ids ) {
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for new unit event \n " ) ;
handle . eventHandler ( out , ( void * ) intptr_t ( unit_id ) ) ; // intptr_t() avoids cast from smaller type warning
2022-01-26 10:41:09 -07:00
}
}
}
2022-03-29 10:42:24 -06:00
2012-12-15 12:40:11 -07:00
static void manageUnitDeathEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2012-12-16 13:39:39 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : UNIT_DEATH ] . begin ( ) , handlers [ EventType : : UNIT_DEATH ] . end ( ) ) ;
2023-09-27 13:32:46 -06:00
vector < int32_t > dead_unit_ids ;
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > units . all ) {
2022-03-29 10:42:24 -06:00
//if ( unit->counters.death_id == -1 ) {
if ( Units : : isActive ( unit ) ) {
livingUnits . insert ( unit - > id ) ;
continue ;
}
2023-09-28 09:19:32 -06:00
if ( ! Units : : isDead ( unit ) ) continue ; // for units that have left the map but aren't dead
2022-03-29 10:42:24 -06:00
//dead: if dead since last check, trigger events
if ( livingUnits . find ( unit - > id ) = = livingUnits . end ( ) )
continue ;
2023-09-27 13:32:46 -06:00
livingUnits . erase ( unit - > id ) ;
dead_unit_ids . emplace_back ( unit - > id ) ;
}
2015-02-14 20:53:06 -07:00
2023-09-27 13:32:46 -06:00
for ( int32_t unit_id : dead_unit_ids ) {
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for unit death event \n " ) ;
2023-09-27 13:32:46 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( unit_id ) ) ;
2012-12-15 12:40:11 -07:00
}
}
}
2012-12-15 14:49:13 -07:00
static void manageItemCreationEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
if ( ! df : : global : : item_next_id )
return ;
2012-12-15 14:49:13 -07:00
if ( nextItem > = * df : : global : : item_next_id ) {
return ;
}
2015-02-14 20:53:06 -07:00
2012-12-16 13:39:39 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : ITEM_CREATED ] . begin ( ) , handlers [ EventType : : ITEM_CREATED ] . end ( ) ) ;
2012-12-15 14:49:13 -07:00
size_t index = df : : item : : binsearch_index ( df : : global : : world - > items . all , nextItem , false ) ;
2013-10-20 18:02:52 -06:00
if ( index ! = 0 ) index - - ;
2023-09-27 13:32:46 -06:00
std : : vector < int32_t > created_items ;
2022-03-29 10:42:24 -06:00
for ( size_t a = index ; a < df : : global : : world - > items . all . size ( ) ; a + + ) {
df : : item * item = df : : global : : world - > items . all [ a ] ;
//already processed
if ( item - > id < nextItem )
continue ;
//invaders
if ( item - > flags . bits . foreign )
continue ;
//traders who bring back your items?
if ( item - > flags . bits . trader )
continue ;
//migrants
if ( item - > flags . bits . owned )
continue ;
//spider webs don't count
if ( item - > flags . bits . spider_web )
continue ;
2023-09-27 13:32:46 -06:00
created_items . push_back ( item - > id ) ;
}
// handle all created items
for ( int32_t item_id : created_items ) {
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for item created event \n " ) ;
2023-09-27 13:32:46 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( item_id ) ) ;
2012-12-15 14:49:13 -07:00
}
}
2023-09-27 13:32:46 -06:00
2012-12-15 14:49:13 -07:00
nextItem = * df : : global : : item_next_id ;
}
2012-12-18 16:34:38 -07:00
static void manageBuildingEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
if ( ! df : : global : : building_next_id )
return ;
2012-12-18 16:34:38 -07:00
/*
* TODO : could be faster
* consider looking at jobs : building creation / destruction
* */
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : BUILDING ] . begin ( ) , handlers [ EventType : : BUILDING ] . end ( ) ) ;
2022-03-29 10:42:24 -06:00
//first alert people about new buildings
2023-09-27 13:32:46 -06:00
vector < int32_t > new_buildings ;
2022-03-29 10:42:24 -06:00
for ( int32_t a = nextBuilding ; a < * df : : global : : building_next_id ; a + + ) {
int32_t index = df : : building : : binsearch_index ( df : : global : : world - > buildings . all , a ) ;
if ( index = = - 1 ) {
//out.print("%s, line %d: Couldn't find new building with id %d.\n", __FILE__, __LINE__, a);
//the tricky thing is that when the game first starts, it's ok to skip buildings, but otherwise, if you skip buildings, something is probably wrong. TODO: make this smarter
continue ;
}
buildings . insert ( a ) ;
2023-09-27 13:32:46 -06:00
new_buildings . emplace_back ( a ) ;
2022-03-29 10:42:24 -06:00
}
nextBuilding = * df : : global : : building_next_id ;
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
//now alert people about destroyed buildings
2023-09-27 13:32:46 -06:00
for ( auto it = buildings . begin ( ) ; it ! = buildings . end ( ) ; ) {
int32_t id = * it ;
2022-03-29 10:42:24 -06:00
int32_t index = df : : building : : binsearch_index ( df : : global : : world - > buildings . all , id ) ;
if ( index ! = - 1 ) {
2023-09-27 13:32:46 -06:00
+ + it ;
2022-03-29 10:42:24 -06:00
continue ;
}
2021-06-18 16:06:14 -06:00
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for destroyed building event \n " ) ;
2022-04-18 20:27:15 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( id ) ) ;
2012-12-18 16:34:38 -07:00
}
2023-09-27 13:32:46 -06:00
it = buildings . erase ( it ) ;
2012-12-18 16:34:38 -07:00
}
2023-09-28 09:19:32 -06:00
//alert people about newly created buildings
std : : for_each ( new_buildings . begin ( ) , new_buildings . end ( ) , [ & ] ( int32_t building ) {
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for created building event \n " ) ;
handle . eventHandler ( out , ( void * ) intptr_t ( building ) ) ;
}
} ) ;
2012-12-18 16:34:38 -07:00
}
static void manageConstructionEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2013-10-20 12:37:34 -06:00
//unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end());
2015-02-14 20:53:06 -07:00
2022-04-18 14:40:22 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : CONSTRUCTION ] . begin ( ) , handlers [ EventType : : CONSTRUCTION ] . end ( ) ) ;
2023-09-27 13:32:46 -06:00
unordered_set < df : : construction > next_construction_set ; // will be swapped with constructions
next_construction_set . reserve ( constructions . bucket_count ( ) ) ;
vector < df : : construction > new_constructions ;
// find new constructions - swapping found constructions over from constructions to next_construction_set
for ( auto c : df : : global : : world - > constructions ) {
auto & construction = * c ;
auto it = constructions . find ( construction ) ;
if ( it = = constructions . end ( ) ) {
// handle new construction event later
new_constructions . emplace_back ( construction ) ;
2022-03-29 10:42:24 -06:00
}
2023-09-27 13:32:46 -06:00
else {
constructions . erase ( it ) ;
}
next_construction_set . emplace ( construction ) ;
}
constructions . swap ( next_construction_set ) ;
// now next_construction_set contains all the constructions that were removed (not found in df::global::world->constructions)
for ( auto & construction : next_construction_set ) {
// handle construction removed event
for ( const auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for destroyed construction event \n " ) ;
2022-04-18 14:40:22 -06:00
handle . eventHandler ( out , ( void * ) & construction ) ;
2022-03-29 10:42:24 -06:00
}
}
2023-09-27 13:32:46 -06:00
// now handle all the new constructions
for ( auto & construction : new_constructions ) {
for ( const auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for created construction event \n " ) ;
handle . eventHandler ( out , ( void * ) & construction ) ;
2012-12-18 16:34:38 -07:00
}
}
}
2013-01-02 16:30:15 -07:00
static void manageSyndromeEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2013-01-02 16:30:15 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : SYNDROME ] . begin ( ) , handlers [ EventType : : SYNDROME ] . end ( ) ) ;
2013-10-20 18:02:52 -06:00
int32_t highestTime = - 1 ;
2023-09-27 13:32:46 -06:00
std : : vector < SyndromeData > new_syndrome_data ;
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > units . all ) {
2013-10-20 18:02:52 -06:00
/*
2018-06-21 09:17:09 -06:00
if ( unit - > flags1 . bits . inactive )
2013-01-02 16:30:15 -07:00
continue ;
2013-10-20 18:02:52 -06:00
*/
2022-03-29 10:42:24 -06:00
for ( size_t b = 0 ; b < unit - > syndromes . active . size ( ) ; b + + ) {
df : : unit_syndrome * syndrome = unit - > syndromes . active [ b ] ;
int32_t startTime = syndrome - > year * ticksPerYear + syndrome - > year_time ;
if ( startTime > highestTime )
highestTime = startTime ;
if ( startTime < = lastSyndromeTime )
continue ;
2023-09-27 13:32:46 -06:00
new_syndrome_data . emplace_back ( unit - > id , b ) ;
}
}
for ( auto & data : new_syndrome_data ) {
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for syndrome event \n " ) ;
handle . eventHandler ( out , ( void * ) & data ) ;
2013-01-02 16:30:15 -07:00
}
}
2023-09-27 13:32:46 -06:00
2013-10-20 18:02:52 -06:00
lastSyndromeTime = highestTime ;
2013-01-02 16:30:15 -07:00
}
2013-01-03 13:52:56 -07:00
static void manageInvasionEvent ( color_ostream & out ) {
2023-01-05 18:11:01 -07:00
if ( ! df : : global : : plotinfo )
2014-07-21 18:14:43 -06:00
return ;
2013-01-03 13:52:56 -07:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : INVASION ] . begin ( ) , handlers [ EventType : : INVASION ] . end ( ) ) ;
2023-01-05 18:11:01 -07:00
if ( df : : global : : plotinfo - > invasions . next_id < = nextInvasion )
2013-01-03 13:52:56 -07:00
return ;
2023-01-05 18:11:01 -07:00
nextInvasion = df : : global : : plotinfo - > invasions . next_id ;
2013-01-03 13:52:56 -07:00
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for invasion event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( nextInvasion - 1 ) ) ;
2013-01-03 13:52:56 -07:00
}
}
2013-06-15 15:59:55 -06:00
static void manageEquipmentEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2013-10-24 17:32:52 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : INVENTORY_CHANGE ] . begin ( ) , handlers [ EventType : : INVENTORY_CHANGE ] . end ( ) ) ;
2015-02-14 20:53:06 -07:00
2013-10-24 17:32:52 -06:00
unordered_map < int32_t , InventoryItem > itemIdToInventoryItem ;
unordered_set < int32_t > currentlyEquipped ;
2023-09-27 13:32:46 -06:00
vector < InventoryChangeData > equipment_pickups ;
vector < InventoryChangeData > equipment_drops ;
vector < InventoryChangeData > equipment_changes ;
2023-09-28 09:19:32 -06:00
// This vector stores the pointers to newly created changed items
// needed as the stack allocated temporary (in the loop) is lost when we go to
// handle the event calls, so we move that data to the heap if its needed,
// and then once we are done we delete everything.
vector < InventoryItem * > changed_items ;
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > units . all ) {
2022-03-29 10:42:24 -06:00
itemIdToInventoryItem . clear ( ) ;
currentlyEquipped . clear ( ) ;
/*if ( unit->flags1.bits.inactive )
continue ;
*/
auto oldEquipment = equipmentLog . find ( unit - > id ) ;
bool hadEquipment = oldEquipment ! = equipmentLog . end ( ) ;
vector < InventoryItem > * temp ;
if ( hadEquipment ) {
temp = & ( ( * oldEquipment ) . second ) ;
} else {
temp = new vector < InventoryItem > ;
}
//vector<InventoryItem>& v = (*oldEquipment).second;
vector < InventoryItem > & v = * temp ;
2022-04-18 20:27:15 -06:00
for ( auto & i : v ) {
2022-03-29 10:42:24 -06:00
itemIdToInventoryItem [ i . itemId ] = i ;
}
for ( size_t b = 0 ; b < unit - > inventory . size ( ) ; b + + ) {
df : : unit_inventory_item * dfitem_new = unit - > inventory [ b ] ;
currentlyEquipped . insert ( dfitem_new - > item - > id ) ;
InventoryItem item_new ( dfitem_new - > item - > id , * dfitem_new ) ;
auto c = itemIdToInventoryItem . find ( dfitem_new - > item - > id ) ;
if ( c = = itemIdToInventoryItem . end ( ) ) {
//new item equipped (probably just picked up)
2023-09-28 09:19:32 -06:00
changed_items . emplace_back ( new InventoryItem ( item_new ) ) ;
equipment_pickups . emplace_back ( unit - > id , nullptr , changed_items . back ( ) ) ;
2022-03-29 10:42:24 -06:00
continue ;
2013-06-15 15:59:55 -06:00
}
2023-09-28 09:19:32 -06:00
InventoryItem item_old = c - > second ;
2022-03-29 10:42:24 -06:00
df : : unit_inventory_item & item0 = item_old . item ;
df : : unit_inventory_item & item1 = item_new . item ;
if ( item0 . mode = = item1 . mode & & item0 . body_part_id = = item1 . body_part_id & & item0 . wound_id = = item1 . wound_id )
continue ;
//some sort of change in how it's equipped
2023-09-28 09:19:32 -06:00
changed_items . emplace_back ( new InventoryItem ( item_new ) ) ;
InventoryItem * item_new_ptr = changed_items . back ( ) ;
changed_items . emplace_back ( new InventoryItem ( item_old ) ) ;
InventoryItem * item_old_ptr = changed_items . back ( ) ;
equipment_changes . emplace_back ( unit - > id , item_old_ptr , item_new_ptr ) ;
2022-03-29 10:42:24 -06:00
}
//check for dropped items
2022-04-18 20:27:15 -06:00
for ( auto i : v ) {
2022-03-29 10:42:24 -06:00
if ( currentlyEquipped . find ( i . itemId ) ! = currentlyEquipped . end ( ) )
continue ;
//TODO: delete ptr if invalid
2023-09-28 09:19:32 -06:00
changed_items . emplace_back ( new InventoryItem ( i ) ) ;
equipment_drops . emplace_back ( unit - > id , changed_items . back ( ) , nullptr ) ;
2022-03-29 10:42:24 -06:00
}
if ( ! hadEquipment )
delete temp ;
//update equipment
vector < InventoryItem > & equipment = equipmentLog [ unit - > id ] ;
equipment . clear ( ) ;
2022-04-18 20:27:15 -06:00
for ( auto dfitem : unit - > inventory ) {
2022-03-29 10:42:24 -06:00
InventoryItem item ( dfitem - > item - > id , * dfitem ) ;
equipment . push_back ( item ) ;
2013-06-15 15:59:55 -06:00
}
}
2023-09-27 13:32:46 -06:00
// now handle events
2023-09-27 16:34:19 -06:00
std : : for_each ( equipment_pickups . begin ( ) , equipment_pickups . end ( ) , [ & ] ( InventoryChangeData & data ) {
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for new item equipped inventory change event \n " ) ;
handle . eventHandler ( out , ( void * ) & data ) ;
}
} ) ;
std : : for_each ( equipment_drops . begin ( ) , equipment_drops . end ( ) , [ & ] ( InventoryChangeData & data ) {
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for dropped item inventory change event \n " ) ;
handle . eventHandler ( out , ( void * ) & data ) ;
}
} ) ;
std : : for_each ( equipment_changes . begin ( ) , equipment_changes . end ( ) , [ & ] ( InventoryChangeData & data ) {
for ( auto & [ _ , handle ] : copy ) {
DEBUG ( log , out ) . print ( " calling handler for inventory change event \n " ) ;
handle . eventHandler ( out , ( void * ) & data ) ;
}
} ) ;
2023-09-28 09:19:32 -06:00
// clean up changed items list
std : : for_each ( changed_items . begin ( ) , changed_items . end ( ) , [ ] ( InventoryItem * p ) {
delete p ;
} ) ;
2013-06-15 15:59:55 -06:00
}
2014-07-01 06:58:48 -06:00
static void updateReportToRelevantUnits ( ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2014-07-01 06:58:48 -06:00
if ( df : : global : : world - > frame_counter < = reportToRelevantUnitsTime )
return ;
reportToRelevantUnitsTime = df : : global : : world - > frame_counter ;
2015-02-14 20:53:06 -07:00
2022-04-18 20:27:15 -06:00
for ( auto unit : df : : global : : world - > units . all ) {
2022-03-29 10:42:24 -06:00
for ( int16_t b = df : : enum_traits < df : : unit_report_type > : : first_item_value ; b < = df : : enum_traits < df : : unit_report_type > : : last_item_value ; b + + ) {
2014-07-01 06:58:48 -06:00
if ( b = = df : : unit_report_type : : Sparring )
continue ;
for ( size_t c = 0 ; c < unit - > reports . log [ b ] . size ( ) ; c + + ) {
int32_t report = unit - > reports . log [ b ] [ c ] ;
if ( std : : find ( reportToRelevantUnits [ report ] . begin ( ) , reportToRelevantUnits [ report ] . end ( ) , unit - > id ) ! = reportToRelevantUnits [ report ] . end ( ) )
continue ;
reportToRelevantUnits [ unit - > reports . log [ b ] [ c ] ] . push_back ( unit - > id ) ;
}
}
}
}
2014-06-23 07:15:46 -06:00
static void manageReportEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2014-06-27 20:09:01 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : REPORT ] . begin ( ) , handlers [ EventType : : REPORT ] . end ( ) ) ;
std : : vector < df : : report * > & reports = df : : global : : world - > status . reports ;
2022-04-18 20:27:15 -06:00
size_t idx = df : : report : : binsearch_index ( reports , lastReport , false ) ;
2022-04-18 20:29:31 -06:00
// returns the index to the key equal to or greater than the key provided
2022-11-06 18:30:28 -07:00
while ( idx < reports . size ( ) & & reports [ idx ] - > id < = lastReport ) {
idx + + ;
}
// returns the index to the key equal to or greater than the key provided
2022-04-18 20:29:31 -06:00
2022-04-18 20:27:15 -06:00
for ( ; idx < reports . size ( ) ; idx + + ) {
df : : report * report = reports [ idx ] ;
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for report event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) intptr_t ( report - > id ) ) ;
2014-06-27 20:09:01 -06:00
}
2022-03-29 10:42:24 -06:00
lastReport = report - > id ;
2014-06-27 20:09:01 -06:00
}
2014-06-23 07:15:46 -06:00
}
2014-06-28 00:31:34 -06:00
static df : : unit_wound * getWound ( df : : unit * attacker , df : : unit * defender ) {
2022-04-18 20:27:15 -06:00
for ( auto wound : defender - > body . wounds ) {
2014-11-30 12:03:00 -07:00
if ( wound - > age < = 1 & & wound - > attacker_unit_id = = attacker - > id ) {
2014-06-28 00:31:34 -06:00
return wound ;
}
}
2022-04-18 20:27:15 -06:00
return nullptr ;
2014-06-28 00:31:34 -06:00
}
static void manageUnitAttackEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2014-06-28 00:31:34 -06:00
multimap < Plugin * , EventHandler > copy ( handlers [ EventType : : UNIT_ATTACK ] . begin ( ) , handlers [ EventType : : UNIT_ATTACK ] . end ( ) ) ;
std : : vector < df : : report * > & reports = df : : global : : world - > status . reports ;
2022-04-18 20:27:15 -06:00
size_t idx = df : : report : : binsearch_index ( reports , lastReportUnitAttack , false ) ;
2022-04-18 20:29:31 -06:00
// returns the index to the key equal to or greater than the key provided
idx = reports [ idx ] - > id = = lastReportUnitAttack ? idx + 1 : idx ; // we need the index after (where the new stuff is)
2014-06-28 00:31:34 -06:00
std : : set < int32_t > strikeReports ;
2022-04-18 20:27:15 -06:00
for ( ; idx < reports . size ( ) ; idx + + ) {
df : : report * report = reports [ idx ] ;
2014-06-28 00:31:34 -06:00
lastReportUnitAttack = report - > id ;
if ( report - > flags . bits . continuation )
continue ;
df : : announcement_type type = report - > type ;
if ( type = = df : : announcement_type : : COMBAT_STRIKE_DETAILS ) {
strikeReports . insert ( report - > id ) ;
}
}
2015-02-14 20:53:06 -07:00
2014-06-28 00:31:34 -06:00
if ( strikeReports . empty ( ) )
return ;
2014-07-01 06:58:48 -06:00
updateReportToRelevantUnits ( ) ;
2023-09-27 13:32:46 -06:00
unordered_set < std : : pair < int32_t , int32_t > , hash_pair > already_done ;
2022-04-18 20:27:15 -06:00
for ( int reportId : strikeReports ) {
2022-03-29 10:42:24 -06:00
df : : report * report = df : : report : : find ( reportId ) ;
if ( ! report )
continue ; //TODO: error
std : : string reportStr = report - > text ;
for ( int32_t b = reportId + 1 ; ; b + + ) {
df : : report * report2 = df : : report : : find ( b ) ;
if ( ! report2 )
break ;
if ( report2 - > type ! = df : : announcement_type : : COMBAT_STRIKE_DETAILS )
break ;
if ( ! report2 - > flags . bits . continuation )
break ;
2022-04-18 20:27:15 -06:00
reportStr + = report2 - > text ;
2022-03-29 10:42:24 -06:00
}
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
std : : vector < int32_t > & relevantUnits = reportToRelevantUnits [ report - > id ] ;
if ( relevantUnits . size ( ) ! = 2 ) {
continue ;
}
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
df : : unit * unit1 = df : : unit : : find ( relevantUnits [ 0 ] ) ;
df : : unit * unit2 = df : : unit : : find ( relevantUnits [ 1 ] ) ;
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
df : : unit_wound * wound1 = getWound ( unit1 , unit2 ) ;
df : : unit_wound * wound2 = getWound ( unit2 , unit1 ) ;
2015-02-14 20:53:06 -07:00
2022-04-18 20:27:15 -06:00
UnitAttackData data { } ;
2022-04-18 14:39:05 -06:00
data . report_id = report - > id ;
2023-09-27 13:32:46 -06:00
if ( wound1 & & already_done . find ( std : : make_pair ( unit1 - > id , unit2 - > id ) ) = = already_done . end ( ) ) {
2022-03-29 10:42:24 -06:00
data . attacker = unit1 - > id ;
data . defender = unit2 - > id ;
data . wound = wound1 - > id ;
2015-02-14 20:53:06 -07:00
2023-09-27 13:32:46 -06:00
already_done . emplace ( unit1 - > id , unit2 - > id ) ;
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for unit1 attack unit attack event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) & data ) ;
}
}
2015-02-14 20:53:06 -07:00
2023-09-27 13:32:46 -06:00
if ( wound2 & & already_done . find ( std : : make_pair ( unit1 - > id , unit2 - > id ) ) = = already_done . end ( ) ) {
2022-03-29 10:42:24 -06:00
data . attacker = unit2 - > id ;
data . defender = unit1 - > id ;
data . wound = wound2 - > id ;
2015-02-14 20:53:06 -07:00
2023-09-27 13:32:46 -06:00
already_done . emplace ( unit1 - > id , unit2 - > id ) ;
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for unit2 attack unit attack event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) & data ) ;
}
}
2014-07-01 06:58:48 -06:00
2022-03-29 10:42:24 -06:00
if ( Units : : isKilled ( unit1 ) ) {
data . attacker = unit2 - > id ;
data . defender = unit1 - > id ;
data . wound = - 1 ;
2023-09-27 13:32:46 -06:00
already_done . emplace ( unit1 - > id , unit2 - > id ) ;
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for unit1 killed unit attack event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) & data ) ;
}
}
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
if ( Units : : isKilled ( unit2 ) ) {
data . attacker = unit1 - > id ;
data . defender = unit2 - > id ;
data . wound = - 1 ;
2023-09-27 13:32:46 -06:00
already_done . emplace ( unit1 - > id , unit2 - > id ) ;
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for unit2 killed unit attack event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) & data ) ;
}
}
2015-02-14 20:53:06 -07:00
2022-03-29 10:42:24 -06:00
if ( ! wound1 & & ! wound2 ) {
//if ( unit1->flags1.bits.inactive || unit2->flags1.bits.inactive )
// continue;
if ( reportStr . find ( " severed part " ) )
continue ;
if ( Once : : doOnce ( " EventManager neither wound " ) ) {
out . print ( " %s, %d: neither wound: %s \n " , __FILE__ , __LINE__ , reportStr . c_str ( ) ) ;
2014-06-28 00:31:34 -06:00
}
}
}
}
2022-04-18 23:08:23 -06:00
static std : : string getVerb ( df : : unit * unit , const std : : string & reportStr ) {
std : : string result ( reportStr ) ;
2014-07-03 02:55:12 -06:00
std : : string name = unit - > name . first_name + " " ;
2014-11-09 16:36:21 -07:00
bool match = strncmp ( result . c_str ( ) , name . c_str ( ) , name . length ( ) ) = = 0 ;
if ( match ) {
2014-07-03 02:55:12 -06:00
result = result . substr ( name . length ( ) ) ;
result = result . substr ( 0 , result . length ( ) - 1 ) ;
return result ;
}
//use profession name
2014-11-09 16:36:21 -07:00
name = " The " + Units : : getProfessionName ( unit ) + " " ;
match = strncmp ( result . c_str ( ) , name . c_str ( ) , name . length ( ) ) = = 0 ;
if ( match ) {
result = result . substr ( name . length ( ) ) ;
result = result . substr ( 0 , result . length ( ) - 1 ) ;
return result ;
}
if ( unit - > id ! = 0 ) {
2014-07-03 02:55:12 -06:00
return " " ;
2014-11-09 16:36:21 -07:00
}
std : : string you = " You " ;
match = strncmp ( result . c_str ( ) , name . c_str ( ) , name . length ( ) ) = = 0 ;
if ( match ) {
result = result . substr ( name . length ( ) ) ;
result = result . substr ( 0 , result . length ( ) - 1 ) ;
return result ;
}
return " " ;
}
static InteractionData getAttacker ( color_ostream & out , df : : report * attackEvent , df : : unit * lastAttacker , df : : report * defendEvent , vector < df : : unit * > & relevantUnits ) {
vector < df : : unit * > attackers = relevantUnits ;
vector < df : : unit * > defenders = relevantUnits ;
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
//find valid interactions: TODO
/*map<int32_t,vector<df::interaction*> > validInteractions;
2022-03-29 10:42:24 -06:00
for ( size_t a = 0 ; a < relevantUnits . size ( ) ; a + + ) {
2014-11-09 16:36:21 -07:00
df : : unit * unit = relevantUnits [ a ] ;
vector < df : : interaction * > & interactions = validInteractions [ unit - > id ] ;
for ( size_t b = 0 ; b < unit - > body .
} */
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
//if attackEvent
// attacker must be same location
// attacker name must start attack str
// attack verb must match valid interaction of this attacker
std : : string attackVerb ;
if ( attackEvent ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-03-29 10:42:24 -06:00
for ( size_t a = 0 ; a < attackers . size ( ) ; a + + ) {
2014-11-09 16:36:21 -07:00
if ( attackers [ a ] - > pos ! = attackEvent - > pos ) {
attackers . erase ( attackers . begin ( ) + a ) ;
a - - ;
continue ;
}
if ( lastAttacker & & attackers [ a ] ! = lastAttacker ) {
attackers . erase ( attackers . begin ( ) + a ) ;
a - - ;
continue ;
}
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
std : : string verbC = getVerb ( attackers [ a ] , attackEvent - > text ) ;
if ( verbC . length ( ) = = 0 ) {
attackers . erase ( attackers . begin ( ) + a ) ;
a - - ;
continue ;
}
attackVerb = verbC ;
}
}
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
//if defendEvent
// defender must be same location
// defender name must start defend str
// defend verb must match valid interaction of some attacker
std : : string defendVerb ;
if ( defendEvent ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-03-29 10:42:24 -06:00
for ( size_t a = 0 ; a < defenders . size ( ) ; a + + ) {
2014-11-09 16:36:21 -07:00
if ( defenders [ a ] - > pos ! = defendEvent - > pos ) {
defenders . erase ( defenders . begin ( ) + a ) ;
a - - ;
continue ;
}
std : : string verbC = getVerb ( defenders [ a ] , defendEvent - > text ) ;
if ( verbC . length ( ) = = 0 ) {
defenders . erase ( defenders . begin ( ) + a ) ;
a - - ;
continue ;
}
defendVerb = verbC ;
}
}
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
//keep in mind one attacker zero defenders is perfectly valid for self-cast
if ( attackers . size ( ) = = 1 & & defenders . size ( ) = = 1 & & attackers [ 0 ] = = defenders [ 0 ] ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
} else {
if ( defenders . size ( ) = = 1 ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
auto a = std : : find ( attackers . begin ( ) , attackers . end ( ) , defenders [ 0 ] ) ;
if ( a ! = attackers . end ( ) )
attackers . erase ( a ) ;
}
if ( attackers . size ( ) = = 1 ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
auto a = std : : find ( defenders . begin ( ) , defenders . end ( ) , attackers [ 0 ] ) ;
if ( a ! = defenders . end ( ) )
defenders . erase ( a ) ;
}
}
2015-02-14 20:53:06 -07:00
2014-11-09 16:36:21 -07:00
//if trying attack-defend pair and it fails to find attacker, try defend only
InteractionData result = /*(InteractionData)*/ { std : : string ( ) , std : : string ( ) , - 1 , - 1 , - 1 , - 1 } ;
if ( attackers . size ( ) > 1 ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
if ( Once : : doOnce ( " EventManager interaction ambiguous attacker " ) ) {
out . print ( " %s,%d: ambiguous attacker on report \n \' %s \' \n '%s' \n " , __FILE__ , __LINE__ , attackEvent ? attackEvent - > text . c_str ( ) : " " , defendEvent ? defendEvent - > text . c_str ( ) : " " ) ;
}
2022-04-18 20:27:15 -06:00
} else if ( attackers . empty ( ) ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
if ( attackEvent & & defendEvent )
2022-04-18 20:27:15 -06:00
return getAttacker ( out , nullptr , nullptr , defendEvent , relevantUnits ) ;
2014-11-09 16:36:21 -07:00
} else {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
//attackers.size() == 1
result . attacker = attackers [ 0 ] - > id ;
2022-04-18 20:27:15 -06:00
if ( ! defenders . empty ( ) )
2014-11-09 16:36:21 -07:00
result . defender = defenders [ 0 ] - > id ;
if ( defenders . size ( ) > 1 ) {
if ( Once : : doOnce ( " EventManager interaction ambiguous defender " ) ) {
out . print ( " %s,%d: ambiguous defender: shouldn't happen. On report \n \' %s \' \n '%s' \n " , __FILE__ , __LINE__ , attackEvent ? attackEvent - > text . c_str ( ) : " " , defendEvent ? defendEvent - > text . c_str ( ) : " " ) ;
}
}
result . attackVerb = attackVerb ;
result . defendVerb = defendVerb ;
if ( attackEvent )
result . attackReport = attackEvent - > id ;
if ( defendEvent )
result . defendReport = defendEvent - > id ;
}
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-11-09 16:36:21 -07:00
return result ;
}
static vector < df : : unit * > gatherRelevantUnits ( color_ostream & out , df : : report * r1 , df : : report * r2 ) {
vector < df : : report * > reports ;
2022-04-18 20:27:15 -06:00
if ( r1 = = r2 ) r2 = nullptr ;
2014-11-09 16:36:21 -07:00
if ( r1 ) reports . push_back ( r1 ) ;
if ( r2 ) reports . push_back ( r2 ) ;
vector < df : : unit * > result ;
unordered_set < int32_t > ids ;
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-04-18 20:27:15 -06:00
for ( auto report : reports ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-04-18 20:27:15 -06:00
vector < int32_t > & units = reportToRelevantUnits [ report - > id ] ;
2014-11-09 16:36:21 -07:00
if ( units . size ( ) > 2 ) {
if ( Once : : doOnce ( " EventManager interaction too many relevant units " ) ) {
2022-04-18 20:27:15 -06:00
out . print ( " %s,%d: too many relevant units. On report \n \' %s \' \n " , __FILE__ , __LINE__ , report - > text . c_str ( ) ) ;
2014-11-09 16:36:21 -07:00
}
}
2022-04-18 20:27:15 -06:00
for ( int & unit_id : units )
if ( ids . find ( unit_id ) = = ids . end ( ) ) {
ids . insert ( unit_id ) ;
result . push_back ( df : : unit : : find ( unit_id ) ) ;
2014-11-09 16:36:21 -07:00
}
}
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2014-07-03 02:55:12 -06:00
return result ;
}
2014-07-01 07:02:20 -06:00
static void manageInteractionEvent ( color_ostream & out ) {
2014-07-21 18:14:43 -06:00
if ( ! df : : global : : world )
return ;
2014-07-03 02:55:12 -06:00
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 ) {
2022-03-29 10:42:24 -06:00
a + + ;
2014-07-03 02:55:12 -06:00
}
if ( a < reports . size ( ) )
updateReportToRelevantUnits ( ) ;
2015-02-14 20:53:06 -07:00
2022-04-18 20:27:15 -06:00
df : : report * lastAttackEvent = nullptr ;
df : : unit * lastAttacker = nullptr ;
2018-04-05 15:48:11 -06:00
//df::unit* lastDefender = NULL;
2014-11-09 16:36:21 -07:00
unordered_map < int32_t , unordered_set < int32_t > > history ;
2022-03-29 10:42:24 -06:00
for ( ; a < reports . size ( ) ; a + + ) {
df : : report * report = reports [ a ] ;
lastReportInteraction = report - > id ;
df : : announcement_type type = report - > type ;
if ( type ! = df : : announcement_type : : INTERACTION_ACTOR & & type ! = df : : announcement_type : : INTERACTION_TARGET )
continue ;
if ( report - > flags . bits . continuation )
continue ;
bool attack = type = = df : : announcement_type : : INTERACTION_ACTOR ;
if ( attack ) {
lastAttackEvent = report ;
2022-04-18 20:27:15 -06:00
lastAttacker = nullptr ;
2022-03-29 10:42:24 -06:00
//lastDefender = NULL;
}
vector < df : : unit * > relevantUnits = gatherRelevantUnits ( out , lastAttackEvent , report ) ;
2022-04-18 20:27:15 -06:00
InteractionData data = getAttacker ( out , lastAttackEvent , lastAttacker , attack ? nullptr : report , relevantUnits ) ;
2022-03-29 10:42:24 -06:00
if ( data . attacker < 0 )
continue ;
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-03-29 10:42:24 -06:00
//if ( !attack && lastAttacker && data.attacker == lastAttacker->id && lastDefender && data.defender == lastDefender->id )
// continue; //lazy way of preventing duplicates
if ( attack & & a + 1 < reports . size ( ) & & reports [ a + 1 ] - > type = = df : : announcement_type : : INTERACTION_TARGET ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-04-18 20:27:15 -06:00
vector < df : : unit * > relevant_units = gatherRelevantUnits ( out , lastAttackEvent , reports [ a + 1 ] ) ;
InteractionData data2 = getAttacker ( out , lastAttackEvent , lastAttacker , reports [ a + 1 ] , relevant_units ) ;
2022-03-29 10:42:24 -06:00
if ( data . attacker = = data2 . attacker & & ( data . defender = = - 1 | | data . defender = = data2 . defender ) ) {
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-03-29 10:42:24 -06:00
data = data2 ;
a + + ;
}
}
{
2014-11-09 16:36:21 -07:00
# define HISTORY_ITEM 1
# if HISTORY_ITEM
2022-03-29 10:42:24 -06:00
unordered_set < int32_t > & b = history [ data . attacker ] ;
if ( b . find ( data . defender ) ! = b . end ( ) )
continue ;
history [ data . attacker ] . insert ( data . defender ) ;
//b.insert(data.defender);
2014-11-09 16:36:21 -07:00
# else
2022-03-29 10:42:24 -06:00
unordered_set < int32_t > & b = history [ data . attackReport ] ;
2014-11-09 16:36:21 -07:00
if ( b . find ( data . defendReport ) ! = b . end ( ) )
continue ;
history [ data . attackReport ] . insert ( data . defendReport ) ;
//b.insert(data.defendReport);
# endif
2022-03-29 10:42:24 -06:00
}
2014-11-14 16:50:19 -07:00
//out.print("%s,%d\n",__FILE__,__LINE__);
2022-03-29 10:42:24 -06:00
lastAttacker = df : : unit : : find ( data . attacker ) ;
//lastDefender = df::unit::find(data.defender);
//fire event
2023-09-27 13:32:46 -06:00
for ( auto & [ _ , handle ] : copy ) {
2022-12-19 14:43:57 -07:00
DEBUG ( log , out ) . print ( " calling handler for interaction event \n " ) ;
2022-03-29 10:42:24 -06:00
handle . eventHandler ( out , ( void * ) & data ) ;
2014-07-03 02:55:12 -06:00
}
2022-03-29 10:42:24 -06:00
//TODO: deduce attacker from latest defend event first
2014-07-03 02:55:12 -06:00
}
2014-07-01 07:02:20 -06:00
}