@ -1,5 +1,5 @@
# include "buildingplan-lib.h"
# include <unordered_map>
# include "df/entity_position.h"
# include "df/interface_key.h"
# include "df/ui_build_selector.h"
@ -14,6 +14,7 @@
# include "uicommon.h"
# include "listcolumn.h"
# include "buildingplan-lib.h"
DFHACK_PLUGIN ( " buildingplan " ) ;
# define PLUGIN_VERSION 0.15
@ -24,18 +25,15 @@ REQUIRE_GLOBAL(world);
# define MAX_MASK 10
# define MAX_MATERIAL 21
using namespace DFHack ;
using namespace df : : enums ;
bool show_help = false ;
bool quickfort_mode = false ;
bool in_dummy_screen = false ;
std : : map< df : : building_type , bool > planmode_enabled ;
std : : unordered_map< BuildingTypeKey , bool , BuildingTypeKeyHash > planmode_enabled ;
class ViewscreenChooseMaterial : public dfhack_viewscreen
{
public :
ViewscreenChooseMaterial ( ItemFilter * filter ) ;
ViewscreenChooseMaterial ( ItemFilter & filter ) ;
void feed ( set < df : : interface_key > * input ) ;
@ -47,14 +45,12 @@ private:
ListColumn < df : : dfhack_material_category > masks_column ;
ListColumn < MaterialInfo > materials_column ;
int selected_column ;
ItemFilter * filter ;
df : : building_type btype ;
ItemFilter & filter ;
void addMaskEntry ( df : : dfhack_material_category & mask , const std : : string & text )
{
auto entry = ListEntry < df : : dfhack_material_category > ( pad_string ( text , MAX_MASK , false ) , mask ) ;
if ( filter - > matches ( mask ) )
if ( filter . matches ( mask ) )
entry . selected = true ;
masks_column . add ( entry ) ;
@ -131,7 +127,7 @@ private:
material . decode ( DFHack : : MaterialInfo : : PLANT_BASE + j , i ) ;
auto name = material . toString ( ) ;
ListEntry < MaterialInfo > entry ( pad_string ( name , MAX_MATERIAL , false ) , material ) ;
if ( filter - > matches ( material ) )
if ( filter . matches ( material ) )
entry . selected = true ;
materials_column . add ( entry ) ;
@ -147,7 +143,7 @@ private:
if ( ! selected_category . whole | | material . matches ( selected_category ) )
{
ListEntry < MaterialInfo > entry ( pad_string ( name , MAX_MATERIAL , false ) , material ) ;
if ( filter - > matches ( material ) )
if ( filter . matches ( material ) )
entry . selected = true ;
materials_column . add ( entry ) ;
@ -167,9 +163,10 @@ private:
}
} ;
DFHack : : MaterialInfo & material_info_identity_fn ( DFHack : : MaterialInfo & m ) { return m ; }
const DFHack : : MaterialInfo & material_info_identity_fn ( const DFHack : : MaterialInfo & m ) { return m ; }
ViewscreenChooseMaterial : : ViewscreenChooseMaterial ( ItemFilter * filter )
ViewscreenChooseMaterial : : ViewscreenChooseMaterial ( ItemFilter & filter )
: filter ( filter )
{
selected_column = 0 ;
masks_column . setTitle ( " Type " ) ;
@ -179,7 +176,6 @@ ViewscreenChooseMaterial::ViewscreenChooseMaterial(ItemFilter *filter)
materials_column . left_margin = MAX_MASK + 3 ;
materials_column . setTitle ( " Material " ) ;
materials_column . multiselect = true ;
this - > filter = filter ;
masks_column . changeHighlight ( 0 ) ;
@ -217,7 +213,7 @@ void ViewscreenChooseMaterial::feed(set<df::interface_key> *input)
}
if ( input - > count ( interface_key : : CUSTOM_SHIFT_C ) )
{
filter - > clear ( ) ;
filter . clear ( ) ;
masks_column . clearSelection ( ) ;
materials_column . clearSelection ( ) ;
populateMaterials ( ) ;
@ -225,17 +221,18 @@ void ViewscreenChooseMaterial::feed(set<df::interface_key> *input)
else if ( input - > count ( interface_key : : SEC_SELECT ) )
{
// Convert list selections to material filters
filter - > mat_mask . whole = 0 ;
filter - > materials . clear ( ) ;
filter . clearMaterialMask ( ) ;
// Category masks
auto masks = masks_column . getSelectedElems ( ) ;
for ( auto it = masks . begin ( ) ; it ! = masks . end ( ) ; + + it )
filter - > mat_mask . whole | = it - > whole ;
filter . addMaterialMask ( it - > whole ) ;
// Specific materials
auto materials = materials_column . getSelectedElems ( ) ;
transform_ ( materials , filter - > materials , material_info_identity_fn ) ;
std : : vector < DFHack : : MaterialInfo > materialInfos ;
transform_ ( materials , materialInfos , material_info_identity_fn ) ;
filter . setMaterials ( materialInfos ) ;
Screen : : dismiss ( this ) ;
}
@ -285,179 +282,167 @@ void ViewscreenChooseMaterial::render()
}
//START Viewscreen Hook
static bool is_planmode_enabled ( df: : building_type type )
static bool is_planmode_enabled ( BuildingTypeKey key )
{
return planmode_enabled [ type ] | | quickfort_mode ;
return planmode_enabled [ key ] | | quickfort_mode ;
}
struct buildingplan_ hook : public df : : viewscreen_dwarfmodest
struct buildingplan_ query_ hook : public df : : viewscreen_dwarfmodest
{
//START UI Methods
typedef df : : viewscreen_dwarfmodest interpose_base ;
void send_key ( const df : : interface_key & key )
{
set < df : : interface_key > keys ;
keys . insert ( key ) ;
this - > feed ( & keys ) ;
}
bool isInPlannedBuildingQueryMode ( )
{
return ( ui - > main . mode = = df : : ui_sidebar_mode : : QueryBuilding | |
ui - > main . mode = = df : : ui_sidebar_mode : : BuildingItems ) & &
planner . get Selected PlannedBuilding( ) ;
planner . getPlannedBuilding ( world - > selected_building ) ;
}
bool isInPlannedBuildingPlacementMode( )
bool handleInput( set < df : : interface_key > * input )
{
return ui - > main . mode = = ui_sidebar_mode : : Build & &
df : : global : : ui_build_selector & &
df : : global : : ui_build_selector - > stage < 2 & &
planner . isPlannableBuilding ( ui_build_selector - > building_type ) ;
}
if ( ! isInPlannedBuildingQueryMode ( ) )
return false ;
std : : vector < Units : : NoblePosition > getNoblePositionOfSelectedBuildingOwner ( )
{
std : : vector < Units : : NoblePosition > np ;
if ( ui - > main . mode ! = df : : ui_sidebar_mode : : QueryBuilding | |
! world - > selected_building | |
! world - > selected_building - > owner )
if ( input - > count ( interface_key : : SUSPENDBUILDING ) )
return true ; // Don't unsuspend planned buildings
if ( input - > count ( interface_key : : DESTROYBUILDING ) )
{
return np ;
// remove persistent data and allow the parent to handle the key
// so the building is removed
planner . getPlannedBuilding ( world - > selected_building ) - > remove ( ) ;
}
switch ( world - > selected_building - > getType ( ) )
{
case building_type : : Bed :
case building_type : : Chair :
case building_type : : Table :
break ;
default :
return np ;
}
return false ;
}
return getUniqueNoblePositions ( world - > selected_building - > owner ) ;
DEFINE_VMETHOD_INTERPOSE ( void , feed , ( set < df : : interface_key > * input ) )
{
if ( ! handleInput ( input ) )
INTERPOSE_NEXT ( feed ) ( input ) ;
}
bool isInNobleRoomQueryMode ( )
DEFINE_VMETHOD_INTERPOSE ( void , render , ( ) )
{
if ( getNoblePositionOfSelectedBuildingOwner ( ) . size ( ) > 0 )
return canReserveRoom ( world - > selected_building ) ;
else
return false ;
INTERPOSE_NEXT ( render ) ( ) ;
if ( ! isInPlannedBuildingQueryMode ( ) )
return ;
// Hide suspend toggle option
auto dims = Gui : : getDwarfmodeViewDims ( ) ;
int left_margin = dims . menu_x1 + 1 ;
int x = left_margin ;
int y = 20 ;
Screen : : Pen pen ( ' ' , COLOR_BLACK ) ;
Screen : : fillRect ( pen , x , y , dims . menu_x2 , y ) ;
// all current buildings only have one filter
auto & filter = planner . getPlannedBuilding ( world - > selected_building ) - > getFilters ( ) [ 0 ] ;
y = 24 ;
OutputString ( COLOR_WHITE , x , y , " Planned Building Filter " , true , left_margin ) ;
+ + y ;
OutputString ( COLOR_BROWN , x , y , " Min Quality: " , false , left_margin ) ;
OutputString ( COLOR_BLUE , x , y , filter . getMinQuality ( ) , true , left_margin ) ;
OutputString ( COLOR_BROWN , x , y , " Max Quality: " , false , left_margin ) ;
OutputString ( COLOR_BLUE , x , y , filter . getMaxQuality ( ) , true , left_margin ) ;
if ( filter . getDecoratedOnly ( ) )
OutputString ( COLOR_BLUE , x , y , " Decorated Only " , true , left_margin ) ;
OutputString ( COLOR_BROWN , x , y , " Materials: " , true , left_margin ) ;
auto filters = filter . getMaterials ( ) ;
for ( auto it = filters . begin ( ) ; it ! = filters . end ( ) ; + + it )
OutputString ( COLOR_BLUE , x , y , " * " + * it , true , left_margin ) ;
}
} ;
struct buildingplan_place_hook : public df : : viewscreen_dwarfmodest
{
typedef df : : viewscreen_dwarfmodest interpose_base ;
bool isInPlannedBuildingPlacementMode ( )
{
return ui - > main . mode = = ui_sidebar_mode : : Build & &
df : : global : : ui_build_selector & &
df : : global : : ui_build_selector - > stage < 2 & &
planner . isPlannableBuilding ( toBuildingTypeKey ( ui_build_selector ) ) ;
}
bool handleInput ( set < df : : interface_key > * input )
{
if ( isInPlannedBuildingPlacementMode ( ) )
if ( ! isInPlannedBuildingPlacementMode ( ) )
{
auto type = ui_build_selector - > building_type ;
if ( input - > count ( interface_key : : CUSTOM_SHIFT_P ) )
{
planmode_enabled [ type ] = ! planmode_enabled [ type ] ;
if ( ! is_planmode_enabled ( type ) )
{
Gui : : refreshSidebar ( ) ;
in_dummy_screen = false ;
}
return true ;
}
else if ( input - > count ( interface_key : : CUSTOM_P ) | |
input - > count ( interface_key : : CUSTOM_F ) | |
input - > count ( interface_key : : CUSTOM_D ) | |
input - > count ( interface_key : : CUSTOM_N ) )
{
show_help = true ;
}
show_help = false ;
return false ;
}
if ( is_planmode_enabled ( type ) )
if ( in_dummy_screen )
{
if ( input - > count ( interface_key : : SELECT ) | | input - > count ( interface_key : : SEC_SELECT )
| | input - > count ( interface_key : : LEAVESCREEN ) )
{
if ( quickfort_mode & & in_dummy_screen )
{
if ( input - > count ( interface_key : : SELECT ) | | input - > count ( interface_key : : SEC_SELECT )
| | input - > count ( interface_key : : LEAVESCREEN ) )
{
in_dummy_screen = false ;
send_key ( interface_key : : LEAVESCREEN ) ;
}
return true ;
}
if ( input - > count ( interface_key : : SELECT ) )
{
if ( ui_build_selector - > errors . size ( ) = = 0 & & planner . allocatePlannedBuilding ( type ) )
{
Gui : : refreshSidebar ( ) ;
if ( quickfort_mode )
{
in_dummy_screen = true ;
}
}
return true ;
}
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_F ) )
{
quickfort_mode = ! quickfort_mode ;
}
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_M ) )
{
Screen : : show ( dts : : make_unique < ViewscreenChooseMaterial > ( planner . getDefaultItemFilterForType ( type ) ) , plugin_self ) ;
}
else if ( input - > count ( interface_key : : CUSTOM_Q ) )
{
planner . adjustMinQuality ( type , - 1 ) ;
}
else if ( input - > count ( interface_key : : CUSTOM_W ) )
{
planner . adjustMinQuality ( type , 1 ) ;
}
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_Q ) )
{
planner . adjustMaxQuality ( type , - 1 ) ;
}
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_W ) )
{
planner . adjustMaxQuality ( type , 1 ) ;
}
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_D ) )
{
planner . getDefaultItemFilterForType ( type ) - > decorated_only =
! planner . getDefaultItemFilterForType ( type ) - > decorated_only ;
}
in_dummy_screen = false ;
// pass LEAVESCREEN up to parent view
input - > clear ( ) ;
input - > insert ( interface_key : : LEAVESCREEN ) ;
return false ;
}
return true ;
}
else if ( isInPlannedBuildingQueryMode ( ) )
if ( input - > count ( interface_key : : CUSTOM_P ) | |
input - > count ( interface_key : : CUSTOM_F ) | |
input - > count ( interface_key : : CUSTOM_D ) | |
input - > count ( interface_key : : CUSTOM_M ) )
{
if ( input - > count ( interface_key : : SUSPENDBUILDING ) )
{
return true ; // Don't unsuspend planned buildings
}
else if ( input - > count ( interface_key : : DESTROYBUILDING ) )
{
planner . removeSelectedPlannedBuilding ( ) ; // Remove persistent data
}
show_help = true ;
}
BuildingTypeKey key = toBuildingTypeKey ( ui_build_selector ) ;
if ( input - > count ( interface_key : : CUSTOM_SHIFT_P ) )
{
planmode_enabled [ key ] = ! planmode_enabled [ key ] ;
if ( ! is_planmode_enabled ( key ) )
Gui : : refreshSidebar ( ) ;
return true ;
}
else if ( isInNobleRoomQueryMode ( ) )
if ( input - > count ( interface_key : : CUSTOM_SHIFT_F ) )
{
if ( Gui : : inRenameBuilding ( ) )
return false ;
auto np = getNoblePositionOfSelectedBuildingOwner ( ) ;
df : : interface_key last_token = get_string_key ( input ) ;
if ( last_token > = interface_key : : STRING_A048 & & last_token < = interface_key : : STRING_A058 )
quickfort_mode = ! quickfort_mode ;
return true ;
}
if ( ! is_planmode_enabled ( key ) )
return false ;
if ( input - > count ( interface_key : : SELECT ) )
{
if ( ui_build_selector - > errors . size ( ) = = 0 & & planner . allocatePlannedBuilding ( key ) )
{
size_t selection = last_token - interface_key : : STRING_A048 ;
if ( np . size ( ) < selection )
return false ;
roomMonitor . toggleRoomForPosition ( world - > selected_building - > id , np . at ( selection - 1 ) . position - > code ) ;
return true ;
Gui : : refreshSidebar ( ) ;
if ( quickfort_mode )
in_dummy_screen = true ;
}
return true ;
}
return false ;
// all current buildings only have one filter
auto filter = planner . getItemFilters ( key ) . rbegin ( ) ;
if ( input - > count ( interface_key : : CUSTOM_SHIFT_M ) )
Screen : : show ( dts : : make_unique < ViewscreenChooseMaterial > ( * filter ) , plugin_self ) ;
else if ( input - > count ( interface_key : : CUSTOM_Q ) )
filter - > decMinQuality ( ) ;
else if ( input - > count ( interface_key : : CUSTOM_W ) )
filter - > incMinQuality ( ) ;
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_Q ) )
filter - > decMaxQuality ( ) ;
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_W ) )
filter - > incMaxQuality ( ) ;
else if ( input - > count ( interface_key : : CUSTOM_SHIFT_D ) )
filter - > toggleDecoratedOnly ( ) ;
else
return false ;
return true ;
}
DEFINE_VMETHOD_INTERPOSE ( void , feed , ( set < df : : interface_key > * input ) )
@ -469,133 +454,176 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
DEFINE_VMETHOD_INTERPOSE ( void , render , ( ) )
{
bool plannable = isInPlannedBuildingPlacementMode ( ) ;
if ( plannable & & is_planmode_enabled ( ui_build_selector - > building_type ) )
BuildingTypeKey key = toBuildingTypeKey ( ui_build_selector ) ;
if ( plannable & & is_planmode_enabled ( key ) )
{
if ( ui_build_selector - > stage < 1 )
{
// No materials but turn on cursor
ui_build_selector - > stage = 1 ;
}
for ( auto iter = ui_build_selector - > errors . begin ( ) ; iter ! = ui_build_selector - > errors . end ( ) ; )
for ( auto iter = ui_build_selector - > errors . begin ( ) ;
iter ! = ui_build_selector - > errors . end ( ) ; )
{
// FIXME Hide bags
if ( ( ( * iter ) - > find ( " Needs " ) ! = string : : npos & & * * iter ! = " Needs adjacent wall " ) | |
( * iter ) - > find ( " No access " ) ! = string : : npos )
{
// FIXME Hide bags
if ( ( ( * iter ) - > find ( " Needs " ) ! = string : : npos
& & * * iter ! = " Needs adjacent wall " )
| | ( * iter ) - > find ( " No access " ) ! = string : : npos )
iter = ui_build_selector - > errors . erase ( iter ) ;
}
else
{
+ + iter ;
}
}
}
INTERPOSE_NEXT ( render ) ( ) ;
if ( ! plannable )
return ;
auto dims = Gui : : getDwarfmodeViewDims ( ) ;
int left_margin = dims . menu_x1 + 1 ;
int x = left_margin ;
auto type = ui_build_selector - > building_type ;
if ( plannable )
if ( in_dummy_screen )
{
if ( quickfort_mode & & in_dummy_screen )
{
Screen : : Pen pen ( ' ' , COLOR_BLACK ) ;
int y = dims . y1 + 1 ;
Screen : : fillRect ( pen , x , y , dims . menu_x2 , y + 20 ) ;
Screen : : Pen pen ( ' ' , COLOR_BLACK ) ;
int y = dims . y1 + 1 ;
Screen : : fillRect ( pen , x , y , dims . menu_x2 , y + 20 ) ;
+ + y ;
+ + y ;
OutputString ( COLOR_BROWN , x , y , " Quickfort Placeholder " , true , left_margin ) ;
OutputString ( COLOR_WHITE , x , y , " Enter, Shift-Enter or Esc " , true , left_margin ) ;
}
else
{
int y = 23 ;
OutputString ( COLOR_BROWN , x , y ,
" Placeholder for legacy Quickfort. This screen is not required for DFHack native quickfort. " ,
true , left_margin ) ;
OutputString ( COLOR_WHITE , x , y , " Enter, Shift-Enter or Esc " , true , left_margin ) ;
return ;
}
if ( show_help )
{
OutputString ( COLOR_BROWN , x , y , " Note: " ) ;
OutputString ( COLOR_WHITE , x , y , " Use Shift-Keys here " , true , left_margin ) ;
}
OutputToggleString ( x , y , " Planning Mode " , " P " , is_planmode_enabled ( type ) , true , left_margin ) ;
int y = 23 ;
if ( is_planmode_enabled ( type ) )
{
OutputToggleString ( x , y , " Quickfort Mode " , " F " , quickfort_mode , true , left_margin ) ;
if ( show_help )
{
OutputString ( COLOR_BROWN , x , y , " Note: " ) ;
OutputString ( COLOR_WHITE , x , y , " Use Shift-Keys here " , true , left_margin ) ;
}
auto filter = planner . getDefaultItemFilterForType ( type ) ;
OutputToggleString ( x , y , " Planning Mode " , " P " , planmode_enabled [ key ] , true , left_margin ) ;
OutputToggleString ( x , y , " Quickfort Mode " , " F " , quickfort_mode , true , left_margin ) ;
OutputHotkeyString ( x , y , " Min Quality: " , " qw " ) ;
OutputString ( COLOR_BROWN , x , y , filter - > getMinQuality ( ) , true , left_margin ) ;
if ( ! is_planmode_enabled ( key ) )
return ;
OutputHotkeyString ( x , y , " Max Quality: " , " QW " ) ;
OutputString ( COLOR_BROWN , x , y , filter - > getMaxQuality ( ) , true , left_margin ) ;
auto filter = planner . getItemFilters ( key ) . rbegin ( ) ;
y + = 2 ;
OutputHotkeyString ( x , y , " Min Quality: " , " qw " ) ;
OutputString ( COLOR_BROWN , x , y , filter - > getMinQuality ( ) , true , left_margin ) ;
OutputToggleString ( x , y , " Decorated Only: " , " D " , filter - > decorated_only , true , left_margin ) ;
OutputHotkeyString ( x , y , " Max Quality: " , " QW " ) ;
OutputString ( COLOR_BROWN , x , y , filter - > getMaxQuality ( ) , true , left_margin ) ;
OutputHotkeyString ( x , y , " Material Filter: " , " M " , true , left_margin ) ;
auto filter_descriptions = filter - > getMaterialFilterAsVector ( ) ;
for ( auto it = filter_descriptions . begin ( ) ; it ! = filter_descriptions . end ( ) ; + + it )
OutputString ( COLOR_BROWN , x , y , " * " + * it , true , left_margin ) ;
}
else
{
in_dummy_screen = false ;
}
}
}
else if ( isInPlannedBuildingQueryMode ( ) )
OutputToggleString ( x , y , " Decorated Only " , " D " , filter - > getDecoratedOnly ( ) , true , left_margin ) ;
OutputHotkeyString ( x , y , " Material Filter: " , " M " , true , left_margin ) ;
auto filter_descriptions = filter - > getMaterials ( ) ;
for ( auto it = filter_descriptions . begin ( ) ;
it ! = filter_descriptions . end ( ) ; + + it )
OutputString ( COLOR_BROWN , x , y , " * " + * it , true , left_margin ) ;
}
} ;
struct buildingplan_room_hook : public df : : viewscreen_dwarfmodest
{
typedef df : : viewscreen_dwarfmodest interpose_base ;
std : : vector < Units : : NoblePosition > getNoblePositionOfSelectedBuildingOwner ( )
{
std : : vector < Units : : NoblePosition > np ;
if ( ui - > main . mode ! = df : : ui_sidebar_mode : : QueryBuilding | |
! world - > selected_building | |
! world - > selected_building - > owner )
{
in_dummy_screen = false ;
// Hide suspend toggle option
int y = 20 ;
Screen : : Pen pen ( ' ' , COLOR_BLACK ) ;
Screen : : fillRect ( pen , x , y , dims . menu_x2 , y ) ;
auto filter = planner . getSelectedPlannedBuilding ( ) - > getFilter ( ) ;
y = 24 ;
OutputString ( COLOR_BROWN , x , y , " Planned Building Filter: " , true , left_margin ) ;
OutputString ( COLOR_BROWN , x , y , " Min Quality: " , false , left_margin ) ;
OutputString ( COLOR_BLUE , x , y , filter - > getMinQuality ( ) , true , left_margin ) ;
OutputString ( COLOR_BROWN , x , y , " Max Quality: " , false , left_margin ) ;
OutputString ( COLOR_BLUE , x , y , filter - > getMaxQuality ( ) , true , left_margin ) ;
if ( filter - > decorated_only )
OutputString ( COLOR_BLUE , x , y , " Decorated Only " , true , left_margin ) ;
OutputString ( COLOR_BROWN , x , y , " Materials: " , true , left_margin ) ;
auto filters = filter - > getMaterialFilterAsVector ( ) ;
for ( auto it = filters . begin ( ) ; it ! = filters . end ( ) ; + + it )
OutputString ( COLOR_BLUE , x , y , " * " + * it , true , left_margin ) ;
return np ;
}
else if ( isInNobleRoomQueryMode ( ) )
switch ( world - > selected_building - > getType ( ) )
{
auto np = getNoblePositionOfSelectedBuildingOwner ( ) ;
int y = 24 ;
OutputString ( COLOR_BROWN , x , y , " DFHack " , true , left_margin ) ;
OutputString ( COLOR_WHITE , x , y , " Auto-allocate to: " , true , left_margin ) ;
for ( size_t i = 0 ; i < np . size ( ) & & i < 9 ; i + + )
{
bool enabled = ( roomMonitor . getReservedNobleCode ( world - > selected_building - > id )
= = np [ i ] . position - > code ) ;
OutputToggleString ( x , y , np [ i ] . position - > name [ 0 ] . c_str ( ) ,
int_to_string ( i + 1 ) . c_str ( ) , enabled , true , left_margin ) ;
}
case building_type : : Bed :
case building_type : : Chair :
case building_type : : Table :
break ;
default :
return np ;
}
return getUniqueNoblePositions ( world - > selected_building - > owner ) ;
}
bool isInNobleRoomQueryMode ( )
{
if ( getNoblePositionOfSelectedBuildingOwner ( ) . size ( ) > 0 )
return canReserveRoom ( world - > selected_building ) ;
else
return false ;
}
bool handleInput ( set < df : : interface_key > * input )
{
if ( ! isInNobleRoomQueryMode ( ) )
return false ;
if ( Gui : : inRenameBuilding ( ) )
return false ;
auto np = getNoblePositionOfSelectedBuildingOwner ( ) ;
df : : interface_key last_token = get_string_key ( input ) ;
if ( last_token > = interface_key : : STRING_A048
& & last_token < = interface_key : : STRING_A058 )
{
in_dummy_screen = false ;
show_help = false ;
size_t selection = last_token - interface_key : : STRING_A048 ;
if ( np . size ( ) < selection )
return false ;
roomMonitor . toggleRoomForPosition ( world - > selected_building - > id , np . at ( selection - 1 ) . position - > code ) ;
return true ;
}
return false ;
}
DEFINE_VMETHOD_INTERPOSE ( void , feed , ( set < df : : interface_key > * input ) )
{
if ( ! handleInput ( input ) )
INTERPOSE_NEXT ( feed ) ( input ) ;
}
DEFINE_VMETHOD_INTERPOSE ( void , render , ( ) )
{
INTERPOSE_NEXT ( render ) ( ) ;
if ( ! isInNobleRoomQueryMode ( ) )
return ;
auto np = getNoblePositionOfSelectedBuildingOwner ( ) ;
auto dims = Gui : : getDwarfmodeViewDims ( ) ;
int left_margin = dims . menu_x1 + 1 ;
int x = left_margin ;
int y = 24 ;
OutputString ( COLOR_BROWN , x , y , " DFHack " , true , left_margin ) ;
OutputString ( COLOR_WHITE , x , y , " Auto-allocate to: " , true , left_margin ) ;
for ( size_t i = 0 ; i < np . size ( ) & & i < 9 ; i + + )
{
bool enabled =
roomMonitor . getReservedNobleCode ( world - > selected_building - > id )
= = np [ i ] . position - > code ;
OutputToggleString ( x , y , np [ i ] . position - > name [ 0 ] . c_str ( ) ,
int_to_string ( i + 1 ) . c_str ( ) , enabled , true , left_margin ) ;
}
}
} ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_hook , feed ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_hook , render ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_query_hook , feed ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_place_hook , feed ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_room_hook , feed ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_query_hook , render ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_place_hook , render ) ;
IMPLEMENT_VMETHOD_INTERPOSE ( buildingplan_room_hook , render ) ;
static command_result buildingplan_cmd ( color_ostream & out , vector < string > & parameters )
{
@ -624,10 +652,14 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
if ( enable ! = is_enabled )
{
planner . reset ( out ) ;
if ( ! INTERPOSE_HOOK ( buildingplan_hook , feed ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_hook , render ) . apply ( enable ) )
planner . reset ( ) ;
if ( ! INTERPOSE_HOOK ( buildingplan_query_hook , feed ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_place_hook , feed ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_room_hook , feed ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_query_hook , render ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_place_hook , render ) . apply ( enable ) | |
! INTERPOSE_HOOK ( buildingplan_room_hook , render ) . apply ( enable ) )
return CR_FAILURE ;
is_enabled = enable ;
@ -640,7 +672,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
{
commands . push_back (
PluginCommand (
" buildingplan " , " Pla ce furniture before it's built " ,
" buildingplan " , " Pla n building construction before you have materials " ,
buildingplan_cmd , false , " Run 'buildingplan debug [on|off]' to toggle debugging, or 'buildingplan version' to query the plugin version. " ) ) ;
planner . initialize ( ) ;
@ -651,7 +683,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
{
switch ( event ) {
case SC_MAP_LOADED :
planner . reset ( out ) ;
planner . reset ( ) ;
roomMonitor . reset ( out ) ;
break ;
default :
@ -661,13 +693,17 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
return CR_OK ;
}
static bool cycle_requested = false ;
# define DAY_TICKS 1200
DFhackCExport command_result plugin_onupdate ( color_ostream & )
{
if ( Maps : : IsValid ( ) & & ! World : : ReadPauseState ( ) & & world - > frame_counter % ( DAY_TICKS / 2 ) = = 0 )
if ( Maps : : IsValid ( ) & & ! World : : ReadPauseState ( )
& & ( cycle_requested | | world - > frame_counter % ( DAY_TICKS / 2 ) = = 0 ) )
{
planner . doCycle ( ) ;
roomMonitor . doCycle ( ) ;
cycle_requested = false ;
}
return CR_OK ;
@ -680,8 +716,11 @@ DFhackCExport command_result plugin_shutdown(color_ostream &)
// Lua API section
static bool isPlannableBuilding ( df : : building_type type ) {
return planner . isPlannableBuilding ( type ) ;
static bool isPlannableBuilding ( df : : building_type type ,
int16_t subtype ,
int32_t custom ) {
return planner . isPlannableBuilding (
toBuildingTypeKey ( type , subtype , custom ) ) ;
}
static void addPlannedBuilding ( df : : building * bld ) {
@ -692,9 +731,14 @@ static void doCycle() {
planner . doCycle ( ) ;
}
static void scheduleCycle ( ) {
cycle_requested = true ;
}
DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION ( isPlannableBuilding ) ,
DFHACK_LUA_FUNCTION ( addPlannedBuilding ) ,
DFHACK_LUA_FUNCTION ( doCycle ) ,
DFHACK_LUA_FUNCTION ( scheduleCycle ) ,
DFHACK_LUA_END
} ;