diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index b078b48fd..6df530a92 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -101,17 +101,36 @@ static const char *modify_mode_name[] = { "+", ".", "-", NULL }; +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 + struct OperationMode { BrushType brush; PaintMode paint; ModifyMode flowmode; ModifyMode setmode; + PermaflowMode permaflow; unsigned int amount; df::coord size; OperationMode() : brush(B_POINT), paint(P_MAGMA), - flowmode(M_INC), setmode(M_KEEP), amount(7), + flowmode(M_INC), setmode(M_KEEP), permaflow(PF_KEEP), amount(7), size(1,1,1) {} } cur_mode; @@ -119,6 +138,17 @@ struct OperationMode { command_result df_liquids_execute(color_ostream &out); command_result df_liquids_execute(color_ostream &out, OperationMode &mode, df::coord pos); +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] + << "]"; +} + command_result df_liquids (color_ostream &out_, vector & parameters) { if(!out_.is_console()) @@ -154,11 +184,8 @@ command_result df_liquids (color_ostream &out_, vector & parameters) string input = ""; std::stringstream str; - 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] << "]#"; + print_prompt(str, cur_mode); + str << "# "; if(out.lineedit(str.str(),input,liquids_hist) == -1) return CR_FAILURE; liquids_hist.add(input); @@ -185,6 +212,10 @@ command_result df_liquids (color_ostream &out_, vector & parameters) << "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 + << "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 << "0-7 - set liquid amount" << endl << "Brush:" << endl << "point - single tile [p]" << endl @@ -297,6 +328,20 @@ command_result df_liquids (color_ostream &out_, vector & parameters) { cur_mode.setmode = M_KEEP; } + 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; + } // blah blah, bad code, bite me. else if(command == "0") cur_mode.amount = 0; @@ -339,11 +384,8 @@ command_result df_liquids_here (color_ostream &out, vector & parameters } out.print("Run liquids-here with these parameters: "); - 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"; + print_prompt(out, cur_mode); + out << endl; return df_liquids_execute(out); } @@ -489,6 +531,7 @@ command_result df_liquids_execute(color_ostream &out, OperationMode &cur_mode, d iter ++; continue; } + auto raw_block = block->getRaw(); df::tile_designation des = mcache.designationAt(current); df::tiletype tt = mcache.tiletypeAt(current); // don't put liquids into places where they don't belong... @@ -548,6 +591,12 @@ command_result df_liquids_execute(color_ostream &out, OperationMode &cur_mode, d // request flow engine updates block->enableBlockUpdates(new_amount != old_amount, new_liquid != old_liquid); } + 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; + } seen_blocks.insert(block); iter++; } @@ -593,7 +642,7 @@ static int paint(lua_State *L) df::coord pos; OperationMode mode; - lua_settop(L, 7); + lua_settop(L, 8); Lua::CheckDFAssign(L, &pos, 1); if (!pos.isValid()) luaL_argerror(L, 1, "invalid cursor position"); @@ -606,6 +655,7 @@ static int paint(lua_State *L) 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); + mode.permaflow = (PermaflowMode)luaL_checkoption(L, 8, ".", permaflow_name); lua_pushboolean(L, df_liquids_execute(*Lua::GetOutput(L), mode, pos)); return 1; diff --git a/scripts/gui/liquids.lua b/scripts/gui/liquids.lua index 27df49e9a..869cac908 100644 --- a/scripts/gui/liquids.lua +++ b/scripts/gui/liquids.lua @@ -16,12 +16,12 @@ local brushes = { } local paints = { - { tag = 'water', caption = 'Water', liquid = true, key = 'w' }, - { tag = 'magma', caption = 'Magma', liquid = true, key = 'l' }, + { tag = 'water', caption = 'Water', liquid = true, flow = true, key = 'w' }, + { tag = 'magma', caption = 'Magma', liquid = true, flow = 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 = 'flowbits', caption = 'Flow Updates', flow = true }, { tag = 'wclean', caption = 'Clean Salt/Stagnant' }, } @@ -37,6 +37,19 @@ local setmode = { { tag = '-', caption = 'Only Decrease' }, } +local permaflows = { + { tag = '.', caption = "Keep Permaflow" }, + { tag = '-', caption = 'Remove Permaflow' }, + { tag = 'N', caption = 'Set Permaflow N' }, + { tag = 'S', caption = 'Set Permaflow S' }, + { tag = 'E', caption = 'Set Permaflow E' }, + { tag = 'W', caption = 'Set Permaflow W' }, + { tag = 'NE', caption = 'Set Permaflow NE' }, + { tag = 'NW', caption = 'Set Permaflow NW' }, + { tag = 'SE', caption = 'Set Permaflow SE' }, + { tag = 'SW', caption = 'Set Permaflow SW' }, +} + Toggle = defclass(Toggle) function Toggle:init(items) @@ -80,6 +93,7 @@ function LiquidsUI:init() paint = mkinstance(Toggle):init(paints), flow = mkinstance(Toggle):init(flowbits), set = mkinstance(Toggle):init(setmode), + permaflow = mkinstance(Toggle):init(permaflows), amount = 7, } guidm.MenuOverlay.init(self) @@ -90,15 +104,8 @@ 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) +function render_liquid(dc, block, x, y) + local dsgn = block.designation[x%16][y%16] if dsgn.flow_size > 0 then if dsgn.liquid_type == df.tile_liquid.Magma then @@ -111,7 +118,51 @@ function LiquidsUI:onRenderBody(dc) end dc:string(" ["..dsgn.flow_size.."/7]") else - dc:string('No Liquid', COLOR_DARKGREY) + dc:string('No Liquid') + end +end + +local permaflow_abbr = { + north = 'N', south = 'S', east = 'E', west = 'W', + northeast = 'NE', northwest = 'NW', southeast = 'SE', southwest = 'SW' +} + +function render_flow_state(dc, block, x, y) + local flow = block.liquid_flow[x%16][y%16] + + if block.flags.update_liquid then + dc:string("Updating", COLOR_GREEN) + else + dc:string("Static") + end + dc:string(", ") + if flow.perm_flow_dir ~= 0 then + local tag = df.tile_liquid_flow_dir[flow.perm_flow_dir] + dc:string("Permaflow "..(permaflow_abbr[tag] or tag), COLOR_CYAN) + elseif flow.temp_flow_timer > 0 then + dc:string("Flowing "..flow.temp_flow_timer, COLOR_GREEN) + else + dc:string("No Flow") + end +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) + + if block then + local x, y = pos2xyz(cursor) + local tile = block.tiletype[x%16][y%16] + + dc:seek(2,3):string(df.tiletype.attrs[tile].caption, COLOR_CYAN) + dc:newline(2):pen(COLOR_DARKGREY) + render_liquid(dc, block, x, y) + dc:newline(2):pen(COLOR_DARKGREY) + render_flow_state(dc, block, x, y) + else + dc:seek(2,3):string("No map data", COLOR_RED):advance(0,2) end dc:newline():pen(COLOR_GREY) @@ -121,10 +172,10 @@ function LiquidsUI:onRenderBody(dc) dc:newline(1):string("p", COLOR_LIGHTGREEN):string(": ") self.paint:render(dc) - local liquid = self.paint:get().liquid + local paint = self.paint:get() dc:newline() - if liquid then + if paint.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(": ") @@ -133,8 +184,15 @@ function LiquidsUI:onRenderBody(dc) dc:advance(0,2) end - dc:newline():newline(1):string("f", COLOR_LIGHTGREEN):string(": ") - self.flow:render(dc) + dc:newline() + if paint.flow then + dc:newline(1):string("f", COLOR_LIGHTGREEN):string(": ") + self.flow:render(dc) + dc:newline(1):string("r", COLOR_LIGHTGREEN):string(": ") + self.permaflow:render(dc) + else + dc:advance(0,2) + end dc:newline():newline(1):pen(COLOR_WHITE) dc:string("Esc", COLOR_LIGHTGREEN):string(": Back, ") @@ -142,7 +200,8 @@ function LiquidsUI:onRenderBody(dc) end function LiquidsUI:onInput(keys) - local liquid = self.paint:get().liquid + local paint = self.paint:get() + local liquid = paint.liquid if keys.CUSTOM_B then self.brush:step() elseif keys.CUSTOM_P then @@ -153,8 +212,10 @@ function LiquidsUI:onInput(keys) self.amount = math.min(7, self.amount+1) elseif liquid and keys.CUSTOM_S then self.set:step() - elseif keys.CUSTOM_F then + elseif paint.flow and keys.CUSTOM_F then self.flow:step() + elseif paint.flow and keys.CUSTOM_R then + self.permaflow:step() elseif keys.LEAVESCREEN then if guidm.getSelection() then guidm.clearSelection() @@ -182,7 +243,8 @@ function LiquidsUI:onInput(keys) cursor, self.brush:get().tag, self.paint:get().tag, self.amount, size, - self.set:get().tag, self.flow:get().tag + self.set:get().tag, self.flow:get().tag, + self.permaflow:get().tag ) elseif self:propagateMoveKeys(keys) then return