2010-04-15 16:24:59 -06:00
# include <iostream>
# include <vector>
2010-05-23 15:06:10 -06:00
# include <map>
2011-05-17 00:36:38 -06:00
# include <set>
2010-10-06 18:27:02 -06:00
# include <cstdlib>
2010-04-15 16:24:59 -06:00
using namespace std ;
2010-05-25 22:48:23 -06:00
# include <DFHack.h>
2011-03-10 19:09:45 -07:00
# include <dfhack/extra/MapExtras.h>
using namespace MapExtras ;
2011-05-17 00:36:38 -06:00
# include <dfhack/extra/termutil.h>
2011-03-10 19:09:45 -07:00
2011-05-14 22:10:47 -06:00
2011-03-10 19:09:45 -07:00
typedef vector < DFHack : : DFCoord > coord_vec ;
class Brush
{
public :
virtual ~ Brush ( ) { } ;
virtual coord_vec points ( MapCache & mc , DFHack : : DFCoord start ) = 0 ;
} ;
/**
2011-03-13 12:38:32 -06:00
* generic 3 D rectangle brush . you can specify the dimensions of
2011-03-10 19:09:45 -07:00
* the rectangle and optionally which tile is its ' center '
*/
class RectangleBrush : public Brush
{
public :
RectangleBrush ( int x , int y , int z = 1 , int centerx = - 1 , int centery = - 1 , int centerz = - 1 )
{
if ( centerx = = - 1 )
cx_ = x / 2 ;
else
cx_ = centerx ;
if ( centery = = - 1 )
cy_ = y / 2 ;
else
cy_ = centery ;
if ( centerz = = - 1 )
2011-03-13 12:38:32 -06:00
cz_ = z / 2 ;
2011-03-10 19:09:45 -07:00
else
cz_ = centerz ;
x_ = x ;
y_ = y ;
z_ = z ;
} ;
coord_vec points ( MapCache & mc , DFHack : : DFCoord start )
{
coord_vec v ;
DFHack : : DFCoord iterstart ( start . x - cx_ , start . y - cy_ , start . z - cz_ ) ;
DFHack : : DFCoord iter = iterstart ;
for ( int xi = 0 ; xi < x_ ; xi + + )
{
for ( int yi = 0 ; yi < y_ ; yi + + )
{
for ( int zi = 0 ; zi < z_ ; zi + + )
{
if ( mc . testCoord ( iter ) )
v . push_back ( iter ) ;
iter . z + + ;
}
iter . z = iterstart . z ;
iter . y + + ;
}
iter . y = iterstart . y ;
iter . x + + ;
}
return v ;
} ;
~ RectangleBrush ( ) { } ;
private :
int x_ , y_ , z_ ;
int cx_ , cy_ , cz_ ;
} ;
/**
* stupid block brush , legacy . use when you want to apply something to a whole DF map block .
*/
class BlockBrush : public Brush
{
public :
BlockBrush ( ) { } ;
~ BlockBrush ( ) { } ;
coord_vec points ( MapCache & mc , DFHack : : DFCoord start )
{
coord_vec v ;
DFHack : : DFCoord blockc = start % 16 ;
DFHack : : DFCoord iterc = blockc * 16 ;
if ( ! mc . testCoord ( start ) )
return v ;
for ( int xi = 0 ; xi < 16 ; xi + + )
{
for ( int yi = 0 ; yi < 16 ; yi + + )
{
v . push_back ( iterc ) ;
iterc . y + + ;
}
iterc . x + + ;
}
return v ;
} ;
} ;
/**
* Column from a position through open space tiles
* example : create a column of magma
*/
class ColumnBrush : public Brush
{
public :
ColumnBrush ( ) { } ;
~ ColumnBrush ( ) { } ;
coord_vec points ( MapCache & mc , DFHack : : DFCoord start )
{
coord_vec v ;
bool juststarted = true ;
while ( mc . testCoord ( start ) )
{
uint16_t tt = mc . tiletypeAt ( start ) ;
if ( DFHack : : LowPassable ( tt ) | | juststarted & & DFHack : : HighPassable ( tt ) )
{
v . push_back ( start ) ;
juststarted = false ;
start . z + + ;
}
else break ;
}
return v ;
} ;
} ;
2010-04-15 16:24:59 -06:00
2010-11-10 18:09:43 -07:00
int main ( int argc , char * * argv )
2010-04-15 16:24:59 -06:00
{
2011-05-14 22:10:47 -06:00
bool temporary_terminal = TemporaryTerminal ( ) ;
2010-11-10 18:09:43 -07:00
bool quiet = false ;
for ( int i = 1 ; i < argc ; i + + )
{
string test = argv [ i ] ;
if ( test = = " -q " )
{
quiet = true ;
}
2010-11-10 18:32:33 -07:00
}
int32_t x , y , z ;
2011-05-14 22:10:47 -06:00
2010-04-17 14:08:16 -06:00
uint32_t x_max , y_max , z_max ;
2010-11-10 18:32:33 -07:00
2010-05-23 15:06:10 -06:00
DFHack : : ContextManager DFMgr ( " Memory.xml " ) ;
DFHack : : Context * DF ;
2010-04-15 16:24:59 -06:00
DFHack : : Maps * Maps ;
2011-03-18 04:38:37 -06:00
DFHack : : Gui * Position ;
2011-03-10 19:09:45 -07:00
Brush * brush = new RectangleBrush ( 1 , 1 ) ;
2011-03-26 17:02:23 -06:00
string brushname = " point " ;
2010-04-15 16:24:59 -06:00
try
{
2010-05-23 15:06:10 -06:00
DF = DFMgr . getSingleContext ( ) ;
DF - > Attach ( ) ;
Maps = DF - > getMaps ( ) ;
2010-06-16 22:46:20 -06:00
Maps - > Start ( ) ;
Maps - > getSize ( x_max , y_max , z_max ) ;
2011-03-18 04:38:37 -06:00
Position = DF - > getGui ( ) ;
2010-04-15 16:24:59 -06:00
}
catch ( exception & e )
{
cerr < < e . what ( ) < < endl ;
2011-05-14 22:10:47 -06:00
if ( temporary_terminal )
cin . ignore ( ) ;
2010-04-15 16:24:59 -06:00
return 1 ;
}
bool end = false ;
2011-03-26 17:02:23 -06:00
cout < < " 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. " < < endl ;
2010-04-15 16:24:59 -06:00
string mode = " magma " ;
2011-03-10 19:09:45 -07:00
2010-04-15 16:24:59 -06:00
string flowmode = " f+ " ;
2010-08-29 12:05:56 -06:00
string setmode = " s. " ;
2011-05-23 13:30:51 -06:00
unsigned int amount = 7 ;
2011-03-10 19:09:45 -07:00
int width = 1 , height = 1 , z_levels = 1 ;
2010-04-15 16:24:59 -06:00
while ( ! end )
{
2010-05-23 15:06:10 -06:00
DF - > Resume ( ) ;
2010-04-15 16:24:59 -06:00
string command = " " ;
2011-03-26 17:02:23 -06:00
cout < < " [ " < < mode < < " : " < < brushname < < " : " < < amount < < " : " < < flowmode < < " : " < < setmode < < " ]# " ;
2010-04-15 16:24:59 -06:00
getline ( cin , command ) ;
2011-05-05 20:10:45 -06:00
if ( std : : cin . eof ( ) )
{
command = " q " ;
std : : cout < < std : : endl ; // No newline from the user here!
}
2011-03-26 17:02:23 -06:00
if ( command = = " help " | | command = = " ? " )
2010-04-15 16:24:59 -06:00
{
cout < < " Modes: " < < endl
< < " m - switch to magma " < < endl
< < " w - switch to water " < < endl
2010-04-17 14:08:16 -06:00
< < " o - make obsidian wall instead " < < endl
2011-03-10 19:09:45 -07:00
< < " of - make obsidian floors " < < endl
< < " rs - make a river source " < < endl
2010-04-15 16:24:59 -06:00
< < " f - flow bits only " < < endl
2011-03-26 17:02:23 -06:00
< < " Set-Modes (only for magma/water): " < < endl
2010-08-29 12:05:56 -06:00
< < " s+ - only add " < < endl
< < " s. - set " < < endl
< < " s- - only remove " < < endl
2011-03-26 17:02:23 -06:00
< < " Properties (only for magma/water): " < < endl
2010-04-15 16:24:59 -06:00
< < " 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
< < " 0-7 - set liquid amount " < < endl
2010-04-17 07:30:25 -06:00
< < " Brush: " < < endl
2010-10-28 20:45:30 -06:00
< < " point - single tile [p] " < < endl
2011-03-10 19:09:45 -07:00
< < " range - block with cursor at bottom north-west [r] " < < endl
2011-03-26 17:02:23 -06:00
< < " (any place, any size) " < < endl
2011-03-10 19:09:45 -07:00
< < " block - DF map block with cursor in it " < < endl
2011-03-26 17:02:23 -06:00
< < " (regular spaced 16x16x1 blocks) " < < endl
< < " column - Column from cursor, up through free space " < < endl
2010-04-15 16:24:59 -06:00
< < " Other: " < < endl
< < " q - quit " < < endl
2011-03-26 17:02:23 -06:00
< < " help or ? - print this list of commands " < < endl
2010-04-15 16:24:59 -06:00
< < " 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 ;
}
else if ( command = = " m " )
{
mode = " magma " ;
}
2010-04-17 14:08:16 -06:00
else if ( command = = " o " )
{
mode = " obsidian " ;
}
2011-03-10 19:09:45 -07:00
else if ( command = = " of " )
2010-04-17 14:08:16 -06:00
{
2011-03-10 19:09:45 -07:00
mode = " obsidian_floor " ;
2010-04-26 10:12:00 -06:00
}
2010-04-15 16:24:59 -06:00
else if ( command = = " w " )
{
mode = " water " ;
}
else if ( command = = " f " )
{
mode = " flowbits " ;
}
2011-03-10 19:09:45 -07:00
else if ( command = = " rs " )
{
mode = " riversource " ;
}
2010-10-28 20:45:30 -06:00
else if ( command = = " point " | | command = = " p " )
2010-04-17 07:30:25 -06:00
{
2011-03-10 19:09:45 -07:00
delete brush ;
2011-03-26 17:02:23 -06:00
brushname = " point " ;
2011-03-10 19:09:45 -07:00
brush = new RectangleBrush ( 1 , 1 ) ;
2010-04-17 07:30:25 -06:00
}
2010-10-28 20:45:30 -06:00
else if ( command = = " range " | | command = = " r " )
2010-10-07 20:28:26 -06:00
{
cout < < " :set range width< " < < width < < " ># " ;
getline ( cin , command ) ;
2010-10-28 20:45:30 -06:00
width = command = = " " ? width : atoi ( command . c_str ( ) ) ;
2010-10-07 20:28:26 -06:00
if ( width < 1 ) width = 1 ;
2011-03-10 19:09:45 -07:00
2010-10-07 20:28:26 -06:00
cout < < " :set range height< " < < height < < " ># " ;
getline ( cin , command ) ;
2010-10-28 20:45:30 -06:00
height = command = = " " ? height : atoi ( command . c_str ( ) ) ;
2010-10-07 20:28:26 -06:00
if ( height < 1 ) height = 1 ;
2011-03-10 19:09:45 -07:00
cout < < " :set range z-levels< " < < z_levels < < " ># " ;
getline ( cin , command ) ;
z_levels = command = = " " ? z_levels : atoi ( command . c_str ( ) ) ;
if ( z_levels < 1 ) z_levels = 1 ;
delete brush ;
2011-03-30 06:27:47 -06:00
if ( width = = 1 & & height = = 1 & & z_levels = = 1 )
2011-03-26 17:02:23 -06:00
{
brushname = " point " ;
}
else
{
brushname = " range " ;
}
2011-03-10 19:09:45 -07:00
brush = new RectangleBrush ( width , height , z_levels , 0 , 0 , 0 ) ;
2010-10-07 20:28:26 -06:00
}
2010-04-17 07:30:25 -06:00
else if ( command = = " block " )
{
2011-03-10 19:09:45 -07:00
delete brush ;
2011-03-26 17:02:23 -06:00
brushname = " block " ;
2011-03-10 19:09:45 -07:00
brush = new BlockBrush ( ) ;
}
else if ( command = = " column " )
{
delete brush ;
2011-03-26 17:02:23 -06:00
brushname = " column " ;
2011-03-10 19:09:45 -07:00
brush = new ColumnBrush ( ) ;
2010-04-17 07:30:25 -06:00
}
2010-04-15 16:24:59 -06:00
else if ( command = = " q " )
{
end = true ;
}
else if ( command = = " f+ " )
{
flowmode = " f+ " ;
}
else if ( command = = " f- " )
{
flowmode = " f- " ;
}
else if ( command = = " f. " )
{
flowmode = " f. " ;
}
2010-08-29 12:05:56 -06:00
else if ( command = = " s+ " )
{
setmode = " s+ " ;
}
else if ( command = = " s- " )
{
setmode = " s- " ;
}
else if ( command = = " s. " )
{
setmode = " s. " ;
}
2010-04-15 16:24:59 -06:00
// blah blah, bad code, bite me.
else if ( command = = " 0 " )
amount = 0 ;
else if ( command = = " 1 " )
amount = 1 ;
else if ( command = = " 2 " )
amount = 2 ;
else if ( command = = " 3 " )
amount = 3 ;
else if ( command = = " 4 " )
amount = 4 ;
else if ( command = = " 5 " )
amount = 5 ;
else if ( command = = " 6 " )
amount = 6 ;
else if ( command = = " 7 " )
amount = 7 ;
else if ( command . empty ( ) )
{
2010-05-23 15:06:10 -06:00
DF - > Suspend ( ) ;
2010-04-15 16:24:59 -06:00
do
{
if ( ! Maps - > Start ( ) )
{
cout < < " Can't see any DF map loaded. " < < endl ;
break ;
}
if ( ! Position - > getCursorCoords ( x , y , z ) )
{
cout < < " Can't get cursor coords! Make sure you have a cursor active in DF. " < < endl ;
break ;
}
cout < < " cursor coords: " < < x < < " / " < < y < < " / " < < z < < endl ;
2011-03-10 19:09:45 -07:00
MapCache mcache ( Maps ) ;
DFHack : : DFCoord cursor ( x , y , z ) ;
coord_vec all_tiles = brush - > points ( mcache , cursor ) ;
2011-03-30 06:27:47 -06:00
cout < < " working... " < < endl ;
2010-04-17 14:08:16 -06:00
if ( mode = = " obsidian " )
2010-04-17 07:30:25 -06:00
{
2011-03-10 19:09:45 -07:00
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
2010-04-17 14:08:16 -06:00
{
2011-03-10 19:09:45 -07:00
mcache . setTiletypeAt ( * iter , 331 ) ;
2011-03-30 22:11:03 -06:00
mcache . setTemp1At ( * iter , 10015 ) ;
mcache . setTemp2At ( * iter , 10015 ) ;
2011-03-30 06:27:47 -06:00
DFHack : : t_designation des = mcache . designationAt ( * iter ) ;
2011-03-30 22:11:03 -06:00
des . bits . flow_size = 0 ;
2011-03-30 06:27:47 -06:00
mcache . setDesignationAt ( * iter , des ) ;
2011-03-10 19:09:45 -07:00
iter + + ;
}
2010-04-17 07:30:25 -06:00
}
2011-03-10 19:09:45 -07:00
if ( mode = = " obsidian_floor " )
2010-04-26 10:12:00 -06:00
{
2011-03-10 19:09:45 -07:00
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
2010-04-26 10:12:00 -06:00
{
2011-03-10 19:09:45 -07:00
mcache . setTiletypeAt ( * iter , 340 ) ;
iter + + ;
2010-04-26 10:12:00 -06:00
}
}
2011-03-10 19:09:45 -07:00
else if ( mode = = " riversource " )
2010-04-26 10:12:00 -06:00
{
2011-03-10 19:09:45 -07:00
set < Block * > seen_blocks ;
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
2010-04-26 10:12:00 -06:00
{
2011-03-10 19:09:45 -07:00
mcache . setTiletypeAt ( * iter , 90 ) ;
DFHack : : t_designation a = mcache . designationAt ( * iter ) ;
a . bits . liquid_type = DFHack : : liquid_water ;
a . bits . liquid_static = false ;
a . bits . flow_size = 7 ;
2011-03-30 22:11:03 -06:00
mcache . setTemp1At ( * iter , 10015 ) ;
mcache . setTemp2At ( * iter , 10015 ) ;
2011-03-10 19:09:45 -07:00
mcache . setDesignationAt ( * iter , a ) ;
Block * b = mcache . BlockAt ( ( * iter ) / 16 ) ;
DFHack : : t_blockflags bf = b - > BlockFlags ( ) ;
bf . bits . liquid_1 = true ;
bf . bits . liquid_2 = true ;
b - > setBlockFlags ( bf ) ;
iter + + ;
2010-04-26 10:12:00 -06:00
}
}
2011-03-10 19:09:45 -07:00
else if ( mode = = " magma " | | mode = = " water " | | mode = = " flowbits " )
2010-04-17 07:30:25 -06:00
{
2011-03-10 19:09:45 -07:00
set < Block * > seen_blocks ;
coord_vec : : iterator iter = all_tiles . begin ( ) ;
while ( iter ! = all_tiles . end ( ) )
2010-10-07 20:28:26 -06:00
{
2011-03-10 19:09:45 -07:00
DFHack : : DFCoord current = * iter ;
DFHack : : t_designation des = mcache . designationAt ( current ) ;
uint16_t tt = mcache . tiletypeAt ( current ) ;
DFHack : : naked_designation & flow = des . bits ;
2011-03-31 05:38:44 -06:00
// don't put liquids into places where they don't belong...
if ( ! DFHack : : FlowPassable ( tt ) )
{
iter + + ;
continue ;
}
2011-03-10 19:09:45 -07:00
if ( mode ! = " flowbits " )
2010-10-07 20:28:26 -06:00
{
2011-03-10 19:09:45 -07:00
if ( setmode = = " s. " )
2010-10-07 20:28:26 -06:00
{
2011-03-10 19:09:45 -07:00
flow . flow_size = amount ;
}
else if ( setmode = = " s+ " )
{
if ( flow . flow_size < amount )
2010-10-07 20:28:26 -06:00
flow . flow_size = amount ;
}
2011-03-10 19:09:45 -07:00
else if ( setmode = = " s- " )
2010-10-07 20:28:26 -06:00
{
2011-03-10 19:09:45 -07:00
if ( flow . flow_size > amount )
flow . flow_size = amount ;
2010-10-07 20:28:26 -06:00
}
2011-03-30 06:27:47 -06:00
if ( amount ! = 0 & & mode = = " magma " )
{
2011-03-10 19:09:45 -07:00
flow . liquid_type = DFHack : : liquid_magma ;
2011-03-30 06:27:47 -06:00
mcache . setTemp1At ( current , 12000 ) ;
mcache . setTemp2At ( current , 12000 ) ;
}
else if ( amount ! = 0 & & mode = = " water " )
{
2011-03-10 19:09:45 -07:00
flow . liquid_type = DFHack : : liquid_water ;
2011-03-30 06:27:47 -06:00
mcache . setTemp1At ( current , 10015 ) ;
mcache . setTemp2At ( current , 10015 ) ;
}
else if ( amount = = 0 & & ( mode = = " water " | | mode = = " magma " ) )
{
// reset temperature to sane default
mcache . setTemp1At ( current , 10015 ) ;
mcache . setTemp2At ( current , 10015 ) ;
}
2011-03-10 19:09:45 -07:00
mcache . setDesignationAt ( current , des ) ;
2010-10-07 20:28:26 -06:00
}
2011-03-10 19:09:45 -07:00
seen_blocks . insert ( mcache . BlockAt ( ( * iter ) / 16 ) ) ;
iter + + ;
}
set < Block * > : : iterator biter = seen_blocks . begin ( ) ;
while ( biter ! = seen_blocks . end ( ) )
{
DFHack : : t_blockflags bflags = ( * biter ) - > BlockFlags ( ) ;
2010-10-07 20:28:26 -06:00
if ( flowmode = = " f+ " )
{
bflags . bits . liquid_1 = true ;
bflags . bits . liquid_2 = true ;
2011-03-10 19:09:45 -07:00
( * biter ) - > setBlockFlags ( bflags ) ;
2010-10-07 20:28:26 -06:00
}
else if ( flowmode = = " f- " )
{
bflags . bits . liquid_1 = false ;
bflags . bits . liquid_2 = false ;
2011-03-10 19:09:45 -07:00
( * biter ) - > setBlockFlags ( bflags ) ;
2010-10-07 20:28:26 -06:00
}
else
{
cout < < " flow bit 1 = " < < bflags . bits . liquid_1 < < endl ;
cout < < " flow bit 2 = " < < bflags . bits . liquid_2 < < endl ;
}
2011-03-10 19:09:45 -07:00
biter + + ;
2010-10-07 20:28:26 -06:00
}
}
2011-03-10 19:09:45 -07:00
if ( mcache . WriteAll ( ) )
cout < < " OK " < < endl ;
else
cout < < " Something failed horribly! RUN! " < < endl ;
2010-10-07 20:28:26 -06:00
Maps - > Finish ( ) ;
2010-04-15 16:24:59 -06:00
} while ( 0 ) ;
}
2011-03-10 19:09:45 -07:00
else
{
cout < < command < < " : unknown command. " < < endl ;
}
2010-04-15 16:24:59 -06:00
}
2010-05-23 15:06:10 -06:00
DF - > Detach ( ) ;
2011-05-14 22:10:47 -06:00
if ( temporary_terminal & & ! quiet )
2011-05-05 20:10:45 -06:00
{
cout < < " Done. Press any key to continue " < < endl ;
cin . ignore ( ) ;
}
2010-04-15 16:24:59 -06:00
return 0 ;
}