diff --git a/src/ui/PartyMenu.lua b/src/ui/PartyMenu.lua index 9bc478fb..6ee4212e 100644 --- a/src/ui/PartyMenu.lua +++ b/src/ui/PartyMenu.lua @@ -304,10 +304,12 @@ function PartyMenu:update(dt) or Strings("{RAM:wNameBuffer} used\nSTRENGTH.")):gsub("{RAM:wNameBuffer}", name) local t2 = (self.game.data.text._CanMoveBouldersText or Strings("{RAM:wNameBuffer} can\nmove boulders.")):gsub("{RAM:wNameBuffer}", name) + -- like surf (#320): the blink belongs UNDER the texts, not as a + -- flashbang on the empty map after them; the stack only updates + -- the top state, so the flash holds until the texts close + self.game.stack:push(Transition.whiteFlash(self.game)) self.game.stack:push(TextBox.new(self.game, t1, function() - self.game.stack:push(TextBox.new(self.game, t2, function() - self.game.stack:push(Transition.whiteFlash(self.game)) - end)) + self.game.stack:push(TextBox.new(self.game, t2)) end, { auto = { sound = function() return require("src.core.Sound").playCry(self.game.data, mon.species) end } })) diff --git a/src/world/OverworldController.lua b/src/world/OverworldController.lua index e2101b85..1fe9b3ef 100644 --- a/src/world/OverworldController.lua +++ b/src/world/OverworldController.lua @@ -2004,23 +2004,19 @@ function OverworldState:trySurf(fx, fy) if not mon then return end local name = mon.nickname or Game.data.pokemon[mon.species].name local p = self.player - p.surfing = true - require("src.core.Music").setSurfing(Game.data, true) local text = (Game.data.text._SurfingGotOnText or Strings("{PLAYER} got on\n{RAM:wNameBuffer}!")) :gsub("{RAM:wNameBuffer}", name) + -- GBPalWhiteOutWithDelay3 runs while the got-on text is still up + -- (start_sub_menus.asm .surf), so the blink reads as a text flash + -- instead of a flashbang on the empty map (#320). The flash sits + -- under the textbox on the stack: only the top state updates, so it + -- holds its frames until the text closes. surfing (and the sprite + -- swap) only applies when the step happens -- no paddling on land. + Game.stack:push(require("src.render.Transition").whiteFlash(Game)) Game.stack:push(TextBox.new(Game, text, function() - -- start_sub_menus.asm .surf: UseItem returns (mount + text done), - -- then GBPalWhiteOutWithDelay3 blinks before the simulated forward - -- press steps onto the water (or across a connection strip, like - -- Cinnabar's east coast onto Route 20) - local Transition = require("src.render.Transition") - if Transition.whiteFlash then - Game.stack:push(Transition.whiteFlash(Game, nil, function() - self:stepForwardOrCrossEdge(p.facing) - end)) - else - self:stepForwardOrCrossEdge(p.facing) - end + p.surfing = true + require("src.core.Music").setSurfing(Game.data, true) + self:stepForwardOrCrossEdge(p.facing) end)) end diff --git a/tests/mod_ui_tests.lua b/tests/mod_ui_tests.lua index a0581ece..0c387c34 100644 --- a/tests/mod_ui_tests.lua +++ b/tests/mod_ui_tests.lua @@ -532,6 +532,30 @@ press(fpm, "a") check(not fpm.submenu and forced == fgame.save.party[1], "forceSwitch still picks immediately (ChooseNextMon / SHIFT)") +-- ------- issue #320: the STRENGTH blink sits under its texts +do + local owStub = { strengthActive = false, + map = { def = { tileset = "OVERWORLD" } }, dark = false } + local sgame = partyGame() + sgame.overworld = owStub + sgame.data.text = {} -- the strength texts fall back to Strings sources + sgame.save.inventory.RAINBOWBADGE = 1 + sgame.save.party[1].moves = { { id = "STRENGTH" } } + local pm = PartyMenu.new(sgame) + pm.game = sgame + sgame.stack:push(pm) + press(pm, "a") -- open the submenu + check(pm.subItems[#pm.subItems].action == "strength", + "the strength row is listed with badge + move") + pm.subIndex = #pm.subItems + press(pm, "a") -- run STRENGTH + local states = sgame.stack.states + check(#states == 2 and states[1].frames ~= nil + and states[2].pages ~= nil, + "the blink sits under the strength texts") + check(owStub.strengthActive == true, "strength still activates") +end + -- ------- mod.ui helpers and theme defaults local items = { { label = "A" }, { label = "B" } } ModUI.insertAfter(items, "A", { label = "X" }) diff --git a/tests/mod_world_tests.lua b/tests/mod_world_tests.lua index caf7ae31..11114556 100644 --- a/tests/mod_world_tests.lua +++ b/tests/mod_world_tests.lua @@ -607,6 +607,38 @@ do end) end +do + -- issue #320: the surf blink sits UNDER the "got on" text (pokered's + -- GBPalWhiteOutWithDelay3 runs while the text is up), and the surfing + -- sprite swap waits for the actual step onto the water + require("src.render.Font").load(Data) + local save = { + flags = {}, + inventory = { SOULBADGE = 1 }, + party = { { species = "SQUIRTLE", moves = { { id = "SURF" } } } }, + player = { name = "RED" }, + } + local stack = { states = {} } + function stack:push(s) self.states[#self.states + 1] = s end + function stack:pop() return table.remove(self.states) end + function stack:top() return self.states[#self.states] end + local game = { data = Data, save = save, stack = stack } + check(bindGame(OW.trySurf, game), "trySurf binds a test Game") + check(bindGame(OW.partyKnows, game), "partyKnows binds the same Game") + local ow = setmetatable({ player = { facing = "down" } }, { __index = OW }) + ow.stepForwardOrCrossEdge = function(_, dir) ow.stepped = dir end + + ow:trySurf(10, 10) + local bottom, top = stack.states[1], stack.states[2] + check(bottom and bottom.frames ~= nil and top and top.pages ~= nil, + "the blink sits under the surf text on the stack") + check(not ow.player.surfing, "no surfing sprite while the text is up") + + top.onDone() + check(ow.player.surfing == true, "surfing applies with the step") + check(ow.stepped == "down", "the step onto the water fires") +end + do -- warp.destination reroutes one door without owning the warp table local warpDef = Data.maps.PALLET_TOWN.warps[1] diff --git a/tests/parity_I_M.lua b/tests/parity_I_M.lua index af47d595..40e70635 100644 --- a/tests/parity_I_M.lua +++ b/tests/parity_I_M.lua @@ -166,6 +166,9 @@ ow.player.facing = "down"; ow.player.surfing = false clearCaptured() local pmSurf = PartyMenu.new(Game) selectSubItem(pmSurf, 3) +-- the blink sits under the got-on text (#320); dismissing the text is +-- what mounts and steps +Game.stack:top().onDone() eq(ow.player.surfing, true, "SURF from the party menu sets player.surfing") check(not onStack(pmSurf), "party menu closes after a successful SURF") check(sawText("got on"), "_SurfingGotOnText shown on a successful SURF") @@ -498,6 +501,7 @@ clearCaptured() -- submenu order: STATS, SWITCH, FLY, CUT, STRENGTH, SURF (move order on mon) local pmFaintSurf = PartyMenu.new(Game) selectSubItem(pmFaintSurf, 6) +Game.stack:top().onDone() -- dismiss the text: mount + step (#320) eq(ow.player.surfing, true, "fainted mon can SURF from the party menu") check(not onStack(pmFaintSurf), "party menu closes after fainted SURF")