mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 04:31:09 +02:00
Binary file not shown.
|
Before Width: | Height: | Size: 370 KiB After Width: | Height: | Size: 753 KiB |
@@ -1,15 +1,11 @@
|
|||||||
-- Pewter City flavor dialogue (pokered/scripts/PewterCity.asm).
|
-- Pewter City flavor dialogue (pokered/scripts/PewterCity.asm).
|
||||||
-- PewterCity_TextPointers text_asm bodies for the SUPER_NERD1 museum
|
-- PewterCity_TextPointers text_asm bodies for the SUPER_NERD1 museum
|
||||||
-- guide, SUPER_NERD2 garden nerd, and the leaving-east YOUNGSTER.
|
-- guide and SUPER_NERD2 garden nerd.
|
||||||
--
|
--
|
||||||
-- The escort choreography (SUPER_NERD1 walking the player to the
|
-- The YOUNGSTER's gym escort (talk + east-exit onStep) lives in
|
||||||
-- museum, YOUNGSTER walking the player to the gym) is scripted NPC
|
-- story5.lua so the lockstep RLE walk is not overwritten by this
|
||||||
-- movement + a wPewterCityCurScript state machine that steers the
|
-- flavor merge. SUPER_NERD1's museum escort is not ported; only the
|
||||||
-- player off-map; the YOUNGSTER's escort to the gym is handled on this
|
-- YES/NO-branched flavor text is here.
|
||||||
-- map by story5.lua's onStep gate at the east exit (before
|
|
||||||
-- EVENT_BEAT_BROCK), while the SUPER_NERD1 museum escort is not ported.
|
|
||||||
-- Here we only port the real YES/NO-branched flavor text these NPCs
|
|
||||||
-- speak when talked to.
|
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -61,15 +57,6 @@ M.PEWTER_CITY = {
|
|||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- PewterCityYoungsterText (scripts/PewterCity.asm): the "follow
|
|
||||||
-- me" line the youngster says when the player is stopped from
|
|
||||||
-- leaving Pewter east before beating Brock; the actual gate/step
|
|
||||||
-- block is handled by story5.lua's onStep for this map.
|
|
||||||
TEXT_PEWTERCITY_YOUNGSTER = function(game, ow, npc, done)
|
|
||||||
local t = text(game)
|
|
||||||
push(game, t._PewterCityYoungsterYoureATrainerFollowMeText
|
|
||||||
or "You're a trainer\nright? BROCK's\nlooking for new\nchallengers!\nFollow me!", done)
|
|
||||||
end,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+167
-25
@@ -262,38 +262,180 @@ M.CINNABAR_ISLAND = {
|
|||||||
-- Pewter's youngster stops you leaving east before Brock is beaten and
|
-- Pewter's youngster stops you leaving east before Brock is beaten and
|
||||||
-- escorts you to the gym (scripts/PewterCity.asm
|
-- escorts you to the gym (scripts/PewterCity.asm
|
||||||
-- PewterCityCheckPlayerLeavingEastScript /
|
-- PewterCityCheckPlayerLeavingEastScript /
|
||||||
-- PewterCityYoungsterShowsPlayerGymScript, engine/events/pewter_guys.asm
|
-- PewterCityYoungsterShowsPlayerGymScript, engine/overworld/auto_movement.asm
|
||||||
-- PewterGymGuyCoords): the "follow me" lines, then the player is walked
|
-- PewterGymGuyMovementScriptPointerTable, engine/events/pewter_guys.asm
|
||||||
-- west along the road to the front of the PEWTER_GYM door at (16,17).
|
-- PewterGymGuyCoords). Same lockstep style as Oak's lab escort: the
|
||||||
|
-- youngster walks RLEList_PewterGymGuy while the player plays the
|
||||||
|
-- reverse of RLEList_PewterGymPlayer with a PewterGuys positioning
|
||||||
|
-- preamble. Ends at (11,18) / (12,18) by the gym, not phasing through
|
||||||
|
-- the building.
|
||||||
|
local pewterEscort = {}
|
||||||
|
|
||||||
|
-- RLEList_PewterGymGuy (NPC directions play forward)
|
||||||
|
pewterEscort.guySteps = {
|
||||||
|
"down", "down",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left", "left",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left",
|
||||||
|
"up", "up", "up", "up", "up",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left", "left",
|
||||||
|
"left", "left", "left",
|
||||||
|
"down", "down", "down", "down", "down",
|
||||||
|
"right", "right", "right",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Walk home: reverse of guySteps with opposite facings (gym → spawn).
|
||||||
|
do
|
||||||
|
local opp = { up = "down", down = "up", left = "right", right = "left" }
|
||||||
|
local ret = {}
|
||||||
|
for i = #pewterEscort.guySteps, 1, -1 do
|
||||||
|
ret[#ret + 1] = opp[pewterEscort.guySteps[i]]
|
||||||
|
end
|
||||||
|
pewterEscort.guyReturnSteps = ret
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RLEList_PewterGymPlayer before reverse / PewterGuys (NO_INPUT, RIGHT×2,
|
||||||
|
-- DOWN×5, LEFT×11, UP×5, LEFT×15)
|
||||||
|
pewterEscort.playerRle = {
|
||||||
|
"NO",
|
||||||
|
"right", "right",
|
||||||
|
"down", "down", "down", "down", "down",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left", "left",
|
||||||
|
"left", "left", "left",
|
||||||
|
"up", "up", "up", "up", "up",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left", "left",
|
||||||
|
"left", "left", "left", "left", "left", "left", "left",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- PewterGymGuyCoords: (x, y) -> positioning moves written after the RLE
|
||||||
|
-- (played in reverse; $00 pauses are one overworld frame ≈ 1/8 tile for
|
||||||
|
-- the NPC, so eight of them ≈ one guy head-start step)
|
||||||
|
pewterEscort.preambles = {
|
||||||
|
["34,16"] = { "left", "down", "down", "right" },
|
||||||
|
["35,17"] = { "left", "down", "right", "left" },
|
||||||
|
["37,18"] = { "left", "left", "left",
|
||||||
|
"NO", "NO", "NO", "NO", "NO", "NO", "NO", "NO" },
|
||||||
|
["37,19"] = { "left", "left", "up", "left" },
|
||||||
|
["36,17"] = { "left", "down", "left",
|
||||||
|
"NO", "NO", "NO", "NO", "NO", "NO", "NO", "NO" },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Realized player path for a trigger tile: PewterGuys overwrites the
|
||||||
|
-- last RLE byte and appends the preamble, then simulated joypad plays
|
||||||
|
-- high→low (reverse). Leading NO×8 collapses to guyHeadStart=1; the
|
||||||
|
-- trailing end-of-list NO is dropped (one-frame pause).
|
||||||
|
function pewterEscort.playerPlan(x, y)
|
||||||
|
local pre = pewterEscort.preambles[x .. "," .. y]
|
||||||
|
if not pre then return nil end
|
||||||
|
local buf = {}
|
||||||
|
for i, d in ipairs(pewterEscort.playerRle) do buf[i] = d end
|
||||||
|
buf[#buf] = pre[1]
|
||||||
|
for i = 2, #pre do buf[#buf + 1] = pre[i] end
|
||||||
|
local path = {}
|
||||||
|
for i = #buf, 1, -1 do path[#path + 1] = buf[i] end
|
||||||
|
local head = 0
|
||||||
|
while path[head + 1] == "NO" do head = head + 1 end
|
||||||
|
local tail = #path
|
||||||
|
while tail > head and path[tail] == "NO" do tail = tail - 1 end
|
||||||
|
local steps = {}
|
||||||
|
for i = head + 1, tail do steps[#steps + 1] = path[i] end
|
||||||
|
return { steps = steps, guyHeadStart = math.floor(head / 8) }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pewterGymEscort(game, ow)
|
||||||
|
if ow.runner:isRunning() or #ow.scriptMoves > 0 then return end
|
||||||
|
local x, y = ow.player.cellX, ow.player.cellY
|
||||||
|
local plan = pewterEscort.playerPlan(x, y)
|
||||||
|
local Music = require("src.core.Music")
|
||||||
|
local t = text(game)
|
||||||
|
local follow = t._PewterCityYoungsterYoureATrainerFollowMeText
|
||||||
|
or "You're a trainer\nright? BROCK's\nlooking for new\nchallengers!\nFollow me!"
|
||||||
|
-- PewterGuys only has entries for five tiles; an unmatched talk tile
|
||||||
|
-- (e.g. (36,16) east of him) just gets the follow-me line, same as a
|
||||||
|
-- failed coords lookup would refuse to arm the walk.
|
||||||
|
if not plan then
|
||||||
|
push(game, follow)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local guy = ow:npcByIndex(5) -- PEWTERCITY_YOUNGSTER
|
||||||
|
local guySteps = pewterEscort.guySteps
|
||||||
|
local head = plan.guyHeadStart
|
||||||
|
|
||||||
|
-- After the walk: face the player, restore map music, "Go take on
|
||||||
|
-- BROCK", then retrace RLEList_PewterGymGuy back to his spawn (35,16).
|
||||||
|
-- (pokered teleports him via MovementData_PewterGymGuyExit; we walk
|
||||||
|
-- the same route home instead. Brock victory still HideObject's him.)
|
||||||
|
local function walkHome()
|
||||||
|
if not guy then return end
|
||||||
|
local ret = pewterEscort.guyReturnSteps
|
||||||
|
local i = 0
|
||||||
|
local function tick()
|
||||||
|
i = i + 1
|
||||||
|
if not ret[i] then
|
||||||
|
guy.facing = "down"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
ow:scriptMove(guy, ret[i], 1, tick)
|
||||||
|
end
|
||||||
|
tick()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function afterWalk()
|
||||||
|
if guy then guy.facing = "left" end
|
||||||
|
Music.playMap(game.data, "PEWTER_CITY")
|
||||||
|
push(game, t._PewterCityYoungsterGoTakeOnBrockText
|
||||||
|
or "Go take on BROCK\nat the GYM first!", walkHome)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lockstep()
|
||||||
|
local i = 0
|
||||||
|
local function tick()
|
||||||
|
i = i + 1
|
||||||
|
local ps = plan.steps[i]
|
||||||
|
if not ps then
|
||||||
|
afterWalk()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local gs = guySteps[head + i]
|
||||||
|
if guy and gs then ow:scriptMove(guy, gs, 1) end
|
||||||
|
ow:scriptMove(ow.player, ps, 1, tick)
|
||||||
|
end
|
||||||
|
tick()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function beginWalk()
|
||||||
|
Music.play(game.data, "Music_MuseumGuy")
|
||||||
|
if guy and head > 0 then
|
||||||
|
local h = 0
|
||||||
|
local function headTick()
|
||||||
|
h = h + 1
|
||||||
|
if h > head then lockstep(); return end
|
||||||
|
ow:scriptMove(guy, guySteps[h], 1, headTick)
|
||||||
|
end
|
||||||
|
headTick()
|
||||||
|
else
|
||||||
|
lockstep()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
push(game, follow, beginWalk)
|
||||||
|
end
|
||||||
|
|
||||||
M.PEWTER_CITY = {
|
M.PEWTER_CITY = {
|
||||||
|
escort = pewterEscort,
|
||||||
|
-- PewterCityYoungsterText: talking also arms the gym escort script
|
||||||
|
talk = {
|
||||||
|
TEXT_PEWTERCITY_YOUNGSTER = function(game, ow, npc, done)
|
||||||
|
pewterGymEscort(game, ow)
|
||||||
|
if done then done() end
|
||||||
|
end,
|
||||||
|
},
|
||||||
onStep = function(game, ow, x, y)
|
onStep = function(game, ow, x, y)
|
||||||
if game.save.flags.EVENT_BEAT_BROCK then return false end
|
if game.save.flags.EVENT_BEAT_BROCK then return false end
|
||||||
if ow.runner:isRunning() or #ow.scriptMoves > 0 then return false end
|
if ow.runner:isRunning() or #ow.scriptMoves > 0 then return false end
|
||||||
if not inCoords({ { 35, 17 }, { 36, 17 }, { 37, 18 }, { 37, 19 } }, x, y) then
|
if not inCoords({ { 35, 17 }, { 36, 17 }, { 37, 18 }, { 37, 19 } }, x, y) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local t = text(game)
|
pewterGymEscort(game, ow)
|
||||||
-- walk up onto the road row (y=17), west to one tile east of the gym
|
|
||||||
-- door, then drop below the door and turn to face it
|
|
||||||
local steps = {}
|
|
||||||
for _ = 1, y - 17 do steps[#steps + 1] = "up" end
|
|
||||||
for _ = 1, x - 17 do steps[#steps + 1] = "left" end
|
|
||||||
steps[#steps + 1] = "down"
|
|
||||||
steps[#steps + 1] = "left"
|
|
||||||
local function walk(i)
|
|
||||||
if not steps[i] then
|
|
||||||
ow.player.facing = "up"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
ow:scriptMove(ow.player, steps[i], 1, function() walk(i + 1) end)
|
|
||||||
end
|
|
||||||
push(game, t._PewterCityYoungsterYoureATrainerFollowMeText
|
|
||||||
or "Hey! You're a\ntrainer, right?", function()
|
|
||||||
push(game, t._PewterCityYoungsterGoTakeOnBrockText
|
|
||||||
or "Go take on BROCK\nat the GYM first!", function()
|
|
||||||
walk(1)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,16 @@ local function range(prefix, first, last)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
-- PewterGym.asm .gymVictory also HideObject TOGGLE_GYM_GUY
|
||||||
|
-- (PEWTERCITY_YOUNGSTER) and TOGGLE_ROUTE_22_RIVAL_1 so the east-exit
|
||||||
|
-- escort NPC and the first Route 22 rival stay gone after the badge.
|
||||||
["OPP_BROCK#1"] = { badge = "BOULDERBADGE", flag = "EVENT_BEAT_BROCK",
|
["OPP_BROCK#1"] = { badge = "BOULDERBADGE", flag = "EVENT_BEAT_BROCK",
|
||||||
item = "TM_BIDE",
|
item = "TM_BIDE",
|
||||||
deactivate = { "EVENT_BEAT_PEWTER_GYM_TRAINER_0" } },
|
deactivate = { "EVENT_BEAT_PEWTER_GYM_TRAINER_0" },
|
||||||
|
hide = {
|
||||||
|
{ "PEWTER_CITY", "PEWTERCITY_YOUNGSTER" },
|
||||||
|
{ "ROUTE_22", "ROUTE22_RIVAL1" },
|
||||||
|
} },
|
||||||
["OPP_MISTY#1"] = { badge = "CASCADEBADGE", flag = "EVENT_BEAT_MISTY",
|
["OPP_MISTY#1"] = { badge = "CASCADEBADGE", flag = "EVENT_BEAT_MISTY",
|
||||||
item = "TM_BUBBLEBEAM",
|
item = "TM_BUBBLEBEAM",
|
||||||
deactivate = range("EVENT_BEAT_CERULEAN_GYM_TRAINER_", 0, 1) },
|
deactivate = range("EVENT_BEAT_CERULEAN_GYM_TRAINER_", 0, 1) },
|
||||||
|
|||||||
@@ -2351,6 +2351,8 @@ end
|
|||||||
-- Badges/items awarded after specific battles (data/scripts/victories.lua).
|
-- Badges/items awarded after specific battles (data/scripts/victories.lua).
|
||||||
-- `deactivate` retires unfought gym/dojo trainers the way the originals'
|
-- `deactivate` retires unfought gym/dojo trainers the way the originals'
|
||||||
-- SetEvent / SetEventRange do after the leader victory.
|
-- SetEvent / SetEventRange do after the leader victory.
|
||||||
|
-- `hide` is { { mapId, objName }, ... } — HideObject on those toggles
|
||||||
|
-- (e.g. Brock victory clears PEWTERCITY_YOUNGSTER / ROUTE22_RIVAL1).
|
||||||
function OverworldState:checkVictoryRewards(trainerClass, partyIndex)
|
function OverworldState:checkVictoryRewards(trainerClass, partyIndex)
|
||||||
local victories = require("data.scripts.victories")
|
local victories = require("data.scripts.victories")
|
||||||
local reward = victories[trainerClass .. "#" .. tostring(partyIndex or 1)]
|
local reward = victories[trainerClass .. "#" .. tostring(partyIndex or 1)]
|
||||||
@@ -2364,6 +2366,13 @@ function OverworldState:checkVictoryRewards(trainerClass, partyIndex)
|
|||||||
Game.save.flags[flag] = true
|
Game.save.flags[flag] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if reward.hide then
|
||||||
|
local Commands = require("src.script.Commands")
|
||||||
|
local ctx = { game = Game, save = Game.save, overworld = self }
|
||||||
|
for _, entry in ipairs(reward.hide) do
|
||||||
|
Commands.hide_object(ctx, entry[1], entry[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
local lines = {}
|
local lines = {}
|
||||||
if reward.badge then
|
if reward.badge then
|
||||||
Game.save.inventory[reward.badge] = 1
|
Game.save.inventory[reward.badge] = 1
|
||||||
|
|||||||
@@ -338,6 +338,15 @@ do
|
|||||||
end
|
end
|
||||||
check(pewterNpc and ow:trainerDefeated(pewterNpc),
|
check(pewterNpc and ow:trainerDefeated(pewterNpc),
|
||||||
"unfought Pewter gym trainer is defeated after badge")
|
"unfought Pewter gym trainer is defeated after badge")
|
||||||
|
-- PewterGym.asm .gymVictory HideObject TOGGLE_GYM_GUY /
|
||||||
|
-- TOGGLE_ROUTE_22_RIVAL_1 (persists via objectToggles)
|
||||||
|
check(Game.save.objectToggles
|
||||||
|
and Game.save.objectToggles.PEWTER_CITY
|
||||||
|
and Game.save.objectToggles.PEWTER_CITY.PEWTERCITY_YOUNGSTER == false,
|
||||||
|
"Brock victory hides PEWTERCITY_YOUNGSTER")
|
||||||
|
check(Game.save.objectToggles.ROUTE_22
|
||||||
|
and Game.save.objectToggles.ROUTE_22.ROUTE22_RIVAL1 == false,
|
||||||
|
"Brock victory hides ROUTE22_RIVAL1")
|
||||||
|
|
||||||
while Game.stack:top() do Game.stack:pop() end
|
while Game.stack:top() do Game.stack:pop() end
|
||||||
Game.save = SaveData.newGame()
|
Game.save = SaveData.newGame()
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
-- Parity test: Pewter City youngster gym escort paths.
|
||||||
|
-- Self-contained: run via `luajit tests/parity_pewter_escort.lua`; also
|
||||||
|
-- dofile'd by tests/run_tests.lua's aggregator.
|
||||||
|
--
|
||||||
|
-- Sources: scripts/PewterCity.asm, engine/overworld/auto_movement.asm
|
||||||
|
-- (RLEList_PewterGymPlayer / RLEList_PewterGymGuy),
|
||||||
|
-- engine/events/pewter_guys.asm (PewterGymGuyCoords).
|
||||||
|
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 and Data.maps.PEWTER_CITY) then Data:load() end
|
||||||
|
local S = require("tests.harness").suite("parity pewter escort")
|
||||||
|
local check, eq = S.check, S.eq
|
||||||
|
|
||||||
|
local mapScripts = require("data.scripts.init")
|
||||||
|
local pewter = mapScripts.get("PEWTER_CITY")
|
||||||
|
check(pewter and pewter.escort, "PEWTER_CITY exposes the escort tables")
|
||||||
|
local escort = pewter.escort
|
||||||
|
|
||||||
|
local function joined(t) return table.concat(t, ",") end
|
||||||
|
|
||||||
|
local D = { up = { 0, -1 }, down = { 0, 1 }, left = { -1, 0 }, right = { 1, 0 } }
|
||||||
|
|
||||||
|
eq(#escort.guySteps, 41, "youngster takes 41 steps (RLEList_PewterGymGuy)")
|
||||||
|
eq(joined({ escort.guySteps[1], escort.guySteps[2], escort.guySteps[#escort.guySteps] }),
|
||||||
|
"down,down,right", "guy path starts with DOWN×2 and ends RIGHT")
|
||||||
|
eq(#escort.guyReturnSteps, 41, "return path mirrors the escort")
|
||||||
|
do
|
||||||
|
local opp = { up = "down", down = "up", left = "right", right = "left" }
|
||||||
|
eq(escort.guyReturnSteps[1], opp[escort.guySteps[#escort.guySteps]],
|
||||||
|
"return starts with opposite of escort's last step")
|
||||||
|
local gx, gy = 12, 18
|
||||||
|
for _, d in ipairs(escort.guyReturnSteps) do
|
||||||
|
gx, gy = gx + D[d][1], gy + D[d][2]
|
||||||
|
end
|
||||||
|
check(gx == 35 and gy == 16,
|
||||||
|
"return path from the gym lands on his spawn (35,16)")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- every east-exit / talk tile lands both sprites by the gym road
|
||||||
|
local triggers = { { 35, 17 }, { 36, 17 }, { 37, 18 }, { 37, 19 }, { 34, 16 } }
|
||||||
|
for _, pos in ipairs(triggers) do
|
||||||
|
local px, py = pos[1], pos[2]
|
||||||
|
local plan = escort.playerPlan(px, py)
|
||||||
|
check(plan, ("playerPlan for (%d,%d)"):format(px, py))
|
||||||
|
local gx, gy = 35, 16
|
||||||
|
local gi = 0
|
||||||
|
for _ = 1, plan.guyHeadStart do
|
||||||
|
gi = gi + 1
|
||||||
|
local d = escort.guySteps[gi]
|
||||||
|
gx, gy = gx + D[d][1], gy + D[d][2]
|
||||||
|
end
|
||||||
|
for i, ps in ipairs(plan.steps) do
|
||||||
|
px, py = px + D[ps][1], py + D[ps][2]
|
||||||
|
local gs = escort.guySteps[plan.guyHeadStart + i]
|
||||||
|
if gs then
|
||||||
|
gx, gy = gx + D[gs][1], gy + D[gs][2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eq(px, 11, ("player from (%d,%d) ends at x=11"):format(pos[1], pos[2]))
|
||||||
|
eq(py, 18, ("player from (%d,%d) ends at y=18"):format(pos[1], pos[2]))
|
||||||
|
eq(gx, 12, ("guy from (%d,%d) ends at x=12"):format(pos[1], pos[2]))
|
||||||
|
eq(gy, 18, ("guy from (%d,%d) ends at y=18"):format(pos[1], pos[2]))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- the short east-road trigger uses no head-start; the (36,17)/(37,18)
|
||||||
|
-- tiles pause for one guy step (eight NO_INPUT frames)
|
||||||
|
eq(escort.playerPlan(35, 17).guyHeadStart, 0, "(35,17) no head-start")
|
||||||
|
eq(escort.playerPlan(36, 17).guyHeadStart, 1, "(36,17) one-step head-start")
|
||||||
|
eq(escort.playerPlan(37, 18).guyHeadStart, 1, "(37,18) one-step head-start")
|
||||||
|
|
||||||
|
-- path stays off the PEWTER_GYM door warp and the blocked gym building
|
||||||
|
-- cells: sample the (35,17) walk and confirm no step lands on (16,17)
|
||||||
|
do
|
||||||
|
local plan = escort.playerPlan(35, 17)
|
||||||
|
local px, py = 35, 17
|
||||||
|
local gx, gy = 35, 16
|
||||||
|
for i, ps in ipairs(plan.steps) do
|
||||||
|
px, py = px + D[ps][1], py + D[ps][2]
|
||||||
|
local gs = escort.guySteps[i]
|
||||||
|
if gs then gx, gy = gx + D[gs][1], gy + D[gs][2] end
|
||||||
|
check(not (px == 16 and py == 17),
|
||||||
|
("player beat %d does not phase onto gym door"):format(i))
|
||||||
|
check(not (gx == 16 and gy == 17),
|
||||||
|
("guy beat %d does not phase onto gym door"):format(i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- gym door warp is still where the player is meant to walk afterward
|
||||||
|
local MapLoader = require("src.world.MapLoader")
|
||||||
|
local city = MapLoader.load(Data, "PEWTER_CITY")
|
||||||
|
local w = city:warpAtCell(16, 17)
|
||||||
|
check(w and w.def.destMap == "PEWTER_GYM", "(16,17) is the Pewter Gym door")
|
||||||
|
|
||||||
|
-- object spawn matches pokered object_event 35, 16
|
||||||
|
local young
|
||||||
|
for _, o in ipairs(Data.maps.PEWTER_CITY.objects) do
|
||||||
|
if o.name == "PEWTERCITY_YOUNGSTER" then young = o; break end
|
||||||
|
end
|
||||||
|
check(young and young.x == 35 and young.y == 16,
|
||||||
|
"PEWTERCITY_YOUNGSTER spawns at (35,16)")
|
||||||
|
|
||||||
|
-- Brock victory permanently HideObject's him (PewterGym.asm .gymVictory)
|
||||||
|
do
|
||||||
|
local victories = require("data.scripts.victories")
|
||||||
|
local hide = victories["OPP_BROCK#1"] and victories["OPP_BROCK#1"].hide
|
||||||
|
check(hide, "OPP_BROCK#1 lists objects to hide")
|
||||||
|
local found
|
||||||
|
for _, entry in ipairs(hide or {}) do
|
||||||
|
if entry[1] == "PEWTER_CITY" and entry[2] == "PEWTERCITY_YOUNGSTER" then
|
||||||
|
found = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
check(found, "Brock victory hides PEWTERCITY_YOUNGSTER")
|
||||||
|
end
|
||||||
|
|
||||||
|
S.finish()
|
||||||
Reference in New Issue
Block a user