@ -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,39 +62,64 @@ 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 ( prevX , prevY , prevZ ) ;
gui - > setViewCoords ( x , y , z ) ; //Set the new screen position!
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 ;
}
@ -107,6 +131,11 @@ command_result follow (Core * c, std::vector <std::string> & parameters)
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 ;