voxel_fix_shots.lua
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
-- Scratch driver: one shot of each fixture the wall-top / statue pass -- touched, so the change can be looked at rather than reasoned about. -- -- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/voxel_fix_shots.lua \ -- SHOT_DIR=mods/DramaticShapeVoxelMod/.claude/voxel_fix AB_TAG=. lovec.exe . -- -- SHOT_DIR is relative to the PROJECT ROOT, which is where lovec runs from -- -- the mod's own .claude/ is where these belong, so it has to be spelt out. -- -- Every scene stands the player on the nearest WALKABLE cell to the vantage -- named below (teleporting into a wall puts the close cameras inside the -- geometry), faces the fixture, and shoots at voxel rung 3 -- the higher -- top-down camera, which is the one that shows what a wall wears on TOP. return function(game) local U = dofile("tests/drivers/util.lua") local Pipelines = require("src.render.Pipelines") local ROOT = (os.getenv("SHOT_DIR") or "mods/DramaticShapeVoxelMod/.claude/voxel_fix") .. "/" .. (os.getenv("AB_TAG") or ".") local handle = game.mods.exports["DRAMATIC_SHAPE"] if not (handle and handle.lib) then print("[voxfix] DRAMATIC_SHAPE mod not loaded") return end local V = handle.lib local DayNight = V.require("DayNight") local ChunkMesher = V.require("ChunkMesher") local Voxel = V.require("VoxelState") local TileShape = V.require("TileShape") -- prove the game is reading THIS tree, not a stale installed copy local ht = TileShape.wallTop and TileShape.wallTop("HOUSE") print(("[voxfix] wallTop present=%s HOUSE(45)=%s") :format(tostring(TileShape.wallTop ~= nil), tostring(ht and ht(45)))) require("src.world.OverworldController").rollEncounter = function() return nil end local TileRenderer = require("src.render.TileRenderer") TileRenderer.tick = function() end TileRenderer.animFrame = function() return 0 end DayNight.setting:sync("day") pcall(os.execute, 'mkdir -p "' .. ROOT .. '" 2>/dev/null') pcall(os.execute, 'mkdir "' .. ROOT:gsub("/", "\\") .. '" 2>nul') local Zoom = require("src.render.Zoom") pcall(function() game.save.options.zoom = 1 Zoom.applyOptions(game.save.options) end) local function settle() for _ = 1, 900 do if ChunkMesher.pending() == 0 then break end U.wait(1) end for _ = 1, 300 do if Voxel.t >= 1 and Voxel.ready and ChunkMesher.pending() == 0 then break end U.wait(1) end U.wait(40) end -- the nearest walkable cell to the vantage, searched in rings -- a -- vantage picked off a map dump is often the fixture itself local function place(x, y, face) local m = game.overworld.map for r = 0, 8 do for dy = -r, r do for dx = -r, r do if math.max(math.abs(dx), math.abs(dy)) == r then local px, py = x + dx, y + dy if m:inBounds(px, py) and m:isWalkableCell(px, py) then game.overworld.player.cellX = px game.overworld.player.cellY = py game.overworld.player.facing = face return px, py end end end end end return x, y end local SCENES = { { map = "BLUES_HOUSE", x = 4, y = 3, face = "up", label = "house_wall_top" }, { map = "VIRIDIAN_POKECENTER", x = 4, y = 3, face = "up", label = "pokecenter_wall_top" }, { map = "ROCKET_HIDEOUT_ELEVATOR", x = 2, y = 3, face = "up", label = "rocket_lift_wall_top" }, { map = "REDS_HOUSE_2F", x = 6, y = 3, face = "up", label = "reds_2f_wall_top" }, { map = "REDS_HOUSE_1F", x = 5, y = 3, face = "up", label = "reds_1f_wall_top" }, { map = "LANCES_ROOM", x = 6, y = 15, face = "up", label = "lances_room_statues" }, { map = "INDIGO_PLATEAU", x = 2, y = 5, face = "up", label = "indigo_plateau_statue" }, -- the west-edge statue itself, close enough to count the birds on it { map = "INDIGO_PLATEAU", x = 1, y = 4, face = "up", label = "indigo_plateau_statue_close", rung = 5 }, { map = "INDIGO_PLATEAU", x = 2, y = 4, face = "up", label = "indigo_plateau_statue_near" }, } local only = os.getenv("VF_ONLY") local shots = 0 for _, s in ipairs(SCENES) do if not (only and only ~= "" and not only:find(s.label, 1, true)) then local ok, err = pcall(function() U.teleport(game, s.map, s.x, s.y, s.face) local px, py = place(s.x, s.y, s.face) Pipelines.setLevel("voxel", s.rung or 3) Pipelines.setLevel("tiltshift", 0) settle() local path = ("%s/%s.png"):format(ROOT, s.label) game.capturePath = path U.wait(8) local f = io.open(path, "rb") if f then f:close() shots = shots + 1 print(("[voxfix] %s -> %s (stood %d,%d)"):format(s.map, path, px, py)) else print("[voxfix] capture missed: " .. path) end end) if not ok then print("[voxfix] " .. s.map .. " failed: " .. tostring(err)) end end end print(("[voxfix] %d/%d shots into %s"):format(shots, #SCENES, ROOT)) love.event.quit() end