2012-04-15 08:40:19 -06:00
// Plugin tiletypes
2011-05-13 11:37:48 -06:00
//
2012-04-15 08:40:19 -06:00
// This plugin allows fine editing of individual game tiles (expect for
// changing material subtypes).
//
// Commands:
// tiletypes - runs the interractive interpreter
// tiletypes-command - run the given command
// (intended to be mapped to a hotkey or used from dfhack-run)
// tiletypes-here - runs the execute method with the last settings from
// tiletypes(-command), including brush!
// (intended to be mapped to a hotkey)
// tiletypes-here-point - runs the execute method with the last settings from
// tiletypes(-command), except with a point brush!
// (intended to be mapped to a hotkey)
// Options (everything but tiletypes-command):
// ?, help - print some help
//
// Options (tiletypes-command):
// (anything) - run the given command
2016-08-13 19:44:01 -06:00
# include <cstdlib>
2011-05-13 11:37:48 -06:00
# include <iostream>
2011-08-10 20:39:12 -06:00
# include <map>
# include <set>
# include <sstream>
2016-08-13 19:44:01 -06:00
# include <vector>
2011-08-10 20:39:12 -06:00
using std : : vector ;
using std : : string ;
using std : : endl ;
using std : : set ;
2012-01-15 13:54:14 -07:00
# include "Console.h"
2016-08-13 19:44:01 -06:00
# include "Core.h"
2021-06-07 06:34:04 -06:00
# include "DataDefs.h"
# include "DataIdentity.h"
2012-01-15 13:54:14 -07:00
# include "Export.h"
2021-06-07 06:16:00 -06:00
# include "LuaTools.h"
2012-01-15 13:54:14 -07:00
# include "PluginManager.h"
# include "TileTypes.h"
2016-08-13 19:44:01 -06:00
# include "modules/Gui.h"
2012-01-15 13:54:14 -07:00
# include "modules/MapCache.h"
2016-08-13 19:44:01 -06:00
# include "modules/Maps.h"
2012-01-19 13:11:52 -07:00
# include "df/tile_dig_designation.h"
2016-08-13 19:44:01 -06:00
# include "df/world.h"
2012-03-24 05:13:51 -06:00
# include "Brushes.h"
2016-08-13 19:44:01 -06:00
2011-08-10 20:39:12 -06:00
using namespace MapExtras ;
using namespace DFHack ;
2012-01-21 17:31:15 -07:00
using namespace df : : enums ;
2011-05-13 11:37:48 -06:00
2014-12-06 16:47:35 -07:00
DFHACK_PLUGIN ( " tiletypes " ) ;
REQUIRE_GLOBAL ( world ) ;
2014-08-11 14:07:52 -06:00
2021-06-07 06:16:00 -06:00
struct tiletypes_options {
// whether to display help
bool help = false ;
bool quiet = false ;
// if set, then use this position instead of the active game cursor
df : : coord cursor ;
static struct_identity _identity ;
} ;
static const struct_field_info tiletypes_options_fields [ ] = {
{ struct_field_info : : PRIMITIVE , " help " , offsetof ( tiletypes_options , help ) , & df : : identity_traits < bool > : : identity , 0 , 0 } ,
{ struct_field_info : : PRIMITIVE , " quiet " , offsetof ( tiletypes_options , quiet ) , & df : : identity_traits < bool > : : identity , 0 , 0 } ,
{ struct_field_info : : SUBSTRUCT , " cursor " , offsetof ( tiletypes_options , cursor ) , & df : : coord : : _identity , 0 , 0 } ,
{ struct_field_info : : END }
} ;
struct_identity tiletypes_options : : _identity ( sizeof ( tiletypes_options ) , & df : : allocator_fn < tiletypes_options > , NULL , " tiletypes_options " , NULL , tiletypes_options_fields ) ;
2022-07-23 23:13:19 -06:00
static const char * HISTORY_FILE = " dfhack-config/tiletypes.history " ;
2012-04-15 08:40:19 -06:00
CommandHistory tiletypes_hist ;
2011-07-18 14:45:00 -06:00
2012-04-15 08:40:19 -06:00
command_result df_tiletypes ( color_ostream & out , vector < string > & parameters ) ;
command_result df_tiletypes_command ( color_ostream & out , vector < string > & parameters ) ;
command_result df_tiletypes_here ( color_ostream & out , vector < string > & parameters ) ;
command_result df_tiletypes_here_point ( color_ostream & out , vector < string > & parameters ) ;
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
{
2022-07-23 23:13:19 -06:00
tiletypes_hist . load ( HISTORY_FILE ) ;
2012-04-15 08:40:19 -06:00
commands . push_back ( PluginCommand ( " tiletypes " , " Paint map tiles freely, similar to liquids. " , df_tiletypes , true ) ) ;
2015-11-09 20:37:45 -07:00
commands . push_back ( PluginCommand ( " tiletypes-command " , " Run tiletypes commands (seperated by ' ; ') " , df_tiletypes_command ) ) ;
commands . push_back ( PluginCommand ( " tiletypes-here " , " Repeat tiletypes command at cursor (with brush) " , df_tiletypes_here ) ) ;
commands . push_back ( PluginCommand ( " tiletypes-here-point " , " Repeat tiletypes command at cursor (without brush) " , df_tiletypes_here_point ) ) ;
2012-04-15 08:40:19 -06:00
return CR_OK ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
DFhackCExport command_result plugin_shutdown ( color_ostream & out )
2011-05-13 11:37:48 -06:00
{
2022-07-23 23:13:19 -06:00
tiletypes_hist . save ( HISTORY_FILE ) ;
2012-04-15 08:40:19 -06:00
return CR_OK ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
void help ( color_ostream & out , std : : vector < std : : string > & commands , int start , int end )
2011-05-13 11:37:48 -06:00
{
2018-04-06 00:18:15 -06:00
std : : string option = commands . size ( ) > size_t ( start ) ? commands [ start ] : " " ;
2012-04-15 08:40:19 -06:00
if ( option . empty ( ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out < < " Commands: " < < std : : endl
< < " quit / q : quit " < < std : : endl
< < " filter / f [options] : change filter options " < < std : : endl
< < " paint / p [options] : change paint options " < < std : : endl
< < " point / p : set point brush " < < std : : endl
< < " range / r [w] [h] [z] : set range brush " < < std : : endl
< < " block : set block brush " < < std : : endl
< < " column : set column brush " < < std : : endl
< < " run / (empty) : paint! " < < std : : endl
< < std : : endl
< < " Filter/paint options: " < < std : : endl
2012-04-19 17:44:26 -06:00
< < " Any: reset to default (no filter/paint) " < < std : : endl
2012-04-15 08:40:19 -06:00
< < " Shape / sh / s: set tile shape information " < < std : : endl
< < " Material / mat / m: set tile material information " < < std : : endl
< < " Special / sp: set special tile information " < < std : : endl
< < " Variant / var / v: set variant tile information " < < std : : endl
< < " All / a: set the four above at the same time (no ANY support) " < < std : : endl
< < " Designated / d: set designated flag " < < std : : endl
< < " Hidden / h: set hidden flag " < < std : : endl
< < " Light / l: set light flag " < < std : : endl
< < " Subterranean / st: set subterranean flag " < < std : : endl
< < " Skyview / sv: set skyview flag " < < std : : endl
2012-04-19 17:44:26 -06:00
< < " Aquifer / aqua: set aquifer flag " < < std : : endl
2013-10-05 10:53:43 -06:00
< < " Stone: paint specific stone material " < < std : : endl
< < " Veintype: use specific vein type for stone " < < std : : endl
2012-04-15 08:40:19 -06:00
< < " See help [option] for more information " < < std : : endl ;
}
else if ( option = = " shape " | | option = = " s " | | option = = " sh " )
{
out < < " Available shapes: " < < std : : endl
< < " ANY " < < std : : endl ;
FOR_ENUM_ITEMS ( tiletype_shape , i )
{
out < < " " < < ENUM_KEY_STR ( tiletype_shape , i ) < < std : : endl ;
}
}
else if ( option = = " material " | | option = = " mat " | | option = = " m " )
{
out < < " Available materials: " < < std : : endl
< < " ANY " < < std : : endl ;
FOR_ENUM_ITEMS ( tiletype_material , i )
{
out < < " " < < ENUM_KEY_STR ( tiletype_material , i ) < < std : : endl ;
}
}
else if ( option = = " special " | | option = = " sp " )
{
out < < " Available specials: " < < std : : endl
< < " ANY " < < std : : endl ;
FOR_ENUM_ITEMS ( tiletype_special , i )
{
out < < " " < < ENUM_KEY_STR ( tiletype_special , i ) < < std : : endl ;
}
}
else if ( option = = " variant " | | option = = " var " | | option = = " v " )
{
out < < " Available variants: " < < std : : endl
< < " ANY " < < std : : endl ;
FOR_ENUM_ITEMS ( tiletype_variant , i )
{
out < < " " < < ENUM_KEY_STR ( tiletype_variant , i ) < < std : : endl ;
}
}
else if ( option = = " designated " | | option = = " d " )
{
out < < " Available designated flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
}
else if ( option = = " hidden " | | option = = " h " )
{
out < < " Available hidden flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
}
else if ( option = = " light " | | option = = " l " )
{
out < < " Available light flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
}
else if ( option = = " subterranean " | | option = = " st " )
{
out < < " Available subterranean flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
}
else if ( option = = " skyview " | | option = = " sv " )
{
out < < " Available skyview flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
2011-05-13 11:37:48 -06:00
}
2012-04-19 17:44:26 -06:00
else if ( option = = " aquifer " | | option = = " aqua " )
{
out < < " Available aquifer flags: " < < std : : endl
< < " ANY, 0, 1 " < < std : : endl ;
}
2013-10-05 10:53:43 -06:00
else if ( option = = " stone " )
{
out < < " The stone option allows painting any specific stone material. " < < std : : endl
< < " The normal 'material' option is forced to STONE, and cannot " < < std : : endl
< < " be changed without cancelling the specific stone selection. " < < std : : endl
< < " Note: this feature paints under ice and constructions, " < < std : : endl
< < " instead of replacing them with brute force. " < < std : : endl ;
}
else if ( option = = " veintype " )
{
out < < " Specifies which vein type to use when painting specific stone. " < < std : : endl
< < " The vein type determines stone drop rate. Available types: " < < std : : endl ;
FOR_ENUM_ITEMS ( inclusion_type , i )
out < < " " < < ENUM_KEY_STR ( inclusion_type , i ) < < std : : endl ;
out < < " Vein type other than CLUSTER forces creation of a vein. " < < std : : endl ;
}
2011-05-13 11:37:48 -06:00
}
2011-08-10 20:39:12 -06:00
struct TileType
{
2012-02-13 15:56:33 -07:00
df : : tiletype_shape shape ;
df : : tiletype_material material ;
df : : tiletype_special special ;
df : : tiletype_variant variant ;
2011-11-20 00:40:01 -07:00
int dig ;
2011-11-05 04:55:23 -06:00
int hidden ;
int light ;
int subterranean ;
int skyview ;
2012-04-19 17:44:26 -06:00
int aquifer ;
2013-10-05 10:53:43 -06:00
int stone_material ;
df : : inclusion_type vein_type ;
2011-05-13 11:37:48 -06:00
TileType ( )
2012-04-19 17:44:26 -06:00
{
clear ( ) ;
}
void clear ( )
2011-05-13 11:37:48 -06:00
{
2012-02-13 15:56:33 -07:00
shape = tiletype_shape : : NONE ;
material = tiletype_material : : NONE ;
special = tiletype_special : : NONE ;
variant = tiletype_variant : : NONE ;
2011-11-20 00:40:01 -07:00
dig = - 1 ;
2011-11-05 04:55:23 -06:00
hidden = - 1 ;
light = - 1 ;
subterranean = - 1 ;
skyview = - 1 ;
2012-04-19 17:44:26 -06:00
aquifer = - 1 ;
2013-10-05 10:53:43 -06:00
stone_material = - 1 ;
vein_type = inclusion_type : : CLUSTER ;
2011-05-13 11:37:48 -06:00
}
bool empty ( )
{
2011-11-05 04:55:23 -06:00
return shape = = - 1 & & material = = - 1 & & special = = - 1 & & variant = = - 1
2012-04-19 17:44:26 -06:00
& & dig = = - 1 & & hidden = = - 1 & & light = = - 1 & & subterranean = = - 1
2013-10-05 10:53:43 -06:00
& & skyview = = - 1 & & aquifer = = - 1 & & stone_material = = - 1 ;
2012-04-19 17:44:26 -06:00
}
inline bool matches ( const df : : tiletype source ,
2013-10-05 10:53:43 -06:00
const df : : tile_designation des ,
const t_matpair mat )
2012-04-19 17:44:26 -06:00
{
bool rv = true ;
rv & = ( shape = = - 1 | | shape = = tileShape ( source ) ) ;
2013-10-05 10:53:43 -06:00
if ( stone_material > = 0 )
rv & = isStoneMaterial ( source ) & & mat . mat_type = = 0 & & mat . mat_index = = stone_material ;
else
rv & = ( material = = - 1 | | material = = tileMaterial ( source ) ) ;
2012-04-19 17:44:26 -06:00
rv & = ( special = = - 1 | | special = = tileSpecial ( source ) ) ;
rv & = ( variant = = - 1 | | variant = = tileVariant ( source ) ) ;
rv & = ( dig = = - 1 | | ( dig ! = 0 ) = = ( des . bits . dig ! = tile_dig_designation : : No ) ) ;
rv & = ( hidden = = - 1 | | ( hidden ! = 0 ) = = des . bits . hidden ) ;
rv & = ( light = = - 1 | | ( light ! = 0 ) = = des . bits . light ) ;
rv & = ( subterranean = = - 1 | | ( subterranean ! = 0 ) = = des . bits . subterranean ) ;
rv & = ( skyview = = - 1 | | ( skyview ! = 0 ) = = des . bits . outside ) ;
rv & = ( aquifer = = - 1 | | ( aquifer ! = 0 ) = = des . bits . water_table ) ;
return rv ;
2011-05-13 11:37:48 -06:00
}
} ;
std : : ostream & operator < < ( std : : ostream & stream , const TileType & paint )
{
bool used = false ;
bool needSpace = false ;
if ( paint . special > = 0 )
{
2012-02-13 18:17:38 -07:00
stream < < ENUM_KEY_STR ( tiletype_special , paint . special ) ;
2011-05-13 11:37:48 -06:00
used = true ;
needSpace = true ;
}
if ( paint . material > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
2012-02-13 18:17:38 -07:00
stream < < ENUM_KEY_STR ( tiletype_material , paint . material ) ;
2011-05-13 11:37:48 -06:00
used = true ;
needSpace = true ;
}
if ( paint . shape > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
2012-02-13 18:17:38 -07:00
stream < < ENUM_KEY_STR ( tiletype_shape , paint . shape ) ;
2011-05-13 11:37:48 -06:00
used = true ;
2011-11-05 04:55:23 -06:00
needSpace = true ;
}
if ( paint . variant > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
2012-02-13 18:17:38 -07:00
stream < < ENUM_KEY_STR ( tiletype_variant , paint . variant ) ;
2011-11-05 04:55:23 -06:00
used = true ;
needSpace = true ;
}
2011-11-20 00:40:01 -07:00
if ( paint . dig > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
2021-05-04 13:35:22 -06:00
stream < < ( paint . dig ? " DESIGNATED " : " UNDESIGNATED " ) ;
2011-11-20 00:40:01 -07:00
used = true ;
needSpace = true ;
}
2011-11-05 04:55:23 -06:00
if ( paint . hidden > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < ( paint . hidden ? " HIDDEN " : " VISIBLE " ) ;
used = true ;
needSpace = true ;
}
if ( paint . light > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < ( paint . light ? " LIGHT " : " DARK " ) ;
used = true ;
needSpace = true ;
}
if ( paint . subterranean > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < ( paint . subterranean ? " SUBTERRANEAN " : " ABOVE GROUND " ) ;
used = true ;
needSpace = true ;
}
if ( paint . skyview > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < ( paint . skyview ? " OUTSIDE " : " INSIDE " ) ;
used = true ;
needSpace = true ;
2011-05-13 11:37:48 -06:00
}
2012-04-19 17:44:26 -06:00
if ( paint . aquifer > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < ( paint . aquifer ? " AQUIFER " : " NO AQUIFER " ) ;
used = true ;
needSpace = true ;
}
2013-10-05 10:53:43 -06:00
if ( paint . stone_material > = 0 )
{
if ( needSpace )
{
stream < < " " ;
needSpace = false ;
}
stream < < MaterialInfo ( 0 , paint . stone_material ) . getToken ( )
< < " " < < ENUM_KEY_STR ( inclusion_type , paint . vein_type ) ;
used = true ;
needSpace = true ;
}
2011-05-13 11:37:48 -06:00
if ( ! used )
{
stream < < " any " ;
}
return stream ;
}
2012-04-15 08:40:19 -06:00
static TileType filter , paint ;
static Brush * brush = new RectangleBrush ( 1 , 1 ) ;
void printState ( color_ostream & out )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out < < " Filter: " < < filter < < std : : endl
< < " Paint: " < < paint < < std : : endl
2012-04-16 20:43:30 -06:00
< < " Brush: " < < brush < < std : : endl ;
2012-04-15 08:40:19 -06:00
}
//zilpin: These two functions were giving me compile errors in VS2008, so I cheated with the C style loop below, just to get it to build.
//Original code is commented out.
void tolower ( std : : string & str )
{
//The C++ way...
//std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::tolower<char> ), std::locale("")));
//The C way...
for ( char * c = ( char * ) str . c_str ( ) ; * c ; + + c )
{
* c = tolower ( * c ) ;
}
}
void toupper ( std : : string & str )
{
//std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::toupper<char>), std::locale("")));
for ( char * c = ( char * ) str . c_str ( ) ; * c ; + + c )
{
* c = toupper ( * c ) ;
}
}
int toint ( const std : : string & str , int failValue = 0 )
{
std : : istringstream ss ( str ) ;
2011-05-13 11:37:48 -06:00
int valInt ;
2012-04-15 08:40:19 -06:00
ss > > valInt ;
if ( ss . fail ( ) )
{
return failValue ;
}
return valInt ;
}
bool tryShape ( std : : string value , TileType & paint )
{
FOR_ENUM_ITEMS ( tiletype_shape , i )
{
if ( value = = ENUM_KEY_STR ( tiletype_shape , i ) )
{
paint . shape = i ;
return true ;
}
}
return false ;
}
bool tryMaterial ( std : : string value , TileType & paint )
{
FOR_ENUM_ITEMS ( tiletype_material , i )
{
if ( value = = ENUM_KEY_STR ( tiletype_material , i ) )
{
paint . material = i ;
return true ;
}
}
return false ;
}
bool trySpecial ( std : : string value , TileType & paint )
{
FOR_ENUM_ITEMS ( tiletype_special , i )
{
if ( value = = ENUM_KEY_STR ( tiletype_special , i ) )
{
paint . special = i ;
return true ;
}
}
return false ;
}
bool tryVariant ( std : : string value , TileType & paint )
{
FOR_ENUM_ITEMS ( tiletype_variant , i )
{
if ( value = = ENUM_KEY_STR ( tiletype_variant , i ) )
{
paint . variant = i ;
return true ;
}
}
return false ;
}
bool processTileType ( color_ostream & out , TileType & paint , std : : vector < std : : string > & params , int start , int end )
{
2014-05-11 12:10:09 -06:00
if ( start = = end )
{
out < < " Missing argument. " < < std : : endl ;
return false ;
}
2012-04-15 08:40:19 -06:00
int loc = start ;
std : : string option = params [ loc + + ] ;
2012-05-07 18:31:28 -06:00
std : : string value = end < = loc ? " " : params [ loc + + ] ;
tolower ( option ) ;
2012-04-15 08:40:19 -06:00
toupper ( value ) ;
int valInt ;
if ( value = = " ANY " )
2011-05-13 11:37:48 -06:00
{
valInt = - 1 ;
}
else
{
valInt = toint ( value , - 2 ) ;
}
bool found = false ;
2012-04-19 17:44:26 -06:00
if ( option = = " any " )
{
paint . clear ( ) ;
}
else if ( option = = " shape " | | option = = " sh " | | option = = " s " )
2011-05-13 11:37:48 -06:00
{
2012-03-15 10:46:08 -06:00
if ( is_valid_enum_item ( ( df : : tiletype_shape ) valInt ) )
2011-05-13 11:37:48 -06:00
{
2012-02-13 18:17:38 -07:00
paint . shape = ( df : : tiletype_shape ) valInt ;
2011-05-13 11:37:48 -06:00
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
if ( ! tryShape ( value , paint ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out < < " Unknown tile shape: " < < value < < std : : endl ;
2011-05-13 11:37:48 -06:00
}
}
}
else if ( option = = " material " | | option = = " mat " | | option = = " m " )
{
2013-10-05 10:53:43 -06:00
// Setting the material conflicts with stone_material
paint . stone_material = - 1 ;
2012-03-15 10:46:08 -06:00
if ( is_valid_enum_item ( ( df : : tiletype_material ) valInt ) )
2011-05-13 11:37:48 -06:00
{
2012-02-13 15:56:33 -07:00
paint . material = ( df : : tiletype_material ) valInt ;
2011-05-13 11:37:48 -06:00
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
if ( ! tryMaterial ( value , paint ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out < < " Unknown tile material: " < < value < < std : : endl ;
2011-05-13 11:37:48 -06:00
}
}
}
else if ( option = = " special " | | option = = " sp " )
{
2012-03-15 10:46:08 -06:00
if ( is_valid_enum_item ( ( df : : tiletype_special ) valInt ) )
2011-05-13 11:37:48 -06:00
{
2012-02-13 18:17:38 -07:00
paint . special = ( df : : tiletype_special ) valInt ;
2011-05-13 11:37:48 -06:00
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
if ( ! trySpecial ( value , paint ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out < < " Unknown tile special: " < < value < < std : : endl ;
2011-05-13 11:37:48 -06:00
}
}
}
2011-11-05 04:55:23 -06:00
else if ( option = = " variant " | | option = = " var " | | option = = " v " )
{
2012-03-15 10:46:08 -06:00
if ( is_valid_enum_item ( ( df : : tiletype_variant ) valInt ) )
2011-11-05 04:55:23 -06:00
{
2012-02-13 18:17:38 -07:00
paint . variant = ( df : : tiletype_variant ) valInt ;
2011-11-05 04:55:23 -06:00
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
if ( ! tryVariant ( value , paint ) )
2012-02-13 18:17:38 -07:00
{
2012-04-15 08:40:19 -06:00
out < < " Unknown tile variant: " < < value < < std : : endl ;
2012-02-13 18:17:38 -07:00
}
2011-11-05 04:55:23 -06:00
}
}
2011-12-29 19:05:53 -07:00
else if ( option = = " designated " | | option = = " d " )
2011-11-20 00:40:01 -07:00
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . dig = valInt ;
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown designation flag: " < < value < < std : : endl ;
2011-11-20 00:40:01 -07:00
}
}
2011-11-05 04:55:23 -06:00
else if ( option = = " hidden " | | option = = " h " )
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . hidden = valInt ;
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown hidden flag: " < < value < < std : : endl ;
2011-11-05 04:55:23 -06:00
}
}
else if ( option = = " light " | | option = = " l " )
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . light = valInt ;
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown light flag: " < < value < < std : : endl ;
2011-11-05 04:55:23 -06:00
}
}
else if ( option = = " subterranean " | | option = = " st " )
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . subterranean = valInt ;
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown subterranean flag: " < < value < < std : : endl ;
2011-11-05 04:55:23 -06:00
}
}
else if ( option = = " skyview " | | option = = " sv " )
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . skyview = valInt ;
found = true ;
}
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown skyview flag: " < < value < < std : : endl ;
}
}
2012-05-07 18:31:28 -06:00
else if ( option = = " aquifer " | | option = = " aqua " )
{
if ( valInt > = - 1 & & valInt < 2 )
{
paint . aquifer = valInt ;
found = true ;
}
else
{
out < < " Unknown aquifer flag: " < < value < < std : : endl ;
}
}
2012-04-15 08:40:19 -06:00
else if ( option = = " all " | | option = = " a " )
{
2012-04-16 20:43:30 -06:00
loc - - ;
2012-04-15 08:40:19 -06:00
for ( ; loc < end ; loc + + )
{
std : : string param = params [ loc ] ;
toupper ( param ) ;
if ( ! ( tryShape ( param , paint ) | | tryMaterial ( param , paint ) | |
trySpecial ( param , paint ) | | tryVariant ( param , paint ) ) )
{
out < < " Unknown description: ' " < < param < < " ' " < < std : : endl ;
break ;
}
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
found = true ;
2011-11-05 04:55:23 -06:00
}
2013-10-05 10:53:43 -06:00
else if ( option = = " stone " )
{
MaterialInfo mat ;
if ( ! mat . findInorganic ( value ) )
out < < " Unknown inorganic material: " < < value < < std : : endl ;
else if ( ! isStoneInorganic ( mat . index ) )
out < < " Not a stone material: " < < value < < std : : endl ;
else
{
paint . material = tiletype_material : : STONE ;
paint . stone_material = mat . index ;
}
}
else if ( option = = " veintype " )
{
if ( ! find_enum_item ( & paint . vein_type , value ) )
out < < " Unknown vein type: " < < value < < std : : endl ;
}
2011-05-13 11:37:48 -06:00
else
{
2012-04-15 08:40:19 -06:00
out < < " Unknown option: ' " < < option < < " ' " < < std : : endl ;
2011-05-13 11:37:48 -06:00
}
return found ;
}
2021-06-07 06:16:00 -06:00
command_result executePaintJob ( color_ostream & out ,
const tiletypes_options & opts )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
if ( paint . empty ( ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out . printerr ( " Set the paint first. \n " ) ;
return CR_OK ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
CoreSuspender suspend ;
if ( ! Maps : : IsValid ( ) )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
out . printerr ( " Map is not available! \n " ) ;
return CR_FAILURE ;
2011-05-13 11:37:48 -06:00
}
2021-06-07 06:16:00 -06:00
uint32_t x_max = 0 , y_max = 0 , z_max = 0 ;
2012-04-15 08:40:19 -06:00
Maps : : getSize ( x_max , y_max , z_max ) ;
2021-06-30 00:04:06 -06:00
df : : coord cursor ;
2021-06-07 06:16:00 -06:00
if ( Maps : : isValidTilePos ( opts . cursor ) )
2011-05-13 11:37:48 -06:00
{
2021-06-07 06:16:00 -06:00
cursor = opts . cursor ;
}
else
{
2021-06-30 00:04:06 -06:00
cursor = Gui : : getCursorPos ( ) ;
if ( ! cursor . isValid ( ) )
2021-06-07 06:16:00 -06:00
{
out . printerr ( " Can't get cursor coords! Make sure you have a cursor active in DF or specify the --cursor option. \n " ) ;
return CR_FAILURE ;
}
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
2021-06-07 06:16:00 -06:00
if ( ! opts . quiet )
out . print ( " Cursor coords: (%d, %d, %d) \n " ,
cursor . x , cursor . y , cursor . z ) ;
2012-04-15 08:40:19 -06:00
MapExtras : : MapCache map ;
coord_vec all_tiles = brush - > points ( map , cursor ) ;
2021-06-07 06:50:23 -06:00
if ( ! opts . quiet )
out . print ( " working... \n " ) ;
2012-04-15 08:40:19 -06:00
2012-04-25 08:38:43 -06:00
// Force the game to recompute its walkability cache
2014-08-11 14:07:52 -06:00
world - > reindex_pathfinding = true ;
2012-04-25 08:38:43 -06:00
2013-10-05 10:53:43 -06:00
int failures = 0 ;
2012-04-15 08:40:19 -06:00
for ( coord_vec : : iterator iter = all_tiles . begin ( ) ; iter ! = all_tiles . end ( ) ; + + iter )
2011-05-13 11:37:48 -06:00
{
2013-10-05 10:53:43 -06:00
MapExtras : : Block * blk = map . BlockAtTile ( * iter ) ;
if ( ! blk )
continue ;
df : : tiletype source = map . tiletypeAt ( * iter ) ;
2012-04-15 08:40:19 -06:00
df : : tile_designation des = map . designationAt ( * iter ) ;
2013-10-05 10:53:43 -06:00
// Stone painting operates on the base layer
if ( paint . stone_material > = 0 )
source = blk - > baseTiletypeAt ( * iter ) ;
t_matpair basemat = blk - > baseMaterialAt ( * iter ) ;
if ( ! filter . matches ( source , des , basemat ) )
2011-05-13 11:37:48 -06:00
{
2012-04-19 17:44:26 -06:00
continue ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
df : : tiletype_shape shape = paint . shape ;
if ( shape = = tiletype_shape : : NONE )
2012-02-13 18:17:38 -07:00
{
2012-04-15 08:40:19 -06:00
shape = tileShape ( source ) ;
}
df : : tiletype_material material = paint . material ;
if ( material = = tiletype_material : : NONE )
{
material = tileMaterial ( source ) ;
}
df : : tiletype_special special = paint . special ;
if ( special = = tiletype_special : : NONE )
{
special = tileSpecial ( source ) ;
}
df : : tiletype_variant variant = paint . variant ;
/*
* FIXME : variant should be :
* 1. If user variant :
* 2. If user variant \ belongs target variants
* 3. use user variant
* 4. Else
* 5. use variant 0
* 6. If the source variant \ belongs target variants
* 7 use source variant
* 8 ElseIf num target shape / material variants > 1
* 9. pick one randomly
* 10. Else
* 11. use variant 0
*
* The following variant check has been disabled because it ' s severely limiting
* the usefullness of the tool .
*/
/*
if ( variant = = tiletype_variant : : NONE )
{
variant = tileVariant ( source ) ;
}
*/
// Remove direction from directionless tiles
DFHack : : TileDirection direction = tileDirection ( source ) ;
2018-04-06 00:18:15 -06:00
if ( ! ( material = = tiletype_material : : RIVER | | shape = = tiletype_shape : : BROOK_BED | | special = = tiletype_special : : TRACK | | ( shape = = tiletype_shape : : WALL & & ( material = = tiletype_material : : CONSTRUCTION | | special = = tiletype_special : : SMOOTH ) ) ) )
2012-04-15 08:40:19 -06:00
{
direction . whole = 0 ;
}
df : : tiletype type = DFHack : : findTileType ( shape , material , variant , special , direction ) ;
// hack for empty space
if ( shape = = tiletype_shape : : EMPTY & & material = = tiletype_material : : AIR & & variant = = tiletype_variant : : VAR_1 & & special = = tiletype_special : : NORMAL & & direction . whole = = 0 )
{
type = tiletype : : OpenSpace ;
}
// make sure it's not invalid
if ( type ! = tiletype : : Void )
2013-10-05 10:53:43 -06:00
{
if ( paint . stone_material > = 0 )
{
if ( ! blk - > setStoneAt ( * iter , type , paint . stone_material , paint . vein_type , true , true ) )
failures + + ;
}
else
map . setTiletypeAt ( * iter , type ) ;
}
2012-04-15 08:40:19 -06:00
if ( paint . hidden > - 1 )
{
des . bits . hidden = paint . hidden ;
}
if ( paint . light > - 1 )
{
des . bits . light = paint . light ;
}
if ( paint . subterranean > - 1 )
{
des . bits . subterranean = paint . subterranean ;
2012-02-13 18:17:38 -07:00
}
2012-04-15 08:40:19 -06:00
if ( paint . skyview > - 1 )
{
des . bits . outside = paint . skyview ;
}
2012-04-19 17:44:26 -06:00
if ( paint . aquifer > - 1 )
{
des . bits . water_table = paint . aquifer ;
}
2012-04-15 08:40:19 -06:00
// Remove liquid from walls, etc
2012-09-10 07:19:21 -06:00
if ( type ! = ( df : : tiletype ) - 1 & & ! DFHack : : FlowPassable ( type ) )
2012-04-15 08:40:19 -06:00
{
des . bits . flow_size = 0 ;
//des.bits.liquid_type = DFHack::liquid_water;
//des.bits.water_table = 0;
des . bits . flow_forbid = 0 ;
//des.bits.liquid_static = 0;
//des.bits.water_stagnant = 0;
//des.bits.water_salt = 0;
}
map . setDesignationAt ( * iter , des ) ;
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
2013-10-05 10:53:43 -06:00
if ( failures > 0 )
2018-06-11 10:57:06 -06:00
out . printerr ( " Could not update %d tiles of %zu. \n " , failures , all_tiles . size ( ) ) ;
2021-06-07 06:16:00 -06:00
else if ( ! opts . quiet )
2018-06-11 10:57:06 -06:00
out . print ( " Processed %zu tiles. \n " , all_tiles . size ( ) ) ;
2013-10-05 10:53:43 -06:00
2012-04-15 08:40:19 -06:00
if ( map . WriteAll ( ) )
2011-11-20 00:40:01 -07:00
{
2021-06-07 06:16:00 -06:00
if ( ! opts . quiet )
out . print ( " OK \n " ) ;
2012-05-07 19:30:33 -06:00
return CR_OK ;
2011-11-20 00:40:01 -07:00
}
2012-04-15 08:40:19 -06:00
else
2011-11-05 04:55:23 -06:00
{
2012-04-15 08:40:19 -06:00
out . printerr ( " Something failed horribly! RUN! \n " ) ;
return CR_FAILURE ;
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
}
command_result processCommand ( color_ostream & out , std : : vector < std : : string > & commands , int start , int end , bool & endLoop , bool hasConsole = false )
{
2021-06-07 06:16:00 -06:00
tiletypes_options opts ;
2018-04-06 00:18:15 -06:00
if ( commands . size ( ) = = size_t ( start ) )
2011-11-05 04:55:23 -06:00
{
2021-06-07 06:16:00 -06:00
return executePaintJob ( out , opts ) ;
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
int loc = start ;
std : : string command = commands [ loc + + ] ;
tolower ( command ) ;
if ( command = = " help " | | command = = " ? " )
2011-11-05 04:55:23 -06:00
{
2012-04-15 08:40:19 -06:00
help ( out , commands , loc , end ) ;
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
else if ( command = = " quit " | | command = = " q " )
2011-11-05 04:55:23 -06:00
{
2012-04-15 08:40:19 -06:00
endLoop = true ;
2011-11-05 04:55:23 -06:00
}
2012-04-15 08:40:19 -06:00
else if ( command = = " filter " | | command = = " f " )
{
processTileType ( out , filter , commands , loc , end ) ;
}
else if ( command = = " paint " | | ( command = = " p " & & commands . size ( ) > 1 ) )
{
processTileType ( out , paint , commands , loc , end ) ;
}
else if ( command = = " point " | | command = = " p " )
{
delete brush ;
brush = new RectangleBrush ( 1 , 1 ) ;
}
else if ( command = = " range " | | command = = " r " )
{
2012-04-21 11:26:40 -06:00
int width = 1 , height = 1 , zLevels = 1 ;
2011-05-13 11:37:48 -06:00
2012-04-21 11:26:40 -06:00
command_result res = parseRectangle ( out , commands , loc , end ,
width , height , zLevels , hasConsole ) ;
2012-04-19 21:13:07 -06:00
if ( res ! = CR_OK )
{
return res ;
2012-04-15 08:40:19 -06:00
}
delete brush ;
2012-04-21 11:26:40 -06:00
brush = new RectangleBrush ( width , height , zLevels , 0 , 0 , 0 ) ;
2012-04-15 08:40:19 -06:00
}
else if ( command = = " block " )
{
delete brush ;
brush = new BlockBrush ( ) ;
}
else if ( command = = " column " )
{
delete brush ;
brush = new ColumnBrush ( ) ;
}
else if ( command = = " run " | | command . empty ( ) )
{
2021-06-07 06:16:00 -06:00
executePaintJob ( out , opts ) ;
2012-04-15 08:40:19 -06:00
}
2011-08-10 20:39:12 -06:00
return CR_OK ;
}
2012-04-15 08:40:19 -06:00
command_result df_tiletypes ( color_ostream & out_ , vector < string > & parameters )
2011-05-13 11:37:48 -06:00
{
2012-01-31 09:55:38 -07:00
for ( size_t i = 0 ; i < parameters . size ( ) ; i + + )
2011-08-14 00:42:21 -06:00
{
if ( parameters [ i ] = = " help " | | parameters [ i ] = = " ? " )
{
2012-04-15 08:40:19 -06:00
out_ . print ( " This tool allows painting tiles types with a brush, using an optional filter. \n "
" The tool is interactive, similarly to the liquids tool. \n "
" Further help is available inside. \n "
2011-08-14 00:42:21 -06:00
) ;
return CR_OK ;
}
}
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
if ( ! out_ . is_console ( ) )
2012-03-29 12:18:14 -06:00
return CR_FAILURE ;
2012-04-15 08:40:19 -06:00
Console & out = static_cast < Console & > ( out_ ) ;
2012-03-10 04:55:42 -07:00
2012-04-15 08:40:19 -06:00
std : : vector < std : : string > commands ;
2011-05-13 11:37:48 -06:00
bool end = false ;
2012-04-15 08:40:19 -06:00
out < < " Welcome to the tiletype tool. \n Type 'help' or '?' for a list of available commands, 'q' to quit. \n Press return after a command to confirm. " < < std : : endl ;
out . printerr ( " THIS TOOL CAN BE DANGEROUS. YOU'VE BEEN WARNED. \n " ) ;
2011-05-13 11:37:48 -06:00
while ( ! end )
{
2012-04-15 08:40:19 -06:00
printState ( out ) ;
2011-05-13 11:37:48 -06:00
std : : string input = " " ;
2018-06-21 07:57:36 -06:00
int rv = 0 ;
2011-05-13 11:37:48 -06:00
2018-07-04 06:21:25 -06:00
while ( ( rv = out . lineedit ( " tiletypes> " , input , tiletypes_hist ) )
= = Console : : RETRY ) ;
if ( rv < = Console : : FAILURE )
return rv = = Console : : FAILURE ? CR_FAILURE : CR_OK ;
2012-04-17 20:12:11 -06:00
tiletypes_hist . add ( input ) ;
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
commands . clear ( ) ;
Core : : cheap_tokenise ( input , commands ) ;
command_result ret = processCommand ( out , commands , 0 , commands . size ( ) , end , true ) ;
if ( ret ! = CR_OK )
2011-05-13 11:37:48 -06:00
{
2012-04-15 08:40:19 -06:00
return ret ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
}
return CR_OK ;
}
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
command_result df_tiletypes_command ( color_ostream & out , vector < string > & parameters )
{
bool dummy ;
int start = 0 , end = 0 ;
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
parameters . push_back ( " ; " ) ;
for ( size_t i = 0 ; i < parameters . size ( ) ; i + + )
{
if ( parameters [ i ] = = " ; " ) {
command_result rv = processCommand ( out , parameters , start , end , dummy ) ;
if ( rv ! = CR_OK ) {
return rv ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
end + + ;
start = end ;
} else {
end + + ;
2011-05-13 11:37:48 -06:00
}
2012-04-15 08:40:19 -06:00
}
return CR_OK ;
}
2021-06-07 06:16:00 -06:00
static bool get_options ( color_ostream & out ,
tiletypes_options & opts ,
const vector < string > & parameters )
{
auto L = Lua : : Core : : State ;
Lua : : StackUnwinder top ( L ) ;
if ( ! lua_checkstack ( L , parameters . size ( ) + 2 ) | |
! Lua : : PushModulePublic (
out , L , " plugins.tiletypes " , " parse_commandline " ) )
{
out . printerr ( " Failed to load tiletypes Lua code \n " ) ;
return false ;
}
Lua : : Push ( L , & opts ) ;
for ( const string & param : parameters )
Lua : : Push ( L , param ) ;
if ( ! Lua : : SafeCall ( out , L , parameters . size ( ) + 1 , 0 ) )
return false ;
return true ;
}
2012-04-15 08:40:19 -06:00
command_result df_tiletypes_here ( color_ostream & out , vector < string > & parameters )
{
2022-03-03 15:00:44 -07:00
CoreSuspender suspend ;
2021-06-07 06:16:00 -06:00
tiletypes_options opts ;
if ( ! get_options ( out , opts , parameters ) | | opts . help )
2012-04-15 08:40:19 -06:00
{
2021-06-07 06:16:00 -06:00
out < < " This command is supposed to be mapped to a hotkey. " < < endl ;
out < < " It will use the current/last parameters set in tiletypes (including brush settings!). " < < endl ;
return opts . help ? CR_OK : CR_FAILURE ;
2012-04-15 08:40:19 -06:00
}
2011-05-13 11:37:48 -06:00
2021-06-07 06:16:00 -06:00
if ( ! opts . quiet )
{
out . print ( " Run tiletypes-here with these parameters: " ) ;
printState ( out ) ;
}
2012-03-10 04:55:42 -07:00
2021-06-07 06:16:00 -06:00
return executePaintJob ( out , opts ) ;
2012-04-15 08:40:19 -06:00
}
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
command_result df_tiletypes_here_point ( color_ostream & out , vector < string > & parameters )
{
2022-03-03 15:00:44 -07:00
CoreSuspender suspend ;
2021-06-07 06:16:00 -06:00
tiletypes_options opts ;
if ( ! get_options ( out , opts , parameters ) | | opts . help )
2012-04-15 08:40:19 -06:00
{
2021-06-07 06:16:00 -06:00
out < < " This command is supposed to be mapped to a hotkey. " < < endl ;
out < < " It will use the current/last parameters set in tiletypes (except with a point brush). " < < endl ;
return opts . help ? CR_OK : CR_FAILURE ;
2012-04-15 08:40:19 -06:00
}
2011-05-13 11:37:48 -06:00
2012-04-15 08:40:19 -06:00
Brush * old = brush ;
brush = new RectangleBrush ( 1 , 1 ) ;
2011-05-13 11:37:48 -06:00
2021-06-07 06:16:00 -06:00
if ( ! opts . quiet )
{
out . print ( " Run tiletypes-here-point with these parameters: " ) ;
printState ( out ) ;
}
2011-05-13 11:37:48 -06:00
2021-06-07 06:16:00 -06:00
command_result rv = executePaintJob ( out , opts ) ;
2012-04-15 08:40:19 -06:00
delete brush ;
brush = old ;
return rv ;
2011-05-13 11:37:48 -06:00
}