diff --git a/src/battle/BattleState.lua b/src/battle/BattleState.lua index 9334bf92..b45ebfe7 100644 --- a/src/battle/BattleState.lua +++ b/src/battle/BattleState.lua @@ -385,8 +385,8 @@ local function displayName(b) end -- Apply the "Enemy " prefix to a pre-built message from a module that --- only knows the raw nickname (Status.beforeMove/residual, --- TrainerAI.useItem): splice it in before the first name occurrence. +-- only knows the raw nickname (Status.beforeMove/residual): splice it +-- in before the first name occurrence. local function prefixEnemy(msg, battler) if battler.isPlayer then return msg end local s = msg:find(battler.name, 1, true) @@ -3044,8 +3044,11 @@ function BattleState:executeAction(user, target, action) -- trainer class AI actions (engine/battle/trainer_ai.asm) if action.special == "aiItem" then self.aiUses = (self.aiUses or 1) - 1 + -- useItem's messages arrive final: its item line prints the raw + -- nickname on purpose (no "Enemy " in AIPrintItemUseText), so the + -- prefix splice must not touch them. for _, m in ipairs(TrainerAI.useItem(self, action.item)) do - self:sayNext(prefixEnemy(m, self.enemy)) + self:sayNext(m) end self:drainNext() require("src.core.Sound").play(self.data, "Heal_Ailment") diff --git a/src/battle/Status.lua b/src/battle/Status.lua index 8fad8716..a42062ae 100644 --- a/src/battle/Status.lua +++ b/src/battle/Status.lua @@ -6,6 +6,7 @@ -- back to the vanilla records, which is bit-identical behavior. local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local Status = {} @@ -34,8 +35,8 @@ end -- sentence rather than the noun: "hurt by poison" and "hurt by the burn" -- decline differently once translated, so a shared fragment cannot be the -- translatable unit. -local function damageOverTime(template) - return function(battler) +local function damageOverTime(label, template) + return function(battler, _, battle) local mon = battler.mon local base = math.max(1, math.floor(mon.stats.hp / 16)) local dmg = base @@ -44,7 +45,7 @@ local function damageOverTime(template) battler.toxicCounter = battler.toxicCounter + 1 end mon.hp = math.max(0, mon.hp - dmg) - return { Strings(template, name(battler)) } + return { romText(battle and battle.data, label, template, name(battler)) } end end @@ -63,53 +64,63 @@ Status.RECORDS = { id = "SLP", label = "SLP", hudLabel = "SLP", catchBonus = 25, shakeBonus = 10, beforeMovePriority = 40, - beforeMove = function(battler) + beforeMove = function(battler, _, battle) battler.sleepTurns = (battler.sleepTurns or 1) - 1 if battler.sleepTurns <= 0 then battler.mon.status = nil - return false, { Strings("%s\nwoke up!", name(battler)) } -- wakes, loses the turn + -- wakes, loses the turn + return false, { romText(battle and battle.data, "_WokeUpText", + "%s\nwoke up!", name(battler)) } end - return false, { Strings("%s\nis fast asleep!", name(battler)) } + return false, { romText(battle and battle.data, "_FastAsleepText", + "%s\nis fast asleep!", name(battler)) } end, onInflict = function(battle, target, opts, display) target.sleepTurns = battle.rng(1, 7) - return { Strings("%s\nfell asleep!", display) } + return { romText(battle.data, "_FellAsleepText", + "%s\nfell asleep!", display) } end, }, FRZ = { id = "FRZ", label = "FRZ", hudLabel = "FRZ", catchBonus = 25, shakeBonus = 10, beforeMovePriority = 30, - beforeMove = function(battler) - return false, { Strings("%s\nis frozen solid!", name(battler)) } + beforeMove = function(battler, _, battle) + return false, { romText(battle and battle.data, "_IsFrozenText", + "%s\nis frozen solid!", name(battler)) } end, canInflict = function(target) return not hasType(target, "ICE") end, - onInflict = function(_, _, _, display) - return { Strings("%s\nwas frozen solid!", display) } + onInflict = function(battle, _, _, display) + return { romText(battle and battle.data, "_FrozenText", + "%s\nwas frozen solid!", display) } end, }, PSN = { id = "PSN", label = "PSN", hudLabel = "PSN", catchBonus = 12, shakeBonus = 5, - residual = damageOverTime(Strings.source("%s's\nhurt by poison!")), + residual = damageOverTime("_HurtByPoisonText", + Strings.source("%s's\nhurt by poison!")), canInflict = function(target) return not hasType(target, "POISON") end, - onInflict = function(_, target, opts, display) + onInflict = function(battle, target, opts, display) if opts.toxic then target.toxicCounter = 1 - -- _BadlyPoisonedText - return { Strings("%s's\nbadly poisoned!", display) } + return { romText(battle and battle.data, "_BadlyPoisonedText", + "%s's\nbadly poisoned!", display) } end - return { Strings("%s\nwas poisoned!", display) } + return { romText(battle and battle.data, "_PoisonedText", + "%s\nwas poisoned!", display) } end, }, BRN = { id = "BRN", label = "BRN", hudLabel = "BRN", catchBonus = 12, shakeBonus = 5, statPenalty = { stat = "attack", div = 2 }, - residual = damageOverTime(Strings.source("%s's\nhurt by the burn!")), + residual = damageOverTime("_HurtByBurnText", + Strings.source("%s's\nhurt by the burn!")), canInflict = function(target) return not hasType(target, "FIRE") end, - onInflict = function(_, _, _, display) - return { Strings("%s\nwas burned!", display) } + onInflict = function(battle, _, _, display) + return { romText(battle and battle.data, "_BurnedText", + "%s\nwas burned!", display) } end, }, PAR = { @@ -117,10 +128,11 @@ Status.RECORDS = { catchBonus = 12, shakeBonus = 5, statPenalty = { stat = "speed", div = 4 }, beforeMovePriority = 10, - beforeMove = function(battler, rng) + beforeMove = function(battler, rng, battle) -- cp 25 percent / jr nc: fully paralyzed on rand < 63 (63/256) if rng(0, 255) < 63 then - return false, { Strings("%s's\nfully paralyzed!", name(battler)) } + return false, { romText(battle and battle.data, "_FullyParalyzedText", + "%s's\nfully paralyzed!", name(battler)) } end return true, {} end, @@ -128,9 +140,10 @@ Status.RECORDS = { -- ParalyzeEffect_: Electric-type moves can't paralyze Ground-types return not (opts.moveType == "ELECTRIC" and hasType(target, "GROUND")) end, - onInflict = function(_, _, _, display) - -- _ParalyzedMayNotAttackText (primary and secondary paralysis) - return { Strings("%s's\nparalyzed! It may\nnot attack!", display) } + onInflict = function(battle, _, _, display) + -- primary and secondary paralysis share this line + return { romText(battle and battle.data, "_ParalyzedMayNotAttackText", + "%s's\nparalyzed! It may\nnot attack!", display) } end, }, } @@ -166,7 +179,8 @@ function Status.beforeMove(battler, rng, battle) end if battler.flinched then battler.flinched = false - return false, { Strings("%s\nflinched!", name(battler)) } + return false, { romText(battle and battle.data, "_FlinchedText", + "%s\nflinched!", name(battler)) } end local record = Status.recordFor(battleStatuses(battle), mon.status) local handler = record and record.beforeMove @@ -184,23 +198,27 @@ function Status.beforeMove(battler, rng, battle) end if battler.boundTurns and battler.boundTurns > 0 then battler.boundTurns = battler.boundTurns - 1 - msgs[#msgs + 1] = Strings("%s\ncan't move!", name(battler)) + msgs[#msgs + 1] = romText(battle and battle.data, "_CantMoveText", + "%s\ncan't move!", name(battler)) return false, msgs end if battler.disabledTurns then battler.disabledTurns = battler.disabledTurns - 1 if battler.disabledTurns <= 0 then battler.disabledTurns, battler.disabledSlot = nil, nil - table.insert(msgs, Strings("%s's\ndisabled no more!", name(battler))) + table.insert(msgs, romText(battle and battle.data, "_DisabledNoMoreText", + "%s's\ndisabled no more!", name(battler))) end end if battler.confusedTurns then battler.confusedTurns = battler.confusedTurns - 1 if battler.confusedTurns <= 0 then battler.confusedTurns = nil - table.insert(msgs, Strings("%s\nsnapped out of\nconfusion!", name(battler))) + table.insert(msgs, romText(battle and battle.data, "_ConfusedNoMoreText", + "%s\nsnapped out of\nconfusion!", name(battler))) else - table.insert(msgs, Strings("%s\nis confused!", name(battler))) + table.insert(msgs, romText(battle and battle.data, "_IsConfusedText", + "%s\nis confused!", name(battler))) -- cp 50 percent + 1 / jr c: hurt itself on rand >= 128 (128/256) if rng(0, 255) < 128 then return false, msgs, true -- hurt itself @@ -241,7 +259,8 @@ function Status.residual(battler, opponent, battle) dmg = math.min(dmg, mon.hp) mon.hp = mon.hp - dmg opponent.mon.hp = math.min(opponent.mon.stats.hp, opponent.mon.hp + dmg) - table.insert(msgs, Strings("LEECH SEED saps\n%s!", name(battler))) + table.insert(msgs, romText(battle and battle.data, "_HurtByLeechSeedText", + "LEECH SEED saps\n%s!", name(battler))) end return msgs end diff --git a/src/battle/TrainerAI.lua b/src/battle/TrainerAI.lua index 08b9aca0..c086c113 100644 --- a/src/battle/TrainerAI.lua +++ b/src/battle/TrainerAI.lua @@ -20,9 +20,16 @@ local TypeChart = require("src.battle.TypeChart") local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local TrainerAI = {} +-- pokered's / text macros print "Enemy " before the +-- enemy mon's nickname (home/text.asm PlaceMoveUsersName) +local function displayName(b) + return b.isPlayer and b.name or ("Enemy " .. b.name) +end + local HEAL_AMOUNT = { POTION = 20, SUPER_POTION = 50, HYPER_POTION = 200 } local X_STAT = { X_ATTACK = "attack", X_DEFEND = "defense", X_SPEED = "speed" } @@ -95,12 +102,16 @@ function TrainerAI.switchAction(battle) return { special = "aiSwitch", index = alive[1] } end --- Apply an aiItem action to the enemy battler; returns messages. +-- Apply an aiItem action to the enemy battler; returns messages, already +-- final: the item line prints the raw nickname (AIPrintItemUseText has no +-- "Enemy " prefix in pokered), the stat lines carry it via displayName, so +-- the caller must not run these through prefixEnemy. function TrainerAI.useItem(battle, item) local enemy = battle.enemy local trainerName = battle.trainer.name local itemName = battle.data.items[item] and battle.data.items[item].name or item - local msgs = { Strings("%s\nused %s!", trainerName, itemName) } + local msgs = { romText(battle.data, "_AIBattleUseItemText", + "%s\nused %s!", trainerName, itemName, enemy.name) } if item == "FULL_HEAL" then enemy.mon.status = nil enemy.toxicCounter = nil @@ -113,10 +124,10 @@ function TrainerAI.useItem(battle, item) elseif X_STAT[item] then local stat = X_STAT[item] enemy.stages[stat] = math.min(6, (enemy.stages[stat] or 0) + 1) - table.insert(msgs, Strings("%s's\n%s rose!", enemy.name, stat:upper())) + table.insert(msgs, Strings("%s's\n%s rose!", displayName(enemy), stat:upper())) elseif item == "GUARD_SPEC" then enemy.mist = true - table.insert(msgs, Strings("%s's\nprotected against\nstat changes!", enemy.name)) + table.insert(msgs, Strings("%s's\nprotected against\nstat changes!", displayName(enemy))) end return msgs end diff --git a/src/inventory/ItemEffects.lua b/src/inventory/ItemEffects.lua index ad1e2165..f7c1b9b3 100644 --- a/src/inventory/ItemEffects.lua +++ b/src/inventory/ItemEffects.lua @@ -12,9 +12,19 @@ local Flags = require("src.script.Flags") local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local ItemEffects = {} +local function notTime(data, save) + return romText(data, "_ItemUseNotTimeText", + "OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) +end + +local function noEffect(data) + return romText(data, "_ItemUseNoEffectText", "It won't have\nany effect.") +end + local HEAL_AMOUNT = { POTION = 20, SUPER_POTION = 50, HYPER_POTION = 200, FRESH_WATER = 50, SODA_POP = 60, LEMONADE = 80, @@ -82,6 +92,14 @@ local function cureActiveToxic(battle, target) end end +-- the per-item cure lines (item_effects.asm .cureStatusAilment picks the +-- text by item id); FULL_RESTORE lands here too when it acts as a cure +local CURE_TEXT = { + ANTIDOTE = "_AntidoteText", BURN_HEAL = "_BurnHealText", + ICE_HEAL = "_IceHealText", AWAKENING = "_AwakeningText", + PARLYZ_HEAL = "_ParlyzHealText", FULL_HEAL = "_FullHealText", +} + -- battle-only stat boosters (engine/items/item_effects.asm ItemUseXStat) local X_ITEMS = { X_ATTACK = "attack", X_DEFEND = "defense", X_SPEED = "speed", @@ -130,8 +148,7 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) if battle and (VITAMINS[itemId] or STONES[itemId] or itemId == "PP_UP" or itemId == "RARE_CANDY" or itemId == "COIN_CASE" or (itemDef and itemDef.machine)) then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", - save.player.name) } + return "failed", { notTime(data, save) } end if BALLS[itemId] then @@ -148,13 +165,14 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- data/scripts/story.lua's snorlaxWake) local mapId, npc = adjacentSleepingSnorlax(save, ow) if npc then - return "flute_wake", { data.text._PlayedFluteHadEffectText - or Strings("{PLAYER} played the\nPOKé FLUTE.") }, + return "flute_wake", { romText(data, "_PlayedFluteHadEffectText", + "{PLAYER} played the\nPOKé FLUTE.") }, { mapId = mapId, npc = npc } end -- otherwise: play the tune, nothing happens (ItemUsePokeFlute's -- PlayedFluteNoEffectText branch) - return "flute_field", { Strings("Played the POKé\nFLUTE.\fNow, that's a\ncatchy tune!") } + return "flute_field", { romText(data, "_PlayedFluteNoEffectText", + "Played the POKé\nFLUTE.\fNow, that's a\ncatchy tune!") } end local woke = false local function wake(mon) @@ -169,17 +187,20 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- WakeUpEntireParty runs on the enemy's bench too for _, mon in ipairs(battle.enemyParty or {}) do wake(mon) end if not woke then - return "failed", { Strings("Played the POKé\nFLUTE.\fNow, that's a\ncatchy tune!") } + return "failed", { romText(data, "_PlayedFluteNoEffectText", + "Played the POKé\nFLUTE.\fNow, that's a\ncatchy tune!") } end - return "flute", { Strings("%s played the\nPOKé FLUTE.", save.player.name), - Strings("All sleeping\nPOKéMON woke up!") } + return "flute", { romText(data, "_PlayedFluteHadEffectText", + "%s played the\nPOKé FLUTE.", save.player.name), + romText(data, "_FluteWokeUpText", + "All sleeping\nPOKéMON woke up!") } end -- battle-only items if X_ITEMS[itemId] or itemId == "DIRE_HIT" or itemId == "GUARD_SPEC" or itemId == "POKE_DOLL" then if not battle then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end local b = battle.player -- PIKAHAPPY_USEDXITEM (item_effects.asm ItemUseXAccuracy / @@ -201,7 +222,8 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- effect, so at +6 it is still consumed and StatModifierUpEffect -- just prints "Nothing happened!" if cur >= 6 then - return "consumed", { Strings("Nothing happened!") } + return "consumed", { romText(data, "_NothingHappenedText", + "Nothing happened!") } end b.stages[stat] = cur + 1 return "consumed", { Strings("%s's\n%s rose!", b.name, stat:upper()) } @@ -210,7 +232,8 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- the item, even when it is already active if itemId == "DIRE_HIT" then b.focusEnergy = true - return "consumed", { Strings("%s's\ngetting pumped!", b.name) } + return "consumed", { romText(data, "_GettingPumpedText", + "%s's\ngetting pumped!", b.name) } end if itemId == "GUARD_SPEC" then b.mist = true @@ -219,10 +242,10 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) if itemId == "POKE_DOLL" then if battle.kind ~= "wild" then -- ItemUsePokeDoll jumps to ItemUseNotTime in trainer battles - return "failed", { Strings( - "OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end - return "consumed_escape", { Strings("The wild POKéMON\nran away!") } + return "consumed_escape", { romText(data, "_WildRanText", + "The wild POKéMON\nran away!", battle.enemy and battle.enemy.name) } end end @@ -231,7 +254,7 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- restore every move with no menu. if itemId == "ETHER" or itemId == "MAX_ETHER" or itemId == "ELIXER" or itemId == "MAX_ELIXER" then - if not target then return "failed", { Strings("It won't have\nany effect.") } end + if not target then return "failed", { noEffect(data) } end local restored = false local full = itemId == "MAX_ETHER" or itemId == "MAX_ELIXER" local allMoves = itemId == "ELIXER" or itemId == "MAX_ELIXER" @@ -253,9 +276,10 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) restored = mv and restore(mv) or false end if not restored then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end - return "consumed", { Strings("%s's PP\nwas restored!", monName(data, target)) } + -- pokered's line names no mon, so the extracted text takes no args + return "consumed", { romText(data, "_PPRestoredText", "PP was restored.") } end -- PIKAHAPPY_USEDITEM (item_effects.asm ItemUseMedicine, item id up to @@ -280,10 +304,11 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) target.status = nil cureActiveToxic(battle, target) require("src.core.Sound").play(data, "Heal_Ailment") - return "consumed", { Strings("%s's\nstatus returned\nto normal!", monName(data, target)) } + return "consumed", { romText(data, CURE_TEXT.FULL_HEAL, + "%s's\nstatus returned\nto normal!", monName(data, target)) } end if not target or target.hp <= 0 or target.hp >= target.stats.hp then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end -- wHPBarOldHP: the bar animation starts from the HP the mon had BEFORE -- the item landed (item_effects.asm latches it with the party menu still @@ -295,7 +320,10 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) else target.hp = math.min(target.stats.hp, target.hp + heal) end - local msgs = { Strings("%s's HP\nwas restored!", monName(data, target)) } + -- _PotionText's second slot is the recovered amount ({NUM: + -- wHPBarHPDifference}); the engine fallback never prints it + local msgs = { romText(data, "_PotionText", "%s's HP\nwas restored!", + monName(data, target), target.hp - before) } if itemId == "FULL_RESTORE" then target.status = nil cureActiveToxic(battle, target) @@ -307,17 +335,18 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) local cures = STATUS_HEAL[itemId] if cures then if not target or not target.status or not cures[target.status] then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end target.status = nil cureActiveToxic(battle, target) require("src.core.Sound").play(data, "Heal_Ailment") - return "consumed", { Strings("%s's\nstatus returned\nto normal!", monName(data, target)) } + return "consumed", { romText(data, CURE_TEXT[itemId], + "%s's\nstatus returned\nto normal!", monName(data, target)) } end if itemId == "REVIVE" or itemId == "MAX_REVIVE" then if not target or target.hp > 0 then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end target.status = nil target.hp = itemId == "REVIVE" and math.floor(target.stats.hp / 2) or target.stats.hp @@ -329,13 +358,14 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) if battle and battle.participants then battle.participants[target] = true end - return "consumed", { Strings("%s\nis revitalized!", monName(data, target)) }, + return "consumed", { romText(data, "_ReviveText", + "%s\nis revitalized!", monName(data, target)) }, { healedFrom = 0 } end if itemId == "RARE_CANDY" then if not target or target.level >= 100 then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end local Growth = require("src.pokemon.Growth") local Stats = require("src.pokemon.Stats") @@ -348,12 +378,13 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- PIKAHAPPY_LEVELUP on a candy level (item_effects.asm:1540) require("src.world.PikachuFollower") .modifyHappiness(save, "LEVELUP", target) - return "consumed", { Strings("%s grew\nto level %d!", monName(data, target), target.level) }, + return "consumed", { romText(data, "_RareCandyText", + "%s grew\nto level %d!", monName(data, target), target.level) }, { leveledTo = target.level } end if STONES[itemId] then - if not target then return "failed", { Strings("It won't have\nany effect.") } end + if not target then return "failed", { noEffect(data) } end -- Yellow's starter Pikachu never evolves: ItemUseEvoStone runs -- IsThisPartyMonStarterPikachu (OT identity match) before -- TryEvolvingMon and bails with the voiced cry + RefusingText. @@ -363,10 +394,8 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) and target.ot == save.player.name and target.otId == save.player.id then require("src.core.Sound").playCry(data, "PIKACHU") - local raw = data.text and data.text._RefusingText - local line = raw and raw:gsub("{RAM:[^}]*}", monName(data, target)) - or Strings("%s\nis refusing!", monName(data, target)) - return "failed", { line } + return "failed", { romText(data, "_RefusingText", + "%s\nis refusing!", monName(data, target)) } end local speciesDef = data.pokemon[target.species] for _, evo in ipairs(speciesDef.evolutions) do @@ -374,44 +403,48 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) return "consumed", nil, { evolveTo = evo.species } end end - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end -- vitamins: +2560 stat exp, refused at 25600+ (ItemUseVitamin, -- engine/items/item_effects.asm) local vitaminStat = VITAMINS[itemId] if vitaminStat then - if not target then return "failed", { Strings("It won't have\nany effect.") } end + if not target then return "failed", { noEffect(data) } end target.statExp = target.statExp or {} local cur = target.statExp[vitaminStat] or 0 if cur >= 25600 then - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end target.statExp[vitaminStat] = math.min(65535, cur + 2560) local Stats = require("src.pokemon.Stats") target.stats = Stats.calc(data.pokemon[target.species], target.level, target.dvs, target.statExp) target.hp = math.min(target.hp, target.stats.hp) + -- _VitaminStatRoseText's slot order is localization-dependent (the + -- Spanish ROM puts the stat before the name), so the extracted line + -- cannot be filled positionally; the engine wording stands return "consumed", { Strings("%s's %s\nrose!", monName(data, target), vitaminStat == "hp" and "HP" or vitaminStat:upper()) } end -- PP UP boosts the move the player picked (ItemUsePPUp's move menu) if itemId == "PP_UP" then - if not target then return "failed", { Strings("It won't have\nany effect.") } end + if not target then return "failed", { noEffect(data) } end local mv = target.moves[moveIndex or 1] local mdef = mv and data.moves[mv.id] if mdef and (mv.ppUps or 0) < 3 then mv.ppUps = (mv.ppUps or 0) + 1 -- each PP UP adds maxPP/5 uses on top of the base maximum mv.pp = mv.pp + math.floor(mdef.pp / 5) - return "consumed", { Strings("%s's PP\nincreased!", mdef.name) } + return "consumed", { romText(data, "_PPIncreasedText", + "%s's PP\nincreased!", mdef.name) } end - return "failed", { Strings("It won't have\nany effect.") } + return "failed", { noEffect(data) } end if itemDef and itemDef.machine then - if not target then return "failed", { Strings("It won't have\nany effect.") } end + if not target then return "failed", { noEffect(data) } end local speciesDef = data.pokemon[target.species] local ok = false for _, m in ipairs(speciesDef.tmhm) do @@ -422,11 +455,16 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) -- plays SFX_DENIED before MonCannotLearnMachineMoveText (the generic -- ItemUseNotTime/NoCyclingAllowedHere paths are silent) require("src.core.Sound").play(data, "Denied") - return "failed", { Strings("%s can't\nlearn that move!", monName(data, target)) } + local moveName = data.moves[itemDef.machine.move].name + return "failed", { romText(data, "_MonCannotLearnMachineMoveText", + "%s can't\nlearn that move!", + monName(data, target), moveName, moveName) } end for _, mv in ipairs(target.moves) do if mv.id == itemDef.machine.move then - return "failed", { Strings("It knows that\nmove already!") } + return "failed", { romText(data, "_AlreadyKnowsText", + "It knows that\nmove already!", + monName(data, target), data.moves[itemDef.machine.move].name) } end end -- HMs are never consumed; TMs are single-use @@ -435,21 +473,21 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) if itemId == "OLD_ROD" or itemId == "GOOD_ROD" or itemId == "SUPER_ROD" then if battle then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end -- FishingInit (engine/items/item_effects.asm): cp wWalkBikeSurfState, 2 -- (surfing) sets carry, and every ItemUseXRod does jp c, ItemUseNotTime -- on that carry -- surfing refuses the rod with the same OAK text as -- the mid-battle case above, no rod-specific message (#533) if ow and ow.player and ow.player.surfing then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end return "fish", itemId end if itemId == "BICYCLE" then if battle then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end return "bicycle" end @@ -459,18 +497,19 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) end if itemId == "TOWN_MAP" then if battle then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end return "townmap" end if itemId == "ITEMFINDER" then if battle then - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end return "itemfinder" end if itemId == "COIN_CASE" then - return "failed", { Strings("Coin count:\n%d", save.coins or 0) } + return "failed", { romText(data, "_CoinCaseNumCoinsText", + "Coin count:\n%d", save.coins or 0) } end if itemId == "REPEL" or itemId == "SUPER_REPEL" or itemId == "MAX_REPEL" then local steps = itemId == "REPEL" and 100 or itemId == "SUPER_REPEL" and 200 or 250 @@ -478,7 +517,7 @@ function ItemEffects.use(data, save, itemId, target, battle, moveIndex, ow) return "consumed", { Strings("%s used\n%s!", save.player.name, name) } end - return "failed", { Strings("OAK: %s!\nThis isn't the\ntime to use that!", save.player.name) } + return "failed", { notTime(data, save) } end return ItemEffects diff --git a/src/pokemon/Evolution.lua b/src/pokemon/Evolution.lua index c2df1741..b92352b6 100644 --- a/src/pokemon/Evolution.lua +++ b/src/pokemon/Evolution.lua @@ -15,6 +15,7 @@ local Screens = require("src.ui.Screens") local Stats = require("src.pokemon.Stats") local TextBox = require("src.render.TextBox") local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local Evolution = {} @@ -140,7 +141,8 @@ function Evolution.learnEvolutionMoves(game, mon, onDone) table.insert(mon.moves, { id = moveId, pp = mdef.pp }) Runtime.emit("pokemon.move_learned", { mon = mon, moveId = moveId }) game.stack:push(TextBox.new(game, - Strings("%s learned\n%s!", name, mdef.name), nextStep)) + romText(game.data, "_LearnedMove1Text", + "%s learned\n%s!", name, mdef.name), nextStep)) else -- LearnMoveFromLevelUp with a full moveset: the forget UI Screens.push(game, "MoveLearnMenu", mon, moveId, nextStep) @@ -161,8 +163,12 @@ function Evolution.evolve(game, mon, newSpecies, onDone, via) Music.play(game.data, Music.special(game.data, "evolution")) local oldName = mon.nickname or game.data.pokemon[mon.species].name Evolution.apply(game, mon, newSpecies, via) - local msg = Strings("What?\n%s is\nevolving!\fCongratulations!\nYour %s\nevolved into\n%s!", - oldName, oldName, game.data.pokemon[newSpecies].name) + -- the congrats page keeps the engine wording: _EvolvedText extracts + -- truncated (it stops at a dynamic marker the decoder does not follow) + local msg = romText(game.data, "_IsEvolvingText", + "What?\n%s is\nevolving!", oldName) + .. "\f" .. Strings("Congratulations!\nYour %s\nevolved into\n%s!", + oldName, game.data.pokemon[newSpecies].name) game.stack:push(TextBox.new(game, msg, function() Music.restoreMap(game.data) -- re-run the evolved species' level-up learn check before onDone diff --git a/src/ui/EvolutionState.lua b/src/ui/EvolutionState.lua index 5954d553..c6aebd0c 100644 --- a/src/ui/EvolutionState.lua +++ b/src/ui/EvolutionState.lua @@ -12,6 +12,7 @@ local Font = require("src.render.Font") local Music = require("src.core.Music") local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local EvolutionState = {} EvolutionState.__index = EvolutionState @@ -89,9 +90,9 @@ function EvolutionState:update(dt) self.done = true self.canceled = true local TextBox = require("src.render.TextBox") - -- mirrors data/generated/text.lua _StoppedEvolvingText game.stack:push(TextBox.new(game, - Strings("Huh? %s\nstopped evolving!", self.oldName), + romText(game.data, "_StoppedEvolvingText", + "Huh? %s\nstopped evolving!", self.oldName), function() Music.restoreMap(game.data) game.stack:pop() -- the evolution screen itself @@ -106,6 +107,8 @@ function EvolutionState:update(dt) require("src.core.Sound").playCry(game.data, self.newSpecies) local TextBox = require("src.render.TextBox") local newName = game.data.pokemon[self.newSpecies].name + -- _EvolvedText extracts truncated (it stops at a dynamic marker the + -- decoder does not follow), so the engine's wording stands here game.stack:push(TextBox.new(game, Strings("Congratulations!\nYour %s\nevolved into\n%s!", self.oldName, newName), diff --git a/src/ui/MoveLearnMenu.lua b/src/ui/MoveLearnMenu.lua index 222f7f1c..f32a60de 100644 --- a/src/ui/MoveLearnMenu.lua +++ b/src/ui/MoveLearnMenu.lua @@ -5,6 +5,7 @@ local Font = require("src.render.Font") local Strings = require("src.core.Strings") +local romText = require("src.core.RomText") local MoveLearnMenu = {} MoveLearnMenu.__index = MoveLearnMenu @@ -43,10 +44,13 @@ function MoveLearnMenu:enter() local mdef = game.data.moves[self.newMoveId] local name = self:monName() self.selecting = false + -- _TryingToLearnText is the whole exchange in pokered, delete prompt + -- included, so the extracted line carries all four slots at once game.stack:push(TextBox.new(game, - Strings("%s is\ntrying to learn\v%s!\fBut, %s\ncan't learn more\vthan 4 moves!\f", - name, mdef.name, name) .. - Strings("Delete an older\nmove to make room\vfor %s?", mdef.name), + romText(game.data, "_TryingToLearnText", + "%s is\ntrying to learn\v%s!\fBut, %s\ncan't learn more\vthan 4 moves!\f" + .. "Delete an older\nmove to make room\vfor %s?", + name, mdef.name, name, mdef.name), nil, { choice = function(yes) if yes then @@ -77,7 +81,8 @@ function MoveLearnMenu:update(dt) -- HMCantDeleteText, then back to the forget list local TextBox = require("src.render.TextBox") self.game.stack:push(TextBox.new(self.game, - Strings("HM techniques\ncan't be deleted!"))) + romText(self.game.data, "_HMCantDeleteText", + "HM techniques\ncan't be deleted!"))) return end local mdef = self.game.data.moves[self.newMoveId] @@ -97,7 +102,8 @@ function MoveLearnMenu:confirmAbandon() local mdef = game.data.moves[self.newMoveId] self.selecting = false game.stack:push(TextBox.new(game, - Strings("Abandon learning\n%s?", mdef.name), nil, { + romText(game.data, "_AbandonLearningText", + "Abandon learning\n%s?", mdef.name), nil, { choice = function(yes) if yes then self:finish(false) else self:enter() end end, @@ -113,12 +119,17 @@ function MoveLearnMenu:finish(learned) game.stack:pop() local msg if learned then - -- OneTwoAndText/PoofText/ForgotAndText - msg = Strings("1, 2 and... Poof!\f%s forgot\n%s!\fAnd...\f%s learned\n%s!", - name, self.forgot, name, mdef.name) + -- pokered pages this as four texts in a row; _ForgotAndText carries + -- the "And..." tail + msg = romText(game.data, "_OneTwoAndText", "1, 2 and...") + .. romText(game.data, "_PoofText", " Poof!") + .. romText(game.data, "_ForgotAndText", + "\f%s forgot\n%s!\fAnd...", name, self.forgot) + .. "\f" .. romText(game.data, "_LearnedMove1Text", + "%s learned\n%s!", name, mdef.name) else - -- DidNotLearnText - msg = Strings("%s\ndid not learn\v%s!", name, mdef.name) + msg = romText(game.data, "_DidNotLearnText", + "%s\ndid not learn\v%s!", name, mdef.name) end game.stack:push(TextBox.new(game, msg, function() if self.onDone then self.onDone(learned) end