CLOSES #1206, CLOSES #1189, CLOSES #1175, CLOSES #1129, CLOSES #1119, CLOSES #1089, CLOSES #1073, CLOSES #1069, CLOSES #1065, CLOSES #1010, CLOSES #990, CLOSES #989, CLOSES #988, CLOSES #978, CLOSES #944, CLOSES #936, CLOSES #1221, CLOSES #1220, CLOSES #1193, CLOSES #1101, CLOSES #1066, CLOSES #1056, CLOSES #1041, CLOSES #984, CLOSES #1225, CLOSES #1214, CLOSES #1011, CLOSES #1035, CLOSES #1219, CLOSES #1048, CLOSES #1047, CLOSES #964, CLOSES #949, CLOSES #1149, CLOSES #1007, CLOSES #914, CLOSES #1115, CLOSES #1146, CLOSES #999, CLOSES #1207, CLOSES #1029, CLOSES #1120, CLOSES #987, CLOSES #983

This commit is contained in:
bryanthaboi
2026-08-13 13:07:20 -04:00
parent 833388c235
commit 37051a26b5
43 changed files with 752 additions and 135 deletions
+13 -13
View File
@@ -246,9 +246,17 @@ return {
-- the table sprites; re-entering the lab applies the same HideObject
-- the gift script now does (OaksLab.asm OakGivesPokedex).
onEnter = function(game, ow)
if not (game.save.flags and game.save.flags.EVENT_GOT_POKEDEX) then
return
local flags = game.save.flags or {}
if flags.EVENT_GOT_STARTER and not flags.EVENT_BATTLED_RIVAL_IN_OAKS_LAB then
local rival = ow:npcByIndex(1)
if rival then
rival.cellX = flags.EVENT_CHOSE_CHARMANDER and 7
or flags.EVENT_CHOSE_SQUIRTLE and 8 or 6
rival.cellY = 4
rival.px, rival.py = rival.cellX * 16, rival.cellY * 16
end
end
if not flags.EVENT_GOT_POKEDEX then return end
local Commands = require("src.script.Commands")
local ctx = { save = game.save, game = game, overworld = ow }
Commands.hide_object(ctx, "OAKS_LAB", "OAKSLAB_POKEDEX1")
@@ -286,6 +294,7 @@ return {
-- fanfare for the taunt/challenge exchange, same as the Yellow port
-- (oaks_lab_yellow.lua); it was silently dropped here (#596).
local rows = {
{ "face_player_dir", "up" },
{ "stop_music" },
{ "play_music", "Music_MeetRival" },
{ "show_text", "_OaksLabRivalIllTakeYouOnText" }, -- 1
@@ -309,28 +318,19 @@ return {
local base = #rows
local party = flags.EVENT_CHOSE_BULBASAUR and 3
or flags.EVENT_CHOSE_SQUIRTLE and 2 or 1
table.insert(rows, { "save_end_battle_text", "_OaksLabRivalIPickedTheWrongPokemonText" })
table.insert(rows, { "start_battle", "trainer", "OPP_RIVAL1", party })
-- OaksLabRivalEndBattleScript: heal + flag on win or loss; no blackout
table.insert(rows, { "heal_party" })
table.insert(rows, { "set_flag", "EVENT_BATTLED_RIVAL_IN_OAKS_LAB" })
-- OaksLabRivalEndBattleScript: on WIN, print the "picked the wrong
-- POKéMON!" gloat, then BOTH win and loss print the shared exit line
-- _OaksLabRivalSmellYouLaterText ("OK! I'll make my POKéMON fight to
-- toughen it up!\012<PLAYER>! Gramps! Smell you later!") before Blue
-- marches out. A loss skips only the gloat (that taunt was already
-- shown in-battle via Rival1WinText), never the exit line (#231). The
-- jump_if_false convergence point is the exit line: base+6 indexes the
-- SmellYouLater row below, so WIN falls IPicked -> SmellYouLater and
-- LOSS jumps straight to SmellYouLater (both then walk-out + hide).
table.insert(rows, { "jump_if_false", base + 6 })
table.insert(rows, { "show_text", "_OaksLabRivalIPickedTheWrongPokemonText" })
table.insert(rows, { "show_text", "_OaksLabRivalSmellYouLaterText" })
-- OaksLabRivalStartsExitScript: parting shot, rival exit fanfare, then
-- walk out past the player. The fanfare was dropped here (#683) -- the
-- parcel scene above already plays Music_MeetRival on both arrival and
-- departure (lines 144-146), and this exit should match (#596).
table.insert(rows, { "stop_music" })
table.insert(rows, { "play_music", "Music_MeetRival" })
table.insert(rows, { "play_music", "Music_MeetRival", { start = "rival" } })
table.insert(rows, { "move_npc_to", 1, 4, 11 })
table.insert(rows, { "hide_object", "OAKS_LAB", "OAKSLAB_RIVAL" })
table.insert(rows, { "play_music", "Music_OaksLab" })
+10 -3
View File
@@ -226,9 +226,15 @@ return {
},
onEnter = function(game, ow)
if not (game.save.flags and game.save.flags.EVENT_GOT_POKEDEX) then
return
local flags = game.save.flags or {}
if flags.EVENT_GOT_STARTER and not flags.EVENT_BATTLED_RIVAL_IN_OAKS_LAB then
local rival = ow:npcByIndex(RIVAL)
if rival then
rival.cellX, rival.cellY = 7, 4
rival.px, rival.py = 7 * 16, 4 * 16
end
end
if not flags.EVENT_GOT_POKEDEX then return end
local Commands = require("src.script.Commands")
local ctx = { save = game.save, game = game, overworld = ow }
Commands.hide_object(ctx, "OAKS_LAB", "OAKSLAB_POKEDEX1")
@@ -296,13 +302,14 @@ return {
table.insert(rows, { "wait", 20 })
table.insert(rows, { "show_text", "_OaksLabRivalSmellYouLaterText" })
table.insert(rows, { "stop_music" })
table.insert(rows, { "play_music", "Music_MeetRival" })
table.insert(rows, { "play_music", "Music_MeetRival", { start = "rival" } })
table.insert(rows, { "move_npc_to", RIVAL, 4, 11 })
table.insert(rows, { "hide_object", "OAKS_LAB", "OAKSLAB_RIVAL" })
table.insert(rows, { "play_music", "Music_OaksLab" })
-- OaksLabPikachuEscapesPokeballScript: the follower reaches the map (#1009)
table.insert(rows, { "face_player_dir", "up" })
table.insert(rows, { "set_field", "pikachuInBall", false })
table.insert(rows, { "spawn_pikachu_follower" })
table.insert(rows, { "play_cry", "PIKACHU" })
table.insert(rows, { "show_text", "_OaksLabPikachuDislikesPokeballsText1" })
table.insert(rows, { "show_text", "_OaksLabPikachuDislikesPokeballsText2" })
+19 -19
View File
@@ -142,20 +142,23 @@ M.VIRIDIAN_CITY = {
M.BLUES_HOUSE = {
talk = {
TEXT_BLUESHOUSE_DAISY_SITTING = {
{ "face_player" }, -- 1
{ "check_flag", "EVENT_GOT_TOWN_MAP" }, -- 2
{ "jump_if_true", 10 }, -- 3
{ "check_flag", "EVENT_GOT_STARTER" }, -- 4
{ "jump_if_false", 12 }, -- 5
{ "show_text", "_BluesHouseDaisyOfferMapText" }, -- 6
{ "face_player" },
{ "check_flag", "EVENT_GOT_TOWN_MAP" },
{ "jump_if_true", "got_map" },
{ "check_flag", "EVENT_GOT_POKEDEX" },
{ "jump_if_false", "too_early" },
{ "show_text", "_BluesHouseDaisyOfferMapText" },
-- _GotMapText: "{PLAYER} got a\n{RAM:wStringBuffer}!" -- the
-- buffer supplies "TOWN MAP" (scripts/BluesHouse.asm GotMapText)
{ "give_item", "TOWN_MAP", 1, "_GotMapText" }, -- 7
{ "set_flag", "EVENT_GOT_TOWN_MAP" }, -- 8
{ "jump", 13 }, -- 9
{ "show_text", "_BluesHouseDaisyUseMapText" }, -- 10
{ "jump", 13 }, -- 11
{ "show_text", "_BluesHouseDaisyRivalAtLabText" }, -- 12
{ "give_item", "TOWN_MAP", 1, "_GotMapText" },
{ "hide_object", "BLUES_HOUSE", "BLUESHOUSE_TOWN_MAP" },
{ "set_flag", "EVENT_GOT_TOWN_MAP" },
{ "jump", "end" },
{ "label", "got_map" },
{ "show_text", "_BluesHouseDaisyUseMapText" },
{ "jump", "end" },
{ "label", "too_early" },
{ "show_text", "_BluesHouseDaisyRivalAtLabText" },
},
},
}
@@ -1058,6 +1061,7 @@ local championsRoomRivalScript = {
-- OakCongratulatesPlayerScript: rival faces left, Oak faces down
{ "face_object", 1, "left" }, -- 17
{ "face_object", 2, "down" }, -- 18
{ "load_player_starter_name" },
{ "show_text", "_ChampionsRoomOakCongratulatesPlayerText" }, -- 19
-- OakDisappointedWithRivalScript: Oak turns to the rival (right)
{ "face_object", 2, "right" }, -- 20
@@ -1067,13 +1071,8 @@ local championsRoomRivalScript = {
{ "show_text", "_ChampionsRoomOakComeWithMeText" }, -- 23
{ "move_npc", 2, "up", 2 }, -- 24 OakExitChampionsRoomMovement
{ "hide_object", "CHAMPIONS_ROOM", "CHAMPIONSROOM_OAK" }, -- 25
-- ChampionsRoomPlayerFollowsOakScript / WalkToHallOfFame_RLEMovement.
-- The player walks out after Oak instead of the screen just fading on the
-- spot (#704). Route one tile right before walking north so the player
-- reaches the north-wall HALL_OF_FAME warp without sharing the rival's
-- (4,2) cell. The original simulated movement bypasses entity collision,
-- but this scene should not visibly walk through the defeated rival.
{ "move_player", "right", 1 }, -- 26
-- scripts/ChampionsRoom.asm WalkToHallOfFame_RLEMovement
{ "move_player", "left", 1 },
{ "move_player", "up", 3 }, -- 27
-- hand the induction off to the HALL_OF_FAME room (consumed by its
-- onEnter), then warp up into it (destWarp 1 lands at (4,7) facing up)
@@ -1238,6 +1237,7 @@ local function pokemonTower2FRivalScript(playerX)
{ "jump_if_false", "end" }, -- 6 loss: stay
{ "set_flag", "EVENT_BEAT_POKEMON_TOWER_RIVAL" }, -- 7
{ "show_text", "_PokemonTower2FRivalDefeatedText" }, -- 8
{ "play_music", "Music_MeetRival", { start = "rival" } },
{ "walk_npc", 1, exitDirs }, -- 9
{ "hide_object", "POKEMON_TOWER_2F", "POKEMONTOWER2F_RIVAL" }, -- 10
{ "jump", "end" }, -- 11
+3
View File
@@ -413,6 +413,9 @@ M.ROUTE_8_GATE = saffronGate("TEXT_ROUTE8GATE_GUARD", { { 2, 3 }, { 2, 4 } }, tr
-- -------------------------------------------------------------------
M.POKEMON_FAN_CLUB = {
onEnter = function(game, ow)
require("src.world.PikachuFollower").onFanClubEntered(game, ow)
end,
talk = {
TEXT_POKEMONFANCLUB_CHAIRMAN = {
{ "face_player" }, -- 1
+18 -13
View File
@@ -142,7 +142,7 @@ M.MT_MOON_POKECENTER = {
local Commands = require("src.script.Commands")
Commands.give_pokemon({ save = game.save, game = game, overworld = ow },
"MAGIKARP", 5)
push(game, ("%s got a\nMAGIKARP!"):format(game.save.player.name), done)
push(game, t._GotMonText or "{PLAYER} got\n{RAM:wNameBuffer}!", done)
end)
end,
},
@@ -512,24 +512,29 @@ M.ROUTE_24 = {
local flags = game.save.flags
local function battleOrDone()
if ow:trainerDefeated(npc) then
push(game, "I hate this!\nMy dreams of\nTEAM ROCKET...", done)
push(game, text(game)._Route24CooltrainerM1YouCouldBecomeATopLeaderText,
done)
else
ow:engageTrainer(npc, done)
end
end
if not flags.EVENT_GOT_NUGGET then
push(game, "Congratulations!\nYou beat our 5\ncontest trainers!\f"
.. "You just earned a\nfabulous prize!", function()
local t = text(game)
push(game, t._Route24CooltrainerM1YouBeatOurContestText .. "\f"
.. t._Route24CooltrainerM1YouJustEarnedAPrizeText, function()
require("src.core.Sound").play(game.data, "Get_Item1")
if not require("src.inventory.Bag").add(game.save, "NUGGET", 1,
game.data) then
push(game, t._Route24CooltrainerM1NoRoomText, done)
return
end
flags.EVENT_GOT_NUGGET = true
require("src.inventory.Bag").add(game.save, "NUGGET", 1)
push(game, ("%s received\na NUGGET!"):format(game.save.player.name),
function()
ask(game, "By the way, would\nyou like to join\nTEAM ROCKET?",
function()
push(game, "Arrgh! You are\nnot convinced?\fThen I'll show\n"
.. "you my power!", battleOrDone)
end)
end)
game.stringBuffer = game.data.items.NUGGET.name
push(game, t._Route24CooltrainerM1ReceivedNuggetText, function()
require("src.core.Sound").play(game.data, "Get_Item1")
push(game, t._Route24CooltrainerM1JoinTeamRocketText,
battleOrDone)
end)
end)
return
end
+22 -10
View File
@@ -508,12 +508,12 @@ M.PEWTER_CITY = {
-- Rival ambush: show the hidden rival, walk him up to the player, run
-- the battle rows, march him back and hide him. On a loss the walk is
-- skipped (the blackout rebuilds the map mid-script).
local function runAmbush(game, ow, rows, playerFacing)
local function runAmbush(game, ow, rows, playerFacing, musicOpts)
if ow.runner:isRunning() then return false end
ow.player.facing = playerFacing
-- the rival encounter sting (MUSIC_MEET_RIVAL); the battle music
-- takes over and the map theme returns after the victory jingle
require("src.core.Music").play(game.data, "Music_MeetRival")
require("src.core.Music").play(game.data, "Music_MeetRival", nil, musicOpts)
ow.runner:run(rows)
return true
end
@@ -567,10 +567,12 @@ local function route22Scene(n, objIndex, objName, oppClass, baseParty, beatFlag,
{ "face_object", objIndex, rivalFacing }, -- 3
{ "show_text", "_Route22RivalBeforeBattleText" .. n }, -- 4
{ "rival_battle", oppClass, baseParty }, -- 5
{ "jump_if_false", 11 }, -- 6
{ "jump_if_false", 12 }, -- 6
{ "set_flag", beatFlag }, -- 7
{ "show_text", "_Route22Rival" .. n .. "DefeatedText" }, -- 8
{ "show_text", "_Route22RivalAfterBattleText" .. n }, -- 9
{ "play_music", "Music_MeetRival", { start = "rival",
tempo = n == 2 and 100 or nil } },
{ "walk_npc", objIndex, route22ExitDirs(n, py) }, -- 10
{ "hide_object", "ROUTE_22", objName }, -- 11
}
@@ -594,7 +596,8 @@ M.ROUTE_22 = {
if f.EVENT_BEAT_GIOVANNI and not f.EVENT_BEAT_ROUTE22_RIVAL_2ND_BATTLE then
return runAmbush(game, ow,
route22Scene(2, 2, "ROUTE22_RIVAL2", "OPP_RIVAL2", 10,
"EVENT_BEAT_ROUTE22_RIVAL_2ND_BATTLE", y), playerFacing)
"EVENT_BEAT_ROUTE22_RIVAL_2ND_BATTLE", y), playerFacing,
{ tempo = 100 })
end
return false
end,
@@ -618,10 +621,11 @@ local function ceruleanRivalScene(px, py)
{ "face_object", 1, "down" }, -- 3
{ "show_text", "_CeruleanCityRivalPreBattleText" }, -- 4
{ "rival_battle", "OPP_RIVAL1", 7 }, -- 5
{ "jump_if_false", 11 }, -- 6
{ "jump_if_false", 12 }, -- 6
{ "set_flag", "EVENT_BEAT_CERULEAN_RIVAL" }, -- 7
{ "show_text", "_CeruleanCityRivalDefeatedText" }, -- 8
{ "show_text", "_CeruleanCityRivalIWentToBillsText" }, -- 9
{ "play_music", "Music_MeetRival", { start = "rival" } },
{ "walk_npc", 1, ceruleanRivalExitDirs(px) }, -- 10
{ "hide_object", "CERULEAN_CITY", "CERULEANCITY_RIVAL" }, -- 11
}
@@ -730,7 +734,7 @@ local JIGGLYPUFF_SILENCE, JIGGLYPUFF_STEP, JIGGLYPUFF_TAIL = 32, 24, 48
-- Built as a TextBox `auto` table: auto.sound fires the frame the last
-- page has typed out (PrintText returning), and auto.tick then runs once
-- per frame while the gate it returns still reads as playing.
local function jigglypuffDance(game, npc)
local function jigglypuffDance(game, npc, ow)
local Music = require("src.core.Music")
-- .findMatchingFacingDirectionLoop: the rotation picks up at the entry
-- matching the sprite's current facing (showMapText has just turned it
@@ -776,7 +780,13 @@ local function jigglypuffDance(game, npc)
if npc then npc.facing = JIGGLYPUFF_SPIN[step] end
return
end
if frames >= JIGGLYPUFF_TAIL then phase = "done" end
if frames >= JIGGLYPUFF_TAIL then
phase = "done"
if require("src.core.GameVersion").isYellow()
and require("src.world.PikachuFollower").starterInParty(game.save) then
ow.pikachuPewterSleepScene = true
end
end
end,
}
end
@@ -789,7 +799,7 @@ M.PEWTER_POKECENTER = {
local TextBox = require("src.render.TextBox")
game.stack:push(TextBox.new(game,
text(game)._PewterPokecenterJigglypuffText or "JIGGLYPUFF: Puu\npupuu!",
done, { auto = jigglypuffDance(game, npc) }))
done, { auto = jigglypuffDance(game, npc, ow) }))
end,
},
}
@@ -864,10 +874,11 @@ M.SILPH_CO_7F = {
{ "face_object", 9, "up" }, -- 4
{ "show_text", "_SilphCo7FRivalWaitedHereText" }, -- 5
{ "rival_battle", "OPP_RIVAL2", 7 }, -- 6
{ "jump_if_false", 12 }, -- 7
{ "jump_if_false", 13 }, -- 7
{ "set_flag", "EVENT_BEAT_SILPH_CO_RIVAL" }, -- 8
{ "show_text", "_SilphCo7FRivalDefeatedText" }, -- 9
{ "show_text", "_SilphCo7FRivalGoodLuckToYouText" }, -- 10
{ "play_music", "Music_MeetRival", { start = "rival" } },
{ "move_npc_to", 9, 5, y + 1 }, -- 11
{ "hide_object", "SILPH_CO_7F", "SILPHCO7F_RIVAL" }, -- 12
}, "down")
@@ -899,10 +910,11 @@ M.SS_ANNE_2F = {
{ "face_object", 2, onLeft and "down" or "right" }, -- 3
{ "show_text", "_SSAnne2FRivalText" }, -- 4
{ "rival_battle", "OPP_RIVAL2", 1 }, -- 5
{ "jump_if_false", 11 }, -- 6
{ "jump_if_false", 12 }, -- 6
{ "set_flag", "EVENT_BEAT_SS_ANNE_RIVAL" }, -- 7
{ "show_text", "_SSAnne2FRivalDefeatedText" }, -- 8
{ "show_text", "_SSAnne2FRivalCutMasterText" }, -- 9
{ "play_music", "Music_MeetRival", { start = "rival" } },
{ "walk_npc", 2, ssAnne2FRivalExitDirs(onLeft) }, -- 10
{ "hide_object", "SS_ANNE_2F", "SSANNE2F_RIVAL" }, -- 11
}, onLeft and "up" or "left")