From 2c1e411e3cd8d13688a10f0006fa76ea685e3b00 Mon Sep 17 00:00:00 2001 From: Colson Rice Date: Fri, 21 Aug 2026 19:37:41 -0400 Subject: [PATCH] Print the Gen 2 battle lines the cart actually writes Five messages in the Gen 2 battle code are written by hand rather than taken from data/text/battle.asm, and each has drifted from what the game prints: SuperEffectiveText lost its hyphen and its line break NotVeryEffectiveText ended on three periods, not the ellipsis glyph the charmap carries BattleText_TheresNoPPLeftForThisMove dropped "There's" PlayerHitTimesText/EnemyHitTimesText printed "Hit 3 time(s)!", showing the parenthetical on screen; Gen 1 already prints "Hit 3 times!" via _HitXTimesText StartPerishText printed a sentence no cart prints The break is \n, which is what RomExtractorGen2 decodes the cart's own $4e into, so these read as an extracted line would. Each goes through Strings now, which is what the rest of this file already does with its messages. SpikesText is left alone and the reason is written down beside it: its third row is a `cont`, and engine messages set self.message directly rather than going through showPages, so printMessage would cut the row carrying . --- src/battle/gen2/Battle.lua | 35 ++++++++++++++++++++++++++++------- tests/gen2_battle_ui_test.lua | 2 +- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/battle/gen2/Battle.lua b/src/battle/gen2/Battle.lua index 9346f9dd..3c7b46b9 100644 --- a/src/battle/gen2/Battle.lua +++ b/src/battle/gen2/Battle.lua @@ -1234,10 +1234,15 @@ function Battle:dealDamage(attacker, defender, damage, opts) if opts.critical then self:emit({ kind = "message", text = "A critical hit!" }) end + -- SuperEffectiveText / NotVeryEffectiveText (data/text/battle.asm:603,608). + -- The cart breaks both across the box's two lines and hyphenates "super-" + -- to do it, and the not-very line ends on the single ellipsis glyph Gold's + -- charmap carries at $75, not three periods. if opts.effectiveness and opts.effectiveness > 10 then - self:emit({ kind = "message", text = "It's super effective!" }) + self:emit({ kind = "message", text = Strings("It's super-\neffective!") }) elseif opts.effectiveness and opts.effectiveness < 10 then - self:emit({ kind = "message", text = "It's not very effective..." }) + self:emit({ kind = "message", + text = Strings("It's not very\neffective…") }) end if endured then self:emit({ kind = "message", @@ -1391,7 +1396,9 @@ function Battle:useMove(attacker, defender, moveId) if not (charging or rampaging or rolling) then if move and (move.pp or 0) <= 0 then - self:emit({ kind = "message", text = "No PP left for this move!" }) + -- BattleText_TheresNoPPLeftForThisMove (data/text/battle.asm:315). + self:emit({ kind = "message", + text = Strings("There's no PP left\nfor this move!") }) return end if move then move.pp = (move.pp or 1) - 1 end @@ -1747,8 +1754,12 @@ function Battle:useMove(attacker, defender, moveId) landed = landed + 1 end if landed > 1 then - self:emit({ kind = "message", - text = ("Hit %d time(s)!"):format(landed) }) + -- PlayerHitTimesText / EnemyHitTimesText (data/text/battle.asm:749,755) + -- are "Hit @ times!". Gen 2 has no singular form of this line, so the + -- plural stands even at one hit rather than the "(s)" this printed. + -- Gen 1 already says it this way (src/battle/EffectRegistry.lua, + -- _HitXTimesText). + self:emit({ kind = "message", text = Strings("Hit %d times!", landed) }) end -- move_effects/pay_day.asm:13 @@ -1968,8 +1979,11 @@ Battle.MOVE_EFFECTS.EFFECT_PERISH_SONG = function(self) if mine.perish and theirs.perish then return fail(self) end if not mine.perish then mine.perish = Effects.PERISH_TURNS end if not theirs.perish then theirs.perish = Effects.PERISH_TURNS end + -- StartPerishText (data/text/battle.asm:986). What shipped here was a + -- sentence no cart prints; the Gen 2 line names both sides and counts in + -- digits. self:emit({ kind = "message", - text = "All POKéMON hearing the song will faint in three turns!" }) + text = Strings("Both POKéMON will\nfaint in 3 turns!") }) end -- BattleCommand_Encore: 3-6 turns locked into the move the target last used. @@ -2099,6 +2113,11 @@ Battle.MOVE_EFFECTS.EFFECT_SPIKES = function(self, attacker, defender) local side = self:sideOf(defender) if self.spikes[side] then return fail(self) end self.spikes[side] = true + -- SpikesText (data/text/battle.asm:974) is three rows, the third scrolled + -- (`cont`) and carrying . The battle message path has no `cont`: + -- src/ui/gen2/BattleState.lua sets self.message straight from the event and + -- printMessage cuts past two rows, so the cart's line cannot be told here + -- yet without the name being dropped on screen. Left as it stands. self:emit({ kind = "message", text = "Spikes were scattered all around!" }) end @@ -2334,7 +2353,9 @@ Battle.MOVE_EFFECTS.EFFECT_BEAT_UP = function(self, attacker, defender, def) { move = def, moveId = def and def.id }) landed = landed + 1 end - self:emit({ kind = "message", text = ("Hit %d time(s)!"):format(landed) }) + -- BattleCommand_EndLoop prints the same line for Beat Up, and Beat Up can + -- land exactly once, which is the case the cart still prints as "times". + self:emit({ kind = "message", text = Strings("Hit %d times!", landed) }) end -- BattleCommand_Heal (effect_commands.asm:5986): Recover and Rest are both diff --git a/tests/gen2_battle_ui_test.lua b/tests/gen2_battle_ui_test.lua index d88c636f..549e84e7 100644 --- a/tests/gen2_battle_ui_test.lua +++ b/tests/gen2_battle_ui_test.lua @@ -175,7 +175,7 @@ do dealt = event.amount end if event.kind == "message" - and event.text == "It's not very effective..." then + and event.text == "It's not very\neffective…" then sawNve = true end end