From e32eff717cb90622d15b2a7b08425ee4c542aa83 Mon Sep 17 00:00:00 2001 From: MarioWizard119 <54223477+MarioWizard119@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:36:07 -0600 Subject: [PATCH] quantum.lua update touch ups Rejoice for it is finished (i think) --- gui/quantum.lua | 484 ++++++++++++++++++++---------------------------- 1 file changed, 201 insertions(+), 283 deletions(-) diff --git a/gui/quantum.lua b/gui/quantum.lua index b8d93d2087..2a3fac8979 100644 --- a/gui/quantum.lua +++ b/gui/quantum.lua @@ -11,262 +11,218 @@ local quickfort = reqscript('quickfort') local quickfort_command = reqscript('internal/quickfort/command') local quickfort_orders = reqscript('internal/quickfort/orders') -QuantumUI = defclass(QuantumUI, guidm.MenuOverlay) + +-- UI Layout +QuantumUI = defclass(QuantumUI, gui.ZScreen) QuantumUI.ATTRS { - frame_inset=1, focus_path='quantum', - sidebar_mode=df.ui_sidebar_mode.LookAround, + pass_movement_keys=true, + pass_mouse_clicks=false } -function QuantumUI:init() - local cart_count = #assign_minecarts.get_free_vehicles() +QuantumWin = defclass(QuantumWin, widgets.Window) +QuantumWin.ATTRS { + frame_title = 'Quantum Stockpile', + frame = { w=60, h=26 }, + resizable = true, + autoarrange_subviews=true +} - local main_panel = widgets.Panel{autoarrange_subviews=true, - autoarrange_gap=1} - main_panel:addviews{ - widgets.Label{text='Quantum'}, +function QuantumWin:init() + cart_count = #assign_minecarts.get_free_vehicles() + + self:addviews{ + widgets.Label{ + text='Quantum' + }, widgets.WrappedLabel{ text_to_wrap=self:callback('get_help_text'), - text_pen=COLOR_GREY}, - widgets.ResizingPanel{autoarrange_subviews=true, subviews={ - widgets.EditField{ - view_id='name', - key='CUSTOM_N', - on_char=self:callback('on_name_char'), - text=''}, - widgets.TooltipLabel{ - text_to_wrap='Give the quantum stockpile a custom name.', - show_tooltip=true}}}, - widgets.ResizingPanel{autoarrange_subviews=true, subviews={ - widgets.CycleHotkeyLabel{ - view_id='dir', - key='CUSTOM_D', - options={{label='North', value={y=-1}}, - {label='South', value={y=1}}, - {label='East', value={x=1}}, - {label='West', value={x=-1}}}}, - widgets.TooltipLabel{ - text_to_wrap='Set the dump direction of the quantum stop.', - show_tooltip=true}}}, - widgets.ResizingPanel{autoarrange_subviews=true, subviews={ - widgets.ToggleHotkeyLabel{ - view_id='refuse', - key='CUSTOM_R', - label='Allow refuse/corpses', - initial_option=false}, - widgets.TooltipLabel{ - text_to_wrap='Note that enabling refuse will cause clothes' .. + text_pen=COLOR_GREY + }, + widgets.HotkeyLabel{ + key='CUSTOM_Q', + label='Place QSP under cursor', + on_activate=self:callback('commit') + }, + widgets.Panel{autoarrange_subviews=true, + frame = { w=75, h=5 }, + resizable = true, + subviews={ + widgets.EditField{ + view_id='name', + key='CUSTOM_N', + on_char=self:callback('on_name_char'), + text='' + }, + widgets.TooltipLabel{ + text_to_wrap='Give the quantum stockpile a custom name.', + show_tooltip=true + } + } + }, + widgets.Panel{ + autoarrange_subviews=true, + frame = { w=75, h=5 }, + resizable = true, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='dir', + key='CUSTOM_D', + options={ + {label='North', value={y=-1}}, + {label='South', value={y=1}}, + {label='East', value={x=1}}, + {label='West', value={x=-1}} + } + }, + widgets.TooltipLabel{ + text_to_wrap='Set the dump direction of the quantum stop.', + show_tooltip=true + } + } + }, + widgets.Panel{ + autoarrange_subviews=true, + frame = { w=75, h=5 }, + resizable = true, + subviews={ + widgets.ToggleHotkeyLabel{ + view_id='refuse', + key='CUSTOM_R', + label='Allow refuse/corpses', + initial_option=false + }, + widgets.TooltipLabel{ + text_to_wrap='Note that enabling refuse will cause clothes' .. ' and armor in this stockpile to quickly rot away.', - show_tooltip=true}}}, + show_tooltip=true + } + } + }, widgets.WrappedLabel{ - text_to_wrap=('%d minecart%s available: %s will be %s'):format( + text_to_wrap=('%d minecart%s available: %s %s'):format( cart_count, cart_count == 1 and '' or 's', cart_count == 1 and 'it' or 'one', - cart_count > 0 and 'automatically assigned to the quantum route' - or 'ordered via the manager for you to assign later')}, + cart_count > 0 and 'will be automatically assigned to the quantum route' + or 'will be ordered for you to assign later') + }, widgets.HotkeyLabel{ key='LEAVESCREEN', label=self:callback('get_back_text'), - on_activate=self:callback('on_back')} + on_activate=self:callback('on_back') + } } +end - self:addviews{main_panel} +function QuantumUI:init() + self:addviews{QuantumWin{}} end -function QuantumUI:get_help_text() - if not self.feeder then - return 'Please select the feeder stockpile with the cursor or mouse.' +-- UI Functions +function QuantumWin:get_help_text() + if not dfhack.gui.getSelectedStockpile() then + return 'Please select the feeder stockpile with the mouse.' end return 'Please select the location of the new quantum stockpile with the' .. - ' cursor or mouse.' + ' mouse, then press "q" or left click' end -function QuantumUI:get_back_text() - if self.feeder then +function QuantumWin:get_back_text() + if + self.feeder + then return 'Cancel selection' - end + end return 'Back' end -function QuantumUI:on_back() - if self.feeder then - self.feeder = nil - self:updateLayout() - else - self:dismiss() - end +function QuantumWin:on_back() + self:dismiss() end -function QuantumUI:on_name_char(char, text) - return #text < 12 -end - -local function is_in_extents(bld, x, y) - local extents = bld.room.extents - if not extents then return true end -- building is solid - local yoff = (y - bld.y1) * (bld.x2 - bld.x1 + 1) - local xoff = x - bld.x1 - return extents[yoff+xoff] == 1 -end - -function QuantumUI:select_stockpile(pos) - local flags, occupancy = dfhack.maps.getTileFlags(pos) - if not flags or occupancy.building == 0 then return end - local bld = dfhack.buildings.findAtTile(pos) - if not bld or bld:getType() ~= df.building_type.Stockpile then return end - - local tiles = {} - - for x=bld.x1,bld.x2 do - for y=bld.y1,bld.y2 do - if is_in_extents(bld, x, y) then - ensure_key(ensure_key(tiles, bld.z), y)[x] = true - end - end - end - - self.feeder = bld - self.feeder_tiles = tiles - - self:updateLayout() -end - -function QuantumUI:render_feeder_overlay() - if not gui.blink_visible(1000) then return end - - local zlevel = self.feeder_tiles[df.global.window_z] - if not zlevel then return end - - local function get_feeder_overlay_char(pos) - return safe_index(zlevel, pos.y, pos.x) and 'X' - end - - self:renderMapOverlay(get_feeder_overlay_char, self.feeder) -end - -function QuantumUI:get_qsp_pos(cursor) - local offsets = self.subviews.dir:getOptionValue() - return { - x = cursor.x + (offsets.x or 0), - y = cursor.y + (offsets.y or 0), - z = cursor.z - } -end - -local function is_valid_pos(cursor, qsp_pos) - local stats = quickfort.apply_blueprint{mode='place', data='c', pos=qsp_pos, - dry_run=true} - local ok = stats.place_designated.value > 0 - - if ok then - stats = quickfort.apply_blueprint{mode='build', data='trackstop', - pos=cursor, dry_run=true} - ok = stats.build_designated.value > 0 - end - - return ok -end - -function QuantumUI:render_destination_overlay() - local cursor = guidm.getCursorPos() - local qsp_pos = self:get_qsp_pos(cursor) - local bounds = {x1=qsp_pos.x, x2=qsp_pos.x, y1=qsp_pos.y, y2=qsp_pos.y} - - local ok = is_valid_pos(cursor, qsp_pos) - - local function get_dest_overlay_char() - return 'X', ok and COLOR_GREEN or COLOR_RED - end - - self:renderMapOverlay(get_dest_overlay_char, bounds) +function QuantumUI:on_back() + self:dismiss() end -function QuantumUI:onRenderBody() - if not self.feeder then return end - - self:render_feeder_overlay() - self:render_destination_overlay() +function QuantumWin:on_name_char(char, text) + return #text < 12 end -function QuantumUI:onInput(keys) - if self:inputToSubviews(keys) then return true end - - self:propagateMoveKeys(keys) - - local pos = nil - if keys._MOUSE_L_DOWN then - pos = dfhack.gui.getMousePos() - if pos then - guidm.setCursorPos(pos) - end - elseif keys.SELECT then - pos = guidm.getCursorPos() - end - - if pos then - if not self.feeder then - self:select_stockpile(pos) - else - local qsp_pos = self:get_qsp_pos(pos) - if not is_valid_pos(pos, qsp_pos) then - return - end - - self:dismiss() - self:commit(pos, qsp_pos) - end - end -end +--UI Data Tables +qspOutputHor = { + ["North"]=0, + ["East"]=1, + ["South"]=0, + ["West"]=-1 +} -local function get_feeder_pos(feeder_tiles) - for z,rows in pairs(feeder_tiles) do - for y,row in pairs(rows) do - for x in pairs(row) do - return xyz2pos(x, y, z) - end - end - end -end +qspOutputVert = { + ["North"]=-1, + ["East"]=0, + ["South"]=1, + ["West"]=0 +} -local function get_moves(move, move_back, start_pos, end_pos, - move_to_greater_token, move_to_less_token) - if start_pos == end_pos then - return move, move_back - end - local diff = math.abs(start_pos - end_pos) - local move_to_greater_pattern = ('{%s %%d}'):format(move_to_greater_token) - local move_to_greater = move_to_greater_pattern:format(diff) - local move_to_less_pattern = ('{%s %%d}'):format(move_to_less_token) - local move_to_less = move_to_less_pattern:format(diff) - if start_pos < end_pos then - return move..move_to_greater, move_back..move_to_less - end - return move..move_to_less, move_back..move_to_greater -end +qspTrackstopDir = { + ["North"]='trackstopN', + ["East"]='trackstopE', + ["South"]='trackstopS', + ["West"]='trackstopW' +} -local function get_quantumstop_data(dump_pos, feeder_pos, name) - local move, move_back = get_moves('', '', dump_pos.z, feeder_pos.z, '<','>') - move, move_back = get_moves(move, move_back, dump_pos.y, feeder_pos.y, - 'Down', 'Up') - move, move_back = get_moves(move, move_back, dump_pos.x, feeder_pos.x, - 'Right', 'Left') +qspOutputType = { + [true]='ry', + [false]='c' +} - local quantumstop_name_part, quantum_name_part = '', '' - if name ~= '' then - quantumstop_name_part = (' name="%s quantum"'):format(name) - quantum_name_part = ('{givename name="%s dumper"}'):format(name) - end - return ('{quantumstop%s move="%s" move_back="%s"}%s') - :format(quantumstop_name_part, move, move_back, quantum_name_part) -end -local function get_quantum_data(name) - local name_part = '' - if name ~= '' then - name_part = (' name="%s"'):format(name) - end - return ('{quantum%s}'):format(name_part) +--Actually making the QSP +function QuantumWin:commit() + name = self.subviews.name.text + dump_dir = self.subviews.dir:getOptionLabel() + allow_refuse = self.subviews.refuse:getOptionValue() + input_id = dfhack.gui.getSelectedStockpile().id + output_hor = qspOutputHor[dump_dir] + output_vert = qspOutputVert[dump_dir] + output_type = qspOutputType[allow_refuse] + trackstop_dir = qspTrackstopDir[dump_dir] + if + name == '' + then + name = 'Unnamed QSP' + end + placed_output = output_type..'{name="'..name..'" quantum=true}:+all' + placed_trackstop = trackstop_dir..'{name="'..name..'" take_from='..input_id..'}' + + quickfort.apply_blueprint{ + mode='place', + pos=dfhack.gui.getMousePos(), + data={ + [0]={ + [output_vert]={[output_hor]=placed_output} + } + } + } + + quickfort.apply_blueprint{ + mode='build', + pos=dfhack.gui.getMousePos(), + data={ + [0]={ + [0]={[0]=placed_trackstop} + } + } + } + + if + cart_count == 0 + then + dfhack.run_command('workorder "{\"amount_left\":1,\"amount_total\":1,\"frequency\":\"OneTime\",\"id\":6,\"is_active\":false,\"is_validated\":true,\"item_subtype\":\"ITEM_TOOL_MINECART\",\"job\":\"MakeTool\",\"material_category\":[\"wood\"]}"') + end + + dfhack.run_command('assign-minecarts all') + self:updateLayout() end local function order_minecart(pos) @@ -275,80 +231,42 @@ local function order_minecart(pos) quickfort_orders.enqueue_additional_order(quickfort_ctx, 'wooden minecart') quickfort_orders.create_orders(quickfort_ctx) end +--Key Input +function QuantumWin:onInput(keys) + pos = dfhack.gui.getSelectedStockpile() + + if + QuantumWin.super.onInput(self, keys) + then + return true + end -local function create_quantum(pos, qsp_pos, feeder_tiles, name, trackstop_dir, - allow_refuse) - local dsg = allow_refuse and 'yr' or 'c' - local stats = quickfort.apply_blueprint{mode='place', data=dsg, pos=qsp_pos} - if stats.place_designated.value == 0 then - error(('failed to place quantum stockpile at (%d, %d, %d)') - :format(qsp_pos.x, qsp_pos.y, qsp_pos.z)) - end - - stats = quickfort.apply_blueprint{mode='build', - data='trackstop'..trackstop_dir, pos=pos} - if stats.build_designated.value == 0 then - error(('failed to build trackstop at (%d, %d, %d)') - :format(pos.x, pos.y, pos.z)) - end - - local feeder_pos = get_feeder_pos(feeder_tiles) - local quantumstop_data = get_quantumstop_data(pos, feeder_pos, name) - stats = quickfort.apply_blueprint{mode='query', data=quantumstop_data, - pos=pos} - if stats.query_skipped_tiles.value > 0 then - error(('failed to query trackstop at (%d, %d, %d)') - :format(pos.x, pos.y, pos.z)) + local pos = nil + if + keys.CUSTOM_Q + then + self:commit() + elseif + keys._MOUSE_L_DOWN and not self:getMouseFramePos() + then + self:commit() + elseif + keys.SELECT + then + pos = guidm.getCursorPos() end - local quantum_data = get_quantum_data(name) - stats = quickfort.apply_blueprint{mode='query', data=quantum_data, - pos=qsp_pos} - if stats.query_skipped_tiles.value > 0 then - error(('failed to query quantum stockpile at (%d, %d, %d)') - :format(qsp_pos.x, qsp_pos.y, qsp_pos.z)) - end + end --- this function assumes that is_valid_pos() has already validated the positions -function QuantumUI:commit(pos, qsp_pos) - local name = self.subviews.name.text - local trackstop_dir = self.subviews.dir:getOptionLabel():sub(1,1) - local allow_refuse = self.subviews.refuse:getOptionValue() - create_quantum(pos, qsp_pos, self.feeder_tiles, name, trackstop_dir, allow_refuse) - - local message = nil - if assign_minecarts.assign_minecart_to_last_route(true) then - message = 'An available minecart was assigned to your new' .. - ' quantum stockpile. You\'re all done!' - else - order_minecart(pos) - message = 'There are no minecarts available to assign to the' .. - ' quantum stockpile, but a manager order to produce' .. - ' one was created for you. Once the minecart is' .. - ' built, please add it to the quantum stockpile route' .. - ' with the "assign-minecarts all" command or manually in' .. - ' the (h)auling menu.' - end - -- display a message box telling the user what we just did - dialogs.MessageBox{text=message:wrap(70)}:show() +function QuantumUI:onDismiss() + view = nil end -if dfhack.internal.IN_TEST then - unit_test_hooks = { - is_in_extents=is_in_extents, - is_valid_pos=is_valid_pos, - get_feeder_pos=get_feeder_pos, - get_moves=get_moves, - get_quantumstop_data=get_quantumstop_data, - get_quantum_data=get_quantum_data, - create_quantum=create_quantum, - } -end +--Misc if dfhack_flags.module then return end -view = QuantumUI{} -view:show() +view = view and view:raise() or QuantumUI{}:show()