@ -3,6 +3,7 @@
# include "DataDefs.h"
# include "Export.h"
# include "PluginManager.h"
# include "MiscUtils.h"
# include "modules/Screen.h"
# include "modules/Gui.h"
@ -16,6 +17,8 @@
# include "df/interface_key.h"
using namespace DFHack ;
using df : : global : : enabler ;
using df : : global : : gps ;
# define FOR_ITER_TOOLS(iter) for(auto iter = tools.begin(); iter != tools.end(); iter++)
@ -34,17 +37,36 @@ void update_embark_sidebar (df::viewscreen_choose_start_sitest * screen)
}
}
void get_embark_pos ( df : : viewscreen_choose_start_sitest * screen ,
int & x1 , int & x2 , int & y1 , int & y2 , int & w , int & h )
{
x1 = screen - > location . embark_pos_min . x ,
x2 = screen - > location . embark_pos_max . x ,
y1 = screen - > location . embark_pos_min . y ,
y2 = screen - > location . embark_pos_max . y ,
w = x2 - x1 + 1 ,
h = y2 - y1 + 1 ;
}
void set_embark_pos ( df : : viewscreen_choose_start_sitest * screen ,
int x1 , int x2 , int y1 , int y2 )
{
screen - > location . embark_pos_min . x = x1 ;
screen - > location . embark_pos_max . x = x2 ;
screen - > location . embark_pos_min . y = y1 ;
screen - > location . embark_pos_max . y = y2 ;
}
# define GET_EMBARK_POS(screen, a, b, c, d, e, f) \
int a , b , c , d , e , f ; \
get_embark_pos ( screen , a , b , c , d , e , f ) ;
void resize_embark ( df : : viewscreen_choose_start_sitest * screen , int dx , int dy )
{
/* Reproduces DF's embark resizing functionality
* Local area resizes up and to the right , unless it ' s already touching the edge
*/
int x1 = screen - > location . embark_pos_min . x ,
x2 = screen - > location . embark_pos_max . x ,
y1 = screen - > location . embark_pos_min . y ,
y2 = screen - > location . embark_pos_max . y ,
width = x2 - x1 + dx ,
height = y2 - y1 + dy ;
GET_EMBARK_POS ( screen , x1 , x2 , y1 , y2 , width , height ) ;
if ( x1 = = x2 & & dx = = - 1 )
dx = 0 ;
if ( y1 = = y2 & & dy = = - 1 )
@ -66,11 +88,7 @@ void resize_embark (df::viewscreen_choose_start_sitest * screen, int dx, int dy)
}
y2 = std : : min ( 15 , y2 ) ;
screen - > location . embark_pos_min . x = x1 ;
screen - > location . embark_pos_max . x = x2 ;
screen - > location . embark_pos_min . y = y1 ;
screen - > location . embark_pos_max . y = y2 ;
set_embark_pos ( screen , x1 , x2 , y1 , y2 ) ;
update_embark_sidebar ( screen ) ;
}
@ -96,6 +114,7 @@ public:
virtual void after_render ( start_sitest * screen ) { } ;
virtual void before_feed ( start_sitest * screen , ikey_set * input , bool & cancel ) { } ;
virtual void after_feed ( start_sitest * screen , ikey_set * input ) { } ;
virtual void after_mouse_event ( start_sitest * screen ) { } ;
} ;
std : : vector < EmbarkTool * > tools ;
@ -320,6 +339,294 @@ public:
} ;
} ;
class MouseControl : public EmbarkTool
{
protected :
// Used for event handling
int prev_x ;
int prev_y ;
bool prev_lbut ;
// Used for controls
bool base_max_x ;
bool base_max_y ;
bool in_local_move ;
bool in_local_edge_resize_x ;
bool in_local_edge_resize_y ;
bool in_local_corner_resize ;
// These keep track of where the embark location would be (i.e. if
// the mouse is dragged out of the local embark area), to prevent
// the mouse from moving the actual area when it's 20+ tiles away
int local_overshoot_x1 ;
int local_overshoot_x2 ;
int local_overshoot_y1 ;
int local_overshoot_y2 ;
inline bool in_local_adjust ( )
{
return in_local_move | | in_local_edge_resize_x | | in_local_edge_resize_y | |
in_local_corner_resize ;
}
void lbut_press ( start_sitest * screen , bool pressed , int x , int y )
{
GET_EMBARK_POS ( screen , x1 , x2 , y1 , y2 , width , height ) ;
in_local_move = in_local_edge_resize_x = in_local_edge_resize_y =
in_local_corner_resize = false ;
if ( pressed )
{
if ( x > = 1 & & x < = 16 & & y > = 2 & & y < = 17 )
{
// Local embark - translate to local map coordinates
x - = 1 ;
y - = 2 ;
if ( ( x = = x1 | | x = = x2 ) & & ( y = = y1 | | y = = y2 ) )
{
in_local_corner_resize = true ;
base_max_x = ( x = = x2 ) ;
base_max_y = ( y = = y2 ) ;
}
else if ( x = = x1 | | x = = x2 )
{
in_local_edge_resize_x = true ;
base_max_x = ( x = = x2 ) ;
base_max_y = false ;
}
else if ( y = = y1 | | y = = y2 )
{
in_local_edge_resize_y = true ;
base_max_x = false ;
base_max_y = ( y = = y2 ) ;
}
else if ( x > x1 & & x < x2 & & y > y1 & & y < y2 )
{
in_local_move = true ;
base_max_x = base_max_y = false ;
local_overshoot_x1 = x1 ;
local_overshoot_x2 = x2 ;
local_overshoot_y1 = y1 ;
local_overshoot_y2 = y2 ;
}
}
}
update_embark_sidebar ( screen ) ;
}
void mouse_move ( start_sitest * screen , int x , int y )
{
GET_EMBARK_POS ( screen , x1 , x2 , y1 , y2 , width , height ) ;
if ( x = = - 1 & & prev_x > ( 2 + 16 ) )
{
x = gps - > dimx ;
gps - > mouse_x = x - 1 ;
}
if ( y = = - 1 & & prev_y > ( 1 + 16 ) )
{
y = gps - > dimy ;
gps - > mouse_y = y - 1 ;
}
if ( in_local_corner_resize | | in_local_edge_resize_x | | in_local_edge_resize_y )
{
x - = 1 ;
y - = 2 ;
}
if ( in_local_corner_resize )
{
x = std : : max ( 0 , std : : min ( 15 , x ) ) ;
y = std : : max ( 0 , std : : min ( 15 , y ) ) ;
if ( base_max_x )
x2 = x ;
else
x1 = x ;
if ( base_max_y )
y2 = y ;
else
y1 = y ;
if ( x1 > x2 )
{
std : : swap ( x1 , x2 ) ;
base_max_x = ! base_max_x ;
}
if ( y1 > y2 )
{
std : : swap ( y1 , y2 ) ;
base_max_y = ! base_max_y ;
}
}
else if ( in_local_edge_resize_x )
{
x = std : : max ( 0 , std : : min ( 15 , x ) ) ;
if ( base_max_x )
x2 = x ;
else
x1 = x ;
if ( x1 > x2 )
{
std : : swap ( x1 , x2 ) ;
base_max_x = ! base_max_x ;
}
}
else if ( in_local_edge_resize_y )
{
y = std : : max ( 0 , std : : min ( 15 , y ) ) ;
if ( base_max_y )
y2 = y ;
else
y1 = y ;
if ( y1 > y2 )
{
std : : swap ( y1 , y2 ) ;
base_max_y = ! base_max_y ;
}
}
else if ( in_local_move )
{
int dx = x - prev_x ;
int dy = y - prev_y ;
local_overshoot_x1 + = dx ;
local_overshoot_x2 + = dx ;
local_overshoot_y1 + = dy ;
local_overshoot_y2 + = dy ;
if ( local_overshoot_x1 < 0 )
{
x1 = 0 ;
x2 = width - 1 ;
}
else if ( local_overshoot_x2 > 15 )
{
x1 = 15 - ( width - 1 ) ;
x2 = 15 ;
}
else
{
x1 = local_overshoot_x1 ;
x2 = local_overshoot_x2 ;
}
if ( local_overshoot_y1 < 0 )
{
y1 = 0 ;
y2 = height - 1 ;
}
else if ( local_overshoot_y2 > 15 )
{
y1 = 15 - ( height - 1 ) ;
y2 = 15 ;
}
else
{
y1 = local_overshoot_y1 ;
y2 = local_overshoot_y2 ;
}
}
set_embark_pos ( screen , x1 , x2 , y1 , y2 ) ;
}
public :
MouseControl ( )
: EmbarkTool ( ) ,
prev_x ( 0 ) ,
prev_y ( 0 ) ,
prev_lbut ( false ) ,
base_max_x ( false ) ,
base_max_y ( false ) ,
in_local_move ( false ) ,
in_local_edge_resize_x ( false ) ,
in_local_edge_resize_y ( false ) ,
in_local_corner_resize ( false ) ,
local_overshoot_x1 ( 0 ) ,
local_overshoot_x2 ( 0 ) ,
local_overshoot_y1 ( 0 ) ,
local_overshoot_y2 ( 0 )
{ }
virtual std : : string getId ( ) { return " mouse " ; }
virtual std : : string getName ( ) { return " Mouse control " ; }
virtual std : : string getDesc ( ) { return " Implements mouse controls on the embark screen " ; }
virtual df : : interface_key getToggleKey ( ) { return df : : interface_key : : CUSTOM_M ; }
virtual void after_render ( start_sitest * screen )
{
GET_EMBARK_POS ( screen , x1 , x2 , y1 , y2 , width , height ) ;
int mouse_x = gps - > mouse_x , mouse_y = gps - > mouse_y ;
int local_x = prev_x - 1 ;
int local_y = prev_y - 2 ;
if ( local_x > = x1 & & local_x < = x2 & & local_y > = y1 & & local_y < = y2 )
{
int screen_x1 = x1 + 1 ;
int screen_x2 = x2 + 1 ;
int screen_y1 = y1 + 2 ;
int screen_y2 = y2 + 2 ;
UIColor fg = in_local_adjust ( ) ? COLOR_GREY : COLOR_DARKGREY ;
Screen : : Pen corner_ul = Screen : : Pen ( ( char ) 201 , fg , COLOR_BLACK ) ;
Screen : : Pen corner_ur = Screen : : Pen ( ( char ) 187 , fg , COLOR_BLACK ) ;
Screen : : Pen corner_dl = Screen : : Pen ( ( char ) 200 , fg , COLOR_BLACK ) ;
Screen : : Pen corner_dr = Screen : : Pen ( ( char ) 188 , fg , COLOR_BLACK ) ;
Screen : : Pen border_ud = Screen : : Pen ( ( char ) 205 , fg , COLOR_BLACK ) ;
Screen : : Pen border_lr = Screen : : Pen ( ( char ) 186 , fg , COLOR_BLACK ) ;
if ( in_local_corner_resize | |
( ( local_x = = x1 | | local_x = = x2 ) & & ( local_y = = y1 | | local_y = = y2 ) ) )
{
if ( local_x = = x1 & & local_y = = y1 )
Screen : : paintTile ( corner_ul , screen_x1 , screen_y1 ) ;
else if ( local_x = = x2 & & local_y = = y1 )
Screen : : paintTile ( corner_ur , screen_x2 , screen_y1 ) ;
else if ( local_x = = x1 & & local_y = = y2 )
Screen : : paintTile ( corner_dl , screen_x1 , screen_y2 ) ;
else if ( local_x = = x2 & & local_y = = y2 )
Screen : : paintTile ( corner_dr , screen_x2 , screen_y2 ) ;
}
else if ( in_local_edge_resize_x | | local_x = = x1 | | local_x = = x2 )
{
if ( ( in_local_edge_resize_x & & ! base_max_x ) | | local_x = = x1 )
{
Screen : : paintTile ( corner_ul , screen_x1 , screen_y1 ) ;
for ( int i = screen_y1 + 1 ; i < = screen_y2 - 1 ; + + i )
Screen : : paintTile ( border_lr , screen_x1 , i ) ;
Screen : : paintTile ( corner_dl , screen_x1 , screen_y2 ) ;
}
else
{
Screen : : paintTile ( corner_ur , screen_x2 , screen_y1 ) ;
for ( int i = screen_y1 + 1 ; i < = screen_y2 - 1 ; + + i )
Screen : : paintTile ( border_lr , screen_x2 , i ) ;
Screen : : paintTile ( corner_dr , screen_x2 , screen_y2 ) ;
}
}
else if ( in_local_edge_resize_y | | local_y = = y1 | | local_y = = y2 )
{
if ( ( in_local_edge_resize_y & & ! base_max_y ) | | local_y = = y1 )
{
Screen : : paintTile ( corner_ul , screen_x1 , screen_y1 ) ;
for ( int i = screen_x1 + 1 ; i < = screen_x2 - 1 ; + + i )
Screen : : paintTile ( border_ud , i , screen_y1 ) ;
Screen : : paintTile ( corner_ur , screen_x2 , screen_y1 ) ;
}
else
{
Screen : : paintTile ( corner_dl , screen_x1 , screen_y2 ) ;
for ( int i = screen_x1 + 1 ; i < = screen_x2 - 1 ; + + i )
Screen : : paintTile ( border_ud , i , screen_y2 ) ;
Screen : : paintTile ( corner_dr , screen_x2 , screen_y2 ) ;
}
}
else
{
Screen : : paintTile ( corner_ul , screen_x1 , screen_y1 ) ;
Screen : : paintTile ( corner_ur , screen_x2 , screen_y1 ) ;
Screen : : paintTile ( corner_dl , screen_x1 , screen_y2 ) ;
Screen : : paintTile ( corner_dr , screen_x2 , screen_y2 ) ;
}
}
}
virtual void after_mouse_event ( start_sitest * screen )
{
if ( enabler - > mouse_lbut ! = prev_lbut )
{
lbut_press ( screen , enabler - > mouse_lbut , gps - > mouse_x , gps - > mouse_y ) ;
}
if ( gps - > mouse_x ! = prev_x | | gps - > mouse_y ! = prev_y )
{
mouse_move ( screen , gps - > mouse_x , gps - > mouse_y ) ;
}
prev_lbut = enabler - > mouse_lbut ;
prev_x = gps - > mouse_x ;
prev_y = gps - > mouse_y ;
} ;
} ;
class embark_tools_settings : public dfhack_viewscreen
{
public :
@ -352,8 +659,9 @@ public:
EmbarkTool * t = * iter ;
x = min_x + 2 ;
OutputString ( COLOR_LIGHTRED , x , y , Screen : : getKeyDisplay ( t - > getToggleKey ( ) ) ) ;
OutputString ( COLOR_WHITE , x , y , " : " + t - > getName ( ) +
( t - > getEnabled ( ) ? " : Enabled " : " : Disabled " ) ) ;
OutputString ( COLOR_WHITE , x , y , " : " + t - > getName ( ) + " : " ) ;
OutputString ( t - > getEnabled ( ) ? COLOR_GREEN : COLOR_RED , x , y ,
t - > getEnabled ( ) ? " Enabled " : " Disabled " ) ;
y + + ;
}
} ;
@ -427,28 +735,24 @@ struct choose_start_site_hook : df::viewscreen_choose_start_sitest
y = dim . y - 5 ;
OutputString ( COLOR_LIGHTRED , x , y , Screen : : getKeyDisplay ( df : : interface_key : : CUSTOM_S ) ) ;
OutputString ( COLOR_WHITE , x , y , " : Enabled: " ) ;
std : : list < std : : string > parts ;
FOR_ITER_TOOLS ( it er )
std : : vector < std : : string > parts ;
FOR_ITER_TOOLS ( it )
{
EmbarkTool * tool = * iter ;
if ( tool - > getEnabled ( ) )
{
parts . push_back ( tool - > getName ( ) ) ;
parts . push_back ( " , " ) ;
}
if ( ( * it ) - > getEnabled ( ) )
parts . push_back ( ( * it ) - > getName ( ) ) ;
}
if ( parts . size ( ) )
{
parts. pop_back ( ) ; // Remove trailing comma
for ( auto iter = parts . begin ( ) ; iter ! = parts . end ( ) ; iter + + )
std : : string label = join_strings ( " , " , parts ) ;
if ( label . size ( ) > dim . x - x - 1 )
{
OutputString ( COLOR_LIGHTMAGENTA , x , y , * iter ) ;
label . resize ( dim . x - x - 1 - 3 ) ;
label . append ( " ... " ) ;
}
OutputString ( COLOR_LIGHTMAGENTA , x , y , label ) ;
}
else
{
OutputString ( COLOR_LIGHTMAGENTA , x , y , " (none) " ) ;
}
}
void display_settings ( )
@ -511,6 +815,7 @@ command_result embark_tools_cmd (color_ostream &out, std::vector <std::string> &
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
{
tools . push_back ( new EmbarkAnywhere ) ;
tools . push_back ( new MouseControl ) ;
tools . push_back ( new NanoEmbark ) ;
tools . push_back ( new SandIndicator ) ;
tools . push_back ( new StablePosition ) ;
@ -550,6 +855,35 @@ DFhackCExport command_result plugin_enable (color_ostream &out, bool enable)
return CR_OK ;
}
DFhackCExport command_result plugin_onupdate ( color_ostream & out )
{
static int8_t mask = 0 ;
static decltype ( gps - > mouse_x ) prev_x = - 1 ;
static decltype ( gps - > mouse_y ) prev_y = - 1 ;
df : : viewscreen * parent = DFHack : : Gui : : getCurViewscreen ( ) ;
VIRTUAL_CAST_VAR ( screen , df : : viewscreen_choose_start_sitest , parent ) ;
if ( ! screen )
return CR_OK ;
int8_t new_mask = ( enabler - > mouse_lbut < < 1 ) |
( enabler - > mouse_rbut < < 2 ) |
( enabler - > mouse_lbut_down < < 3 ) |
( enabler - > mouse_rbut_down < < 4 ) |
( enabler - > mouse_lbut_lift < < 5 ) |
( enabler - > mouse_rbut_lift < < 6 ) ;
if ( mask ! = new_mask | | prev_x ! = gps - > mouse_x | | prev_y ! = gps - > mouse_y )
{
FOR_ITER_TOOLS ( iter )
{
if ( ( * iter ) - > getEnabled ( ) )
( * iter ) - > after_mouse_event ( screen ) ;
}
}
mask = new_mask ;
prev_x = gps - > mouse_x ;
prev_y = gps - > mouse_y ;
return CR_OK ;
}
command_result embark_tools_cmd ( color_ostream & out , std : : vector < std : : string > & parameters )
{
CoreSuspender suspend ;