Make tiletypes more useful

* Paint, filter, and brush state is now saved between calls.
 * Added 'all' paint option to set material, shape, special, and variant at
      the same time.
 * Added tiletypes-here (like liquids here, except is uses the saved brush
      settings)
 * Added tiletypes-here-point (like liquids here, always only the tile under
      the cursor)
 * Added tiletypes-command: runs tiletypes commands seperated by ';' tokens
      (affects saved state)
 * Make the internal workings match liquids a bit more
 * Give brush objects a descriptor string
 * Make Core::cheap_tokenise available
develop
Jared Adams 2012-04-15 08:40:19 -06:00
parent c69af6ab9e
commit f3c7a685f5
4 changed files with 582 additions and 386 deletions

@ -118,7 +118,7 @@ struct Core::Private
} }
}; };
void cheap_tokenise(string const& input, vector<string> &output) void Core::cheap_tokenise(string const& input, vector<string> &output)
{ {
string *cur = NULL; string *cur = NULL;
@ -177,7 +177,7 @@ void fHKthread(void * iodata)
color_ostream_proxy out(core->getConsole()); color_ostream_proxy out(core->getConsole());
vector <string> args; vector <string> args;
cheap_tokenise(stuff, args); Core::cheap_tokenise(stuff, args);
if (args.empty()) { if (args.empty()) {
out.printerr("Empty hotkey command.\n"); out.printerr("Empty hotkey command.\n");
continue; continue;
@ -218,7 +218,7 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
{ {
// cut the input into parts // cut the input into parts
vector <string> parts; vector <string> parts;
cheap_tokenise(command,parts); Core::cheap_tokenise(command,parts);
if(parts.size() == 0) if(parts.size() == 0)
{ {
clueless_counter ++; clueless_counter ++;

@ -135,6 +135,8 @@ namespace DFHack
PluginManager *getPluginManager() { return plug_mgr; } PluginManager *getPluginManager() { return plug_mgr; }
static void cheap_tokenise(std::string const& input, std::vector<std::string> &output);
private: private:
DFHack::Console con; DFHack::Console con;

@ -6,6 +6,9 @@ class Brush
public: public:
virtual ~Brush(){}; virtual ~Brush(){};
virtual coord_vec points(MapExtras::MapCache & mc,DFHack::DFCoord start) = 0; virtual coord_vec points(MapExtras::MapCache & mc,DFHack::DFCoord start) = 0;
virtual std::string str() const {
return "unknown";
}
}; };
/** /**
* generic 3D rectangle brush. you can specify the dimensions of * generic 3D rectangle brush. you can specify the dimensions of
@ -56,6 +59,13 @@ public:
return v; return v;
}; };
~RectangleBrush(){}; ~RectangleBrush(){};
std::string str() const {
if (x_ == 1 && y_ == 1 && z_ == 1) {
return "point";
} else {
return "rectangle";
}
}
private: private:
int x_, y_, z_; int x_, y_, z_;
int cx_, cy_, cz_; int cx_, cy_, cz_;
@ -89,6 +99,9 @@ public:
} }
return v; return v;
}; };
std::string str() const {
return "block";
}
}; };
/** /**
@ -117,6 +130,9 @@ public:
} }
return v; return v;
}; };
std::string str() const {
return "column";
}
}; };
/** /**
@ -168,6 +184,9 @@ public:
return v; return v;
} }
std::string str() const {
return "flood";
}
private: private:
void maybeFlood(DFCoord c, std::stack<DFCoord> &to_flood, MapExtras::MapCache &mc) { void maybeFlood(DFCoord c, std::stack<DFCoord> &to_flood, MapExtras::MapCache &mc) {
if (mc.testCoord(c)) { if (mc.testCoord(c)) {
@ -176,3 +195,7 @@ private:
} }
Core *c_; Core *c_;
}; };
std::ostream &operator<<(std::ostream &stream, const Brush& brush) {
stream << brush.str();
}

@ -1,4 +1,24 @@
// Plugin tiletypes
// //
// 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
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <map> #include <map>
@ -25,39 +45,120 @@ using namespace MapExtras;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
//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. CommandHistory tiletypes_hist;
//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... command_result df_tiletypes (color_ostream &out, vector <string> & parameters);
for(char *c=(char *)str.c_str(); *c; ++c) 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);
DFHACK_PLUGIN("tiletypes");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
*c = tolower(*c); tiletypes_hist.load("tiletypes.history");
commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true));
commands.push_back(PluginCommand("tiletypes-command", "Run the given commands (seperated by ' ; '; an empty command is the same as run).", df_tiletypes_command));
commands.push_back(PluginCommand("tiletypes-here", "Use the last settings from tiletypes, including brush, at cursor location.", df_tiletypes_here));
commands.push_back(PluginCommand("tiletypes-here-point", "Use the last settings from tiletypes, not including brush, at cursor location.", df_tiletypes_here_point));
return CR_OK;
} }
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
tiletypes_hist.save("tiletypes.history");
return CR_OK;
} }
void toupper(std::string &str) void help( color_ostream & out, std::vector<std::string> &commands, int start, int end)
{ {
//std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::toupper<char>), std::locale(""))); std::string option = commands.size() > start ? commands[start] : "";
for(char *c=(char *)str.c_str(); *c; ++c) if (option.empty())
{ {
*c = toupper(*c); 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
<< " 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
<< "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")
int toint(const std::string &str, int failValue = 0)
{ {
std::istringstream ss(str); out << "Available materials:" << std::endl
int valInt; << " ANY" << std::endl;
ss >> valInt; FOR_ENUM_ITEMS(tiletype_material,i)
if (ss.fail())
{ {
return failValue; 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;
} }
return valInt;
} }
struct TileType struct TileType
@ -217,12 +318,116 @@ std::ostream &operator<<(std::ostream &stream, const TileType &paint)
return stream; return stream;
} }
bool processTileType(TileType &paint, const std::string &option, const std::string &value) static TileType filter, paint;
static Brush *brush = new RectangleBrush(1,1);
void printState(color_ostream &out)
{
out << "Filter: " << filter << std::endl
<< "Paint: " << paint << std::endl
<< "Brush: " << brush->str() << std::endl;
}
//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);
int valInt;
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)
{
if (params.size() < start + 2)
{ {
std::string val = value; return false;
toupper(val); }
int loc = start;
std::string option = params[loc++];
std::string value = params[loc++];
toupper(value);
int valInt; int valInt;
if (val == "ANY") if (value == "ANY")
{ {
valInt = -1; valInt = -1;
} }
@ -241,19 +446,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
FOR_ENUM_ITEMS(tiletype_shape,i) if (!tryShape(value, paint))
{
if (val == ENUM_KEY_STR(tiletype_shape,i))
{
paint.shape = i;
found = true;
break;
}
}
if (!found)
{ {
std::cout << "Unknown tile shape: " << value << std::endl; out << "Unknown tile shape: " << value << std::endl;
} }
} }
} }
@ -266,19 +461,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
FOR_ENUM_ITEMS(tiletype_material, i) if (!tryMaterial(value, paint))
{
if (val == ENUM_KEY_STR(tiletype_material,i))
{
paint.material = i;
found = true;
break;
}
}
if (!found)
{ {
std::cout << "Unknown tile material: " << value << std::endl; out << "Unknown tile material: " << value << std::endl;
} }
} }
} }
@ -291,19 +476,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
FOR_ENUM_ITEMS(tiletype_special, i) if (!trySpecial(value, paint))
{
if (val == ENUM_KEY_STR(tiletype_special,i))
{
paint.special = i;
found = true;
break;
}
}
if (!found)
{ {
std::cout << "Unknown tile special: " << value << std::endl; out << "Unknown tile special: " << value << std::endl;
} }
} }
} }
@ -316,19 +491,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
FOR_ENUM_ITEMS(tiletype_variant, i) if (!tryVariant(value, paint))
{
if (val == ENUM_KEY_STR(tiletype_variant,i))
{
paint.variant = i;
found = true;
break;
}
}
if (!found)
{ {
std::cout << "Unknown tile variant: " << value << std::endl; out << "Unknown tile variant: " << value << std::endl;
} }
} }
} }
@ -341,7 +506,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
std::cout << "Unknown designation flag: " << value << std::endl; out << "Unknown designation flag: " << value << std::endl;
} }
} }
else if (option == "hidden" || option == "h") else if (option == "hidden" || option == "h")
@ -353,7 +518,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
std::cout << "Unknown hidden flag: " << value << std::endl; out << "Unknown hidden flag: " << value << std::endl;
} }
} }
else if (option == "light" || option == "l") else if (option == "light" || option == "l")
@ -365,7 +530,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
std::cout << "Unknown light flag: " << value << std::endl; out << "Unknown light flag: " << value << std::endl;
} }
} }
else if (option == "subterranean" || option == "st") else if (option == "subterranean" || option == "st")
@ -377,7 +542,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
std::cout << "Unknown subterranean flag: " << value << std::endl; out << "Unknown subterranean flag: " << value << std::endl;
} }
} }
else if (option == "skyview" || option == "sv") else if (option == "skyview" || option == "sv")
@ -389,264 +554,64 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri
} }
else else
{ {
std::cout << "Unknown skyview flag: " << value << std::endl; out << "Unknown skyview flag: " << value << std::endl;
}
}
else if (option == "all" || option == "a")
{
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;
}
} }
found = true;
} }
else else
{ {
std::cout << "Unknown option: '" << option << "'" << std::endl; out << "Unknown option: '" << option << "'" << std::endl;
} }
return found; return found;
} }
void help( std::ostream & out, const std::string &option) command_result executePaintJob(color_ostream &out)
{ {
if (option.empty()) if (paint.empty())
{ {
out << "Commands:" << std::endl out.printerr("Set the paint first.\n");
<< " 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 : set range brush" << std::endl
<< " block : set block brush" << std::endl
<< " column : set column brush" << std::endl
<< std::endl
<< "Filter/paint options:" << std::endl
<< " 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
<< " 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
<< "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;
}
}
CommandHistory tiletypes_hist;
command_result df_tiletypes (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("tiletypes");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
tiletypes_hist.load("tiletypes.history");
commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
tiletypes_hist.save("tiletypes.history");
return CR_OK; return CR_OK;
} }
command_result df_tiletypes (color_ostream &out, vector <string> & parameters) CoreSuspender suspend;
{
uint32_t x_max = 0, y_max = 0, z_max = 0; uint32_t x_max = 0, y_max = 0, z_max = 0;
int32_t x = 0, y = 0, z = 0; int32_t x = 0, y = 0, z = 0;
for(size_t i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
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"
);
return CR_OK;
}
}
if(!out.is_console())
return CR_FAILURE;
Console &con = static_cast<Console&>(out);
TileType filter, paint;
Brush *brush = new RectangleBrush(1,1);
bool end = false;
std::string brushname = "point";
int width = 1, height = 1, z_levels = 1;
con << "Welcome to the tiletype tool.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl;
con.printerr("THIS TOOL CAN BE DANGEROUS. YOU'VE BEEN WARNED.\n");
while (!end)
{
con << "Filter: " << filter << std::endl
<< "Paint: " << paint << std::endl
<< "Brush: " << brushname << std::endl;
std::string input = "";
std::string command = "";
std::string option = "";
std::string value = "";
con.lineedit("tiletypes> ",input,tiletypes_hist);
tiletypes_hist.add(input);
std::istringstream ss(input);
ss >> command >> option >> value;
tolower(command);
tolower(option);
if (command == "help" || command == "?")
{
help(con,option);
}
else if (command == "quit" || command == "q")
{
end = true;
}
else if (command == "filter" || command == "f")
{
processTileType(filter, option, value);
}
else if (command == "paint" || (command == "p" && !option.empty()))
{
processTileType(paint, option, value);
}
else if (command == "point" || command == "p")
{
delete brush;
brushname = "point";
brush = new RectangleBrush(1,1);
}
else if (command == "range" || command == "r")
{
std::stringstream ss;
CommandHistory hist;
ss << "Set range width <" << width << "> ";
con.lineedit(ss.str(),command,hist);
width = command == "" ? width : toint(command);
if (width < 1) width = 1;
ss.str("");
ss << "Set range height <" << height << "> ";
con.lineedit(ss.str(),command,hist);
height = command == "" ? height : toint(command);
if (height < 1) height = 1;
ss.str("");
ss << "Set range z-levels <" << z_levels << "> ";
con.lineedit(ss.str(),command,hist);
z_levels = command == "" ? z_levels : toint(command);
if (z_levels < 1) z_levels = 1;
delete brush;
if (width == 1 && height == 1 && z_levels == 1)
{
brushname = "point";
}
else
{
brushname = "range";
}
brush = new RectangleBrush(width, height, z_levels, 0, 0, 0);
}
else if (command == "block")
{
delete brush;
brushname = "block";
brush = new BlockBrush();
}
else if (command == "column")
{
delete brush;
brushname = "column";
brush = new ColumnBrush();
}
else if (command.empty())
{
if (paint.empty())
{
con.printerr("Set the paint first.\n");
continue;
}
CoreSuspender suspend;
if (!Maps::IsValid()) if (!Maps::IsValid())
{ {
con.printerr("Map is not available!\n"); out.printerr("Map is not available!\n");
return CR_FAILURE; return CR_FAILURE;
} }
Maps::getSize(x_max, y_max, z_max); Maps::getSize(x_max, y_max, z_max);
if (!Gui::getCursorCoords(x,y,z)) if (!Gui::getCursorCoords(x,y,z))
{ {
con.printerr("Can't get cursor coords! Make sure you have a cursor active in DF.\n"); out.printerr("Can't get cursor coords! Make sure you have a cursor active in DF.\n");
return CR_FAILURE; return CR_FAILURE;
} }
con.print("Cursor coords: (%d, %d, %d)\n",x,y,z); out.print("Cursor coords: (%d, %d, %d)\n", x, y, z);
DFHack::DFCoord cursor(x,y,z); DFHack::DFCoord cursor(x,y,z);
MapExtras::MapCache map; MapExtras::MapCache map;
coord_vec all_tiles = brush->points(map, cursor); coord_vec all_tiles = brush->points(map, cursor);
con.print("working...\n"); out.print("working...\n");
for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter) for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter)
{ {
@ -660,7 +625,7 @@ command_result df_tiletypes (color_ostream &out, vector <string> & parameters)
|| (filter.dig > -1 && (filter.dig != 0) != (des.bits.dig != tile_dig_designation::No)) || (filter.dig > -1 && (filter.dig != 0) != (des.bits.dig != tile_dig_designation::No))
) )
{ {
continue; return CR_OK;
} }
df::tiletype_shape shape = paint.shape; df::tiletype_shape shape = paint.shape;
@ -706,13 +671,15 @@ command_result df_tiletypes (color_ostream &out, vector <string> & parameters)
*/ */
// Remove direction from directionless tiles // Remove direction from directionless tiles
DFHack::TileDirection direction = tileDirection(source); DFHack::TileDirection direction = tileDirection(source);
if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH))) { if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH)))
{
direction.whole = 0; direction.whole = 0;
} }
df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction); df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction);
// hack for empty space // 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) { if (shape == tiletype_shape::EMPTY && material == tiletype_material::AIR && variant == tiletype_variant::VAR_1 && special == tiletype_special::NORMAL && direction.whole == 0)
{
type = tiletype::OpenSpace; type = tiletype::OpenSpace;
} }
// make sure it's not invalid // make sure it's not invalid
@ -756,13 +723,217 @@ command_result df_tiletypes (color_ostream &out, vector <string> & parameters)
if (map.WriteAll()) if (map.WriteAll())
{ {
con.print("OK\n"); out.print("OK\n");
} }
else else
{ {
con.printerr("Something failed horribly! RUN!\n"); out.printerr("Something failed horribly! RUN!\n");
return CR_FAILURE;
}
}
command_result processCommand(color_ostream &out, std::vector<std::string> &commands, int start, int end, bool & endLoop, bool hasConsole = false)
{
if (commands.size() == start)
{
return executePaintJob(out);
}
std::ostringstream ss_o;
int loc = start;
std::string command = commands[loc++];
tolower(command);
if (command == "help" || command == "?")
{
help(out, commands, loc, end);
}
else if (command == "quit" || command == "q")
{
endLoop = true;
}
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")
{
int width = 0, height = 0, z_levels = 0;
if (commands.size() > loc + 1)
{
width = toint(commands[loc++]);
height = toint(commands[loc++]);
if (commands.size() > loc) {
z_levels = toint(commands[loc++]);
}
}
if (width < 1 || height < 1) {
if (hasConsole) {
Console &con = static_cast<Console&>(out);
CommandHistory hist;
ss_o << "Set range width <" << width << "> ";
con.lineedit(ss_o.str(),command,hist);
width = command == "" ? width : toint(command);
ss_o.str("");
ss_o << "Set range height <" << height << "> ";
con.lineedit(ss_o.str(),command,hist);
height = command == "" ? height : toint(command);
ss_o.str("");
ss_o << "Set range z-levels <" << z_levels << "> ";
con.lineedit(ss_o.str(),command,hist);
z_levels = command == "" ? z_levels : toint(command);
} else {
return CR_WRONG_USAGE;
}
}
if (width < 1) width = 1;
if (height < 1) height = 1;
if (z_levels < 1) z_levels = 1;
delete brush;
brush = new RectangleBrush(width, height, z_levels, 0, 0, 0);
}
else if (command == "block")
{
delete brush;
brush = new BlockBrush();
}
else if (command == "column")
{
delete brush;
brush = new ColumnBrush();
}
else if (command == "run" || command.empty())
{
executePaintJob(out);
}
return CR_OK;
}
command_result df_tiletypes (color_ostream &out_, vector <string> & parameters)
{
for(size_t i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
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"
);
return CR_OK;
}
}
if(!out_.is_console())
return CR_FAILURE;
Console &out = static_cast<Console&>(out_);
std::vector<std::string> commands;
bool end = false;
out << "Welcome to the tiletype tool.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl;
out.printerr("THIS TOOL CAN BE DANGEROUS. YOU'VE BEEN WARNED.\n");
while (!end)
{
printState(out);
std::string input = "";
if (out.lineedit("tiletypes> ",input,tiletypes_hist) == -1)
return CR_FAILURE;
commands.clear();
Core::cheap_tokenise(input, commands);
command_result ret = processCommand(out, commands, 0, commands.size(), end, true);
if (ret != CR_OK)
{
return ret;
}
}
return CR_OK;
}
command_result df_tiletypes_command (color_ostream &out, vector <string> & parameters)
{
bool dummy;
int start = 0, end = 0;
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;
} }
end++;
start = end;
} else {
end++;
} }
} }
return CR_OK; return CR_OK;
} }
command_result df_tiletypes_here (color_ostream &out, vector <string> & parameters)
{
for(size_t i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
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 CR_OK;
}
}
out.print("Run tiletypes-here with these parameters: ");
printState(out);
return executePaintJob(out);
}
command_result df_tiletypes_here_point (color_ostream &out, vector <string> & parameters)
{
for(size_t i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
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 CR_OK;
}
}
Brush *old = brush;
brush = new RectangleBrush(1, 1);
out.print("Run tiletypes-here with these parameters: ");
printState(out);
command_result rv = executePaintJob(out);
delete brush;
brush = old;
return rv;
}