|  |  | @ -3,9 +3,19 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | local utils = require 'utils' |  |  |  | local utils = require 'utils' | 
			
		
	
		
		
			
				
					
					|  |  |  | local ms = require 'memscan' |  |  |  | local ms = require 'memscan' | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local scan_all = false |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | local is_known = dfhack.internal.getAddress |  |  |  | local is_known = dfhack.internal.getAddress | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local scan_all = false | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local force_scan = {} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | for _,v in ipairs({...}) do | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if v == 'all' then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         scan_all = true | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         force_scan[v] = true | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | collectgarbage() |  |  |  | collectgarbage() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | print[[ |  |  |  | print[[ | 
			
		
	
	
		
		
			
				
					|  |  | @ -48,6 +58,52 @@ local function validate_offset(name,validator,addr,tname,...) | 
			
		
	
		
		
			
				
					
					|  |  |  |     ms.found_offset(name,obj) |  |  |  |     ms.found_offset(name,obj) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function exec_finder(finder, names) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local search = scan_all | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if type(names) ~= 'table' then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         names = { names } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for _,v in ipairs(names) do | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if force_scan[v] or not is_known(v) then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             search = true | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         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 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 searcher:reset() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 error('Quit') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         print('Already known: '..table.concat(names,', ')) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local ordinal_names = { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     [0] = '1st entry', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     [1] = '2nd entry' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | setmetatable(ordinal_names, { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     __index = function(self,idx) return (idx+1)..'th entry' end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | }) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function list_index_choices(length_func) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return function(id) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if id > 0 then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             local ok, len = pcall(length_func) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if not ok then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 len = 5 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             elseif len > 10 then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 len = 10 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return id % len | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- Cursor group |  |  |  | -- Cursor group | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
	
		
		
			
				
					|  |  | @ -90,19 +146,14 @@ local function find_cursor() | 
			
		
	
		
		
			
				
					
					|  |  |  |     return false |  |  |  |     return false | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not ( |  |  |  | exec_finder(find_cursor, { 'cursor', 'selection_rect', 'gamemode', 'gametype' }) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     is_known 'cursor' and is_known 'selection_rect' and |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     is_known 'gamemode' and is_known 'gametype' |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | ) then |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     find_cursor() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- Announcements |  |  |  | -- Announcements | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_announcements() |  |  |  | local function find_announcements() | 
			
		
	
		
		
			
				
					
					|  |  |  |     idx, addr = data.int32_t:find_one{ |  |  |  |     local idx, addr = data.int32_t:find_one{ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         25, 25, 31, 31, 24, 24, 40, 40, 40, 40, 40, 40, 40 |  |  |  |         25, 25, 31, 31, 24, 24, 40, 40, 40, 40, 40, 40, 40 | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     if idx then |  |  |  |     if idx then | 
			
		
	
	
		
		
			
				
					|  |  | @ -113,9 +164,7 @@ local function find_announcements() | 
			
		
	
		
		
			
				
					
					|  |  |  |     dfhack.printerr('Could not find announcements.') |  |  |  |     dfhack.printerr('Could not find announcements.') | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'announcements' then |  |  |  | exec_finder(find_announcements, 'announcements') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_announcements() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- d_init |  |  |  | -- d_init | 
			
		
	
	
		
		
			
				
					|  |  | @ -142,7 +191,7 @@ local function is_valid_d_init(di) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_d_init() |  |  |  | local function find_d_init() | 
			
		
	
		
		
			
				
					
					|  |  |  |     idx, addr = data.int16_t:find_one{ |  |  |  |     local idx, addr = data.int16_t:find_one{ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         1,0, 2,0, 5,0, 25,0,   -- path_cost |  |  |  |         1,0, 2,0, 5,0, 25,0,   -- path_cost | 
			
		
	
		
		
			
				
					
					|  |  |  |         4,4,                   -- embark_rect |  |  |  |         4,4,                   -- embark_rect | 
			
		
	
		
		
			
				
					
					|  |  |  |         20,1000,1000,1000,1000 -- store_dist |  |  |  |         20,1000,1000,1000,1000 -- store_dist | 
			
		
	
	
		
		
			
				
					|  |  | @ -155,10 +204,30 @@ local function find_d_init() | 
			
		
	
		
		
			
				
					
					|  |  |  |     dfhack.printerr('Could not find d_init') |  |  |  |     dfhack.printerr('Could not find d_init') | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'd_init' then |  |  |  | exec_finder(find_d_init, 'd_init') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_d_init() |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- gview | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_gview() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local vs_vtable = dfhack.internal.getVTable('viewscreenst') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if not vs_vtable then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         dfhack.printerr('Cannot search for gview - no viewscreenst vtable.') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local idx, addr = data.uint32_t:find_one{0, vs_vtable} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if idx then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ms.found_offset('gview', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     dfhack.printerr('Could not find gview') | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_gview, 'gview') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- World |  |  |  | -- World | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
	
		
		
			
				
					|  |  | @ -184,10 +253,9 @@ local function is_valid_world(world) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_world() |  |  |  | local function find_world() | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | Searching for world. Please open the stockpile creation |  |  |  | Searching for world. Please open the stockpile creation | 
			
		
	
		
		
			
				
					
					|  |  |  | menu, and follow instructions below:]], |  |  |  | menu, and select different types as instructed below:]], | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         'int32_t', |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |         { 'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins' }, |  |  |  |         { 'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins' }, | 
			
		
	
		
		
			
				
					
					|  |  |  |         df.stockpile_category |  |  |  |         df.stockpile_category | 
			
		
	
	
		
		
			
				
					|  |  | @ -195,9 +263,7 @@ menu, and follow instructions below:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |     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 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'world' then |  |  |  | exec_finder(find_world, 'world') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_world() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- UI |  |  |  | -- UI | 
			
		
	
	
		
		
			
				
					|  |  | @ -220,10 +286,9 @@ local function is_valid_ui(ui) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_ui() |  |  |  | local function find_ui() | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | Searching for ui. Please open the designation |  |  |  | Searching for ui. Please open the designation | 
			
		
	
		
		
			
				
					
					|  |  |  | menu, and follow instructions below:]], |  |  |  | menu, and switch modes as instructed below:]], | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         'int16_t', |  |  |  |         'int16_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |         { 'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps', 'DesignateUpStair', |  |  |  |         { 'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps', 'DesignateUpStair', | 
			
		
	
		
		
			
				
					
					|  |  |  |           'DesignateDownStair', 'DesignateUpDownStair', 'DesignateUpRamp', 'DesignateChopTrees' }, |  |  |  |           'DesignateDownStair', 'DesignateUpDownStair', 'DesignateUpRamp', 'DesignateChopTrees' }, | 
			
		
	
	
		
		
			
				
					|  |  | @ -232,9 +297,7 @@ menu, and follow instructions below:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |     validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode') |  |  |  |     validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode') | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'ui' then |  |  |  | exec_finder(find_ui, 'ui') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_ui() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- ui_sidebar_menus |  |  |  | -- ui_sidebar_menus | 
			
		
	
	
		
		
			
				
					|  |  | @ -261,21 +324,19 @@ local function is_valid_ui_sidebar_menus(usm) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_ui_sidebar_menus() |  |  |  | local function find_ui_sidebar_menus() | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | Searching for ui_sidebar_menus. Please open the add job |  |  |  | Searching for ui_sidebar_menus. Please open the add job | 
			
		
	
		
		
			
				
					
					|  |  |  | ui of Mason, Craftsdwarfs, or Carpenters workshop, and |  |  |  | ui of Mason, Craftsdwarfs, or Carpenters workshop, and | 
			
		
	
		
		
			
				
					
					|  |  |  | select entries in the list:]], |  |  |  | select entries in the list:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |         'int32_t', |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |         { 0, 1, 2, 3, 4, 5, 6 } |  |  |  |         { 0, 1, 2, 3, 4, 5, 6 }, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ordinal_names | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |     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 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'ui_sidebar_menus' then |  |  |  | exec_finder(find_ui_sidebar_menus, 'ui_sidebar_menus') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_ui_sidebar_menus() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- ui_build_selector |  |  |  | -- ui_build_selector | 
			
		
	
	
		
		
			
				
					|  |  | @ -299,8 +360,7 @@ local function is_valid_ui_build_selector(ubs) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_ui_build_selector() |  |  |  | local function find_ui_build_selector() | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 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 | 
			
		
	
	
		
		
			
				
					|  |  | @ -312,9 +372,7 @@ number, so when it shows "Min (5000df", it means 50000:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |                     addr, df.ui_build_selector, 'plate_info', 'unit_min') |  |  |  |                     addr, df.ui_build_selector, 'plate_info', 'unit_min') | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'ui_build_selector' then |  |  |  | exec_finder(find_ui_build_selector, 'ui_build_selector') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_ui_build_selector() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- ui_selected_unit |  |  |  | -- ui_selected_unit | 
			
		
	
	
		
		
			
				
					|  |  | @ -322,7 +380,7 @@ end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_ui_selected_unit() |  |  |  | local function find_ui_selected_unit() | 
			
		
	
		
		
			
				
					
					|  |  |  |     if not is_known 'world' then |  |  |  |     if not is_known 'world' then | 
			
		
	
		
		
			
				
					
					|  |  |  |         dfhack.printerr('Cannot find ui_selected_unit: no world') |  |  |  |         dfhack.printerr('Cannot search for ui_selected_unit: no world') | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         return |  |  |  |         return | 
			
		
	
		
		
			
				
					
					|  |  |  |     end |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -330,30 +388,27 @@ local function find_ui_selected_unit() | 
			
		
	
		
		
			
				
					
					|  |  |  |         dfhack.units.setNickname(unit, i) |  |  |  |         dfhack.units.setNickname(unit, i) | 
			
		
	
		
		
			
				
					
					|  |  |  |     end |  |  |  |     end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | Searching for ui_selected_unit. Please activate the 'v' |  |  |  | Searching for ui_selected_unit. Please activate the 'v' | 
			
		
	
		
		
			
				
					
					|  |  |  | mode, point it at units, and enter their numeric nickname |  |  |  | mode, point it at units, and enter their numeric nickname | 
			
		
	
		
		
			
				
					
					|  |  |  | into the prompts below:]], |  |  |  | into the prompts below:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |         'int32_t', |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |         function() |  |  |  |         function() | 
			
		
	
		
		
			
				
					
					|  |  |  |             return utils.prompt_input('  Enter index: ', utils.check_number) |  |  |  |             return utils.prompt_input('  Enter index: ', utils.check_number) | 
			
		
	
		
		
			
				
					
					|  |  |  |         end |  |  |  |         end, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'noprompt' | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |     ms.found_offset('ui_selected_unit', addr) |  |  |  |     ms.found_offset('ui_selected_unit', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'ui_selected_unit' then |  |  |  | exec_finder(find_ui_selected_unit, 'ui_selected_unit') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_ui_selected_unit() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | -- ui_unit_view_mode |  |  |  | -- ui_unit_view_mode | 
			
		
	
		
		
			
				
					
					|  |  |  | -- |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | local function find_ui_unit_view_mode() |  |  |  | local function find_ui_unit_view_mode() | 
			
		
	
		
		
			
				
					
					|  |  |  |     local addr = ms.find_menu_cursor( |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         searcher, [[ |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 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', | 
			
		
	
	
		
		
			
				
					|  |  | @ -363,6 +418,143 @@ with 'v', switch the pages as requested:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |     ms.found_offset('ui_unit_view_mode', addr) |  |  |  |     ms.found_offset('ui_unit_view_mode', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if scan_all or not is_known 'ui_unit_view_mode' then |  |  |  | exec_finder(find_ui_unit_view_mode, 'ui_unit_view_mode') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     find_ui_unit_view_mode() |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- ui_look_cursor | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function look_item_list_count() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return #df.global.ui_look_list.items | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_ui_look_cursor() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for ui_look_cursor. Please activate the 'k' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | mode, find a tile with many items or units on the ground, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | and select list entries as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         list_index_choices(look_item_list_count), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ordinal_names | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('ui_look_cursor', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_ui_look_cursor, 'ui_look_cursor') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- ui_building_item_cursor | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function building_item_list_count() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return #df.global.world.selected_building.contained_items | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_ui_building_item_cursor() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for ui_building_item_cursor. Please activate the 't' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | mode, find a cluttered workshop, trade depot, or other building | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | with many contained items, and select as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         list_index_choices(building_item_list_count), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ordinal_names | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('ui_building_item_cursor', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_ui_building_item_cursor, 'ui_building_item_cursor') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- ui_workshop_in_add | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_ui_workshop_in_add() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for ui_workshop_in_add. Please activate the 'q' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | mode, find a workshop without jobs (or delete jobs), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | and do as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int8_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         { 1, 0 }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         { [1] = 'enter the add job menu', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           [0] = 'add job, thus exiting the menu' } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('ui_workshop_in_add', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | --exec_finder(find_ui_workshop_in_add, 'ui_workshop_in_add') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- ui_workshop_job_cursor | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function workshop_job_list_count() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return #df.global.world.selected_building.jobs | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_ui_workshop_job_cursor() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_menu_cursor([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for ui_workshop_job_cursor. Please activate the 'q' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | mode, find a workshop with many jobs, and select as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         list_index_choices(workshop_job_list_count), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ordinal_names | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('ui_workshop_job_cursor', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_ui_workshop_job_cursor, 'ui_workshop_job_cursor') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- window_x | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_window_x() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_counter([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for window_x. Please exit to main dwarfmode menu, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | scroll to the LEFT edge, then do as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', 10, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'Please press Right to scroll right one step.' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('window_x', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_window_x, 'window_x') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- window_y | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_window_y() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_counter([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for window_y. Please exit to main dwarfmode menu, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | scroll to the TOP edge, then do as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', 10, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'Please press Down to scroll down one step.' | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('window_y', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  | end |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | exec_finder(find_window_y, 'window_y') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- window_z | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | local function find_window_z() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     local addr = searcher:find_counter([[ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Searching for window_z. Please exit to main dwarfmode menu, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | scroll to ground level, then do as instructed:]], | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         'int32_t', -1, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         "Please press '>' to scroll 1 Z level down." | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ms.found_offset('window_z', addr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | end | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | --exec_finder(find_window_z, 'window_z') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- THE END | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | -- | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | print('Done.') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | searcher:reset() | 
			
		
	
	
		
		
			
				
					|  |  | 
 |