singe/testScripts/scene61.singe
2026-09-14 14:20:17 -05:00

103 lines
3.1 KiB
Text

-- Forge milestone 2, genre one: the rail shooter. A camera on a rail that stops at encounters,
-- zombies that spawn there and walk to it, a gun whose ray says which part it hit, ragdolls, and
-- the rail moving on when the stop is clear. The pointer is aimed at each zombie's head through
-- sceneProject, which is what a light gun would do with a person behind it.
dofile("Forge/AuthorCompile.singe")
local font = fontLoad("Singe/FreeSansBold.ttf", 18)
fontSelect(font)
fontQuality(FONT_QUALITY_BLENDED)
dofile(authorBuild("testScripts/author/railshooter.game", singeGetDataPath() .. "railshooter.singe"))
local gameUpdate = onOverlayUpdate
local frames = 0
local shots = 0
local hits = 0
local heads = 0
local kills = 0
local stopped = 0
local ended = false
local lastShot = 0
local GIVE_UP = 60
local realEvent = authorEvent
function authorEvent(name, event)
if name == "hit" then
hits = hits + 1
if event.part == "head" then
heads = heads + 1
end
elseif name == "death" then
kills = kills + 1
elseif name == "stopped" then
stopped = stopped + 1
elseif name == "railEnd" then
ended = true
end
return realEvent(name, event)
end
local function fire(x, y, on)
authorSetPointer(1, x, y, on)
authorSwitchDown(SWITCH_BUTTON3)
authorSwitchUp(SWITCH_BUTTON3)
end
function onOverlayUpdate()
local t = authorTime()
local gun = authorEntity("gun1")
frames = frames + 1
-- Aim at the nearest living zombie's head and fire, no faster than a person would; reload
-- off the picture when empty.
if gun and (t - lastShot > 0.25) then
local nearest, best = nil, math.huge
for _, zombie in ipairs(authorEach("zombie")) do
if zombie.vars.state ~= "dead" then
local far = authorDistance(zombie, authorEntity("camera"))
if far < best then
nearest, best = zombie, far
end
end
end
if gun.vars.ammo <= 0 then
fire(-10, -10, false)
lastShot = t
elseif nearest then
local head = nodeFind("b_Head_05", nearest.model)
local hx, hy, hz = nodeGetWorldPosition(head)
local sx, sy, _, inFront = sceneProject(hx, hy, hz)
if inFront then
fire(sx, sy, true)
lastShot = t
end
end
end
local r = gameUpdate()
colorForeground(255, 255, 255, 255)
fontPrint(12, 450, string.format("authored rail shooter, %.1fs, zombies %d, kills %d, heads %d, stops %d", t, authorCount("zombie"), kills, heads, stopped))
if (shots == 0 and t > 5) or (shots == 1 and kills > 0) or (shots == 2 and stopped == 2) or (shots == 3 and ended) then
shots = shots + 1
singeScreenshot()
end
if (ended and t > 1) or (t > GIVE_UP) then
debugPrint(string.format("RAIL RESULT score=%d health=%d bites=%d stops=%d kills=%d hits=%d heads=%d ended=%s after=%.1fs",
AUTHOR_VARS.score, AUTHOR_VARS.health, AUTHOR_VARS.bites, stopped, kills, hits, heads, tostring(ended), t))
if stopped < 2 then debugPrint("RAIL FAIL the rail did not reach both stops") end
if kills < 7 then debugPrint("RAIL FAIL not every zombie was killed") end
if heads == 0 then debugPrint("RAIL FAIL no shot was reported on the head") end
if not ended then debugPrint("RAIL FAIL the rail never ended") end
singeQuit()
end
return r
end