@ -43,6 +43,7 @@
 
		
	
		
			
				# include  <unordered_map>  
		
	
		
			
				# include  <unordered_set>  
		
	
		
			
				# include  <array>  
		
	
		
			
				# include  <utility>  
		
	
		
			
				
 
		
	
		
			
				namespace  DFHack  {  
		
	
		
			
				    DBG_DECLARE ( eventmanager ,  log ,  DebugCategory : : LINFO ) ; 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -246,6 +247,15 @@ static int32_t reportToRelevantUnitsTime = -1;
 
		
	
		
			
				//interaction
  
		
	
		
			
				static  int32_t  lastReportInteraction ;  
		
	
		
			
				
 
		
	
		
			
				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 ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				} ;  
		
	
		
			
				
 
		
	
		
			
				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"};
  
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -276,9 +286,9 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event
 
		
	
		
			
				        gameLoaded  =  false ; 
 
		
	
		
			
				
 
		
	
		
			
				        multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : UNLOAD ] . begin ( ) ,  handlers [ EventType : : UNLOAD ] . end ( ) ) ; 
 
		
	
		
			
				        for  ( auto  & key_value  copy )  { 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for map unloaded state change event \n " ) ; 
 
		
	
		
			
				            key_value. second  . eventHandler ( out ,  nullptr ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  nullptr ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    }  else  if  (  event  = =  DFHack : : SC_MAP_LOADED  )  { 
 
		
	
		
			
				        /*
 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -375,8 +385,7 @@ void DFHack::EventManager::manageEvents(color_ostream& out) {
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        int32_t  eventFrequency  =  - 100 ; 
 
		
	
		
			
				        if  (  a  ! =  EventType : : TICK  ) 
 
		
	
		
			
				            for  ( auto  & key_value  :  handlers [ a ] )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  handlers [ a ] )  { 
 
		
	
		
			
				                if  ( handle . freq  <  eventFrequency  | |  eventFrequency  = =  - 100  ) 
 
		
	
		
			
				                    eventFrequency  =  handle . freq ; 
 
		
	
		
			
				            } 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -439,8 +448,7 @@ static void manageJobInitiatedEvent(color_ostream& out) {
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        if  (  link - > item - > id  < =  lastJobId  ) 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for job initiated event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) link - > item ) ; 
 
		
	
		
			
				        } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -455,17 +463,24 @@ static void manageJobStartedEvent(color_ostream& out) {
 
		
	
		
			
				
 
		
	
		
			
				    static  unordered_set < int32_t >  startedJobs ; 
 
		
	
		
			
				
 
		
	
		
			
				    vector < df : : job * >  new_started_jobs ; 
 
		
	
		
			
				    // iterate event handler callbacks
 
 
		
	
		
			
				    multimap < Plugin * ,  EventHandler >  copy ( handlers [ EventType : : JOB_STARTED ] . begin ( ) ,  handlers [ EventType : : JOB_STARTED ] . end ( ) ) ; 
 
		
	
		
			
				    for  ( df : : job_list_link *  link  =  df : : global : : world - > jobs . list . next ;  link  ! =  nullptr ;  link  =  link - > next )  { 
 
		
	
		
			
				        df : : job *  job  =  link - > item ; 
 
		
	
		
			
				
 
		
	
		
			
				    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 ; 
 
		
	
		
			
				        if  ( job  & &  Job : : getWorker ( job )  & &  ! startedJobs . count ( job - > id ) )  { 
 
		
	
		
			
				            startedJobs . emplace ( job - > id ) ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                auto  & handler  =  key_value . second ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                // the jobs must have a worker to start
 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for job started event \n " ) ; 
 
		
	
		
			
				                handler . eventHandler ( out ,  job ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  job ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				        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 ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -487,11 +502,11 @@ static void manageJobCompletedEvent(color_ostream& out) {
 
		
	
		
			
				    int32_t  tick1  =  df : : global : : world - > frame_counter ; 
 
		
	
		
			
				
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : JOB_COMPLETED ] . begin ( ) ,  handlers [ EventType : : JOB_COMPLETED ] . end ( ) ) ; 
 
		
	
		
			
				    < int32_t ,  df : : job * >  nowJobs ; 
 
		
	
		
			
				    unordered_ map< int32_t ,  df : : job * >  nowJobs ; 
 
		
	
		
			
				    for  (  df : : job_list_link *  link  =  & df : : global : : world - > jobs . list ;  link  ! =  nullptr ;  link  =  link - > next  )  { 
 
		
	
		
			
				        if  (  link - > item  = =  nullptr  ) 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        nowJobs [link - > item - > id ]  =  link - > item  ; 
 
		
	
		
			
				        nowJobs .emplace ( link - > item - > id ,  link - > item )  ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				#if 0  
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -573,8 +588,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
 
		
	
		
			
				                continue ; 
 
		
	
		
			
				
 
		
	
		
			
				            //still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen
 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for repeated job completed event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * )  & job0 ) ; 
 
		
	
		
			
				            } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -586,28 +600,27 @@ static void manageJobCompletedEvent(color_ostream& out) {
 
		
	
		
			
				        if  (  job0 . flags . bits . repeat  | |  job0 . completion_timer  ! =  0  ) 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for job completed event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * )  & job0 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    //erase old jobs, copy over possibly altered jobs
 
 
		
	
		
			
				    for  ( auto  & prevJob  prevJobs )  { 
 
		
	
		
			
				        Job : : deleteJobStruct ( prev Job. second  ,  true ) ; 
 
		
	
		
			
				    for  ( auto  & [ _ , prev_job ]  prevJobs )  { 
 
		
	
		
			
				        Job : : deleteJobStruct ( prev _job ,  true ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				    prevJobs . clear ( ) ; 
 
		
	
		
			
				
 
		
	
		
			
				    //create new jobs
 
 
		
	
		
			
				    for  ( auto  & nowJob  nowJobs )  { 
 
		
	
		
			
				    for  ( auto  & [ _ , now_job ]  nowJobs )  { 
 
		
	
		
			
				        /*map<int32_t, df::job*>::iterator i = prevJobs.find((*j).first);
 
 
		
	
		
			
				        if  (  i  ! =  prevJobs . end ( )  )  { 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        } */ 
 
		
	
		
			
				
 
		
	
		
			
				        df : : job *  newJob  =  Job : : cloneJobStruct ( now Job. second  ,  true ) ; 
 
		
	
		
			
				        prevJobs [newJob - > id ]  =  newJob  ; 
 
		
	
		
			
				        df : : job *  newJob  =  Job : : cloneJobStruct ( now _job ,  true ) ; 
 
		
	
		
			
				        prevJobs .emplace ( newJob - > id ,  newJob )  ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -617,16 +630,18 @@ static void manageNewUnitActiveEvent(color_ostream& out) {
 
		
	
		
			
				
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : UNIT_NEW_ACTIVE ] . begin ( ) ,  handlers [ EventType : : UNIT_NEW_ACTIVE ] . end ( ) ) ; 
 
		
	
		
			
				    // iterate event handler callbacks
 
 
		
	
		
			
				    for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				        auto  & handler  =  key_value . second ; 
 
		
	
		
			
				    vector < int32_t >  new_active_unit_ids ; 
 
		
	
		
			
				    for  ( df : : unit *  unit  :  df : : global : : world - > units . active )  { 
 
		
	
		
			
				            int32_t  id  =  unit - > id ; 
 
		
	
		
			
				            if  ( ! activeUnits . count ( id ) )  { 
 
		
	
		
			
				                activeUnits . emplace ( id ) ; 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for new unit event \n " ) ; 
 
		
	
		
			
				                handler . eventHandler ( out ,  ( void * )  intptr_t ( id ) ) ;  // intptr_t() avoids cast from smaller type warning
 
 
		
	
		
			
				        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
 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -635,22 +650,26 @@ static void manageUnitDeathEvent(color_ostream& out) {
 
		
	
		
			
				    if  ( ! df : : global : : world ) 
 
		
	
		
			
				        return ; 
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : UNIT_DEATH ] . begin ( ) ,  handlers [ EventType : : UNIT_DEATH ] . end ( ) ) ; 
 
		
	
		
			
				    vector < int32_t >  dead_unit_ids ; 
 
		
	
		
			
				    for  ( auto  unit  :  df : : global : : world - > units . all )  { 
 
		
	
		
			
				        //if ( unit->counters.death_id == -1 ) {
 
 
		
	
		
			
				        if  (  Units : : isActive ( unit )  )  { 
 
		
	
		
			
				            livingUnits . insert ( unit - > id ) ; 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        if  ( ! Units : : isDead ( unit ) )  continue ;  // for units that have left the map but aren't dead
 
 
		
	
		
			
				        //dead: if dead since last check, trigger events
 
 
		
	
		
			
				        if  (  livingUnits . find ( unit - > id )  = =  livingUnits . end ( )  ) 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        livingUnits . erase ( unit - > id ) ; 
 
		
	
		
			
				        dead_unit_ids . emplace_back ( unit - > id ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				    for  ( int32_t  unit_id  :  dead_unit_ids )  { 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for unit death event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( unit - > ) ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( unit _ id) ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        livingUnits . erase ( unit - > id ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -666,6 +685,8 @@ static void manageItemCreationEvent(color_ostream& out) {
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : ITEM_CREATED ] . begin ( ) ,  handlers [ EventType : : ITEM_CREATED ] . end ( ) ) ; 
 
		
	
		
			
				    size_t  index  =  df : : item : : binsearch_index ( df : : global : : world - > items . all ,  nextItem ,  false ) ; 
 
		
	
		
			
				    if  (  index  ! =  0  )  index - - ; 
 
		
	
		
			
				
 
		
	
		
			
				    std : : vector < int32_t >  created_items ; 
 
		
	
		
			
				    for  (  size_t  a  =  index ;  a  <  df : : global : : world - > items . all . size ( ) ;  a + +  )  { 
 
		
	
		
			
				        df : : item *  item  =  df : : global : : world - > items . all [ a ] ; 
 
		
	
		
			
				        //already processed
 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -683,12 +704,17 @@ static void manageItemCreationEvent(color_ostream& out) {
 
		
	
		
			
				        //spider webs don't count
 
 
		
	
		
			
				        if  (  item - > flags . bits . spider_web  ) 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        created_items . push_back ( item - > id ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    // handle all created items
 
 
		
	
		
			
				    for  ( int32_t  item_id  :  created_items )  { 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for item created event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( item - > id ) ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( item _ id) ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    nextItem  =  * df : : global : : item_next_id ; 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -703,6 +729,7 @@ static void manageBuildingEvent(color_ostream& out) {
 
		
	
		
			
				     * */ 
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : BUILDING ] . begin ( ) ,  handlers [ EventType : : BUILDING ] . end ( ) ) ; 
 
		
	
		
			
				    //first alert people about new buildings
 
 
		
	
		
			
				    vector < int32_t >  new_buildings ; 
 
		
	
		
			
				    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  )  { 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -711,30 +738,34 @@ static void manageBuildingEvent(color_ostream& out) {
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        buildings . insert ( a ) ; 
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for created building event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( a ) ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        new_buildings . emplace_back ( a ) ; 
 
		
	
		
			
				
 
		
	
		
			
				    } 
 
		
	
		
			
				    nextBuilding  =  * df : : global : : building_next_id ; 
 
		
	
		
			
				
 
		
	
		
			
				    //now alert people about destroyed buildings
 
 
		
	
		
			
				    for  (  auto  a =  buildings . begin ( ) ;  a   ! =  buildings . end ( ) ;  )  { 
 
		
	
		
			
				        int32_t  id  =  * a ; 
 
		
	
		
			
				    for  (  auto  it =  buildings . begin ( ) ;  it   ! =  buildings . end ( ) ;  )  { 
 
		
	
		
			
				        int32_t  id  =  * it ; 
 
		
	
		
			
				        int32_t  index  =  df : : building : : binsearch_index ( df : : global : : world - > buildings . all , id ) ; 
 
		
	
		
			
				        if  (  index  ! =  - 1  )  { 
 
		
	
		
			
				            a + + ; 
 
		
	
		
			
				            + + it ; 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for destroyed building event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( id ) ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        a =  buildings . erase ( a  ) ; 
 
		
	
		
			
				        it =  buildings . erase ( it  ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    //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 ) ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } ) ; 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
		
			
				static  void  manageConstructionEvent ( color_ostream &  out )  {  
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -743,44 +774,52 @@ static void manageConstructionEvent(color_ostream& out) {
 
		
	
		
			
				    //unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end());
 
 
		
	
		
			
				
 
		
	
		
			
				    multimap < Plugin * ,  EventHandler >  copy ( handlers [ EventType : : CONSTRUCTION ] . begin ( ) ,  handlers [ EventType : : CONSTRUCTION ] . end ( ) ) ; 
 
		
	
		
			
				    // find & send construction removals
 
 
		
	
		
			
				    for  ( auto  iter  =  constructions . begin ( ) ;  iter  ! =  constructions . end ( ) ; )  { 
 
		
	
		
			
				        auto  & construction  =  * iter ; 
 
		
	
		
			
				        // if we can't find it, it was removed
 
 
		
	
		
			
				        if  ( df : : construction : : find ( construction . pos )  ! =  nullptr )  { 
 
		
	
		
			
				            + + iter ; 
 
		
	
		
			
				            continue ; 
 
		
	
		
			
				
 
		
	
		
			
				    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 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        else  { 
 
		
	
		
			
				            constructions . erase ( it ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        // send construction to handlers, because it was removed
 
 
		
	
		
			
				        for  ( const  auto  & key_value :  copy )  { 
 
		
	
		
			
				            EventHandler  handle  =  key_value . second ; 
 
		
	
		
			
				        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 )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for destroyed construction event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * )  & construction ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        // erase from existent constructions
 
 
		
	
		
			
				        iter  =  constructions . erase ( iter ) ; 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    // find & send construction additions
 
 
		
	
		
			
				    for  ( auto  c :  df : : global : : world - > constructions )  { 
 
		
	
		
			
				        auto  & construction  =  * c ; 
 
		
	
		
			
				        // add construction to constructions, if it isn't already present
 
 
		
	
		
			
				        if  ( constructions . emplace ( construction ) . second )  { 
 
		
	
		
			
				            // send construction to handlers, because it is new
 
 
		
	
		
			
				            for  ( const  auto  & key_value :  copy )  { 
 
		
	
		
			
				                EventHandler  handle  =  key_value . second ; 
 
		
	
		
			
				    // 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 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				}  
		
	
		
			
				}  
		
	
		
			
				
 
		
	
		
			
				static  void  manageSyndromeEvent ( color_ostream &  out )  {  
		
	
		
			
				    if  ( ! df : : global : : world ) 
 
		
	
		
			
				        return ; 
 
		
	
		
			
				    multimap < Plugin * , EventHandler >  copy ( handlers [ EventType : : SYNDROME ] . begin ( ) ,  handlers [ EventType : : SYNDROME ] . end ( ) ) ; 
 
		
	
		
			
				    int32_t  highestTime  =  - 1 ; 
 
		
	
		
			
				
 
		
	
		
			
				    std : : vector < SyndromeData >  new_syndrome_data ; 
 
		
	
		
			
				    for  ( auto  unit  :  df : : global : : world - > units . all )  { 
 
		
	
		
			
				
 
		
	
		
			
				/*
  
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -795,14 +834,16 @@ static void manageSyndromeEvent(color_ostream& out) {
 
		
	
		
			
				            if  (  startTime  < =  lastSyndromeTime  ) 
 
		
	
		
			
				                continue ; 
 
		
	
		
			
				
 
		
	
		
			
				            SyndromeData  data ( unit - > id ,  b ) ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            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 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				    }   
		
	
		
			
				
  
		
	
		
			
				    lastSyndromeTime  =  highestTime ; 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -815,8 +856,7 @@ static void manageInvasionEvent(color_ostream& out) {
 
		
	
		
			
				        return ; 
 
		
	
		
			
				    nextInvasion  =  df : : global : : plotinfo - > invasions . next_id ; 
 
		
	
		
			
				
 
		
	
		
			
				    for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				        EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				    for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				        DEBUG ( log , out ) . print ( " calling handler for invasion event \n " ) ; 
 
		
	
		
			
				        handle . eventHandler ( out ,  ( void * ) intptr_t ( nextInvasion - 1 ) ) ; 
 
		
	
		
			
				    } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -829,6 +869,18 @@ static void manageEquipmentEvent(color_ostream& out) {
 
		
	
		
			
				
 
		
	
		
			
				    unordered_map < int32_t ,  InventoryItem >  itemIdToInventoryItem ; 
 
		
	
		
			
				    unordered_set < int32_t >  currentlyEquipped ; 
 
		
	
		
			
				
 
		
	
		
			
				    vector < InventoryChangeData >  equipment_pickups ; 
 
		
	
		
			
				    vector < InventoryChangeData >  equipment_drops ; 
 
		
	
		
			
				    vector < InventoryChangeData >  equipment_changes ; 
 
		
	
		
			
				
 
		
	
		
			
				
 
		
	
		
			
				    // 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 ; 
 
		
	
		
			
				
 
		
	
		
			
				    for  ( auto  unit  :  df : : global : : world - > units . all )  { 
 
		
	
		
			
				        itemIdToInventoryItem . clear ( ) ; 
 
		
	
		
			
				        currentlyEquipped . clear ( ) ; 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -856,40 +908,30 @@ static void manageEquipmentEvent(color_ostream& out) {
 
		
	
		
			
				            auto  c  =  itemIdToInventoryItem . find ( dfitem_new - > item - > id ) ; 
 
		
	
		
			
				            if  (  c  = =  itemIdToInventoryItem . end ( )  )  { 
 
		
	
		
			
				                //new item equipped (probably just picked up)
 
 
		
	
		
			
				                InventoryChangeData  data ( unit - > id ,  nullptr ,  & item_new ) ; 
 
		
	
		
			
				                for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                    EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				                    DEBUG ( log , out ) . print ( " calling handler for new item equipped inventory change event \n " ) ; 
 
		
	
		
			
				                    handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				                } 
 
		
	
		
			
				                changed_items . emplace_back ( new  InventoryItem ( item_new ) ) ; 
 
		
	
		
			
				                equipment_pickups . emplace_back ( unit - > id ,  nullptr ,  changed_items . back ( ) ) ; 
 
		
	
		
			
				                continue ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				            InventoryItem  item_old  =  ( * c ) . second ; 
 
		
	
		
			
				            InventoryItem  item_old  =  c - > second ; 
 
		
	
		
			
				
 
		
	
		
			
				            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
 
 
		
	
		
			
				
 
		
	
		
			
				            InventoryChangeData  data ( unit - > id ,  & item_old ,  & item_new ) ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for inventory change event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				            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 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        //check for dropped items
 
 
		
	
		
			
				        for  ( auto  i  :  v )  { 
 
		
	
		
			
				            if  (  currentlyEquipped . find ( i . itemId )  ! =  currentlyEquipped . end ( )  ) 
 
		
	
		
			
				                continue ; 
 
		
	
		
			
				            //TODO: delete ptr if invalid
 
 
		
	
		
			
				            InventoryChangeData  data ( unit - > id ,  & i ,  nullptr ) ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for dropped item inventory change event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				            changed_items . emplace_back ( new  InventoryItem ( i ) ) ; 
 
		
	
		
			
				            equipment_drops . emplace_back ( unit - > id ,  changed_items . back ( ) ,  nullptr ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				        if  (  ! hadEquipment  ) 
 
		
	
		
			
				            delete  temp ; 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -902,6 +944,31 @@ static void manageEquipmentEvent(color_ostream& out) {
 
		
	
		
			
				            equipment . push_back ( item ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				
 
		
	
		
			
				    // now handle events
 
 
		
	
		
			
				    std : : for_each ( equipment_pickups . begin ( ) ,  equipment_pickups . end ( ) ,  [ & ] ( InventoryChangeData &  data )  { 
 
		
	
		
			
				        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 ) ; 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } ) ; 
 
		
	
		
			
				
 
		
	
		
			
				    // clean up changed items list
 
 
		
	
		
			
				    std : : for_each ( changed_items . begin ( ) ,  changed_items . end ( ) ,  [ ] ( InventoryItem *  p ) { 
 
		
	
		
			
				        delete  p ; 
 
		
	
		
			
				    } ) ; 
 
		
	
		
			
				}  
		
	
		
			
				
 
		
	
		
			
				static  void  updateReportToRelevantUnits ( )  {  
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -939,8 +1006,7 @@ static void manageReportEvent(color_ostream& out) {
 
		
	
		
			
				
 
		
	
		
			
				    for  (  ;  idx  <  reports . size ( ) ;  idx + +  )  { 
 
		
	
		
			
				        df : : report *  report  =  reports [ idx ] ; 
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for report event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) intptr_t ( report - > id ) ) ; 
 
		
	
		
			
				        } 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -981,7 +1047,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
 
		
	
		
			
				    if  (  strikeReports . empty ( )  ) 
 
		
	
		
			
				        return ; 
 
		
	
		
			
				    updateReportToRelevantUnits ( ) ; 
 
		
	
		
			
				    map< int32_t ,  map < int32_t ,  int32_t >  >  alreadyD  one; 
 
		
	
		
			
				    unordered_set< std : : pair < int32_t ,  int32_t > ,  hash_pair >  already_d  one; 
 
		
	
		
			
				    for  ( int  reportId  :  strikeReports )  { 
 
		
	
		
			
				        df : : report *  report  =  df : : report : : find ( reportId ) ; 
 
		
	
		
			
				        if  (  ! report  ) 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -1011,27 +1077,25 @@ static void manageUnitAttackEvent(color_ostream& out) {
 
		
	
		
			
				
 
		
	
		
			
				        UnitAttackData  data { } ; 
 
		
	
		
			
				        data . report_id  =  report - > id ; 
 
		
	
		
			
				        if  (  wound1  & &  ! alreadyDone [ unit1 - > id ] [ unit2 - > id ] )  { 
 
		
	
		
			
				        if  (  wound1  & &  already_done . find ( std : : make_pair ( unit1 - > id , unit2 - > id ) )  = =  already_done . end ( ) )  { 
 
		
	
		
			
				            data . attacker  =  unit1 - > id ; 
 
		
	
		
			
				            data . defender  =  unit2 - > id ; 
 
		
	
		
			
				            data . wound  =  wound1 - > id ; 
 
		
	
		
			
				
 
		
	
		
			
				            alreadyDone [ data . attacker ] [ data . defender ]  =  1 ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            already_done . emplace ( unit1 - > id ,  unit2 - > id ) ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for unit1 attack unit attack event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				
 
		
	
		
			
				        if  (  wound2  & &  ! alreadyDone [ unit1 - > id ] [ unit2 - > id ] )  { 
 
		
	
		
			
				        if  (  wound2  & &  already_done . find ( std : : make_pair ( unit1 - > id , unit2 - > id ) )  = =  already_done . end ( ) )  { 
 
		
	
		
			
				            data . attacker  =  unit2 - > id ; 
 
		
	
		
			
				            data . defender  =  unit1 - > id ; 
 
		
	
		
			
				            data . wound  =  wound2 - > id ; 
 
		
	
		
			
				
 
		
	
		
			
				            alreadyDone [ data . attacker ] [ data . defender ]  =  1 ; 
 
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				            already_done . emplace ( unit1 - > id ,  unit2 - > id ) ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for unit2 attack unit attack event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -1041,9 +1105,9 @@ static void manageUnitAttackEvent(color_ostream& out) {
 
		
	
		
			
				            data . attacker  =  unit2 - > id ; 
 
		
	
		
			
				            data . defender  =  unit1 - > id ; 
 
		
	
		
			
				            data . wound  =  - 1 ; 
 
		
	
		
			
				            alreadyDone [ data . attacker ] [ data . defender ]  =  1 ;   
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ;  
 
		
	
		
			
				
  
		
	
		
			
				            already_done . emplace ( unit1 - > id ,  unit2 - > id ) ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for unit1 killed unit attack event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -1053,9 +1117,9 @@ static void manageUnitAttackEvent(color_ostream& out) {
 
		
	
		
			
				            data . attacker  =  unit1 - > id ; 
 
		
	
		
			
				            data . defender  =  unit2 - > id ; 
 
		
	
		
			
				            data . wound  =  - 1 ; 
 
		
	
		
			
				            alreadyDone [ data . attacker ] [ data . defender ]  =  1 ;   
		
	
		
			
				            for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				                EventHandler  & handle  =  key_value . second ;  
 
		
	
		
			
				
  
		
	
		
			
				            already_done . emplace ( unit1 - > id ,  unit2 - > id ) ; 
 
		
	
		
			
				            for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				                DEBUG ( log , out ) . print ( " calling handler for unit2 killed unit attack event \n " ) ; 
 
		
	
		
			
				                handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				            } 
 
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
			
			@ -1313,8 +1377,7 @@ static void manageInteractionEvent(color_ostream& out) {
 
		
	
		
			
				        lastAttacker  =  df : : unit : : find ( data . attacker ) ; 
 
		
	
		
			
				        //lastDefender = df::unit::find(data.defender);
 
 
		
	
		
			
				        //fire event
 
 
		
	
		
			
				        for  ( auto  & key_value  :  copy )  { 
 
		
	
		
			
				            EventHandler  & handle  =  key_value . second ; 
 
		
	
		
			
				        for  ( auto  & [ _ , handle ]  :  copy )  { 
 
		
	
		
			
				            DEBUG ( log , out ) . print ( " calling handler for interaction event \n " ) ; 
 
		
	
		
			
				            handle . eventHandler ( out ,  ( void * ) & data ) ; 
 
		
	
		
			
				        }