Petr Mrázek 2012-02-22 15:22:19 +01:00
commit 0807baf0c0
3 changed files with 94 additions and 19 deletions

@ -144,6 +144,18 @@ namespace DFHack
*/ */
bool getWindowSize(int32_t & width, int32_t & height); bool getWindowSize(int32_t & width, int32_t & height);
/*
*Menu width:
*3:3 - menu and area map closed
*2:3 - menu open single width
*1:3 - menu open double width
*1:2 - menu and area map open
*2:2 - area map open
*/
bool getMenuWidth(uint8_t & menu_width, uint8_t & area_map_width);
bool setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width);
/* /*
* Screen tiles * Screen tiles
*/ */

@ -478,6 +478,7 @@ struct Gui::Private
Private() Private()
{ {
Started = false; Started = false;
StartedMenu = false;
StartedScreen = false; StartedScreen = false;
} }
@ -486,6 +487,10 @@ struct Gui::Private
int32_t * window_y_offset; int32_t * window_y_offset;
int32_t * window_z_offset; int32_t * window_z_offset;
bool StartedMenu;
uint8_t * menu_width_offset;
uint8_t * area_map_width_offset;
bool StartedScreen; bool StartedScreen;
void * screen_tiles_ptr_offset; void * screen_tiles_ptr_offset;
@ -507,6 +512,11 @@ Gui::Gui()
if(d->window_z_offset && d->window_y_offset && d->window_x_offset) if(d->window_z_offset && d->window_y_offset && d->window_x_offset)
d->Started = true; d->Started = true;
d->menu_width_offset = (uint8_t *) mem->getAddress("ui_menu_width");
d->area_map_width_offset = (uint8_t *) mem->getAddress("ui_area_map_width");
if (d->menu_width_offset && d->area_map_width_offset)
d->StartedMenu = true;
d->screen_tiles_ptr_offset = (void *) mem->getAddress ("screen_tiles_pointer"); d->screen_tiles_ptr_offset = (void *) mem->getAddress ("screen_tiles_pointer");
if(d->screen_tiles_ptr_offset) if(d->screen_tiles_ptr_offset)
d->StartedScreen = true; d->StartedScreen = true;
@ -616,6 +626,28 @@ bool Gui::getWindowSize (int32_t &width, int32_t &height)
return true; return true;
} }
bool Gui::getMenuWidth(uint8_t &menu_width, uint8_t &area_map_width)
{
if (!d->StartedMenu) return false;
Process * p = d->owner;
p->readByte (d->menu_width_offset, menu_width);
p->readByte (d->area_map_width_offset, area_map_width);
return true;
}
bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width)
{
if (!d->StartedMenu) return false;
Process * p = d->owner;
p->writeByte (d->menu_width_offset, menu_width);
p->writeByte (d->area_map_width_offset, area_map_width);
return true;
}
bool Gui::getScreenTiles (int32_t width, int32_t height, t_screen screen[]) bool Gui::getScreenTiles (int32_t width, int32_t height, t_screen screen[])
{ {
if(!d->StartedScreen) return false; if(!d->StartedScreen) return false;

@ -21,6 +21,7 @@ command_result follow (Core * c, std::vector <std::string> & parameters);
df::unit *followedUnit; df::unit *followedUnit;
int32_t prevX, prevY, prevZ; int32_t prevX, prevY, prevZ;
uint8_t prevMenuWidth;
DFHACK_PLUGIN("follow"); DFHACK_PLUGIN("follow");
@ -33,6 +34,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
)); ));
followedUnit = 0; followedUnit = 0;
prevX=prevY=prevZ = -1; prevX=prevY=prevZ = -1;
prevMenuWidth = 0;
return CR_OK; return CR_OK;
} }
@ -42,17 +44,14 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
return CR_OK; 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) DFhackCExport command_result plugin_onstatechange(Core* c, state_change_event event)
{ {
switch (event) { switch (event) {
case SC_GAME_LOADED: case SC_GAME_LOADED:
case SC_GAME_UNLOADED: case SC_GAME_UNLOADED: //Make sure our plugin's variables are clean
followedUnit = 0; followedUnit = 0;
prevX=prevY=prevZ = -1; prevX=prevY=prevZ = -1;
prevMenuWidth = 0;
break; break;
default: default:
break; break;
@ -63,39 +62,64 @@ DFhackCExport command_result plugin_onstatechange(Core* c, state_change_event ev
DFhackCExport command_result plugin_onupdate ( Core * c ) 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(); DFHack::World *world =c->getWorld();
if (world->ReadPauseState() && prevX==-1) return CR_OK; if (world->ReadPauseState() && prevX==-1) return CR_OK; //Wait until the game is unpaused after first running "follow" to begin following
Gui *gui = c->getGui();
df::coord &unitPos = followedUnit->pos; 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->getViewCoords(x,y,z);
gui->getWindowSize(w,h); 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; prevX = x;
prevY = y; prevY = y;
prevZ = z; 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; followedUnit = 0;
prevX=prevY=prevZ = -1; prevX=prevY=prevZ = -1;
prevMenuWidth = 0;
c->con.print("No longer following anything.\n"); c->con.print("No longer following anything.\n");
return CR_OK; return CR_OK;
} }
uint32_t x_max, y_max, z_max; 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; x_max *= 16;
y_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); 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
prevY = unitPos.y + h/2 >= y_max ? y_max-h+2 : (unitPos.y >= h/2 ? unitPos.y - h/2 : 0); y = unitPos.y + h/2 >= y_max ? y_max-h : (unitPos.y >= h/2 ? unitPos.y - h/2 : 0);
prevZ = unitPos.z; 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; return CR_OK;
} }
@ -107,6 +131,11 @@ command_result follow (Core * c, std::vector <std::string> & parameters)
CoreSuspender suspend(c); CoreSuspender suspend(c);
if (followedUnit)
{
c->con.print("No longer following previously selected unit.\n");
followedUnit = 0;
}
followedUnit = getSelectedUnit(c); followedUnit = getSelectedUnit(c);
if (followedUnit) 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(" %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; else followedUnit = 0;
return CR_OK; return CR_OK;