forge/testScripts/ports/karisPort.singe
2026-10-06 16:57:52 -05:00

106 lines
3.7 KiB
Text

-- The Forge port of a KarisFramework game, driven and traced as the original is.
local here = ((debug.getinfo(1, "S").source:gsub("^@", "")):match("^(.*[/\\])") or "")
QTE_LEVEL_FINISH = 110
local library = os.getenv("SINGE_LIBRARY") or (os.getenv("HOME") .. "/claude/singetest/ported")
local game = os.getenv("PORT_GAME") or "TimeGal"
local name = (os.getenv("PORT_SCRIPT") or "Timegal.singe"):gsub("%.singe$", "")
local stem = name:match("([^/\\]+)$")
dofile("Forge/AuthorCompile.singe")
dofile(here .. "karisDrive.singe")
local realSkip = discSkipToFrame
discSkipToFrame = function(frame)
karisTraceSeek(frame)
return realSkip(frame)
end
dofile(authorBuild(library .. "/" .. game .. "/" .. name .. ".forge", singeGetDataPath() .. stem .. ".port.singe"))
local realUpdate = onOverlayUpdate
local frames = 0
function karisPress(switch, down)
if down then
authorSwitchDown(switch)
else
authorSwitchUp(switch)
end
end
function karisMouse(x, y)
onMouseMoved(x, y, 0, 0, 0)
end
local function view()
local q = authorEntity("game").q
-- The style the qte behaviour plays, as the flags the view reports.
local held = (q.qteStyle == "held")
local checkpoints = (q.qteStyle == "checkpoints")
local segmented = (q.qteStyle == "segments") or checkpoints or (q.qteStyle == "trophies")
local m = q.move[q.currentMove]
local window = nil
local chosen = nil
if checkpoints then
if (q.currentLevel == 103) and m and (m[2] ~= nil) then
window = { from = m[2], to = m[3], kind = m[7], death = 0, alt = 0, alt2 = 0 }
end
elseif (q.currentLevel == 103) and m and (m[1] ~= nil) then
window = { from = m[1], to = m[2], kind = m[3], death = m[4], alt = m[5], alt2 = m[6] }
end
local zone = (m and (m[3] == q.ACTDOWN) and (m[7] ~= nil)) and { m[7], m[8], m[9], m[10] } or nil
local mouse = q.ratiox and { q.ratiox, q.ratioy, q.ratioxOffset, q.ratioyOffset } or nil
local pairs = nil
if segmented and q.ACTUP then
pairs = karisPairs(q)
end
if ((q.lvlState == 19) or (segmented and (q.lvlState == 11))) and q.choice then
chosen = {}
for index, c in ipairs(q.choice) do
chosen[index] = { right = c[2] }
end
end
if checkpoints and (q.lvlState == 12) and q.opt then
chosen = {}
for index, c in ipairs(q.opt) do
chosen[index] = { right = c[2] }
end
end
-- Kimmy's new-game menu is a level the framework never numbered (nil there); the port
-- numbers it, and reports it as the original does.
local screen = q.currentLevel
if held and (screen == q.levelNG) then
screen = nil
end
-- The map-mode lineage never numbered its finish screen either.
if segmented and (screen == QTE_LEVEL_FINISH) then
screen = nil
end
return { screen = screen, step = q.lvlState, level = q.iLevel or q.iCurPos or q.iStageIndex, scene = q.iScene or q.iSegPointer, move = q.currentMove, frame = discGetFrame(), frames = frames, score = q.iScore, lives = q.iLives, window = window, choices = chosen, order = q.optorder, choice = q.iChoice,
kimmy = held, rdg = segmented, timegal = checkpoints, multi = held and q.multi[q.currentMove] or nil, path = held and q.path[q.currentMove] or nil, timed = held and q.timed or nil,
freeplay = (q.dip_CoinsPerCredit == q.DOPT_FREEPLAY), credits = q.iCredits, zone = zone, mouse = mouse, pairs = pairs, mashKind = segmented and q.MASH or nil,
hud = karisHudFlags(function(name) return q[name] end), service = karisServiceState(screen, function(name) return q[name] end) }
end
function onOverlayUpdate()
frames = frames + 1
if authorEntity("game").q.gameflow == "running" then
karisDrive(view())
end
local r = realUpdate()
if (frames > 100) and karisDone(view()) or (frames > KARIS_FRAMES) then
debugPrint("TRACE end after " .. frames .. " frames")
singeQuit()
end
return r
end