|
|
|
@ -46,6 +46,11 @@ end
|
|
|
|
|
|
|
|
|
|
collectgarbage()
|
|
|
|
|
|
|
|
|
|
function prompt_proceed(indent)
|
|
|
|
|
if not indent then indent = 0 end
|
|
|
|
|
return utils.prompt_yes_no(string.rep(' ', indent) .. 'Proceed?', true)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
print[[
|
|
|
|
|
WARNING: THIS SCRIPT IS STRICTLY FOR DFHACK DEVELOPERS.
|
|
|
|
|
|
|
|
|
@ -88,7 +93,7 @@ local searcher = ms.DiffSearcher.new(data)
|
|
|
|
|
local function get_screen(class, prompt)
|
|
|
|
|
if not is_known('gview') then
|
|
|
|
|
print('Please navigate to '..prompt)
|
|
|
|
|
if not utils.prompt_yes_no('Proceed?', true) then
|
|
|
|
|
if not prompt_proceed() then
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
@ -98,7 +103,7 @@ local function get_screen(class, prompt)
|
|
|
|
|
local cs = dfhack.gui.getCurViewscreen(true)
|
|
|
|
|
if not df.is_instance(class, cs) then
|
|
|
|
|
print('Please navigate to '..prompt)
|
|
|
|
|
if not utils.prompt_yes_no('Proceed?', true) then
|
|
|
|
|
if not prompt_proceed() then
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
@ -172,8 +177,9 @@ local function exec_finder(finder, names, validators)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if search then
|
|
|
|
|
if not dfhack.safecall(finder) then
|
|
|
|
|
if not utils.prompt_yes_no('Proceed with the rest of the script?') then
|
|
|
|
|
local ok, err = dfhack.safecall(finder)
|
|
|
|
|
if not ok then
|
|
|
|
|
if tostring(err):find('abort') or not utils.prompt_yes_no('Proceed with the rest of the script?') then
|
|
|
|
|
searcher:reset()
|
|
|
|
|
qerror('Quit')
|
|
|
|
|
end
|
|
|
|
@ -217,6 +223,7 @@ local function dwarfmode_feed_input(...)
|
|
|
|
|
if not df.isvalid(screen) then
|
|
|
|
|
qerror('could not retrieve dwarfmode screen')
|
|
|
|
|
end
|
|
|
|
|
try_save_cursor()
|
|
|
|
|
for _,v in ipairs({...}) do
|
|
|
|
|
gui.simulateInput(screen, v)
|
|
|
|
|
end
|
|
|
|
@ -259,9 +266,29 @@ local function dwarfmode_to_top()
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local prev_cursor = df.global.T_cursor:new()
|
|
|
|
|
prev_cursor.x = -30000
|
|
|
|
|
function try_save_cursor()
|
|
|
|
|
if not dfhack.internal.getAddress('cursor') then return end
|
|
|
|
|
for _, v in pairs(df.global.cursor) do
|
|
|
|
|
if v < 0 then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
prev_cursor:assign(df.global.cursor)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function try_restore_cursor()
|
|
|
|
|
if not dfhack.internal.getAddress('cursor') then return end
|
|
|
|
|
if prev_cursor.x >= 0 then
|
|
|
|
|
df.global.cursor:assign(prev_cursor)
|
|
|
|
|
dwarfmode_feed_input('CURSOR_DOWN_Z', 'CURSOR_UP_Z')
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function feed_menu_choice(catnames,catkeys,enum,enter_seq,exit_seq,prompt)
|
|
|
|
|
return function (idx)
|
|
|
|
|
if idx == 0 and prompt and not utils.prompt_yes_no(' Proceed?', true) then
|
|
|
|
|
if idx == 0 and prompt and not prompt_proceed(2) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
if idx > 0 then
|
|
|
|
@ -305,7 +332,7 @@ local function feed_list_choice(count,upkey,downkey)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
print(' Please select the first list item.')
|
|
|
|
|
if not utils.prompt_yes_no(' Proceed?', true) then
|
|
|
|
|
if not prompt_proceed(2) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
return true, 0
|
|
|
|
@ -316,14 +343,14 @@ end
|
|
|
|
|
local function feed_menu_bool(enter_seq, exit_seq)
|
|
|
|
|
return function(idx)
|
|
|
|
|
if idx == 0 then
|
|
|
|
|
if not utils.prompt_yes_no(' Proceed?', true) then
|
|
|
|
|
if not prompt_proceed(2) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
return true, 0
|
|
|
|
|
end
|
|
|
|
|
if idx == 5 then
|
|
|
|
|
print(' Please resize the game window.')
|
|
|
|
|
if not utils.prompt_yes_no(' Proceed?', true) then
|
|
|
|
|
if not prompt_proceed(2) then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -539,7 +566,7 @@ end
|
|
|
|
|
|
|
|
|
|
local function find_gps()
|
|
|
|
|
print('\nPlease ensure the mouse cursor is not over the game window.')
|
|
|
|
|
if not utils.prompt_yes_no('Proceed?', true) then
|
|
|
|
|
if not prompt_proceed() then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
@ -555,7 +582,7 @@ local function find_gps()
|
|
|
|
|
|
|
|
|
|
local idx, addr = zone.area.int32_t:find_one{w, h, -1, -1}
|
|
|
|
|
if not idx then
|
|
|
|
|
idx, addr = data.int32_t.find_one{w, h, -1, -1}
|
|
|
|
|
idx, addr = data.int32_t:find_one{w, h, -1, -1}
|
|
|
|
|
end
|
|
|
|
|
if idx then
|
|
|
|
|
validate_offset('gps', is_valid_gps, addr, df.graphic, 'dimx')
|
|
|
|
@ -709,11 +736,18 @@ local function find_ui_sidebar_menus()
|
|
|
|
|
dwarfmode_feed_input('D_BUILDJOB')
|
|
|
|
|
|
|
|
|
|
addr = searcher:find_interactive([[
|
|
|
|
|
Auto-searching for ui_sidebar_menus. Please select a Mason,
|
|
|
|
|
Craftsdwarfs, or Carpenters workshop, open the Add Job
|
|
|
|
|
menu, and move the cursor within:]],
|
|
|
|
|
Auto-searching for ui_sidebar_menus. Please select a Mason's,
|
|
|
|
|
Craftsdwarf's, or Carpenter's workshop:]],
|
|
|
|
|
'int32_t',
|
|
|
|
|
feed_list_choice(7),
|
|
|
|
|
function(idx)
|
|
|
|
|
if idx == 0 then
|
|
|
|
|
prompt_proceed(2)
|
|
|
|
|
-- ensure that the job list isn't full
|
|
|
|
|
dwarfmode_feed_input('BUILDJOB_CANCEL', 'BUILDJOB_ADD')
|
|
|
|
|
return true, 0
|
|
|
|
|
end
|
|
|
|
|
return feed_list_choice(7)(idx)
|
|
|
|
|
end,
|
|
|
|
|
20
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
@ -875,7 +909,23 @@ end
|
|
|
|
|
--
|
|
|
|
|
|
|
|
|
|
local function find_ui_menu_width()
|
|
|
|
|
local addr = searcher:find_menu_cursor([[
|
|
|
|
|
local addr
|
|
|
|
|
|
|
|
|
|
if dwarfmode_to_top() then
|
|
|
|
|
addr = searcher:find_interactive('Auto-searching for ui_menu_width', 'int8_t', function(idx)
|
|
|
|
|
local val = (idx % 3) + 1
|
|
|
|
|
if idx == 0 then
|
|
|
|
|
print('Switch to the default [map][menu][map] layout (with Tab)')
|
|
|
|
|
if not prompt_proceed(2) then return false end
|
|
|
|
|
else
|
|
|
|
|
dwarfmode_feed_input('CHANGETAB', val ~= 3 and 'CHANGETAB')
|
|
|
|
|
end
|
|
|
|
|
return true, val
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not addr then
|
|
|
|
|
addr = searcher:find_menu_cursor([[
|
|
|
|
|
Searching for ui_menu_width. Please exit to the main
|
|
|
|
|
dwarfmode menu, then use Tab to do as instructed below:]],
|
|
|
|
|
'int8_t',
|
|
|
|
@ -884,10 +934,16 @@ dwarfmode menu, then use Tab to do as instructed below:]],
|
|
|
|
|
[3] = 'hide the menu completely',
|
|
|
|
|
[1] = 'switch to the default [map][menu][map] layout' }
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
ms.found_offset('ui_menu_width', addr)
|
|
|
|
|
|
|
|
|
|
-- NOTE: Assume that the vars are adjacent, as always
|
|
|
|
|
ms.found_offset('ui_area_map_width', addr+1)
|
|
|
|
|
|
|
|
|
|
-- reset to make sure view is small enough for window_x/y scan on small maps
|
|
|
|
|
df.global.ui_menu_width = 2
|
|
|
|
|
df.global.ui_area_map_width = 3
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
@ -1087,12 +1143,20 @@ local function find_ui_workshop_job_cursor()
|
|
|
|
|
|
|
|
|
|
if dwarfmode_to_top() then
|
|
|
|
|
dwarfmode_feed_input('D_BUILDJOB')
|
|
|
|
|
|
|
|
|
|
addr = searcher:find_interactive([[
|
|
|
|
|
Auto-searching for ui_workshop_job_cursor. Please highlight a
|
|
|
|
|
workshop with at least 5 contained jobs, and select as instructed:]],
|
|
|
|
|
Mason's or Carpenter's workshop, or any building with a job
|
|
|
|
|
selection interface navigable with just "Enter":]],
|
|
|
|
|
'int32_t',
|
|
|
|
|
feed_list_choice(workshop_job_list_count),
|
|
|
|
|
function(idx)
|
|
|
|
|
if idx == 0 then prompt_proceed(2) end
|
|
|
|
|
for i = 1, 10 - workshop_job_list_count() do
|
|
|
|
|
dwarfmode_feed_input('BUILDJOB_ADD', 'SELECT', 'SELECT', 'SELECT', 'SELECT', 'SELECT')
|
|
|
|
|
end
|
|
|
|
|
dwarfmode_feed_input('SECONDSCROLL_DOWN')
|
|
|
|
|
-- adding jobs resets the cursor position, so it is difficult to determine here
|
|
|
|
|
return true
|
|
|
|
|
end,
|
|
|
|
|
20
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
@ -1119,6 +1183,7 @@ local function find_ui_building_in_assign()
|
|
|
|
|
|
|
|
|
|
if dwarfmode_to_top() then
|
|
|
|
|
dwarfmode_feed_input('D_BUILDJOB')
|
|
|
|
|
try_restore_cursor()
|
|
|
|
|
|
|
|
|
|
addr = searcher:find_interactive([[
|
|
|
|
|
Auto-searching for ui_building_in_assign. Please select a room,
|
|
|
|
@ -1160,6 +1225,7 @@ local function find_ui_building_in_resize()
|
|
|
|
|
|
|
|
|
|
if dwarfmode_to_top() then
|
|
|
|
|
dwarfmode_feed_input('D_BUILDJOB')
|
|
|
|
|
try_restore_cursor()
|
|
|
|
|
|
|
|
|
|
addr = searcher:find_interactive([[
|
|
|
|
|
Auto-searching for ui_building_in_resize. Please select a room,
|
|
|
|
@ -1396,7 +1462,7 @@ function step_n_frames(cnt, feed)
|
|
|
|
|
while world.frame_counter-ctick < cnt do
|
|
|
|
|
print(" Please step the game "..(cnt-world.frame_counter+ctick)..more.." frames.")
|
|
|
|
|
more = ' more'
|
|
|
|
|
if not utils.prompt_yes_no(' Proceed?', true) then
|
|
|
|
|
if not prompt_proceed(2) then
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -1531,9 +1597,45 @@ end
|
|
|
|
|
|
|
|
|
|
local function find_process_jobs()
|
|
|
|
|
local zone = get_process_zone() or searcher
|
|
|
|
|
local addr
|
|
|
|
|
|
|
|
|
|
stop_autosave()
|
|
|
|
|
|
|
|
|
|
if dwarfmode_to_top() and dfhack.internal.getAddress('cursor') then
|
|
|
|
|
local cursor = df.global.T_cursor:new()
|
|
|
|
|
addr = zone:find_interactive([[
|
|
|
|
|
Searching for process_jobs. Please position the cursor to the right
|
|
|
|
|
of at least 10 vacant natural floor tiles.]],
|
|
|
|
|
'int8_t',
|
|
|
|
|
function(idx)
|
|
|
|
|
if idx == 0 then
|
|
|
|
|
dwarfmode_feed_input('D_LOOK')
|
|
|
|
|
if not prompt_proceed(2) then return false end
|
|
|
|
|
cursor:assign(df.global.cursor)
|
|
|
|
|
elseif idx == 6 then
|
|
|
|
|
print(' Please resize the game window.')
|
|
|
|
|
if not prompt_proceed(2) then return false end
|
|
|
|
|
end
|
|
|
|
|
dwarfmode_to_top()
|
|
|
|
|
dwarfmode_step_frames(1)
|
|
|
|
|
if idx % 2 == 0 then
|
|
|
|
|
dwarfmode_feed_input(
|
|
|
|
|
'D_BUILDING',
|
|
|
|
|
'HOTKEY_BUILDING_CONSTRUCTION',
|
|
|
|
|
'HOTKEY_BUILDING_CONSTRUCTION_WALL'
|
|
|
|
|
)
|
|
|
|
|
df.global.cursor:assign(cursor)
|
|
|
|
|
df.global.cursor.x = df.global.cursor.x + (idx / 2)
|
|
|
|
|
dwarfmode_feed_input('CURSOR_RIGHT', 'CURSOR_LEFT', 'SELECT', 'SELECT')
|
|
|
|
|
return true, 1
|
|
|
|
|
else
|
|
|
|
|
return true, 0
|
|
|
|
|
end
|
|
|
|
|
end,
|
|
|
|
|
20)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not addr then
|
|
|
|
|
local addr = zone:find_menu_cursor([[
|
|
|
|
|
Searching for process_jobs. Please do as instructed below:]],
|
|
|
|
|
'int8_t',
|
|
|
|
@ -1541,6 +1643,7 @@ Searching for process_jobs. Please do as instructed below:]],
|
|
|
|
|
{ [1] = 'designate a building to be constructed, e.g a bed or a wall',
|
|
|
|
|
[0] = 'step or unpause the game to reset the flag' }
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
ms.found_offset('process_jobs', addr)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
@ -1550,16 +1653,49 @@ end
|
|
|
|
|
|
|
|
|
|
local function find_process_dig()
|
|
|
|
|
local zone = get_process_zone() or searcher
|
|
|
|
|
local addr
|
|
|
|
|
|
|
|
|
|
stop_autosave()
|
|
|
|
|
|
|
|
|
|
local addr = zone:find_menu_cursor([[
|
|
|
|
|
if dwarfmode_to_top() and dfhack.internal.getAddress('cursor') then
|
|
|
|
|
local cursor = df.global.T_cursor:new()
|
|
|
|
|
addr = zone:find_interactive([[
|
|
|
|
|
Searching for process_dig. Please position the cursor to the right
|
|
|
|
|
of at least 10 unmined, unrevealed tiles.]],
|
|
|
|
|
'int8_t',
|
|
|
|
|
function(idx)
|
|
|
|
|
if idx == 0 then
|
|
|
|
|
dwarfmode_feed_input('D_LOOK')
|
|
|
|
|
if not prompt_proceed(2) then return false end
|
|
|
|
|
cursor:assign(df.global.cursor)
|
|
|
|
|
elseif idx == 6 then
|
|
|
|
|
print(' Please resize the game window.')
|
|
|
|
|
if not prompt_proceed(2) then return false end
|
|
|
|
|
end
|
|
|
|
|
dwarfmode_to_top()
|
|
|
|
|
dwarfmode_step_frames(1)
|
|
|
|
|
if idx % 2 == 0 then
|
|
|
|
|
dwarfmode_feed_input('D_DESIGNATE', 'DESIGNATE_DIG')
|
|
|
|
|
df.global.cursor:assign(cursor)
|
|
|
|
|
df.global.cursor.x = df.global.cursor.x + (idx / 2)
|
|
|
|
|
dwarfmode_feed_input('SELECT', 'SELECT')
|
|
|
|
|
return true, 1
|
|
|
|
|
else
|
|
|
|
|
return true, 0
|
|
|
|
|
end
|
|
|
|
|
end,
|
|
|
|
|
20)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not addr then
|
|
|
|
|
addr = zone:find_menu_cursor([[
|
|
|
|
|
Searching for process_dig. Please do as instructed below:]],
|
|
|
|
|
'int8_t',
|
|
|
|
|
{ 1, 0 },
|
|
|
|
|
{ [1] = 'designate a tile to be mined out',
|
|
|
|
|
[0] = 'step or unpause the game to reset the flag' }
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
ms.found_offset('process_dig', addr)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
@ -1671,7 +1807,7 @@ exec_finder(find_gps, 'gps', is_valid_gps)
|
|
|
|
|
print('\nCompound globals (need loaded world):\n')
|
|
|
|
|
|
|
|
|
|
print('\nPlease load the save previously processed with prepare-save.')
|
|
|
|
|
if not utils.prompt_yes_no('Proceed?', true) then
|
|
|
|
|
if not prompt_proceed() then
|
|
|
|
|
searcher:reset()
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|