mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
205 lines
8.7 KiB
Lua
205 lines
8.7 KiB
Lua
-- The Safari Zone game entrance (scripts/SafariZoneGate.asm).
|
|
--
|
|
-- Stepping on (3,2)/(4,2) next to the worker fires the join prompt
|
|
-- (.PlayerNextToSafariZoneWorker1CoordsArray). Paying ¥500 hands over
|
|
-- 30 SAFARI BALLs and starts the 502-step game
|
|
-- (SafariZoneGateWouldYouLikeToJoinScript: wSafariSteps = 502,
|
|
-- wNumSafariBalls = SAFARI_BALLS_RECEIVED), then auto-walks the player
|
|
-- up through the north warp into the zone. Declining walks you back
|
|
-- so you can't slip past. Returning to the gate ends the game, the
|
|
-- worker takes the leftover balls back and the auto-walk drops you 3
|
|
-- cells below the warp you came in by (#540).
|
|
--
|
|
-- Step/ball bookkeeping lives in src/world/OverworldController.lua
|
|
-- (safariStep/safariGameOver, from
|
|
-- engine/events/hidden_events/safari_game.asm); the in-battle
|
|
-- BALL/BAIT/ROCK/RUN game is src/battle/BattleState.lua makeSafari.
|
|
|
|
local M = {}
|
|
|
|
local FEE = 500
|
|
local BALLS = 30
|
|
local STEPS = 502
|
|
|
|
-- SafariZoneGateSafariZoneWorker1WouldYouLikeToJoinText .success closes with
|
|
-- `ld a, PAD_UP / ld c, 3 / SafariZoneEntranceAutoWalk`: paying walks the
|
|
-- player up out of the gate and through the north warp, it is never left to
|
|
-- the player. EVENT_IN_SAFARI_ZONE is already set when that walk runs, so
|
|
-- the two gate steps taken before the warp fires are charged against
|
|
-- wSafariSteps (home/overworld.asm:307-310) -- which is why the counter
|
|
-- reads 500/500 on arrival even though the script wrote 502 (#540). The
|
|
-- port's counter only runs on the nine interior maps (FieldDefaults
|
|
-- safari.stepMaps, OverworldState:inSafariStepZone), so charge those two
|
|
-- steps here instead.
|
|
local function walkIntoZone(game, ow)
|
|
local p = ow.player
|
|
-- only from the two trigger cells in front of the worker, which are the
|
|
-- columns the north warps sit on; a player who paid after TALKING to him
|
|
-- from somewhere else walks in on their own, as they do today
|
|
local w = p.cellY == 2 and ow.map:warpAtCell(p.cellX, 0) or nil
|
|
if not w then return end
|
|
ow:scriptMove(p, "up", 2, function()
|
|
local st = game.save.safari
|
|
if st then st.steps = st.steps - 2 end
|
|
-- scripted steps skip onStepComplete (and with it CheckWarpsNoCollision),
|
|
-- so take that warp explicitly once the walk lands on it
|
|
ow:takeWarp(w.def)
|
|
end)
|
|
end
|
|
|
|
local function startGame(game, ow, t, done, balls, introText)
|
|
game.save.safari = { balls = balls or BALLS, steps = STEPS }
|
|
game.save.safariNags = nil
|
|
local TextBox = require("src.render.TextBox")
|
|
local paid = introText
|
|
or (t._SafariZoneGateSafariZoneWorker1ThatllBe500PleaseText
|
|
or "That'll be ¥500\nplease!\f{PLAYER} received\n30 SAFARI BALLs!")
|
|
:gsub("{NUM:[^}]*}", "500")
|
|
paid = paid:gsub("{PLAYER}", game.save.player.name)
|
|
local pa = t._SafariZoneGateSafariZoneWorker1CallYouOnThePAText
|
|
or "\fWe'll call you on\nthe PA when you\nrun out of time\nor SAFARI BALLs!"
|
|
local luck = t._SafariZoneGateSafariZoneWorker1GoodLuckText or "Good Luck!"
|
|
game.stack:push(TextBox.new(game, paid .. pa .. "\f" .. luck, function()
|
|
if done then done() end
|
|
walkIntoZone(game, ow)
|
|
end))
|
|
end
|
|
|
|
-- Yellow's soft-lock fix (scripts/SafariZoneGate_2.asm): a player short of
|
|
-- the full fee still gets in.
|
|
-- 0 < money < 500: SafariZoneEntranceCalculateLowCostAdmission takes
|
|
-- everything and hands over min(money/23 + 1, 29) balls.
|
|
-- money == 0: SafariZoneEntranceGetLowCostAdmissionText nags four times
|
|
-- (LowCostText5/6/7/8), then relents -- free entry, one ball.
|
|
local function yellowLowCost(game, ow, t, done, back)
|
|
local TextBox = require("src.render.TextBox")
|
|
if game.save.money > 0 then
|
|
local balls = math.min(math.floor(game.save.money / 23) + 1, 29)
|
|
game.save.money = 0
|
|
local intro =
|
|
(t._SafariZoneGateSafariZoneWorker1NotEnoughMoneyText
|
|
or "Oops! Not enough\nmoney!")
|
|
.. (t._SafariZoneLowCostText1
|
|
or "\fOh, all right, pay\nme what you have.")
|
|
.. "\f" .. (t._SafariZoneLowCostText2
|
|
or "But, I can't give\nyou all 30 BALLs.")
|
|
startGame(game, ow, t, done, balls, intro)
|
|
return
|
|
end
|
|
local nag = game.save.safariNags or 0
|
|
game.save.safariNags = nag + 1
|
|
if nag >= 3 then
|
|
local intro =
|
|
(t._SafariZoneLowCostText8 or "Read my lips, NO!\nGet it?")
|
|
.. (t._SafariZoneLowCostText3
|
|
or "\fYou're persistent,\naren't you?\fOK, you can go in\nfor free, but\njust this once!")
|
|
startGame(game, ow, t, done, 1, intro)
|
|
return
|
|
end
|
|
local nags = {
|
|
t._SafariZoneLowCostText5 or "I'm sorry, but you\nhave to pay to\nenter.",
|
|
t._SafariZoneLowCostText6 or "You can't enter\nwithout paying!",
|
|
t._SafariZoneLowCostText7 or "I said, no money,\nno entry!",
|
|
}
|
|
back(nags[nag + 1])
|
|
end
|
|
|
|
local function joinPrompt(game, ow, done)
|
|
done = done or function() end
|
|
local TextBox = require("src.render.TextBox")
|
|
local ChoiceBox = require("src.ui.ChoiceBox")
|
|
local t = game.data.text
|
|
local back = function(text)
|
|
game.stack:push(TextBox.new(game, text, function()
|
|
ow:scriptMove(ow.player, "down", 1, done)
|
|
end))
|
|
end
|
|
game.stack:push(TextBox.new(game,
|
|
t._SafariZoneGateSafariZoneWorker1WouldYouLikeToJoinText
|
|
or "For just ¥500 you\ncan join the hunt!\fWould you like to\njoin the hunt?",
|
|
function()
|
|
game.stack:push(ChoiceBox.new(game, function(yes)
|
|
if not yes then
|
|
back(t._SafariZoneGateSafariZoneWorker1PleaseComeAgainText
|
|
or "OK! Please come\nagain!")
|
|
elseif game.save.money < FEE then
|
|
if require("src.core.GameVersion").isYellow() then
|
|
yellowLowCost(game, ow, t, done, back)
|
|
else
|
|
back(t._SafariZoneGateSafariZoneWorker1NotEnoughMoneyText
|
|
or "Oops! Not enough\nmoney!")
|
|
end
|
|
else
|
|
game.save.money = game.save.money - FEE
|
|
startGame(game, ow, t, done)
|
|
end
|
|
end))
|
|
end))
|
|
end
|
|
|
|
M.SAFARI_ZONE_GATE = {
|
|
talk = {
|
|
TEXT_SAFARIZONEGATE_SAFARI_ZONE_WORKER1 = function(game, ow, npc, done)
|
|
local TextBox = require("src.render.TextBox")
|
|
local t = game.data.text
|
|
if game.save.safari then
|
|
game.stack:push(TextBox.new(game,
|
|
t._SafariZoneGateSafariZoneWorker1GoodLuckText or "Good Luck!", done))
|
|
return
|
|
end
|
|
game.stack:push(TextBox.new(game,
|
|
t._SafariZoneGateSafariZoneWorker1Text or "Welcome to the\nSAFARI ZONE!",
|
|
function() joinPrompt(game, ow, done) end))
|
|
end,
|
|
},
|
|
|
|
-- the join trigger cells in front of the worker
|
|
onStep = function(game, ow, x, y)
|
|
if y ~= 2 or (x ~= 3 and x ~= 4) then return false end
|
|
if game.save.safari then return false end -- paid, walking in
|
|
joinPrompt(game, ow, nil)
|
|
return true
|
|
end,
|
|
|
|
-- arriving back from the zone (the north warps): the worker asks
|
|
-- "Leaving early?" -- yes ends the game and takes the leftover balls,
|
|
-- no walks you back into the zone
|
|
onEnter = function(game, ow)
|
|
if not game.save.safari or ow.player.cellY > 1 then return end
|
|
-- QUEUED, never pushed: onEnter runs inside the arriving warp's
|
|
-- Transition midpoint, and Transition:finish pops whatever is on top
|
|
-- the same frame (Timing.WARP_FADE_IN is 0) -- so a box pushed here is
|
|
-- swallowed, and on a build where it survived it drew over a screen
|
|
-- still faded to black (#540). Same contract as M.HALL_OF_FAME in
|
|
-- data/scripts/story.lua.
|
|
--
|
|
-- SafariZoneGateLeavingSafariScript .leaving_early: YES prints the
|
|
-- return-balls text, faces the player down and runs
|
|
-- SafariZoneEntranceAutoWalk with `PAD_DOWN, c = 3`, landing on the
|
|
-- counter row 3 cells below the warp you came in by; NO prints
|
|
-- "Good Luck!" and walks one step back up through that same warp.
|
|
local rightSide = ow.player.cellX ~= 3
|
|
local dest = game.data.maps.SAFARI_ZONE_CENTER.warps[rightSide and 2 or 1]
|
|
ow:queueScript({
|
|
{ "ask", "_SafariZoneGateSafariZoneWorker1LeavingEarlyText" },
|
|
{ "jump_if_false", "stay" },
|
|
-- the port never reaches SafariZoneGateLeavingSafariScript's own
|
|
-- GOOD_HAUL_COME_AGAIN branch (safariGameOver warps straight to the
|
|
-- counter), so the sign-off rides on this path
|
|
{ "show_text", "_SafariZoneGateSafariZoneWorker1ReturnSafariBallsText" },
|
|
{ "show_text", "_SafariZoneGateSafariZoneWorker1GoodHaulComeAgainText" },
|
|
-- no value: set_field assigns nil, which is how save.safari is cleared
|
|
{ "set_field", "safari" },
|
|
-- move_player runs through scriptMove, which skips onStepComplete, so
|
|
-- walking back down past (x,2) cannot re-fire the join trigger
|
|
{ "move_player", "down", 3 },
|
|
{ "jump", "end" },
|
|
{ "label", "stay" },
|
|
{ "show_text", "_SafariZoneGateSafariZoneWorker1GoodLuckText" },
|
|
{ "warp", "SAFARI_ZONE_CENTER", dest.x, dest.y, "up" },
|
|
})
|
|
end,
|
|
}
|
|
|
|
return M
|