327 lines
9.6 KiB
Lua
327 lines
9.6 KiB
Lua
-- Interface front-end for liquids plugin.
|
|
--[[=begin
|
|
|
|
gui/liquids
|
|
===========
|
|
To use, bind to a key (the example config uses Alt-L) and activate in the :kbd:`k` mode.
|
|
|
|
.. image:: /docs/images/liquids.png
|
|
|
|
This script is a gui front-end to `liquids` and works similarly,
|
|
allowing you to add or remove water & magma, and create obsidian walls & floors.
|
|
|
|
.. warning::
|
|
|
|
There is **no undo support**. Bugs in this plugin have been
|
|
known to create pathfinding problems and heat traps.
|
|
|
|
The :kbd:`b` key changes how the affected area is selected. The default :guilabel:`Rectangle`
|
|
mode works by selecting two corners like any ordinary designation. The :kbd:`p`
|
|
key chooses between adding water, magma, obsidian walls & floors, or just
|
|
tweaking flags.
|
|
|
|
When painting liquids, it is possible to select the desired level with :kbd:`+`:kbd:`-`,
|
|
and choose between setting it exactly, only increasing or only decreasing
|
|
with :kbd:`s`.
|
|
|
|
In addition, :kbd:`f` allows disabling or enabling the flowing water computations
|
|
for an area, and :kbd:`r` operates on the "permanent flow" property that makes
|
|
rivers power water wheels even when full and technically not flowing.
|
|
|
|
After setting up the desired operations using the described keys, use :kbd:`Enter` to apply them.
|
|
|
|
=end]]
|
|
local utils = require 'utils'
|
|
local gui = require 'gui'
|
|
local guidm = require 'gui.dwarfmode'
|
|
local dlg = require 'gui.dialogs'
|
|
|
|
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, flow = true, key = 'D_LOOK_ARENA_WATER' },
|
|
{ tag = 'magma', caption = 'Magma', liquid = true, flow = true, key = 'D_LOOK_ARENA_MAGMA' },
|
|
{ tag = 'obsidian', caption = 'Obsidian Wall' },
|
|
{ tag = 'obsidian_floor', caption = 'Obsidian Floor' },
|
|
{ tag = 'riversource', caption = 'River Source' },
|
|
{ tag = 'flowbits', caption = 'Flow Updates', flow = true },
|
|
{ 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' },
|
|
}
|
|
|
|
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)
|
|
|
|
Toggle.ATTRS{ items = {}, selected = 1 }
|
|
|
|
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(" ("):key(item.key):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:assign{
|
|
brush = Toggle{ items = brushes },
|
|
paint = Toggle{ items = paints },
|
|
flow = Toggle{ items = flowbits },
|
|
set = Toggle{ items = setmode },
|
|
permaflow = Toggle{ items = permaflows },
|
|
amount = 7,
|
|
}
|
|
end
|
|
|
|
function LiquidsUI:onDestroy()
|
|
guidm.clearSelection()
|
|
end
|
|
|
|
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
|
|
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')
|
|
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)
|
|
|
|
dc:newline(1):key('CUSTOM_B'):string(": ")
|
|
self.brush:render(dc)
|
|
dc:newline(1):key('CUSTOM_P'):string(": ")
|
|
self.paint:render(dc)
|
|
|
|
local paint = self.paint:get()
|
|
|
|
dc:newline()
|
|
if paint.liquid then
|
|
dc:newline(1):string("Amount: "..self.amount)
|
|
dc:advance(1):string("("):key('SECONDSCROLL_UP'):key('SECONDSCROLL_DOWN'):string(")")
|
|
dc:newline(3):key('CUSTOM_S'):string(": ")
|
|
self.set:render(dc)
|
|
else
|
|
dc:advance(0,2)
|
|
end
|
|
|
|
dc:newline()
|
|
if paint.flow then
|
|
dc:newline(1):key('CUSTOM_F'):string(": ")
|
|
self.flow:render(dc)
|
|
dc:newline(1):key('CUSTOM_R'):string(": ")
|
|
self.permaflow:render(dc)
|
|
else
|
|
dc:advance(0,2)
|
|
end
|
|
|
|
dc:newline():newline(1):pen(COLOR_WHITE)
|
|
dc:key('LEAVESCREEN'):string(": Back, ")
|
|
dc:key('SELECT'):string(": Paint")
|
|
end
|
|
|
|
function ensure_blocks(cursor, size, cb)
|
|
size = size or xyz2pos(1,1,1)
|
|
local cx,cy,cz = pos2xyz(cursor)
|
|
local all = true
|
|
for x=1,size.x or 1,16 do
|
|
for y=1,size.y or 1,16 do
|
|
for z=1,size.z do
|
|
if not dfhack.maps.getTileBlock(cx+x-1, cy+y-1, cz+z-1) then
|
|
all = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if all then
|
|
cb()
|
|
return
|
|
end
|
|
dlg.showYesNoPrompt(
|
|
'Instantiate Blocks',
|
|
'Not all map blocks are allocated - instantiate?\n\nWarning: new untested feature.',
|
|
COLOR_YELLOW,
|
|
function()
|
|
for x=1,size.x or 1,16 do
|
|
for y=1,size.y or 1,16 do
|
|
for z=1,size.z do
|
|
dfhack.maps.ensureTileBlock(cx+x-1, cy+y-1, cz+z-1)
|
|
end
|
|
end
|
|
end
|
|
cb()
|
|
end,
|
|
function()
|
|
cb()
|
|
end
|
|
)
|
|
end
|
|
|
|
function LiquidsUI:onInput(keys)
|
|
local paint = self.paint:get()
|
|
local liquid = paint.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 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()
|
|
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
|
|
local cb = curry(
|
|
liquids.paint,
|
|
cursor,
|
|
self.brush:get().tag, self.paint:get().tag,
|
|
self.amount, size,
|
|
self.set:get().tag, self.flow:get().tag,
|
|
self.permaflow:get().tag
|
|
)
|
|
ensure_blocks(cursor, size, cb)
|
|
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 = LiquidsUI()
|
|
list:show()
|