2012-03-23 17:13:16 -06:00
// plugin liquids
//
// This is a rewrite of the liquids module which can also be used non-interactively (hotkey).
// First the user sets the mode and other parameters with the interactive command liqiudsgo
// just like in the original liquids module.
// They are stored in statics to allow being used after the interactive session was closed.
// After defining an action the non-interactive command liquids-here can be used to call the
// execute method without the necessity to go back to the console. This allows convenient painting
// of liquids and obsidian using the ingame cursor and a hotkey.
//
// Commands:
// liquids - basically the original liquids with the map changing stuff moved to an execute method
// liquids-here - runs the execute method with the last settings from liquids
// (intended to be mapped to a hotkey)
// Options:
// ?, help - print some help
//
// TODO:
// - maybe allow all parameters be passed as command line options? tedious parsing but might be useful
// - grab the code from digcircle to get a circle brush - could be nice when painting with obsidian
// - maybe store the last parameters in a file to make them persistent after dfhack is closed?
2016-08-13 19:44:01 -06:00
# include <cstdlib>
2011-07-27 18:35:45 -06:00
# include <iostream>
# include <map>
2016-08-13 19:44:01 -06:00
# include <memory>
2011-07-27 18:35:45 -06:00
# include <set>
# include <sstream>
2016-08-13 19:44:01 -06:00
# include <stack>
# include <vector>
2011-07-27 18:35:45 -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"
2012-01-15 13:54:14 -07:00
# include "Export.h"
2016-08-13 19:44:01 -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"
# include "df/world.h"
2012-03-23 17:13:16 -06:00
# include "Brushes.h"
2016-08-13 19:44:01 -06:00
2011-07-27 18:35:45 -06:00
using namespace MapExtras ;
using namespace DFHack ;
2012-01-21 17:31:15 -07:00
using namespace df : : enums ;
2014-12-06 16:47:35 -07:00
DFHACK_PLUGIN ( " liquids " ) ;
REQUIRE_GLOBAL ( world ) ;
2011-07-27 18:35:45 -06:00
2012-02-21 10:19:17 -07:00
CommandHistory liquids_hist ;
2012-03-10 04:55:42 -07:00
command_result df_liquids ( color_ostream & out , vector < string > & parameters ) ;
2012-03-23 17:13:16 -06:00
command_result df_liquids_here ( color_ostream & out , vector < string > & parameters ) ;
2012-02-21 10:19:17 -07:00
2012-03-10 04:55:42 -07:00
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
2012-02-21 10:19:17 -07:00
{
liquids_hist . load ( " liquids.history " ) ;
2012-03-23 17:13:16 -06:00
commands . push_back ( PluginCommand (
" liquids " , " Place magma, water or obsidian. " ,
2013-10-30 14:58:14 -06:00
df_liquids , true ,
" This tool allows placing magma, water and other similar things. \n "
" It is interactive and further help is available when you run it. \n "
" The settings will be remembered until dfhack is closed and you can call \n "
" 'liquids-here' (mapped to a hotkey) to paint liquids at the cursor position \n "
" without the need to go back to the dfhack console. \n " ) ) ; // interactive, needs console for prompt
2012-03-23 17:13:16 -06:00
commands . push_back ( PluginCommand (
" liquids-here " , " Use settings from liquids at cursor position. " ,
df_liquids_here , Gui : : cursor_hotkey , // non-interactive, needs ingame cursor
2013-10-30 14:58:14 -06:00
" This command is intended to be mapped to a hotkey and is identical to pressing Enter in liquids with the current parameters. \n " ) ) ;
2012-02-21 10:19:17 -07:00
return CR_OK ;
}
2012-03-10 04:55:42 -07:00
DFhackCExport command_result plugin_shutdown ( color_ostream & out )
2012-02-21 10:19:17 -07:00
{
liquids_hist . save ( " liquids.history " ) ;
return CR_OK ;
}
2012-08-25 00:37:03 -06:00
enum BrushType {
B_POINT , B_RANGE , B_BLOCK , B_COLUMN , B_FLOOD
} ;
static const char * brush_name [ ] = {
" point " , " range " , " block " , " column " , " flood " , NULL
} ;
enum PaintMode {
P_WATER , P_MAGMA , P_OBSIDIAN , P_OBSIDIAN_FLOOR ,
P_RIVER_SOURCE , P_FLOW_BITS , P_WCLEAN
} ;
static const char * paint_mode_name [ ] = {
" water " , " magma " , " obsidian " , " obsidian_floor " ,
" riversource " , " flowbits " , " wclean " , NULL
} ;
enum ModifyMode {
M_INC , M_KEEP , M_DEC
} ;
static const char * modify_mode_name [ ] = {
" + " , " . " , " - " , NULL
} ;
2012-08-26 10:08:28 -06:00
enum PermaflowMode {
PF_KEEP , PF_NONE ,
PF_NORTH , PF_SOUTH , PF_EAST , PF_WEST ,
PF_NORTHEAST , PF_NORTHWEST , PF_SOUTHEAST , PF_SOUTHWEST
} ;
static const char * permaflow_name [ ] = {
" . " , " - " , " N " , " S " , " E " , " W " ,
" NE " , " NW " , " SE " , " SW " , NULL
} ;
# define X(name) tile_liquid_flow_dir::name
static const df : : tile_liquid_flow_dir permaflow_id [ ] = {
X ( none ) , X ( none ) , X ( north ) , X ( south ) , X ( east ) , X ( west ) ,
X ( northeast ) , X ( northwest ) , X ( southeast ) , X ( southwest )
} ;
# undef X
2012-08-25 00:37:03 -06:00
struct OperationMode {
BrushType brush ;
PaintMode paint ;
ModifyMode flowmode ;
ModifyMode setmode ;
2012-08-26 10:08:28 -06:00
PermaflowMode permaflow ;
2012-08-25 00:37:03 -06:00
unsigned int amount ;
df : : coord size ;
OperationMode ( ) :
brush ( B_POINT ) , paint ( P_MAGMA ) ,
2012-08-26 10:08:28 -06:00
flowmode ( M_INC ) , setmode ( M_KEEP ) , permaflow ( PF_KEEP ) , amount ( 7 ) ,
2012-08-25 00:37:03 -06:00
size ( 1 , 1 , 1 )
{ }
} cur_mode ;
command_result df_liquids_execute ( color_ostream & out ) ;
command_result df_liquids_execute ( color_ostream & out , OperationMode & mode , df : : coord pos ) ;
2012-01-05 16:35:05 -07:00
2012-08-26 10:08:28 -06:00
static void print_prompt ( std : : ostream & str , OperationMode & cur_mode )
{
str < < " [ " < < paint_mode_name [ cur_mode . paint ] < < " : " < < brush_name [ cur_mode . brush ] ;
if ( cur_mode . brush = = B_RANGE )
str < < " (w " < < cur_mode . size . x < < " :h " < < cur_mode . size . y < < " :z " < < cur_mode . size . z < < " ) " ;
str < < " : " < < cur_mode . amount < < " :f " < < modify_mode_name [ cur_mode . flowmode ]
< < " :s " < < modify_mode_name [ cur_mode . setmode ]
< < " :pf " < < permaflow_name [ cur_mode . permaflow ]
< < " ] " ;
}
2012-03-10 04:55:42 -07:00
command_result df_liquids ( color_ostream & out_ , vector < string > & parameters )
2011-07-27 18:35:45 -06:00
{
2012-03-23 17:13:16 -06:00
if ( ! out_ . is_console ( ) )
return CR_FAILURE ;
2012-03-10 04:55:42 -07:00
Console & out = static_cast < Console & > ( out_ ) ;
2012-01-31 09:55:38 -07:00
for ( size_t i = 0 ; i < parameters . size ( ) ; i + + )
2011-08-08 17:50:22 -06:00
{
if ( parameters [ i ] = = " help " | | parameters [ i ] = = " ? " )
2013-10-30 14:58:14 -06:00
return CR_WRONG_USAGE ;
2011-08-08 17:50:22 -06:00
}
2012-01-24 04:36:30 -07:00
if ( ! Maps : : IsValid ( ) )
{
2012-03-10 04:55:42 -07:00
out . printerr ( " Map is not available! \n " ) ;
2012-01-24 04:36:30 -07:00
return CR_FAILURE ;
}
2012-04-19 21:13:07 -06:00
std : : vector < std : : string > commands ;
2011-07-27 18:35:45 -06:00
bool end = false ;
2012-03-23 17:13:16 -06:00
2012-03-10 04:55:42 -07:00
out < < " Welcome to the liquid spawner. \n Type 'help' or '?' for a list of available commands, 'q' to quit. \n Press return after a command to confirm. " < < std : : endl ;
2011-07-27 18:35:45 -06:00
while ( ! end )
{
2012-04-19 21:13:07 -06:00
string input = " " ;
2012-03-23 17:13:16 -06:00
2011-07-27 18:35:45 -06:00
std : : stringstream str ;
2012-08-26 10:08:28 -06:00
print_prompt ( str , cur_mode ) ;
str < < " # " ;
2018-06-21 07:57:36 -06:00
int rv ;
2018-07-04 06:21:25 -06:00
while ( ( rv = out . lineedit ( str . str ( ) , input , liquids_hist ) )
= = Console : : RETRY ) ;
if ( rv < = Console : : FAILURE )
return rv = = Console : : FAILURE ? CR_FAILURE : CR_OK ;
2012-04-19 21:13:07 -06:00
liquids_hist . add ( input ) ;
commands . clear ( ) ;
Core : : cheap_tokenise ( input , commands ) ;
string command = commands . empty ( ) ? " " : commands [ 0 ] ;
2012-03-23 17:13:16 -06:00
2011-07-27 18:35:45 -06:00
if ( command = = " help " | | command = = " ? " )
{
2012-03-10 04:55:42 -07:00
out < < " Modes: " < < endl
2011-07-27 18:35:45 -06:00
< < " m - switch to magma " < < endl
< < " w - switch to water " < < endl
< < " o - make obsidian wall instead " < < endl
< < " of - make obsidian floors " < < endl
< < " rs - make a river source " < < endl
< < " f - flow bits only " < < endl
2011-09-01 17:25:01 -06:00
< < " wclean - remove salt and stagnant flags from tiles " < < endl
2011-07-27 18:35:45 -06:00
< < " Set-Modes (only for magma/water): " < < endl
< < " s+ - only add " < < endl
< < " s. - set " < < endl
< < " s- - only remove " < < endl
< < " Properties (only for magma/water): " < < endl
< < " f+ - make the spawned liquid flow " < < endl
< < " f. - don't change flow state (read state in flow mode) " < < endl
< < " f- - make the spawned liquid static " < < endl
2012-08-26 10:08:28 -06:00
< < " Permaflow (only for water): " < < endl
< < " pf. - don't change permaflow state " < < endl
< < " pf- - make the spawned liquid static " < < endl
< < " pf[NS][EW] - make the spawned liquid permanently flow " < < endl
2011-07-27 18:35:45 -06:00
< < " 0-7 - set liquid amount " < < endl
< < " Brush: " < < endl
< < " point - single tile [p] " < < endl
< < " range - block with cursor at bottom north-west [r] " < < endl
< < " (any place, any size) " < < endl
< < " block - DF map block with cursor in it " < < endl
< < " (regular spaced 16x16x1 blocks) " < < endl
< < " column - Column from cursor, up through free space " < < endl
2012-01-05 16:35:05 -07:00
< < " flood - Flood-fill water tiles from cursor " < < endl
< < " (only makes sense with wclean) " < < endl
2011-07-27 18:35:45 -06:00
< < " Other: " < < endl
< < " q - quit " < < endl
< < " help or ? - print this list of commands " < < endl
< < " empty line - put liquid " < < endl
< < endl
< < " Usage: point the DF cursor at a tile you want to modify " < < endl
< < " and use the commands available :) " < < endl ;
2012-03-23 17:13:16 -06:00
out < < endl < < " Settings will be remembered until you quit DF. You can call liquids-here to execute the last configured action. Useful in combination with keybindings. " < < endl ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " m " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_MAGMA ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " o " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_OBSIDIAN ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " of " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_OBSIDIAN_FLOOR ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " w " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_WATER ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " f " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_FLOW_BITS ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " rs " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_RIVER_SOURCE ;
2011-07-27 18:35:45 -06:00
}
2011-09-01 17:25:01 -06:00
else if ( command = = " wclean " )
{
2012-08-25 00:37:03 -06:00
cur_mode . paint = P_WCLEAN ;
2011-09-01 17:25:01 -06:00
}
2011-07-27 18:35:45 -06:00
else if ( command = = " point " | | command = = " p " )
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_POINT ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " range " | | command = = " r " )
{
2018-04-05 00:16:40 -06:00
int width = 1 , height = 1 , z_levels = 1 ;
2012-04-21 11:26:40 -06:00
command_result res = parseRectangle ( out , commands , 1 , commands . size ( ) ,
width , height , z_levels ) ;
2012-04-19 21:13:07 -06:00
if ( res ! = CR_OK )
{
return res ;
}
if ( width = = 1 & & height = = 1 & & z_levels = = 1 )
2011-07-27 18:35:45 -06:00
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_POINT ;
cur_mode . size = df : : coord ( 1 , 1 , 1 ) ;
2011-07-27 18:35:45 -06:00
}
else
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_RANGE ;
cur_mode . size = df : : coord ( width , height , z_levels ) ;
2011-07-27 18:35:45 -06:00
}
}
else if ( command = = " block " )
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_BLOCK ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " column " )
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_COLUMN ;
2011-07-27 18:35:45 -06:00
}
2012-03-23 17:13:16 -06:00
else if ( command = = " flood " )
{
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_FLOOD ;
2012-03-23 17:13:16 -06:00
}
2011-07-27 18:35:45 -06:00
else if ( command = = " q " )
{
end = true ;
}
else if ( command = = " f+ " )
{
2012-08-25 00:37:03 -06:00
cur_mode . flowmode = M_INC ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " f- " )
{
2012-08-25 00:37:03 -06:00
cur_mode . flowmode = M_DEC ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " f. " )
{
2012-08-25 00:37:03 -06:00
cur_mode . flowmode = M_KEEP ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " s+ " )
{
2012-08-25 00:37:03 -06:00
cur_mode . setmode = M_INC ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " s- " )
{
2012-08-25 00:37:03 -06:00
cur_mode . setmode = M_DEC ;
2011-07-27 18:35:45 -06:00
}
else if ( command = = " s. " )
{
2012-08-25 00:37:03 -06:00
cur_mode . setmode = M_KEEP ;
2011-07-27 18:35:45 -06:00
}
2012-08-26 10:08:28 -06:00
else if ( command . size ( ) > 2 & & memcmp ( command . c_str ( ) , " pf " , 2 ) = = 0 )
{
auto * tail = command . c_str ( ) + 2 ;
for ( int pm = PF_KEEP ; pm < = PF_SOUTHWEST ; pm + + )
{
if ( strcmp ( tail , permaflow_name [ pm ] ) ! = 0 )
continue ;
cur_mode . permaflow = PermaflowMode ( pm ) ;
tail = NULL ;
break ;
}
if ( tail )
out < < command < < " : invalid permaflow mode " < < endl ;
}
2011-07-27 18:35:45 -06:00
// blah blah, bad code, bite me.
else if ( command = = " 0 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 0 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 1 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 1 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 2 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 2 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 3 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 3 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 4 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 4 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 5 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 5 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 6 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 6 ;
2011-07-27 18:35:45 -06:00
else if ( command = = " 7 " )
2012-08-25 00:37:03 -06:00
cur_mode . amount = 7 ;
2011-07-27 18:35:45 -06:00
else if ( command . empty ( ) )
{
2012-03-23 17:13:16 -06:00
df_liquids_execute ( out ) ;
}
else
{
out < < command < < " : unknown command. " < < endl ;
}
}
return CR_OK ;
}
command_result df_liquids_here ( color_ostream & out , vector < string > & parameters )
{
for ( size_t i = 0 ; i < parameters . size ( ) ; i + + )
{
if ( parameters [ i ] = = " help " | | parameters [ i ] = = " ? " )
2013-10-30 14:58:14 -06:00
return CR_WRONG_USAGE ;
2012-03-23 17:13:16 -06:00
}
2012-03-10 04:55:42 -07:00
2012-03-23 17:13:16 -06:00
out . print ( " Run liquids-here with these parameters: " ) ;
2012-08-26 10:08:28 -06:00
print_prompt ( out , cur_mode ) ;
out < < endl ;
2012-03-23 17:13:16 -06:00
return df_liquids_execute ( out ) ;
}
command_result df_liquids_execute ( color_ostream & out )
{
2012-08-25 00:37:03 -06:00
CoreSuspender suspend ;
2012-03-23 17:13:16 -06:00
2012-08-25 00:37:03 -06:00
auto cursor = Gui : : getCursorPos ( ) ;
if ( ! cursor . isValid ( ) )
2012-03-23 17:13:16 -06:00
{
2012-08-25 00:37:03 -06:00
out . printerr ( " Can't get cursor coords! Make sure you have a cursor active in DF. \n " ) ;
return CR_WRONG_USAGE ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
auto rv = df_liquids_execute ( out , cur_mode , cursor ) ;
if ( rv = = CR_OK )
out < < " OK " < < endl ;
return rv ;
}
command_result df_liquids_execute ( color_ostream & out , OperationMode & cur_mode , df : : coord cursor )
{
// create brush type depending on old parameters
2018-04-05 00:15:32 -06:00
std : : unique_ptr < Brush > brush ;
2012-08-25 00:37:03 -06:00
switch ( cur_mode . brush )
2012-03-23 17:13:16 -06:00
{
2012-08-25 00:37:03 -06:00
case B_POINT :
2018-04-05 00:15:32 -06:00
brush . reset ( new RectangleBrush ( 1 , 1 , 1 , 0 , 0 , 0 ) ) ;
2012-08-25 00:37:03 -06:00
break ;
case B_RANGE :
2018-04-05 00:15:32 -06:00
brush . reset ( new RectangleBrush ( cur_mode . size . x , cur_mode . size . y , cur_mode . size . z , 0 , 0 , 0 ) ) ;
2012-08-25 00:37:03 -06:00
break ;
case B_BLOCK :
2018-04-05 00:15:32 -06:00
brush . reset ( new BlockBrush ( ) ) ;
2012-08-25 00:37:03 -06:00
break ;
case B_COLUMN :
2018-04-05 00:15:32 -06:00
brush . reset ( new ColumnBrush ( ) ) ;
2012-08-25 00:37:03 -06:00
break ;
case B_FLOOD :
2018-04-05 00:15:32 -06:00
brush . reset ( new FloodBrush ( & Core : : getInstance ( ) ) ) ;
2012-08-25 00:37:03 -06:00
break ;
default :
2012-03-23 17:13:16 -06:00
// this should never happen!
out < < " Old brushtype is invalid! Resetting to point brush. \n " ;
2012-08-25 00:37:03 -06:00
cur_mode . brush = B_POINT ;
2018-04-05 00:15:32 -06:00
brush . reset ( new RectangleBrush ( 1 , 1 , 1 , 0 , 0 , 0 ) ) ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
if ( ! Maps : : IsValid ( ) )
2012-03-23 17:13:16 -06:00
{
2012-08-25 00:37:03 -06:00
out < < " Can't see any DF map loaded. " < < endl ;
return CR_FAILURE ;
}
MapCache mcache ;
coord_vec all_tiles = brush - > points ( mcache , cursor ) ;
2012-04-25 08:38:43 -06:00
2012-08-25 00:37:03 -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
2012-08-25 00:37:03 -06:00
switch ( cur_mode . paint )
{
case P_OBSIDIAN :
2012-03-23 17:13:16 -06:00
{
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
{
mcache . setTiletypeAt ( * iter , tiletype : : LavaWall ) ;
mcache . setTemp1At ( * iter , 10015 ) ;
mcache . setTemp2At ( * iter , 10015 ) ;
df : : tile_designation des = mcache . designationAt ( * iter ) ;
des . bits . flow_size = 0 ;
2012-04-26 08:51:39 -06:00
des . bits . flow_forbid = false ;
2012-03-23 17:13:16 -06:00
mcache . setDesignationAt ( * iter , des ) ;
iter + + ;
}
2012-08-25 00:37:03 -06:00
break ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
case P_OBSIDIAN_FLOOR :
2012-03-23 17:13:16 -06:00
{
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
{
mcache . setTiletypeAt ( * iter , findRandomVariant ( tiletype : : LavaFloor1 ) ) ;
iter + + ;
}
2012-08-25 00:37:03 -06:00
break ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
case P_RIVER_SOURCE :
2012-03-23 17:13:16 -06:00
{
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
{
mcache . setTiletypeAt ( * iter , tiletype : : RiverSource ) ;
df : : tile_designation a = mcache . designationAt ( * iter ) ;
a . bits . liquid_type = tile_liquid : : Water ;
a . bits . liquid_static = false ;
a . bits . flow_size = 7 ;
mcache . setTemp1At ( * iter , 10015 ) ;
mcache . setTemp2At ( * iter , 10015 ) ;
mcache . setDesignationAt ( * iter , a ) ;
Block * b = mcache . BlockAt ( ( * iter ) / 16 ) ;
2012-05-12 10:12:09 -06:00
b - > enableBlockUpdates ( true ) ;
2012-03-23 17:13:16 -06:00
iter + + ;
}
2012-08-25 00:37:03 -06:00
break ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
case P_WCLEAN :
2012-03-23 17:13:16 -06:00
{
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
2011-07-27 18:35:45 -06:00
{
2012-03-23 17:13:16 -06:00
DFHack : : DFCoord current = * iter ;
df : : tile_designation des = mcache . designationAt ( current ) ;
des . bits . water_salt = false ;
des . bits . water_stagnant = false ;
mcache . setDesignationAt ( current , des ) ;
iter + + ;
}
2012-08-25 00:37:03 -06:00
break ;
2012-03-23 17:13:16 -06:00
}
2012-08-25 00:37:03 -06:00
case P_MAGMA :
case P_WATER :
case P_FLOW_BITS :
2012-03-23 17:13:16 -06:00
{
set < Block * > seen_blocks ;
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
{
DFHack : : DFCoord current = * iter ; // current tile coord
DFHack : : DFCoord curblock = current / 16 ; // current block coord
// check if the block is actually there
2012-05-12 10:12:09 -06:00
auto block = mcache . BlockAt ( curblock ) ;
if ( ! block )
2011-07-27 18:35:45 -06:00
{
2012-03-23 17:13:16 -06:00
iter + + ;
continue ;
2011-07-27 18:35:45 -06:00
}
2012-08-26 10:08:28 -06:00
auto raw_block = block - > getRaw ( ) ;
2012-03-23 17:13:16 -06:00
df : : tile_designation des = mcache . designationAt ( current ) ;
df : : tiletype tt = mcache . tiletypeAt ( current ) ;
// don't put liquids into places where they don't belong...
if ( ! DFHack : : FlowPassable ( tt ) )
2011-07-27 18:35:45 -06:00
{
2012-03-23 17:13:16 -06:00
iter + + ;
continue ;
2011-07-27 18:35:45 -06:00
}
2012-08-25 00:37:03 -06:00
if ( cur_mode . paint ! = P_FLOW_BITS )
2011-07-27 18:35:45 -06:00
{
2012-05-12 10:12:09 -06:00
unsigned old_amount = des . bits . flow_size ;
unsigned new_amount = old_amount ;
df : : tile_liquid old_liquid = des . bits . liquid_type ;
df : : tile_liquid new_liquid = old_liquid ;
// Compute new liquid type and amount
2012-08-25 00:37:03 -06:00
switch ( cur_mode . setmode )
2011-07-27 18:35:45 -06:00
{
2012-08-25 00:37:03 -06:00
case M_KEEP :
new_amount = cur_mode . amount ;
break ;
case M_INC :
if ( old_amount < cur_mode . amount )
new_amount = cur_mode . amount ;
break ;
case M_DEC :
if ( old_amount > cur_mode . amount )
new_amount = cur_mode . amount ;
2011-07-27 18:35:45 -06:00
}
2012-08-25 00:37:03 -06:00
if ( cur_mode . paint = = P_MAGMA )
2012-05-12 10:12:09 -06:00
new_liquid = tile_liquid : : Magma ;
2012-08-25 00:37:03 -06:00
else if ( cur_mode . paint = = P_WATER )
2012-05-12 10:12:09 -06:00
new_liquid = tile_liquid : : Water ;
// Store new amount and type
des . bits . flow_size = new_amount ;
des . bits . liquid_type = new_liquid ;
// Compute temperature
if ( ! old_amount )
old_liquid = tile_liquid : : Water ;
if ( ! new_amount )
new_liquid = tile_liquid : : Water ;
if ( old_liquid ! = new_liquid )
2011-09-01 17:25:01 -06:00
{
2012-05-12 10:12:09 -06:00
if ( new_liquid = = tile_liquid : : Water )
{
mcache . setTemp1At ( current , 10015 ) ;
mcache . setTemp2At ( current , 10015 ) ;
}
else
{
mcache . setTemp1At ( current , 12000 ) ;
mcache . setTemp2At ( current , 12000 ) ;
}
2011-07-27 18:35:45 -06:00
}
2012-04-26 08:51:39 -06:00
// mark the tile passable or impassable like the game does
2012-05-12 10:12:09 -06:00
des . bits . flow_forbid = ( new_liquid = = tile_liquid : : Magma | | new_amount > 3 ) ;
2012-03-23 17:13:16 -06:00
mcache . setDesignationAt ( current , des ) ;
2012-05-12 10:12:09 -06:00
// request flow engine updates
block - > enableBlockUpdates ( new_amount ! = old_amount , new_liquid ! = old_liquid ) ;
2012-03-23 17:13:16 -06:00
}
2012-08-26 10:08:28 -06:00
if ( cur_mode . permaflow ! = PF_KEEP & & raw_block )
{
auto & flow = raw_block - > liquid_flow [ current . x & 15 ] [ current . y & 15 ] ;
flow . bits . perm_flow_dir = permaflow_id [ cur_mode . permaflow ] ;
flow . bits . temp_flow_timer = 0 ;
}
2012-05-12 10:12:09 -06:00
seen_blocks . insert ( block ) ;
2012-03-23 17:13:16 -06:00
iter + + ;
}
set < Block * > : : iterator biter = seen_blocks . begin ( ) ;
while ( biter ! = seen_blocks . end ( ) )
{
2012-08-25 00:37:03 -06:00
switch ( cur_mode . flowmode )
2012-03-23 17:13:16 -06:00
{
2012-08-25 00:37:03 -06:00
case M_INC :
2012-05-12 10:12:09 -06:00
( * biter ) - > enableBlockUpdates ( true ) ;
2012-08-25 00:37:03 -06:00
break ;
case M_DEC :
2012-05-12 10:12:09 -06:00
if ( auto block = ( * biter ) - > getRaw ( ) )
{
block - > flags . bits . update_liquid = false ;
block - > flags . bits . update_liquid_twice = false ;
}
2012-08-25 00:37:03 -06:00
break ;
case M_KEEP :
{
auto bflags = ( * biter ) - > BlockFlags ( ) ;
2015-02-14 20:53:06 -07:00
out < < " flow bit 1 = " < < bflags . bits . update_liquid < < endl ;
2012-08-25 00:37:03 -06:00
out < < " flow bit 2 = " < < bflags . bits . update_liquid_twice < < endl ;
}
2012-03-23 17:13:16 -06:00
}
biter + + ;
}
2012-08-25 00:37:03 -06:00
break ;
2011-07-27 18:35:45 -06:00
}
2012-08-25 00:37:03 -06:00
}
if ( ! mcache . WriteAll ( ) )
{
out < < " Something failed horribly! RUN! " < < endl ;
return CR_FAILURE ;
}
2012-03-21 06:57:55 -06:00
2011-07-27 18:35:45 -06:00
return CR_OK ;
}
2012-08-25 00:37:03 -06:00
static int paint ( lua_State * L )
{
df : : coord pos ;
OperationMode mode ;
2012-08-26 10:08:28 -06:00
lua_settop ( L , 8 ) ;
2012-08-25 00:37:03 -06:00
Lua : : CheckDFAssign ( L , & pos , 1 ) ;
if ( ! pos . isValid ( ) )
luaL_argerror ( L , 1 , " invalid cursor position " ) ;
mode . brush = ( BrushType ) luaL_checkoption ( L , 2 , NULL , brush_name ) ;
mode . paint = ( PaintMode ) luaL_checkoption ( L , 3 , NULL , paint_mode_name ) ;
mode . amount = luaL_optint ( L , 4 , 7 ) ;
if ( mode . amount < 0 | | mode . amount > 7 )
luaL_argerror ( L , 4 , " invalid liquid amount " ) ;
if ( ! lua_isnil ( L , 5 ) )
Lua : : CheckDFAssign ( L , & mode . size , 5 ) ;
mode . setmode = ( ModifyMode ) luaL_checkoption ( L , 6 , " . " , modify_mode_name ) ;
mode . flowmode = ( ModifyMode ) luaL_checkoption ( L , 7 , " + " , modify_mode_name ) ;
2012-08-26 10:08:28 -06:00
mode . permaflow = ( PermaflowMode ) luaL_checkoption ( L , 8 , " . " , permaflow_name ) ;
2012-08-25 00:37:03 -06:00
lua_pushboolean ( L , df_liquids_execute ( * Lua : : GetOutput ( L ) , mode , pos ) ) ;
return 1 ;
}
DFHACK_PLUGIN_LUA_COMMANDS {
DFHACK_LUA_COMMAND ( paint ) ,
DFHACK_LUA_END
} ;