mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 00:02:23 +02:00
yellow alpha
This commit is contained in:
+76
-2
@@ -173,6 +173,27 @@ function Commands.check_item(ctx, itemId)
|
||||
ctx.lastCheck = (ctx.save.inventory[itemId] or 0) > 0
|
||||
end
|
||||
|
||||
-- check_dex_owned <n>: lastCheck = the player owns at least n species
|
||||
-- (the CountSetBits-over-wPokedexOwned gate in Yellow's OaksLabOak1Text)
|
||||
function Commands.check_dex_owned(ctx, n)
|
||||
local owned = 0
|
||||
for _ in pairs(ctx.save.pokedex and ctx.save.pokedex.owned or {}) do
|
||||
owned = owned + 1
|
||||
end
|
||||
ctx.lastCheck = owned >= (n or 1)
|
||||
end
|
||||
|
||||
-- dex_rating: DisplayDexRating (engine/events/pokedex_rating.asm) --
|
||||
-- Oak's seen/owned tally plus the per-decade rating line; blocks until
|
||||
-- the box closes. Headless-safe no-op without an overworld.
|
||||
function Commands.dex_rating(ctx)
|
||||
local ow = ctx.overworld
|
||||
if not ow then return end
|
||||
local runner = ctx.runner
|
||||
ow:dexRating(function() runner:resume() end)
|
||||
runner:yield()
|
||||
end
|
||||
|
||||
function Commands.jump_if_true(ctx, target)
|
||||
if ctx.lastCheck then return target end
|
||||
end
|
||||
@@ -561,7 +582,10 @@ end
|
||||
-- AskName runs for party (AddPartyMon) and box (SendNewMonToBox) when a
|
||||
-- script runner is present; mods that pre-set gift.nickname skip it.
|
||||
-- Box deposits also print SentToBoxText (give_pokemon.asm:36-37).
|
||||
function Commands.give_pokemon(ctx, species, level)
|
||||
-- skipNickname suppresses the AskName prompt: Yellow's lab Pikachu is
|
||||
-- added straight through AddPartyMon (pokeyellow scripts/OaksLab.asm
|
||||
-- OaksLabPlayerReceivedMonText) -- the starter Pikachu keeps its name.
|
||||
function Commands.give_pokemon(ctx, species, level, skipNickname)
|
||||
-- Native mods can transform a gift before the Pokémon object is created.
|
||||
-- This is intentionally an event rather than a special-case starter hook:
|
||||
-- mods can use the same seam for story gifts, fossils, or custom scripts.
|
||||
@@ -597,7 +621,7 @@ function Commands.give_pokemon(ctx, species, level)
|
||||
ctx.boxNum = boxNum
|
||||
-- AskName: both AddPartyMon and SendNewMonToBox; skip mod-set nicks
|
||||
-- and callback-style callers with no script runner to yield on.
|
||||
if not gift.nickname and ctx.runner then
|
||||
if not gift.nickname and not skipNickname and ctx.runner then
|
||||
askNickname(ctx, mon)
|
||||
end
|
||||
if boxNum then
|
||||
@@ -748,7 +772,46 @@ end
|
||||
-- player CHARMANDER -> base+0, SQUIRTLE -> base+1, BULBASAUR -> base+2.
|
||||
-- offsets (flag -> party offset) lets a modded roster remap the pick;
|
||||
-- field.starterCounterpicks is the data-side default when stamped.
|
||||
-- Yellow's rival parties key off wRivalStarter (save.rivalStarter,
|
||||
-- 1 JOLTEON / 2 FLAREON / 3 VAPOREON -- set in oaks_lab_yellow.lua), not
|
||||
-- the player's starter counterpick. Keyed by the Red call-site party so
|
||||
-- the shared story scripts need no version branches:
|
||||
-- Route 22 #1 RIVAL1 4 -> party 2 (fixed; Route22Script_50ed6), and
|
||||
-- a win upgrades FLAREON to JOLTEON (Route22Rival1AfterBattleScript)
|
||||
-- Cerulean RIVAL1 7 -> party 3 (fixed; CeruleanCity.asm:143)
|
||||
-- S.S. Anne RIVAL2 1 -> party 1 (fixed; SSAnne2F.asm:98)
|
||||
-- Tower 2F RIVAL2 4 -> 1 + starter (PokemonTower2F.asm:148)
|
||||
-- Silph 7F RIVAL2 7 -> 4 + starter (SilphCo7F.asm:185)
|
||||
-- Route 22 #2 RIVAL2 10 -> 7 + starter (Route22Script_50ee1)
|
||||
-- Champion RIVAL3 1 -> 0 + starter (ChampionsRoom.asm:69)
|
||||
local YELLOW_RIVAL_PARTIES = {
|
||||
OPP_RIVAL1 = {
|
||||
[4] = { party = 2, upgradeOnWin = { from = 2, to = 1 } },
|
||||
[7] = { party = 3 },
|
||||
},
|
||||
OPP_RIVAL2 = {
|
||||
[1] = { party = 1 }, [4] = { base = 1 },
|
||||
[7] = { base = 4 }, [10] = { base = 7 },
|
||||
},
|
||||
OPP_RIVAL3 = { [1] = { base = 0 } },
|
||||
}
|
||||
|
||||
function Commands.rival_battle(ctx, oppClass, baseParty, offsets)
|
||||
local GameVersion = require("src.core.GameVersion")
|
||||
if GameVersion.isYellow() then
|
||||
local spec = YELLOW_RIVAL_PARTIES[oppClass]
|
||||
and YELLOW_RIVAL_PARTIES[oppClass][baseParty]
|
||||
if spec then
|
||||
local starter = ctx.save.rivalStarter or 1
|
||||
local party = spec.party or (spec.base + starter)
|
||||
Commands.start_battle(ctx, "trainer", oppClass, party)
|
||||
if spec.upgradeOnWin and ctx.lastBattleResult == "win"
|
||||
and ctx.save.rivalStarter == spec.upgradeOnWin.from then
|
||||
ctx.save.rivalStarter = spec.upgradeOnWin.to
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
offsets = offsets
|
||||
or (ctx.game.data.field and ctx.game.data.field.starterCounterpicks)
|
||||
local offset = 0
|
||||
@@ -951,6 +1014,17 @@ function Commands.stop_music(ctx)
|
||||
require("src.core.Music").stop()
|
||||
end
|
||||
|
||||
-- play_default_music: PlayDefaultMusic -- resume the current map's own
|
||||
-- theme (data.audio.mapSongs) after a cutscene override, keeping the
|
||||
-- bike/surf substitution rules. Headless-safe no-op without an overworld.
|
||||
function Commands.play_default_music(ctx)
|
||||
local ow = ctx.overworld
|
||||
if not ow then return end
|
||||
require("src.core.Music").playMap(ctx.game.data, ow.map.id,
|
||||
ctx.save and ctx.save.onBike,
|
||||
ow.player and ow.player.surfing)
|
||||
end
|
||||
|
||||
-- replace_block <bx> <by> <blockId>: the Cut-tree/card-key-door idiom,
|
||||
-- on the current map
|
||||
function Commands.replace_block(ctx, bx, by, blockId)
|
||||
|
||||
@@ -191,8 +191,18 @@ function ScriptRunner:yield()
|
||||
end
|
||||
|
||||
function ScriptRunner:resume(...)
|
||||
if not self.co then return end
|
||||
local ok, err = coroutine.resume(self.co, ...)
|
||||
local co = self.co
|
||||
if not co then return end
|
||||
-- A completion callback can fire synchronously from inside the running
|
||||
-- coroutine (e.g. a battle that finishes during its own stack push when
|
||||
-- the party is already fainted). Resuming a running coroutine is an
|
||||
-- error that would kill the whole script, so land the pending yield
|
||||
-- first and continue on the next update tick instead.
|
||||
if coroutine.status(co) == "running" then
|
||||
self.waitingFrames = 1
|
||||
return
|
||||
end
|
||||
local ok, err = coroutine.resume(co, ...)
|
||||
if not ok then
|
||||
local source = self.ctx and self.ctx.source
|
||||
local where = source
|
||||
@@ -209,8 +219,10 @@ function ScriptRunner:resume(...)
|
||||
self.co = nil
|
||||
self.waitingFrames = nil
|
||||
self.waitingCheck = nil
|
||||
elseif coroutine.status(self.co) == "dead" then
|
||||
self.co = nil
|
||||
-- status via the captured co: a nested resume during the call above may
|
||||
-- already have torn self.co down, and status(nil) would throw
|
||||
elseif coroutine.status(co) == "dead" then
|
||||
if self.co == co then self.co = nil end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user