第 1 卷第 1 章:1–9 年
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
--@ module = true
|
||||
-- 向当前界面发送按键。用法:dfhack-run "dfannals/act SELECT"
|
||||
-- 多个按键按顺序发送:dfhack-run "dfannals/act STANDARDSCROLL_DOWN SELECT"
|
||||
local gui = require('gui')
|
||||
|
||||
local args = {...}
|
||||
local scr = dfhack.gui.getCurViewscreen()
|
||||
local sent = {}
|
||||
|
||||
for _, name in ipairs(args) do
|
||||
local key = df.interface_key[name]
|
||||
if key then
|
||||
scr:feed_key(key)
|
||||
sent[#sent + 1] = name
|
||||
else
|
||||
sent[#sent + 1] = '?未知按键:' .. name
|
||||
end
|
||||
end
|
||||
|
||||
local f = io.open('dfannals-act.log', 'a')
|
||||
if f then
|
||||
f:write(string.format('%s\t%s\tfocus=%s\n', os.date('%H:%M:%S'),
|
||||
table.concat(sent, ' '), table.concat(dfhack.gui.getCurFocus(), '/')))
|
||||
f:close()
|
||||
end
|
||||
|
||||
print('sent: ' .. table.concat(sent, ' '))
|
||||
@@ -0,0 +1,28 @@
|
||||
--@ module = true
|
||||
-- 在窗口坐标 (x, y) 模拟一次左键点击。用法:dfhack-run "dfannals/click 160 40"
|
||||
-- 方式与 DFHack 自带测试工具一致:设置鼠标位置后 simulateInput('_MOUSE_L')。
|
||||
local gui = require('gui')
|
||||
|
||||
local args = {...}
|
||||
local x, y = tonumber(args[1]), tonumber(args[2])
|
||||
if not x or not y then
|
||||
print('用法: dfannals/click <x> <y>')
|
||||
return
|
||||
end
|
||||
|
||||
df.global.gps.mouse_x = math.floor(x)
|
||||
df.global.gps.precise_mouse_x = math.floor(x) * df.global.gps.tile_pixel_x
|
||||
df.global.gps.mouse_y = math.floor(y)
|
||||
df.global.gps.precise_mouse_y = math.floor(y) * df.global.gps.tile_pixel_y
|
||||
|
||||
local scr = dfhack.gui.getCurViewscreen()
|
||||
gui.simulateInput(scr, '_MOUSE_L')
|
||||
|
||||
local f = io.open('dfannals-act.log', 'a')
|
||||
if f then
|
||||
f:write(string.format('%s\tclick %d,%d\tfocus=%s\n', os.date('%H:%M:%S'), x, y,
|
||||
table.concat(dfhack.gui.getCurFocus(), '/')))
|
||||
f:close()
|
||||
end
|
||||
|
||||
print(string.format('clicked %d,%d', x, y))
|
||||
@@ -0,0 +1,57 @@
|
||||
--@ module = true
|
||||
-- 把当前界面的字段结构导出到 dfannals-dump.txt,用于摸清 UI 元素。
|
||||
-- 用法:dfhack-run "dfannals/dump"
|
||||
local MAX_ITEMS = 400
|
||||
|
||||
local function is_scalar(v)
|
||||
local t = type(v)
|
||||
return t == 'number' or t == 'string' or t == 'boolean'
|
||||
end
|
||||
|
||||
local function describe(obj, max_depth)
|
||||
local out = {}
|
||||
local function rec(o, prefix, depth)
|
||||
if depth > max_depth or #out > MAX_ITEMS then return end
|
||||
local ok, iter, state, ctrl = pcall(pairs, o)
|
||||
if not ok then return end
|
||||
for k, v in iter, state, ctrl do
|
||||
if #out > MAX_ITEMS then return end
|
||||
local key = tostring(k)
|
||||
if is_scalar(v) then
|
||||
out[#out + 1] = string.format('%s%s = %s', prefix, key, tostring(v))
|
||||
else
|
||||
local t = type(v)
|
||||
out[#out + 1] = string.format('%s%s <%s>', prefix, key, t)
|
||||
if t == 'table' or t == 'userdata' then
|
||||
rec(v, prefix .. ' ', depth + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rec(obj, '', 1)
|
||||
return out
|
||||
end
|
||||
|
||||
local f = io.open('dfannals-dump.txt', 'w')
|
||||
if not f then return end
|
||||
|
||||
local function write(line) f:write(line .. '\n') end
|
||||
|
||||
write('# focus=' .. table.concat(dfhack.gui.getCurFocus(), '/'))
|
||||
write('# date=' .. os.date('%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
local scr = dfhack.gui.getCurViewscreen()
|
||||
local depth = 0
|
||||
while scr and depth < 3 do
|
||||
write('==== 屏幕层 ' .. depth .. ' ====')
|
||||
local ok, lines = pcall(describe, scr, 2)
|
||||
if ok then
|
||||
for _, l in ipairs(lines) do write(l) end
|
||||
else
|
||||
write('(失败: ' .. tostring(lines) .. ')')
|
||||
end
|
||||
scr = scr.parent
|
||||
depth = depth + 1
|
||||
end
|
||||
|
||||
f:close()
|
||||
@@ -0,0 +1,39 @@
|
||||
--@ module = true
|
||||
-- 观测模式:把界面焦点变化持续追加到 dfannals-observe.log。
|
||||
-- 用途:发现"新建世界 → 进入 legends → 导出"之间的真实界面序列。
|
||||
|
||||
local repeatUtil = require('repeat-util')
|
||||
|
||||
local LOG = 'dfannals-observe.log'
|
||||
local last = nil
|
||||
local ticks = 0
|
||||
|
||||
local function focus_string()
|
||||
local ok, focus = pcall(dfhack.gui.getCurFocus)
|
||||
if not ok or not focus then return '?' end
|
||||
return table.concat(focus, '/')
|
||||
end
|
||||
|
||||
function tick()
|
||||
ticks = ticks + 1
|
||||
local fs = focus_string()
|
||||
if fs ~= last then
|
||||
last = fs
|
||||
local f = io.open(LOG, 'a')
|
||||
if f then
|
||||
f:write(string.format('%s\t%s\n', os.date('%H:%M:%S'), fs))
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function start()
|
||||
repeatUtil.scheduleEvery('dfannals-observe', 10, tick)
|
||||
local f = io.open(LOG, 'a')
|
||||
if f then
|
||||
f:write('--- observe start ' .. os.date('%Y-%m-%d %H:%M:%S') .. '\n')
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
start()
|
||||
@@ -0,0 +1,56 @@
|
||||
--@ module = true
|
||||
-- 把当前界面状态写入 dfannals-probe.txt,供 WSL 侧读取。
|
||||
-- 用法(在 WSL 里):"Dwarf Fortress.exe" 所在目录的 dfhack-run.exe dfannals/probe
|
||||
|
||||
local function safe_type(obj)
|
||||
if not obj then return '?' end
|
||||
local ok, t = pcall(function() return obj._type end)
|
||||
if ok and t then return tostring(t) end
|
||||
return '?'
|
||||
end
|
||||
|
||||
local function viewstack()
|
||||
local out = {}
|
||||
local scr = dfhack.gui.getCurViewscreen()
|
||||
local depth = 0
|
||||
while scr and depth < 15 do
|
||||
out[#out + 1] = string.format('[%d] %s', depth, safe_type(scr))
|
||||
local ok, parent = pcall(function() return scr.parent end)
|
||||
if not ok then break end
|
||||
scr = parent
|
||||
depth = depth + 1
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
local function world_info()
|
||||
local lines = {}
|
||||
local ok, folder = pcall(dfhack.world.ReadWorldFolder)
|
||||
lines[#lines + 1] = 'world_folder=' .. (ok and tostring(folder) or '?')
|
||||
local ok2, year = pcall(dfhack.world.ReadCurrentYear)
|
||||
lines[#lines + 1] = 'current_year=' .. (ok2 and tostring(year) or '?')
|
||||
local ok3, legends = pcall(dfhack.world.isLegends)
|
||||
lines[#lines + 1] = 'is_legends=' .. (ok3 and tostring(legends) or '?')
|
||||
local ok4, fort = pcall(dfhack.world.isFortressMode)
|
||||
lines[#lines + 1] = 'is_fortress=' .. (ok4 and tostring(fort) or '?')
|
||||
local ok5, name = pcall(function() return dfhack.translation.translateName(df.global.world.world_data.name) end)
|
||||
lines[#lines + 1] = 'world_name=' .. (ok5 and tostring(name) or '?')
|
||||
return lines
|
||||
end
|
||||
|
||||
function dump()
|
||||
local lines = {}
|
||||
local ok, focus = pcall(dfhack.gui.getCurFocus)
|
||||
lines[#lines + 1] = 'focus=' .. ((ok and focus) and table.concat(focus, '/') or '?')
|
||||
for _, l in ipairs(world_info()) do lines[#lines + 1] = l end
|
||||
lines[#lines + 1] = 'viewstack:'
|
||||
for _, l in ipairs(viewstack()) do lines[#lines + 1] = ' ' .. l end
|
||||
|
||||
local f = io.open('dfannals-probe.txt', 'w')
|
||||
if f then
|
||||
f:write(table.concat(lines, '\n') .. '\n')
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
dump()
|
||||
@@ -0,0 +1,49 @@
|
||||
--@ module = true
|
||||
-- 遍历当前界面的控件树,导出控件名与矩形坐标,用于定位可点击目标。
|
||||
-- 用法:dfhack-run "dfannals/widgets"
|
||||
local MAX_DEPTH = 8
|
||||
local MAX_LINES = 600
|
||||
|
||||
local function rect_str(w)
|
||||
local ok, r = pcall(function() return w.rect end)
|
||||
if not ok or not r then return '' end
|
||||
local function g(k)
|
||||
local ok2, v = pcall(function() return r[k] end)
|
||||
return ok2 and tostring(v) or '?'
|
||||
end
|
||||
return string.format('rect=(%s,%s)-(%s,%s)', g('x1'), g('y1'), g('x2'), g('y2'))
|
||||
end
|
||||
|
||||
local out = {}
|
||||
local function walk(w, depth)
|
||||
if not w or depth > MAX_DEPTH or #out > MAX_LINES then return end
|
||||
local ok, name = pcall(function() return w.name end)
|
||||
local nm = ok and tostring(name) or ''
|
||||
local txt = ''
|
||||
local ok3, t = pcall(function() return w.text end)
|
||||
if ok3 and t then txt = tostring(t) end
|
||||
out[#out + 1] = string.format('%s%s %s %s', string.rep(' ', depth), nm, rect_str(w),
|
||||
txt ~= '' and ('text=' .. txt) or '')
|
||||
local ok2, children = pcall(function() return w.children end)
|
||||
if ok2 and children then
|
||||
for _, c in ipairs(children) do walk(c, depth + 1) end
|
||||
end
|
||||
end
|
||||
|
||||
local f = io.open('dfannals-widgets.txt', 'w')
|
||||
if not f then return end
|
||||
f:write('# focus=' .. table.concat(dfhack.gui.getCurFocus(), '/') .. '\n')
|
||||
|
||||
local sw, sh = dfhack.screen.getWindowSize()
|
||||
f:write(string.format('# window=%dx%d\n', sw, sh))
|
||||
|
||||
local scr = dfhack.gui.getCurViewscreen()
|
||||
local ok, widgets = pcall(function() return scr.widgets end)
|
||||
if ok and widgets then
|
||||
walk(widgets, 0)
|
||||
else
|
||||
out[#out + 1] = '(该界面没有 widgets 字段)'
|
||||
end
|
||||
|
||||
for _, l in ipairs(out) do f:write(l .. '\n') end
|
||||
f:close()
|
||||
Reference in New Issue
Block a user