@@ -4,6 +4,7 @@ local dialogs = require('gui.dialogs')
44local overlay = require (" plugins.overlay" )
55local utils = require (" utils" )
66local widgets = require (" gui.widgets" )
7+ local lever = reqscript (" lever" )
78
89local function mech_iter (b ) -- iterate mechanisms backwards
910 local t = b .contained_items
@@ -35,6 +36,40 @@ local function get_mech_target(m) --mechanism target building if exists
3536 return i and df .building .find (m .general_refs [i ].building_id ) or nil
3637end
3738
39+ local function is_lever (b ) -- building is a lever
40+ return b and b ._type == df .building_trapst and b .trap_type == df .trap_type .Lever
41+ end
42+
43+ local function get_pull_job (b ) -- pending pull job on lever, or nil
44+ for _ , j in ipairs (b .jobs ) do
45+ if j .job_type == df .job_type .PullLever then
46+ return j
47+ end
48+ end
49+ end
50+
51+ local ASCII_LEVER_OFF = string.char (0x95 ) -- ò
52+ local ASCII_LEVER_ON = string.char (0xA2 ) -- ó
53+
54+ local function get_lever_state_char (lever ) -- lever position glyph for the current tileset
55+ -- match the current mode because ASCII and premium lever glyphs differ in directions
56+ if dfhack .screen .inGraphicsMode () then
57+ return lever .state == 0 and " /" or " \\ "
58+ end
59+ return lever .state == 0 and ASCII_LEVER_OFF or ASCII_LEVER_ON
60+ end
61+
62+ local function get_pull_label (lever ) -- button label and pen for the lever's pull state
63+ local state_char = get_lever_state_char (lever ) -- current lever position
64+ local job = get_pull_job (lever )
65+ if not job then
66+ return " Pull " .. state_char , COLOR_WHITE
67+ elseif dfhack .job .getWorker (job ) then
68+ return " Pulling " .. state_char , COLOR_GREEN -- a citizen has taken the job
69+ end
70+ return " Queued " .. state_char , COLOR_YELLOW -- queued, not yet taken
71+ end
72+
3873local function has_link_tab (b ) -- linked building tab exists
3974 if not b then
4075 return
@@ -148,7 +183,7 @@ local valid_build = {
148183MechLinkOverlay = defclass (MechLinkOverlay , overlay .OverlayWidget )
149184MechLinkOverlay .ATTRS
150185{
151- desc = " Allows unlinking mechanisms from buildings." ,
186+ desc = " Allows unlinking mechanisms and pulling linked levers from buildings." ,
152187 default_enabled = true ,
153188 default_pos = {x =- 41 , y =- 4 },
154189 frame = {w = 56 , h = 27 },
@@ -303,6 +338,55 @@ function MechLinkOverlay:activate_button(n)
303338 end
304339end
305340
341+ function MechLinkOverlay :get_pull_button (n , ensure )
342+ local button = self .subviews [" pull_" .. n ]
343+ if not button and ensure then
344+ self :addviews
345+ {
346+ widgets .TextButton
347+ {
348+ view_id = " pull_" .. n ,
349+ frame = {t = 0 , r = 17 , w = 11 , h = 1 },
350+ label = " " , -- set per-frame in update_buttons
351+ on_activate = function () self :activate_pull (n ) end ,
352+ visible = false ,
353+ },
354+ }
355+ button = self .subviews [" pull_" .. n ]
356+ button :updateLayout (self .frame_body )
357+ end
358+
359+ return button
360+ end
361+
362+ function MechLinkOverlay :pull_target (n ) -- linked lever for button n, or nil
363+ local button = self :get_pull_button (n )
364+ if not button then
365+ return
366+ end
367+
368+ local idx = self :idx_from_offset (button .frame .t )
369+ if idx > 0 and idx < # self .building .contained_items then
370+ local target = get_mech_target (self .building .contained_items [idx ].item )
371+ if is_lever (target ) then
372+ return target
373+ end
374+ end
375+ end
376+
377+ function MechLinkOverlay :activate_pull (n )
378+ local target = self :pull_target (n )
379+ if not target then
380+ return
381+ end
382+ local job = get_pull_job (target )
383+ if job then
384+ dfhack .job .removeJob (job ) -- cancel queued pull
385+ else
386+ lever .leverPullJob (target , true ) -- do now
387+ end
388+ end
389+
306390function MechLinkOverlay :ask_unlink_all ()
307391 local saved_mode = self .subviews .unlink_mode :getOptionValue ()
308392 local message = {
@@ -356,6 +440,20 @@ function MechLinkOverlay:update_buttons()
356440 button .visible = true
357441 end
358442 button :updateLayout ()
443+
444+ local pbutton = self :get_pull_button (i , true )
445+ pbutton .visible = false
446+ local target = idx > 0 and idx < bci_len and
447+ get_mech_target (self .building .contained_items [idx ].item )
448+ if is_lever (target ) then
449+ local label , pen = get_pull_label (target )
450+ pbutton :setLabel (label )
451+ pbutton .label .text_pen = pen
452+ pbutton .frame .t = offset
453+ pbutton .frame .r = h_offset + 9
454+ pbutton .visible = true
455+ end
456+ pbutton :updateLayout ()
359457 end
360458
361459 local b = (self .frame .h % 3 ) == 1 and # self .links >= self .num_buttons and 0 or 1
@@ -371,6 +469,10 @@ function MechLinkOverlay:preUpdateLayout(parent_rect)
371469 if button then
372470 button .visible = false
373471 end
472+ local pbutton = self :get_pull_button (i )
473+ if pbutton then
474+ pbutton .visible = false
475+ end
374476 end
375477
376478 local h = parent_rect .height - 49
0 commit comments