-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest.lua
More file actions
202 lines (179 loc) · 6.82 KB
/
test.lua
File metadata and controls
202 lines (179 loc) · 6.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
-- test.lua
-- Continuous scanner for combat activity sides[] and unit path goals.
-- Usage:
-- test -- toggle on/off
-- test stop -- stop explicitly
--
-- Writes to test_results.txt (appended, with tick timestamps).
-- On first enable: does a full one-shot dump of enum values and sides structure.
-- Every 10 ticks: logs a quick per-unit snapshot (path goal, activity).
local repeatUtil = require("repeat-util")
local CALLBACK_ID = "test_scanner"
local SCAN_INTERVAL = 10 -- ticks between quick scans
local enabled = false
local log_file = nil
local scan_count = 0
local function open_log()
log_file = io.open("test_results.txt", "a")
if log_file then
log_file:write(("\n\n=== SESSION START frame=%d ===\n"):format(
df.global.world.frame_counter))
log_file:flush()
end
end
local function close_log()
if log_file then log_file:close(); log_file = nil end
end
local function w(fmt, ...)
local s = fmt:format(...)
if log_file then log_file:write(s .. "\n"); log_file:flush() end
end
---------------------------------------------------------------------------
-- ONE-SHOT FULL DUMP (runs once on enable)
---------------------------------------------------------------------------
local function full_dump()
local frame = df.global.world.frame_counter
w("--- FULL DUMP @ frame=%d ---", frame)
-- unit_path_goal enum
w("[unit_path_goal]")
local goal_names = {
"None", "SeekStation", "ArcherReposition", "MoveItem",
"AttemptFlee", "SeekDFGoal", "ReturnHome", "Wander",
"AttackTarget", "Rout", "Flee", "Travel", "Wait",
"Rest", "Eat", "Drink", "Sleep",
-- Additional guesses for unknowns 3, 179, 180
"SeekEnemy", "Attack", "Chase", "Pursue", "Engage",
"HoldPosition", "TakePosition", "SeekCover", "Cover",
"Flank", "Regroup", "Retreat", "SeekSafety",
"GoHome", "GoStation", "GuardPost", "Lurk",
"SeekTarget", "ChargeTarget", "MoveToTarget",
"Ambush", "Patrol", "Guard", "Defend",
"Formation", "Rally", "Advance", "Skirmish",
"SeekFlee", "Rescue", "Aid",
}
local goal_map = {}
for _, name in ipairs(goal_names) do
local ok, val = pcall(function() return df.unit_path_goal[name] end)
if ok and type(val) == "number" then
w(" .%s = %d", name, val)
goal_map[val] = name
end
end
-- store for quick scans
_G.__test_goal_map = goal_map
-- activity_entry_type by number
w("[activity_entry_type 0..14]")
for i = 0, 14 do
local ok, name = pcall(function() return df.activity_entry_type[i] end)
if ok then w(" [%d] = %s", i, tostring(name)) end
end
-- combat activity sides
w("[combat activity sides]")
pcall(function()
for _, entry in ipairs(df.global.world.activities.all) do
if entry.type ~= 2 then goto next_e end
w(" activity id=%d type=2", entry.id)
for i = 0, #entry.events - 1 do
local ev = entry.events[i]
w(" event[%d] sides_count=%d", i, #ev.sides)
for j = 0, #ev.sides - 1 do
local side = ev.sides[j]
w(" side[%d]:", j)
pcall(function()
for k, v in pairs(side) do
w(" .%s = %s", tostring(k), tostring(v))
end
end)
pcall(function()
for k, v in pairs(side.flags) do
w(" .flags.%s = %s", tostring(k), tostring(v))
end
end)
pcall(function()
if #side.units > 0 then
local ids = {}
for u = 0, #side.units - 1 do
ids[#ids+1] = tostring(side.units[u])
end
w(" .units=[%s]", table.concat(ids, ","))
end
end)
end
end
::next_e::
end
end)
w("--- END FULL DUMP ---")
end
---------------------------------------------------------------------------
-- QUICK SCAN (every SCAN_INTERVAL ticks)
---------------------------------------------------------------------------
local function quick_scan()
local frame = df.global.world.frame_counter
local goal_map = _G.__test_goal_map or {}
scan_count = scan_count + 1
-- Check which units are in magazine reload windows
local in_reload = {}
pcall(function()
local ammo = _G.__ammo
if not ammo or not ammo.reloading then return end
for key, until_frame in pairs(ammo.reloading) do
if frame < until_frame then
-- key format: "unit_id:sub_id:mat_t:mat_i"
local uid = tonumber(key:match("^(%d+):"))
if uid then in_reload[uid] = true end
end
end
end)
-- Only log if something interesting is happening
local lines = {}
for _, unit in ipairs(df.global.world.units.active) do
if dfhack.units.isDead(unit) then goto skip end
local goal, dest = -1, "?"
pcall(function()
goal = unit.path.goal
dest = ("(%d,%d,%d)"):format(unit.path.dest.x, unit.path.dest.y, unit.path.dest.z)
end)
local goal_name = goal_map[goal] or ("UNKNOWN(%d)"):format(goal)
local reload_tag = in_reload[unit.id] and " [RELOAD]" or ""
lines[#lines+1] = (" unit#%d goal=%s dest=%s%s"):format(
unit.id, goal_name, dest, reload_tag)
::skip::
end
if #lines > 0 then
w("[scan#%d frame=%d]", scan_count, frame)
for _, l in ipairs(lines) do w(l) end
end
end
---------------------------------------------------------------------------
-- ENABLE / DISABLE
---------------------------------------------------------------------------
local function stop()
repeatUtil.cancel(CALLBACK_ID)
close_log()
enabled = false
print("[test] Scanner stopped.")
end
local function start()
open_log()
full_dump()
repeatUtil.scheduleEvery(CALLBACK_ID, SCAN_INTERVAL, "ticks", quick_scan)
enabled = true
print(("[test] Scanner started — logging to test_results.txt every %d ticks."):format(
SCAN_INTERVAL))
end
dfhack.onStateChange[CALLBACK_ID] = function(sc)
if sc == SC_WORLD_UNLOADED and enabled then stop() end
end
---------------------------------------------------------------------------
-- ARGUMENT PARSING
---------------------------------------------------------------------------
local args = { ... }
local cmd = args[1] or "toggle"
if cmd == "stop" then
stop()
elseif cmd == "toggle" then
if enabled then stop() else start() end
else
print("[test] Usage: test [stop]")
end