-- A Forge release is standalone (FORGE.md). -- -- Building it is half the test; the half that matters is that the result runs somewhere Forge has -- never been. The runtime a compiled game loads is Singe/Author.singe, which whatever Singe the -- player has will have extracted -- but a game should not change behaviour because the engine under -- it moved on, so a release carries its own copy and loads that instead. FORGE_LIBRARY = true dofile("Forge/Forge.singe") local font = fontLoad("Singe/FreeSansBold.ttf", 15) local out = singeGetDataPath() local work = out .. "release.forge" local dest = out .. "Released" fontSelect(font) fontQuality(FONT_QUALITY_BLENDED) overlaySetResolution(720, 480) local source = assert(io.open("testScripts/author/platformer.forge", "r")) local copy = assert(io.open(work, "w")) -- With credits, so the release can be checked for them: the fields go to games.dat, the notes to -- CREDITS.txt, and the licence file travels with the game. copy:write((source:read("a"):gsub("(\n\ttitle%s*=[^\n]*\n)", "%1\tcredits = { developer = \"Test Developer\", year = 1983, notes = { \"Original game: Test Author\", \"Converted by: Test Porter\" }, licenses = { \"LICENSE.txt\" } },\n", 1))) source:close() copy:close() copy = assert(io.open(out .. "LICENSE.txt", "w")) copy:write("A licence the release must carry.\n") copy:close() if not forgeBegin(work) then debugPrint("RELEASE FAIL could not open " .. work) singeQuit() end local frames = 0 local stage = 0 local function step() if stage == 1 then local folder = forgeExport(dest, "Platformer") debugPrint("RELEASE built into " .. tostring(folder)) elseif stage == 2 then -- Everything a standalone game needs has to be there. for _, name in ipairs({ "Platformer.singe", "Author.singe", "games.dat", "Platformer.forge" }) do local f = io.open(dest .. "/" .. name, "r") if f == nil then debugPrint("RELEASE FAIL missing " .. name) else f:close() end end debugPrint("RELEASE all four files present") elseif stage == 3 then -- And it must load its own runtime, not the engine's. local text = assert(io.open(dest .. "/Platformer.singe", "r")):read("a") if text:find('dofile%(here %.%. "Author%.singe"%)') and text:find('debug%.getinfo') then debugPrint("RELEASE the game finds its own directory and loads the runtime there") elseif text:find('Singe/Author%.singe') then debugPrint("RELEASE FAIL the game still loads the engine's runtime, which no longer ships") else debugPrint("RELEASE FAIL the game does not load a runtime at all") end elseif stage == 4 then -- The original author's credits: in games.dat for the menu, the notes in CREDITS.txt, and -- the licence beside the game. local dat = assert(io.open(dest .. "/games.dat", "r")):read("a") local credits = io.open(dest .. "/CREDITS.txt", "r") local licence = io.open(dest .. "/LICENSE.txt", "r") local notes = credits and credits:read("a") or "" if credits then credits:close() end if licence then licence:close() end if dat:find('DEVELOPER = "Test Developer"', 1, true) and dat:find("YEAR = 1983", 1, true) and notes:find("Original game: Test Author", 1, true) and (licence ~= nil) then debugPrint("RELEASE the credits travel: games.dat, CREDITS.txt, and the licence") else debugPrint("RELEASE FAIL credits missing from the release") end elseif stage == 5 then -- Whether it truly stands alone cannot be answered from in here: DIR is the directory of -- the script the engine was *launched* with, so a game reached by dofile would look for the -- runtime beside this scene instead of beside itself. A released game is the main script, -- which is a different run of the engine. harness/verify.sh launches it with -- Singe/Author.singe moved aside and checks it still runs. debugPrint("RELEASE RESULT done") end end function onOverlayUpdate() frames = frames + 1 if frames % 14 == 0 and stage < 6 then stage = stage + 1 step() end if frames == 20 or frames == 70 then singeScreenshot() end if frames > 90 then singeQuit() end return OVERLAY_UPDATED end