Implement a more automated search mode based on keys for some globals.

develop
Alexander Gavrilov 2012-10-02 19:53:16 +04:00
parent 7962f24cce
commit 33aead34b4
2 changed files with 279 additions and 34 deletions

@ -358,7 +358,7 @@ end
-- Interactive search utility -- Interactive search utility
function DiffSearcher:find_interactive(prompt,data_type,condition_cb) function DiffSearcher:find_interactive(prompt,data_type,condition_cb,iter_limit)
enum = enum or {} enum = enum or {}
-- Loop for restarting search from scratch -- Loop for restarting search from scratch
@ -374,6 +374,11 @@ function DiffSearcher:find_interactive(prompt,data_type,condition_cb)
while true do while true do
print('') print('')
if iter_limit and ccursor >= iter_limit then
dfhack.printerr(' Iteration limit reached without a solution.')
break
end
local ok, value, delta = condition_cb(ccursor) local ok, value, delta = condition_cb(ccursor)
ccursor = ccursor + 1 ccursor = ccursor + 1

@ -2,6 +2,7 @@
local utils = require 'utils' local utils = require 'utils'
local ms = require 'memscan' local ms = require 'memscan'
local gui = require 'gui'
local is_known = dfhack.internal.getAddress local is_known = dfhack.internal.getAddress
@ -53,6 +54,35 @@ end
local searcher = ms.DiffSearcher.new(data) 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
return nil
end
return true
end
while true do
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
return nil
end
else
return cs
end
end
end
local function screen_title()
return get_screen(df.viewscreen_titlest, 'the title screen')
end
local function screen_dwarfmode()
return get_screen(df.viewscreen_dwarfmodest, 'the main dwarf mode screen')
end
local function validate_offset(name,validator,addr,tname,...) local function validate_offset(name,validator,addr,tname,...)
local obj = data:object_by_field(addr,tname,...) local obj = data:object_by_field(addr,tname,...)
if obj and not validator(obj) then if obj and not validator(obj) then
@ -136,13 +166,95 @@ local function list_index_choices(length_func)
end end
end end
local function can_feed()
return not force_scan['nofeed'] and is_known 'gview'
end
local function dwarfmode_feed_input(...)
local screen = screen_dwarfmode()
if not df.isvalid(screen) then
qerror('could not retrieve dwarfmode screen')
end
for _,v in ipairs({...}) do
gui.simulateInput(screen, v)
end
end
local function dwarfmode_to_top()
if not can_feed() then
return false
end
local screen = screen_dwarfmode()
if not df.isvalid(screen) then
return false
end
for i=0,10 do
if is_known 'ui' and df.global.ui.main.mode == df.ui_sidebar_mode.Default then
break
end
gui.simulateInput(screen, 'LEAVESCREEN')
end
-- force pause just in case
screen.keyRepeat = 1
return true
end
local function feed_menu_choice(catnames,catkeys,enum)
return function (idx)
idx = idx % #catnames + 1
dwarfmode_feed_input(catkeys[idx])
if enum then
return true, enum[catnames[idx]]
else
return true, catnames[idx]
end
end
end
local function feed_list_choice(count,upkey,downkey)
return function(idx)
if idx > 0 then
local ok, len
if type(count) == 'number' then
ok, len = true, count
else
ok, len = pcall(count)
end
if not ok then
len = 5
elseif len > 10 then
len = 10
end
local hcnt = len-1
local rix = 1 + (idx-1) % (hcnt*2)
if rix >= hcnt then
dwarfmode_feed_input(upkey or 'SECONDSCROLL_UP')
return true, hcnt*2 - rix
else
dwarfmode_feed_input(donwkey or 'SECONDSCROLL_DOWN')
return true, rix
end
else
print(' Please select the first list item.')
if not utils.prompt_yes_no(' Proceed?') then
return false
end
return true, 0
end
end
end
-- --
-- Cursor group -- Cursor group
-- --
local function find_cursor() local function find_cursor()
print('\nPlease navigate to the title screen to find cursor.') if not screen_title() then
if not utils.prompt_yes_no('Proceed?', true) then
return false return false
end end
@ -354,13 +466,35 @@ local function is_valid_world(world)
end end
local function find_world() local function find_world()
local addr = searcher:find_menu_cursor([[ local catnames = {
'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins'
}
local catkeys = {
'STOCKPILE_GRAVEYARD', 'STOCKPILE_REFUSE', 'STOCKPILE_STONE', 'STOCKPILE_WOOD',
'STOCKPILE_GEM', 'STOCKPILE_BARBLOCK', 'STOCKPILE_CLOTH', 'STOCKPILE_LEATHER',
'STOCKPILE_AMMO', 'STOCKPILE_COINS'
}
local addr
if dwarfmode_to_top() then
dwarfmode_feed_input('D_STOCKPILES')
addr = searcher:find_interactive(
'Auto-searching for world.',
'int32_t',
feed_menu_choice(catnames, catkeys, df.stockpile_category),
20
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for world. Please open the stockpile creation Searching for world. Please open the stockpile creation
menu, and select different types as instructed below:]], menu, and select different types as instructed below:]],
'int32_t', 'int32_t', catnames, df.stockpile_category
{ 'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins' }, )
df.stockpile_category end
)
validate_offset('world', is_valid_world, addr, df.world, 'selected_stockpile_type') validate_offset('world', is_valid_world, addr, df.world, 'selected_stockpile_type')
end end
@ -385,14 +519,37 @@ local function is_valid_ui(ui)
end end
local function find_ui() local function find_ui()
local addr = searcher:find_menu_cursor([[ local catnames = {
'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps',
'DesignateUpStair', 'DesignateDownStair', 'DesignateUpDownStair',
'DesignateUpRamp', 'DesignateChopTrees'
}
local catkeys = {
'DESIGNATE_DIG', 'DESIGNATE_CHANNEL', 'DESIGNATE_DIG_REMOVE_STAIRS_RAMPS',
'DESIGNATE_STAIR_UP', 'DESIGNATE_STAIR_DOWN', 'DESIGNATE_STAIR_UPDOWN',
'DESIGNATE_RAMP', 'DESIGNATE_CHOP'
}
local addr
if dwarfmode_to_top() then
dwarfmode_feed_input('D_DESIGNATE')
addr = searcher:find_interactive(
'Auto-searching for ui.',
'int16_t',
feed_menu_choice(catnames, catkeys, df.ui_sidebar_mode),
20
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for ui. Please open the designation Searching for ui. Please open the designation
menu, and switch modes as instructed below:]], menu, and switch modes as instructed below:]],
'int16_t', 'int16_t', catnames, df.ui_sidebar_mode
{ 'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps', 'DesignateUpStair', )
'DesignateDownStair', 'DesignateUpDownStair', 'DesignateUpRamp', 'DesignateChopTrees' }, end
df.ui_sidebar_mode
)
validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode') validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode')
end end
@ -421,14 +578,32 @@ local function is_valid_ui_sidebar_menus(usm)
end end
local function find_ui_sidebar_menus() local function find_ui_sidebar_menus()
local addr = searcher:find_menu_cursor([[ local addr
if dwarfmode_to_top() then
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:]],
'int32_t',
feed_list_choice(7),
20
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for ui_sidebar_menus. Please switch to 'q' mode, Searching for ui_sidebar_menus. Please switch to 'q' mode,
select a Mason, Craftsdwarfs, or Carpenters workshop, open select a Mason, Craftsdwarfs, or Carpenters workshop, open
the Add Job menu, and move the cursor within:]], the Add Job menu, and move the cursor within:]],
'int32_t', 'int32_t',
{ 0, 1, 2, 3, 4, 5, 6 }, { 0, 1, 2, 3, 4, 5, 6 },
ordinal_names ordinal_names
) )
end
validate_offset('ui_sidebar_menus', is_valid_ui_sidebar_menus, validate_offset('ui_sidebar_menus', is_valid_ui_sidebar_menus,
addr, df.ui_sidebar_menus, 'workshop_job', 'cursor') addr, df.ui_sidebar_menus, 'workshop_job', 'cursor')
end end
@ -455,14 +630,41 @@ local function is_valid_ui_build_selector(ubs)
end end
local function find_ui_build_selector() local function find_ui_build_selector()
local addr = searcher:find_menu_cursor([[ local addr
if dwarfmode_to_top() then
addr = searcher:find_interactive([[
Auto-searching for ui_build_selector. This requires mechanisms.]],
'int32_t',
function(idx)
if idx == 0 then
dwarfmode_to_top()
dwarfmode_feed_input(
'D_BUILDING',
'HOTKEY_BUILDING_TRAP',
'HOTKEY_BUILDING_TRAP_TRIGGER',
'BUILDING_TRIGGER_ENABLE_CREATURE'
)
else
dwarfmode_feed_input('BUILDING_TRIGGER_MIN_SIZE_DOWN')
end
return true, 50000 - 1000*idx
end,
20
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for ui_build_selector. Please start constructing Searching for ui_build_selector. Please start constructing
a pressure plate, and enable creatures. Then change the min a pressure plate, and enable creatures. Then change the min
weight as requested, remembering that the ui truncates the weight as requested, remembering that the ui truncates the
number, so when it shows "Min (5000df", it means 50000:]], number, so when it shows "Min (5000df", it means 50000:]],
'int32_t', 'int32_t',
{ 50000, 49000, 48000, 47000, 46000, 45000, 44000 } { 50000, 49000, 48000, 47000, 46000, 45000, 44000 }
) )
end
validate_offset('ui_build_selector', is_valid_ui_build_selector, validate_offset('ui_build_selector', is_valid_ui_build_selector,
addr, df.ui_build_selector, 'plate_info', 'unit_min') addr, df.ui_build_selector, 'plate_info', 'unit_min')
end end
@ -601,13 +803,33 @@ end
-- --
local function find_ui_unit_view_mode() local function find_ui_unit_view_mode()
local addr = searcher:find_menu_cursor([[ local catnames = { 'General', 'Inventory', 'Preferences', 'Wounds' }
local catkeys = { 'UNITVIEW_GEN', 'UNITVIEW_INV', 'UNITVIEW_PRF', 'UNITVIEW_WND' }
local addr
if dwarfmode_to_top() and is_known('ui_selected_unit') then
dwarfmode_feed_input('D_VIEWUNIT')
if df.global.ui_selected_unit < 0 then
df.global.ui_selected_unit = 0
end
addr = searcher:find_interactive(
'Auto-searching for ui_unit_view_mode.',
'int32_t',
feed_menu_choice(catnames, catkeys, df.ui_unit_view_mode.T_value),
10
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for ui_unit_view_mode. Having selected a unit Searching for ui_unit_view_mode. Having selected a unit
with 'v', switch the pages as requested:]], with 'v', switch the pages as requested:]],
'int32_t', 'int32_t', catnames, df.ui_unit_view_mode.T_value
{ 'General', 'Inventory', 'Preferences', 'Wounds' }, )
df.ui_unit_view_mode.T_value end
)
ms.found_offset('ui_unit_view_mode', addr) ms.found_offset('ui_unit_view_mode', addr)
end end
@ -620,14 +842,32 @@ local function look_item_list_count()
end end
local function find_ui_look_cursor() local function find_ui_look_cursor()
local addr = searcher:find_menu_cursor([[ local addr
if dwarfmode_to_top() then
dwarfmode_feed_input('D_LOOK')
addr = searcher:find_interactive([[
Auto-searching for ui_look_cursor. Please select a tile
with at least 5 items or units on the ground, and move
the cursor as instructed:]],
'int32_t',
feed_list_choice(look_item_list_count),
20
)
end
if not addr then
addr = searcher:find_menu_cursor([[
Searching for ui_look_cursor. Please activate the 'k' Searching for ui_look_cursor. Please activate the 'k'
mode, find a tile with many items or units on the ground, mode, find a tile with many items or units on the ground,
and select list entries as instructed:]], and select list entries as instructed:]],
'int32_t', 'int32_t',
list_index_choices(look_item_list_count), list_index_choices(look_item_list_count),
ordinal_names ordinal_names
) )
end
ms.found_offset('ui_look_cursor', addr) ms.found_offset('ui_look_cursor', addr)
end end
@ -989,10 +1229,10 @@ end
print('\nInitial globals (need title screen):\n') print('\nInitial globals (need title screen):\n')
exec_finder(find_gview, 'gview')
exec_finder(find_cursor, { 'cursor', 'selection_rect', 'gamemode', 'gametype' }) exec_finder(find_cursor, { 'cursor', 'selection_rect', 'gamemode', 'gametype' })
exec_finder(find_announcements, 'announcements') exec_finder(find_announcements, 'announcements')
exec_finder(find_d_init, 'd_init') exec_finder(find_d_init, 'd_init')
exec_finder(find_gview, 'gview')
exec_finder(find_enabler, 'enabler') exec_finder(find_enabler, 'enabler')
exec_finder(find_gps, 'gps') exec_finder(find_gps, 'gps')