summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dfhack.init-example3
-rw-r--r--library/include/modules/Gui.h3
-rw-r--r--library/lua/gui.lua5
-rw-r--r--library/lua/gui/dwarfmode.lua52
-rw-r--r--library/modules/Gui.cpp17
-rw-r--r--plugins/liquids.cpp328
-rw-r--r--plugins/lua/liquids.lua11
-rw-r--r--scripts/gui/liquids.lua201
8 files changed, 491 insertions, 129 deletions
diff --git a/dfhack.init-example b/dfhack.init-example
index c9408e37..552b2b3a 100644
--- a/dfhack.init-example
+++ b/dfhack.init-example
@@ -48,3 +48,6 @@ keybinding add Ctrl-M@dwarfmode/QueryBuilding/Some gui/mechanisms
# browse rooms of same owner
keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list.work
+
+# interface for the liquids plugin
+keybinding add Alt-L@dwarfmode/LookAround gui/liquids
diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h
index 273d84ce..58f22241 100644
--- a/library/include/modules/Gui.h
+++ b/library/include/modules/Gui.h
@@ -97,6 +97,9 @@ namespace DFHack
/*
* Cursor and window coords
*/
+ DFHACK_EXPORT df::coord getViewportPos();
+ DFHACK_EXPORT df::coord getCursorPos();
+
DFHACK_EXPORT bool getViewCoords (int32_t &x, int32_t &y, int32_t &z);
DFHACK_EXPORT bool setViewCoords (const int32_t x, const int32_t y, const int32_t z);
diff --git a/library/lua/gui.lua b/library/lua/gui.lua
index ac032166..9e189ea1 100644
--- a/library/lua/gui.lua
+++ b/library/lua/gui.lua
@@ -18,7 +18,7 @@ function simulateInput(screen,...)
error('Invalid keycode: '..arg)
end
end
- if type(arg) == 'number' then
+ if type(kv) == 'number' then
keys[#keys+1] = kv
end
end
@@ -277,6 +277,9 @@ end
function Screen:onDismiss()
end
+function Screen:onDestroy()
+end
+
function Screen:onResize(w,h)
self:updateLayout()
end
diff --git a/library/lua/gui/dwarfmode.lua b/library/lua/gui/dwarfmode.lua
index c1a8bcb9..1f7ae1b0 100644
--- a/library/lua/gui/dwarfmode.lua
+++ b/library/lua/gui/dwarfmode.lua
@@ -6,6 +6,9 @@ local gui = require('gui')
local utils = require('utils')
local dscreen = dfhack.screen
+
+local g_cursor = df.global.cursor
+local g_sel_rect = df.global.selection_rect
local world_map = df.global.world.map
AREA_MAP_WIDTH = 23
@@ -43,8 +46,8 @@ function getPanelLayout()
end
function getCursorPos()
- if df.global.cursor.x ~= -30000 then
- return copyall(df.global.cursor)
+ if g_cursor ~= -30000 then
+ return copyall(g_cursor)
end
end
@@ -56,6 +59,51 @@ function clearCursorPos()
df.global.cursor = xyz2pos(nil)
end
+function getSelection()
+ local p1, p2
+ if g_sel_rect.start_x ~= -30000 then
+ p1 = xyz2pos(g_sel_rect.start_x, g_sel_rect.start_y, g_sel_rect.start_z)
+ end
+ if g_sel_rect.end_x ~= -30000 then
+ p2 = xyz2pos(g_sel_rect.end_x, g_sel_rect.end_y, g_sel_rect.end_z)
+ end
+ return p1, p2
+end
+
+function setSelectionStart(pos)
+ g_sel_rect.start_x = pos.x
+ g_sel_rect.start_y = pos.y
+ g_sel_rect.start_z = pos.z
+end
+
+function setSelectionEnd(pos)
+ g_sel_rect.end_x = pos.x
+ g_sel_rect.end_y = pos.y
+ g_sel_rect.end_z = pos.z
+end
+
+function clearSelection()
+ g_sel_rect.start_x = -30000
+ g_sel_rect.start_y = -30000
+ g_sel_rect.start_z = -30000
+ g_sel_rect.end_x = -30000
+ g_sel_rect.end_y = -30000
+ g_sel_rect.end_z = -30000
+end
+
+function getSelectionRange(p1, p2)
+ local r1 = xyz2pos(
+ math.min(p1.x, p2.x), math.min(p1.y, p2.y), math.min(p1.z, p2.z)
+ )
+ local r2 = xyz2pos(
+ math.max(p1.x, p2.x), math.max(p1.y, p2.y), math.max(p1.z, p2.z)
+ )
+ local sz = xyz2pos(
+ r2.x - r1.x + 1, r2.y - r1.y + 1, r2.z - r1.z + 1
+ )
+ return r1, sz, r2
+end
+
Viewport = defclass(Viewport)
function Viewport.make(map,x,y,z)
diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp
index 91a17e99..0f28860b 100644
--- a/library/modules/Gui.cpp
+++ b/library/modules/Gui.cpp
@@ -998,6 +998,23 @@ df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)
return ws;
}
+df::coord Gui::getViewportPos()
+{
+ if (!df::global::window_x || !df::global::window_y || !df::global::window_z)
+ return df::coord(0,0,0);
+
+ return df::coord(*df::global::window_x, *df::global::window_y, *df::global::window_z);
+}
+
+df::coord Gui::getCursorPos()
+{
+ using df::global::cursor;
+ if (!cursor)
+ return df::coord();
+
+ return df::coord(cursor->x, cursor->y, cursor->z);
+}
+
bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z)
{
x = *df::global::window_x;
diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp
index b036e4fa..b078b48f 100644
--- a/plugins/liquids.cpp
+++ b/plugins/liquids.cpp
@@ -27,6 +27,7 @@
#include <set>
#include <cstdlib>
#include <sstream>
+#include <memory>
using std::vector;
using std::string;
using std::endl;
@@ -41,6 +42,7 @@ using std::set;
#include "modules/Gui.h"
#include "TileTypes.h"
#include "modules/MapCache.h"
+#include "LuaTools.h"
#include "Brushes.h"
using namespace MapExtras;
using namespace DFHack;
@@ -50,7 +52,6 @@ CommandHistory liquids_hist;
command_result df_liquids (color_ostream &out, vector <string> & parameters);
command_result df_liquids_here (color_ostream &out, vector <string> & parameters);
-command_result df_liquids_execute (color_ostream &out);
DFHACK_PLUGIN("liquids");
@@ -74,13 +75,49 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK;
}
-// static stuff to be remembered between sessions
-static string brushname = "point";
-static string mode="magma";
-static string flowmode="f+";
-static string _setmode ="s.";
-static unsigned int amount = 7;
-static int width = 1, height = 1, z_levels = 1;
+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
+};
+
+struct OperationMode {
+ BrushType brush;
+ PaintMode paint;
+ ModifyMode flowmode;
+ ModifyMode setmode;
+ unsigned int amount;
+ df::coord size;
+
+ OperationMode() :
+ brush(B_POINT), paint(P_MAGMA),
+ flowmode(M_INC), setmode(M_KEEP), amount(7),
+ 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);
command_result df_liquids (color_ostream &out_, vector <string> & parameters)
{
@@ -117,10 +154,11 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
string input = "";
std::stringstream str;
- str <<"[" << mode << ":" << brushname;
- if (brushname == "range")
- str << "(w" << width << ":h" << height << ":z" << z_levels << ")";
- str << ":" << amount << ":" << flowmode << ":" << _setmode << "]#";
+ 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] << "]#";
if(out.lineedit(str.str(),input,liquids_hist) == -1)
return CR_FAILURE;
liquids_hist.add(input);
@@ -168,38 +206,39 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
}
else if(command == "m")
{
- mode = "magma";
+ cur_mode.paint = P_MAGMA;
}
else if(command == "o")
{
- mode = "obsidian";
+ cur_mode.paint = P_OBSIDIAN;
}
else if(command == "of")
{
- mode = "obsidian_floor";
+ cur_mode.paint = P_OBSIDIAN_FLOOR;
}
else if(command == "w")
{
- mode = "water";
+ cur_mode.paint = P_WATER;
}
else if(command == "f")
{
- mode = "flowbits";
+ cur_mode.paint = P_FLOW_BITS;
}
else if(command == "rs")
{
- mode = "riversource";
+ cur_mode.paint = P_RIVER_SOURCE;
}
else if(command == "wclean")
{
- mode = "wclean";
+ cur_mode.paint = P_WCLEAN;
}
else if(command == "point" || command == "p")
{
- brushname = "point";
+ cur_mode.brush = B_POINT;
}
else if(command == "range" || command == "r")
{
+ int width, height, z_levels;
command_result res = parseRectangle(out, commands, 1, commands.size(),
width, height, z_levels);
if (res != CR_OK)
@@ -209,24 +248,26 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
if (width == 1 && height == 1 && z_levels == 1)
{
- brushname = "point";
+ cur_mode.brush = B_POINT;
+ cur_mode.size = df::coord(1, 1, 1);
}
else
{
- brushname = "range";
+ cur_mode.brush = B_RANGE;
+ cur_mode.size = df::coord(width, height, z_levels);
}
}
else if(command == "block")
{
- brushname = "block";
+ cur_mode.brush = B_BLOCK;
}
else if(command == "column")
{
- brushname = "column";
+ cur_mode.brush = B_COLUMN;
}
else if(command == "flood")
{
- brushname = "flood";
+ cur_mode.brush = B_FLOOD;
}
else if(command == "q")
{
@@ -234,45 +275,45 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
}
else if(command == "f+")
{
- flowmode = "f+";
+ cur_mode.flowmode = M_INC;
}
else if(command == "f-")
{
- flowmode = "f-";
+ cur_mode.flowmode = M_DEC;
}
else if(command == "f.")
{
- flowmode = "f.";
+ cur_mode.flowmode = M_KEEP;
}
else if(command == "s+")
{
- _setmode = "s+";
+ cur_mode.setmode = M_INC;
}
else if(command == "s-")
{
- _setmode = "s-";
+ cur_mode.setmode = M_DEC;
}
else if(command == "s.")
{
- _setmode = "s.";
+ cur_mode.setmode = M_KEEP;
}
// blah blah, bad code, bite me.
else if(command == "0")
- amount = 0;
+ cur_mode.amount = 0;
else if(command == "1")
- amount = 1;
+ cur_mode.amount = 1;
else if(command == "2")
- amount = 2;
+ cur_mode.amount = 2;
else if(command == "3")
- amount = 3;
+ cur_mode.amount = 3;
else if(command == "4")
- amount = 4;
+ cur_mode.amount = 4;
else if(command == "5")
- amount = 5;
+ cur_mode.amount = 5;
else if(command == "6")
- amount = 6;
+ cur_mode.amount = 6;
else if(command == "7")
- amount = 7;
+ cur_mode.amount = 7;
else if(command.empty())
{
df_liquids_execute(out);
@@ -298,78 +339,78 @@ command_result df_liquids_here (color_ostream &out, vector <string> & parameters
}
out.print("Run liquids-here with these parameters: ");
- out << "[" << mode << ":" << brushname;
- if (brushname == "range")
- out << "(w" << width << ":h" << height << ":z" << z_levels << ")";
- out << ":" << amount << ":" << flowmode << ":" << _setmode << "]\n";
+ out << "[" << paint_mode_name[cur_mode.paint] << ":" << brush_name[cur_mode.brush];
+ if (cur_mode.brush == B_RANGE)
+ out << "(w" << cur_mode.size.x << ":h" << cur_mode.size.y << ":z" << cur_mode.size.z << ")";
+ out << ":" << cur_mode.amount << ":f" << modify_mode_name[cur_mode.flowmode]
+ << ":" << modify_mode_name[cur_mode.setmode] << "]\n";
return df_liquids_execute(out);
}
command_result df_liquids_execute(color_ostream &out)
{
- // create brush type depending on old parameters
- Brush * brush;
+ CoreSuspender suspend;
- if (brushname == "point")
- {
- brush = new RectangleBrush(1,1,1,0,0,0);
- //width = 1;
- //height = 1;
- //z_levels = 1;
- }
- else if (brushname == "range")
+ auto cursor = Gui::getCursorPos();
+ if (!cursor.isValid())
{
- brush = new RectangleBrush(width,height,z_levels,0,0,0);
+ out.printerr("Can't get cursor coords! Make sure you have a cursor active in DF.\n");
+ return CR_WRONG_USAGE;
}
- else if(brushname == "block")
+
+ 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
+ Brush *brush;
+
+ switch (cur_mode.brush)
{
+ case B_POINT:
+ brush = new RectangleBrush(1,1,1,0,0,0);
+ break;
+ case B_RANGE:
+ brush = new RectangleBrush(cur_mode.size.x,cur_mode.size.y,cur_mode.size.z,0,0,0);
+ break;
+ case B_BLOCK:
brush = new BlockBrush();
- }
- else if(brushname == "column")
- {
+ break;
+ case B_COLUMN:
brush = new ColumnBrush();
- }
- else if(brushname == "flood")
- {
+ break;
+ case B_FLOOD:
brush = new FloodBrush(&Core::getInstance());
- }
- else
- {
+ break;
+ default:
// this should never happen!
out << "Old brushtype is invalid! Resetting to point brush.\n";
- brushname = "point";
- width = 1;
- height = 1;
- z_levels = 1;
- brush = new RectangleBrush(width,height,z_levels,0,0,0);
+ cur_mode.brush = B_POINT;
+ brush = new RectangleBrush(1,1,1,0,0,0);
}
- CoreSuspender suspend;
+ std::auto_ptr<Brush> brush_ref(brush);
- do
+ if (!Maps::IsValid())
{
- if (!Maps::IsValid())
- {
- out << "Can't see any DF map loaded." << endl;
- break;;
- }
- int32_t x,y,z;
- if(!Gui::getCursorCoords(x,y,z))
- {
- out << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
- break;
- }
- out << "cursor coords: " << x << "/" << y << "/" << z << endl;
- MapCache mcache;
- DFHack::DFCoord cursor(x,y,z);
- coord_vec all_tiles = brush->points(mcache,cursor);
- out << "working..." << endl;
+ out << "Can't see any DF map loaded." << endl;
+ return CR_FAILURE;
+ }
+
+ MapCache mcache;
+ coord_vec all_tiles = brush->points(mcache,cursor);
- // Force the game to recompute its walkability cache
- df::global::world->reindex_pathfinding = true;
+ // Force the game to recompute its walkability cache
+ df::global::world->reindex_pathfinding = true;
- if(mode == "obsidian")
+ switch (cur_mode.paint)
+ {
+ case P_OBSIDIAN:
{
coord_vec::iterator iter = all_tiles.begin();
while (iter != all_tiles.end())
@@ -383,8 +424,9 @@ command_result df_liquids_execute(color_ostream &out)
mcache.setDesignationAt(*iter, des);
iter ++;
}
+ break;
}
- if(mode == "obsidian_floor")
+ case P_OBSIDIAN_FLOOR:
{
coord_vec::iterator iter = all_tiles.begin();
while (iter != all_tiles.end())
@@ -392,8 +434,9 @@ command_result df_liquids_execute(color_ostream &out)
mcache.setTiletypeAt(*iter, findRandomVariant(tiletype::LavaFloor1));
iter ++;
}
+ break;
}
- else if(mode == "riversource")
+ case P_RIVER_SOURCE:
{
coord_vec::iterator iter = all_tiles.begin();
while (iter != all_tiles.end())
@@ -413,8 +456,9 @@ command_result df_liquids_execute(color_ostream &out)
iter++;
}
+ break;
}
- else if(mode=="wclean")
+ case P_WCLEAN:
{
coord_vec::iterator iter = all_tiles.begin();
while (iter != all_tiles.end())
@@ -426,8 +470,11 @@ command_result df_liquids_execute(color_ostream &out)
mcache.setDesignationAt(current,des);
iter++;
}
+ break;
}
- else if(mode== "magma" || mode== "water" || mode == "flowbits")
+ case P_MAGMA:
+ case P_WATER:
+ case P_FLOW_BITS:
{
set <Block *> seen_blocks;
coord_vec::iterator iter = all_tiles.begin();
@@ -450,30 +497,29 @@ command_result df_liquids_execute(color_ostream &out)
iter++;
continue;
}
- if(mode != "flowbits")
+ if(cur_mode.paint != P_FLOW_BITS)
{
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
- if(_setmode == "s.")
- {
- new_amount = amount;
- }
- else if(_setmode == "s+")
- {
- if(old_amount < amount)
- new_amount = amount;
- }
- else if(_setmode == "s-")
+ switch (cur_mode.setmode)
{
- if (old_amount > amount)
- new_amount = amount;
+ 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;
}
- if (mode == "magma")
+ if (cur_mode.paint == P_MAGMA)
new_liquid = tile_liquid::Magma;
- else if (mode == "water")
+ else if (cur_mode.paint == P_WATER)
new_liquid = tile_liquid::Water;
// Store new amount and type
des.bits.flow_size = new_amount;
@@ -508,34 +554,64 @@ command_result df_liquids_execute(color_ostream &out)
set <Block *>::iterator biter = seen_blocks.begin();
while (biter != seen_blocks.end())
{
- if(flowmode == "f+")
+ switch (cur_mode.flowmode)
{
+ case M_INC:
(*biter)->enableBlockUpdates(true);
- }
- else if(flowmode == "f-")
- {
+ break;
+ case M_DEC:
if (auto block = (*biter)->getRaw())
{
block->flags.bits.update_liquid = false;
block->flags.bits.update_liquid_twice = false;
}
- }
- else
- {
- auto bflags = (*biter)->BlockFlags();
- out << "flow bit 1 = " << bflags.bits.update_liquid << endl;
- out << "flow bit 2 = " << bflags.bits.update_liquid_twice << endl;
+ break;
+ case M_KEEP:
+ {
+ auto bflags = (*biter)->BlockFlags();
+ out << "flow bit 1 = " << bflags.bits.update_liquid << endl;
+ out << "flow bit 2 = " << bflags.bits.update_liquid_twice << endl;
+ }
}
biter ++;
}
+ break;
}
- if(mcache.WriteAll())
- out << "OK" << endl;
- else
- out << "Something failed horribly! RUN!" << endl;
- } while (0);
+ }
+
+ if(!mcache.WriteAll())
+ {
+ out << "Something failed horribly! RUN!" << endl;
+ return CR_FAILURE;
+ }
- // cleanup
- delete brush;
return CR_OK;
}
+
+static int paint(lua_State *L)
+{
+ df::coord pos;
+ OperationMode mode;
+
+ lua_settop(L, 7);
+ 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);
+
+ lua_pushboolean(L, df_liquids_execute(*Lua::GetOutput(L), mode, pos));
+ return 1;
+}
+
+DFHACK_PLUGIN_LUA_COMMANDS {
+ DFHACK_LUA_COMMAND(paint),
+ DFHACK_LUA_END
+};
diff --git a/plugins/lua/liquids.lua b/plugins/lua/liquids.lua
new file mode 100644
index 00000000..22ce4da3
--- /dev/null
+++ b/plugins/lua/liquids.lua
@@ -0,0 +1,11 @@
+local _ENV = mkmodule('plugins.liquids')
+
+--[[
+
+ Native functions:
+
+ * paint(pos,brush,paint,amount,size,setmode,flowmode)
+
+--]]
+
+return _ENV \ No newline at end of file
diff --git a/scripts/gui/liquids.lua b/scripts/gui/liquids.lua
new file mode 100644
index 00000000..27df49e9
--- /dev/null
+++ b/scripts/gui/liquids.lua
@@ -0,0 +1,201 @@
+-- Interface front-end for liquids plugin.
+
+local utils = require 'utils'
+local gui = require 'gui'
+local guidm = require 'gui.dwarfmode'
+
+local liquids = require('plugins.liquids')
+
+local sel_rect = df.global.selection_rect
+
+local brushes = {
+ { tag = 'range', caption = 'Rectangle', range = true },
+ { tag = 'block', caption = '16x16 block' },
+ { tag = 'column', caption = 'Column' },
+ { tag = 'flood', caption = 'Flood' },
+}
+
+local paints = {
+ { tag = 'water', caption = 'Water', liquid = true, key = 'w' },
+ { tag = 'magma', caption = 'Magma', liquid = true, key = 'l' },
+ { tag = 'obsidian', caption = 'Obsidian Wall' },
+ { tag = 'obsidian_floor', caption = 'Obsidian Floor' },
+ { tag = 'riversource', caption = 'River Source' },
+ { tag = 'flowbits', caption = 'Flow Updates' },
+ { tag = 'wclean', caption = 'Clean Salt/Stagnant' },
+}
+
+local flowbits = {
+ { tag = '+', caption = 'Enable Updates' },
+ { tag = '-', caption = 'Disable Updates' },
+ { tag = '.', caption = 'Keep Updates' },
+}
+
+local setmode = {
+ { tag = '.', caption = 'Set Exactly' },
+ { tag = '+', caption = 'Only Increase' },
+ { tag = '-', caption = 'Only Decrease' },
+}
+
+Toggle = defclass(Toggle)
+
+function Toggle:init(items)
+ self:init_fields{
+ items = items,
+ selected = 1
+ }
+ return self
+end
+
+function Toggle:get()
+ return self.items[self.selected]
+end
+
+function Toggle:render(dc)
+ local item = self:get()
+ if item then
+ dc:string(item.caption)
+ if item.key then
+ dc:string(" ("):string(item.key, COLOR_LIGHTGREEN):string(")")
+ end
+ else
+ dc:string('NONE', COLOR_RED)
+ end
+end
+
+function Toggle:step(delta)
+ if #self.items > 1 then
+ delta = delta or 1
+ self.selected = 1 + (self.selected + delta - 1) % #self.items
+ end
+end
+
+LiquidsUI = defclass(LiquidsUI, guidm.MenuOverlay)
+
+LiquidsUI.focus_path = 'liquids'
+
+function LiquidsUI:init()
+ self:init_fields{
+ brush = mkinstance(Toggle):init(brushes),
+ paint = mkinstance(Toggle):init(paints),
+ flow = mkinstance(Toggle):init(flowbits),
+ set = mkinstance(Toggle):init(setmode),
+ amount = 7,
+ }
+ guidm.MenuOverlay.init(self)
+ return self
+end
+
+function LiquidsUI:onDestroy()
+ guidm.clearSelection()
+end
+
+function LiquidsUI:onRenderBody(dc)
+ dc:clear():seek(1,1):string("Paint Liquids Cheat", COLOR_WHITE)
+
+ local cursor = guidm.getCursorPos()
+ local block = dfhack.maps.getTileBlock(cursor)
+ local tile = block.tiletype[cursor.x%16][cursor.y%16]
+ local dsgn = block.designation[cursor.x%16][cursor.y%16]
+
+ dc:seek(2,3):string(df.tiletype.attrs[tile].caption, COLOR_CYAN):newline(2)
+
+ if dsgn.flow_size > 0 then
+ if dsgn.liquid_type == df.tile_liquid.Magma then
+ dc:pen(COLOR_RED):string("Magma")
+ else
+ dc:pen(COLOR_BLUE)
+ if dsgn.water_stagnant then dc:string("Stagnant ") end
+ if dsgn.water_salt then dc:string("Salty ") end
+ dc:string("Water")
+ end
+ dc:string(" ["..dsgn.flow_size.."/7]")
+ else
+ dc:string('No Liquid', COLOR_DARKGREY)
+ end
+
+ dc:newline():pen(COLOR_GREY)
+
+ dc:newline(1):string("b", COLOR_LIGHTGREEN):string(": ")
+ self.brush:render(dc)
+ dc:newline(1):string("p", COLOR_LIGHTGREEN):string(": ")
+ self.paint:render(dc)
+
+ local liquid = self.paint:get().liquid
+
+ dc:newline()
+ if liquid then
+ dc:newline(1):string("Amount: "..self.amount)
+ dc:advance(1):string("("):string("-+", COLOR_LIGHTGREEN):string(")")
+ dc:newline(3):string("s", COLOR_LIGHTGREEN):string(": ")
+ self.set:render(dc)
+ else
+ dc:advance(0,2)
+ end
+
+ dc:newline():newline(1):string("f", COLOR_LIGHTGREEN):string(": ")
+ self.flow:render(dc)
+
+ dc:newline():newline(1):pen(COLOR_WHITE)
+ dc:string("Esc", COLOR_LIGHTGREEN):string(": Back, ")
+ dc:string("Enter", COLOR_LIGHTGREEN):string(": Paint")
+end
+
+function LiquidsUI:onInput(keys)
+ local liquid = self.paint:get().liquid
+ if keys.CUSTOM_B then
+ self.brush:step()
+ elseif keys.CUSTOM_P then
+ self.paint:step()
+ elseif liquid and keys.SECONDSCROLL_UP then
+ self.amount = math.max(0, self.amount-1)
+ elseif liquid and keys.SECONDSCROLL_DOWN then
+ self.amount = math.min(7, self.amount+1)
+ elseif liquid and keys.CUSTOM_S then
+ self.set:step()
+ elseif keys.CUSTOM_F then
+ self.flow:step()
+ elseif keys.LEAVESCREEN then
+ if guidm.getSelection() then
+ guidm.clearSelection()
+ return
+ end
+ self:dismiss()
+ self:sendInputToParent('CURSOR_DOWN_Z')
+ self:sendInputToParent('CURSOR_UP_Z')
+ elseif keys.SELECT then
+ local cursor = guidm.getCursorPos()
+ local sp = guidm.getSelection()
+ local size = nil
+ if self.brush:get().range then
+ if not sp then
+ guidm.setSelectionStart(cursor)
+ return
+ else
+ guidm.clearSelection()
+ cursor, size = guidm.getSelectionRange(cursor, sp)
+ end
+ else
+ guidm.clearSelection()
+ end
+ liquids.paint(
+ cursor,
+ self.brush:get().tag, self.paint:get().tag,
+ self.amount, size,
+ self.set:get().tag, self.flow:get().tag
+ )
+ elseif self:propagateMoveKeys(keys) then
+ return
+ elseif keys.D_LOOK_ARENA_WATER then
+ self.paint.selected = 1
+ elseif keys.D_LOOK_ARENA_MAGMA then
+ self.paint.selected = 2
+ end
+end
+
+if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/LookAround') then
+ qerror("This script requires the main dwarfmode view in 'k' mode")
+end
+
+local list = mkinstance(LiquidsUI):init()
+list:show()