@ -21,6 +21,7 @@ command_result follow (Core * c, std::vector <std::string> & parameters);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				df : : unit  * followedUnit ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				int32_t  prevX ,  prevY ,  prevZ ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				uint8_t  prevMenuWidth ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				DFHACK_PLUGIN ( " follow " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -33,6 +34,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    followedUnit  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevX = prevY = prevZ  =  - 1 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevMenuWidth  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				} 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -42,17 +44,14 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				} 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				// Called to notify the plugin about important state changes.
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				// Invoked with DF suspended, and always before the matching plugin_onupdate.
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				// More event codes may be added in the future.
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				DFhackCExport  command_result  plugin_onstatechange ( Core *  c ,  state_change_event  event ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				{ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    switch  ( event )  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    case  SC_GAME_LOADED : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    case  SC_GAME_UNLOADED : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    case  SC_GAME_UNLOADED :  //Make sure our plugin's variables are clean
  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        followedUnit  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevX = prevY = prevZ  =  - 1 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevMenuWidth  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        break ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    default : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        break ; 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -63,50 +62,80 @@ DFhackCExport command_result plugin_onstatechange(Core* c, state_change_event ev
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				DFhackCExport  command_result  plugin_onupdate  (  Core  *  c  ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				{ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( ! followedUnit )  return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( ! followedUnit )  return  CR_OK ;  //Don't do anything if we're not following a unit
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    DFHack : : World  * world  = c - > getWorld ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( world - > ReadPauseState ( )  & &  prevX = = - 1 )  return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    Gui  * gui  =  c - > getGui ( ) ;  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( world - > ReadPauseState ( )  & &  prevX = = - 1 )  return  CR_OK ;  //Wait until the game is unpaused after first running "follow" to begin following
  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    df : : coord  & unitPos  =  followedUnit - > pos ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    int32_t  x , y , z , w , h ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    Gui  * gui  =  c - > getGui ( ) ;   //Get all of the relevant data for determining the size of the map on the window
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    int32_t  x , y , z , w , h , c_x , c_y , c_z ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    uint8_t  menu_width ,  area_map_width ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > getViewCoords ( x , y , z ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > getWindowSize ( w , h ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( prevX = = - 1 ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > getMenuWidth ( menu_width ,  area_map_width ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > getCursorCoords ( c_x , c_y , c_z ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( c_z  = =  - 3000  & &  menu_width  = =  3 )  menu_width  =  2 ;  //Presence of the cursor means that there's actually a width-2 menu open
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    h  - =  2 ;  //account for vertical borders
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( menu_width  = =  1 )  w  - =  57 ;  //Menu is open doubly wide
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  if  ( menu_width  = =  2  & &  area_map_width  = =  3 )  w  - =  33 ;  //Just the menu is open
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  if  ( menu_width  = =  2  & &  area_map_width  = =  2 )  w  - =  26 ;  //Just the area map is open
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  w  - =  2 ;  //No menu or area map, just account for borders
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( prevMenuWidth  = =  0 )  prevMenuWidth  =  menu_width ;  //have we already had a menu width?
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( prevX = = - 1 )  //have we already had previous values for the window location?
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevX  =  x ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevY  =  y ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevZ  =  z ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  if ( prevX  ! =  x  | |  prevY  ! =  y  | |  prevZ  ! =  z ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  if ( ( prevX  ! =  x  | |  prevY  ! =  y  | |  prevZ  ! =  z )  & &  prevMenuWidth  = =  menu_width )  //User has manually moved the window, stop following the unit
  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        followedUnit  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevX = prevY = prevZ  =  - 1 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevMenuWidth  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        c - > con . print ( " No longer following anything. \n " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    uint32_t  x_max ,  y_max ,  z_max ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    Simple : : Maps : : getSize ( x_max ,  y_max ,  z_max ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    Simple : : Maps : : getSize ( x_max ,  y_max ,  z_max ) ;  //Get map size in tiles so we can prevent the camera from going off the edge
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    x_max  * =  16 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    y_max  * =  16 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevX  =  unitPos . x  +  w / 2  > =  x_max  ?  x_max - w + 2  :  ( unitPos . x  > =  w / 2  ?  unitPos . x  -  w / 2  :  0 ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevY  =  unitPos . y  +  h / 2  > =  y_max  ?  y_max - h + 2  :  ( unitPos . y  > =  h / 2  ?  unitPos . y  -  h / 2  :  0 ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevZ  =  unitPos . z ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    x  =  unitPos . x  +  w / 2  > =  x_max  ?  x_max - w  :  ( unitPos . x  > =  w / 2  ?  unitPos . x  -  w / 2  :  0 ) ;  //Calculate a new screen position centered on the selected unit
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    y  =  unitPos . y  +  h / 2  > =  y_max  ?  y_max - h  :  ( unitPos . y  > =  h / 2  ?  unitPos . y  -  h / 2  :  0 ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    z  =  unitPos . z ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > setViewCoords ( x ,  y ,  z ) ;  //Set the new screen position!
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    gui - > setViewCoords ( prevX ,  prevY ,  prevZ ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( c_x  ! =  3000  & &  ! world - > ReadPauseState ( ) )  gui - > setCursorCoords ( c_x  -  ( prevX - x ) ,  c_y  -  ( prevY - y ) ,  z ) ;  //If, for some reason, the cursor is active and the screen is still moving, move the cursor along with the screen
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevX  =  x ;  //Save this round's stuff for next time so we can monitor for changes made by the user
 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevY  =  y ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevZ  =  z ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    prevMenuWidth  =  menu_width ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  CR_OK ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				} 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				command_result  follow  ( Core  *  c ,  std : : vector  < std : : string >  &  parameters ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				{ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				{   
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( ! parameters . empty ( ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        return  CR_WRONG_USAGE ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    CoreSuspender  suspend ( c ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( followedUnit ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        c - > con . print ( " No longer following previously selected unit. \n " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        followedUnit  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    followedUnit  =  getSelectedUnit ( c ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  ( followedUnit ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    { 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -116,7 +145,9 @@ command_result follow (Core * c, std::vector <std::string> & parameters)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            c - > con . print ( "  %s " ,  followedUnit - > name . first_name . c_str ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        c - > con . print ( " . \n " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        c - > con . print ( " . Simply manually move the view to break the following. \n " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevX = prevY = prevZ  =  - 1 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        prevMenuWidth  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else  followedUnit  =  0 ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  CR_OK ;