Delay evolution until trainer text ends

This commit is contained in:
johnjohto
2026-07-30 10:25:08 -04:00
parent b99b497893
commit 4250e3aa32
4 changed files with 101 additions and 1 deletions
+12 -1
View File
@@ -265,7 +265,18 @@ function Commands.start_battle(ctx, kind, a, b)
ctx.lastBattleResult = result
ctx.lastCheck = result == "win"
if ctx.overworld then
ctx.overworld:afterBattle(result, battle)
-- A map script often follows a trainer battle with its own text.
-- Keep a level evolution behind that text: otherwise afterBattle
-- pushes the evolution screen, then this runner resumes and pushes
-- the trainer's text on top of it.
if result == "win" then
ctx.afterScript = ctx.afterScript or {}
table.insert(ctx.afterScript, function()
ctx.overworld:afterBattle(result, battle)
end)
else
ctx.overworld:afterBattle(result, battle)
end
end
runner:resume()
end
+4
View File
@@ -125,6 +125,10 @@ function ScriptRunner:run(script, extra)
end
self.co = coroutine.create(function()
self:exec(script, ctx)
-- Commands can defer a game action until the script's own dialogue is
-- done. start_battle uses this for win-path evolutions, which must not
-- be covered by post-battle trainer text.
for _, callback in ipairs(ctx.afterScript or {}) do callback() end
if ctx.onDone then ctx.onDone() end
if Runtime.wants("script.ended") then
Runtime.emit("script.ended", { ctx = ctx, completed = true })
+84
View File
@@ -0,0 +1,84 @@
-- A trainer script's post-battle text must finish before a level evolution.
-- Its start_battle row resumes the script after OverworldState:afterBattle,
-- so this covers the same handoff used by trainer and Rocket encounters.
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local Data = require("src.core.Data")
if not Data.maps then Data:load() end
local S = require("tests.harness").suite("parity trainer evolution order")
local check = S.check
local Game = require("src.core.Game")
local SaveData = require("src.core.SaveData")
local StateStack = require("src.core.StateStack")
local ScriptRunner = require("src.script.ScriptRunner")
local OverworldState = require("src.world.OverworldController")
local Pokemon = require("src.pokemon.Pokemon")
require("src.render.Font").load(Data)
Game.data = Data
Game.save = SaveData.newGame()
Game.stack = StateStack; StateStack:init()
Game.renderer = { worldViewSize = function() return 160, 144 end }
local caterpie = Pokemon.new(Data, "CATERPIE", 7)
Game.save.party = { caterpie }
local fakeBattle
local originalBattleState = package.loaded["src.battle.BattleState"]
package.loaded["src.battle.BattleState"] = {
newTrainer = function()
fakeBattle = { leveledUp = { [caterpie] = true } }
return fakeBattle
end,
}
local overworld = setmetatable({}, { __index = OverworldState })
overworld:enter("ROUTE_1", 5, 5, "down")
local runner = ScriptRunner.new(Game, overworld)
runner:run({
{ "start_battle", "trainer", "OPP_YOUNGSTER", 1 },
{ "show_text", "THE TRAINER TALKS AFTER THE FIGHT" },
{ "show_text", "THE TRAINER HAS MORE TO SAY" },
})
check(fakeBattle ~= nil, "trainer battle starts and yields the script")
Game.stack:pop()
fakeBattle.onFinish("win")
package.loaded["src.battle.BattleState"] = originalBattleState
local function stateHas(state, text)
for _, page in ipairs(state.pages or {}) do
for _, line in ipairs(page) do
if type(line) == "string" and line:find(text, 1, true) then return true end
end
end
return false
end
local afterText = Game.stack:top()
check(stateHas(afterText, "THE TRAINER TALKS"),
"the trainer's after-battle text is shown first")
check(#Game.stack.states == 1,
"the evolution screen waits until trainer after-text closes")
Game.stack:pop()
afterText.onDone()
local moreText = Game.stack:top()
check(stateHas(moreText, "MORE TO SAY"),
"all trainer after-text finishes before evolution")
check(#Game.stack.states == 1,
"the evolution still waits for the last trainer text")
Game.stack:pop()
moreText.onDone()
local evolutionText = Game.stack:top()
check(stateHas(evolutionText, "evolving"),
"the level evolution starts after trainer after-text closes")
S.finish()
+1
View File
@@ -3279,6 +3279,7 @@ runSuites(orderedGlob("tests/parity_*.lua", {
"tests/parity_hof.lua", "tests/parity_trade_gift.lua",
"tests/parity_yellow_trades.lua",
"tests/parity_yellow_bills_pikachu.lua",
"tests/parity_trainer_evolution_order.lua",
"tests/parity_intro.lua", "tests/parity_tilt.lua",
"tests/parity_gbcfx.lua",
}))