mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 07:41:21 +02:00
93 lines
4.3 KiB
Markdown
93 lines
4.3 KiB
Markdown
# RFC 0010: Deferred trainer preparation and battle-local party scope
|
|
|
|
## Status
|
|
|
|
Proposed.
|
|
|
|
## Motivation
|
|
|
|
Challenge and tournament mods sometimes need a player to choose an eligible
|
|
subset of the save party before a trainer battle. The current public surface
|
|
can replace the opponent through `trainer.party` and observe
|
|
`world.trainer_engaged`, but it cannot pause the engagement before battle
|
|
construction or keep unselected save-party members out of initial send,
|
|
switch, replacement, exhaustion, experience, and party-menu traversal.
|
|
|
|
Temporarily rewriting `game.save.party` is not a safe substitute: it changes
|
|
authoritative save state, composes poorly with checkpoints and other mods, and
|
|
can strand excluded Pokémon if a callback or process fails.
|
|
|
|
## Decision and plan extended
|
|
|
|
This implements **D-AT-001: battle-local Gym registration without save-party
|
|
mutation**, the consuming design decision tracked as capability `AT-SP-001` in
|
|
the Adaptive Trainers implementation plan. The plan file is
|
|
[`docs/superpowers/plans/2026-08-14-adaptive-trainers.md`](https://github.com/MaxTomahawk/gen1recomp-adaptive-trainers/blob/main/docs/superpowers/plans/2026-08-14-adaptive-trainers.md),
|
|
Task 5. The engine delta also extends the additive, guarded public-hook
|
|
decision used by RFC 0007 and the screen facade documented in
|
|
`docs/modding.md`; it deliberately contains none of the consuming mod's Gym
|
|
or party-size policy.
|
|
|
|
## Exact API delta
|
|
|
|
Add the guarded hook:
|
|
|
|
```lua
|
|
mod.hooks:wrap("trainer.before_battle", function(next, game, context, continue)
|
|
-- context = { trainerClass, partyIndex, mapId, npcId }
|
|
-- Return true only when the battle has been deferred.
|
|
-- continue({ cancel = true }) returns without constructing a battle.
|
|
-- Call continue() for the full save party, or:
|
|
-- continue({ playerPartyIndices = { 2, 4, 5 } })
|
|
end)
|
|
```
|
|
|
|
The hook runs after the trainer's challenge text and immediately before the
|
|
trainer battle is constructed. A mod may push a registered screen with
|
|
`mod.ui.push`, return `true`, and retain `continue` for its confirm/cancel
|
|
callback. `continue` is one-shot and returns `false` after the first call.
|
|
Returning anything other than `true` without calling it continues immediately
|
|
with vanilla scope. With no subscriber, no context or continuation is built.
|
|
|
|
`playerPartyIndices` is an ordered, one-based list into `game.save.party`.
|
|
Valid unique indices create `battle.playerParty` as a battle-local view of the
|
|
same Pokémon records; the save party itself is never reordered or replaced.
|
|
Malformed or empty scopes degrade to the full party. The view governs initial
|
|
send, all battle party menus and targets, voluntary and forced replacement,
|
|
exhaustion/blackout checks, participant and EXP.ALL traversal, party counts,
|
|
and party-ball presentation. Checkpoints preserve the index list and rebuild
|
|
the same view before restoring battlers.
|
|
|
|
`{ cancel = true }` ends a deferred encounter through its normal completion
|
|
callback without constructing a battle or writing trainer-defeated state. A
|
|
cancelled sight encounter is suppressed while the player remains on the same
|
|
cell, preventing immediate reacquisition; moving or directly talking permits a
|
|
new challenge. Cancellation is also one-shot; if supplied alongside a party
|
|
index list, cancellation wins.
|
|
|
|
The API sets no maximum, chooses no members, identifies no boss, and contains
|
|
no scaling or challenge policy.
|
|
|
|
## Migration and compatibility
|
|
|
|
Existing mods change nothing. `BattleState.newTrainer(game, class, index)`
|
|
keeps its current behavior; the optional fourth argument is additive. Existing
|
|
battle checkpoints without a party scope restore against the full save party.
|
|
Wild, Safari, link, and no-mod battles are unchanged.
|
|
|
|
## Verification
|
|
|
|
- The catalog-driven hook gate proves empty-chain parity and the guarded hot
|
|
path proves no-mod engagement starts exactly once without allocation.
|
|
- A sandboxed fixture mod defers through its public hook facade, inspects the
|
|
data-only context, and resumes once with ordered indices.
|
|
- Engine tests cover initial send, party menus, replacement/exhaustion,
|
|
EXP traversal, invalid-scope fallback, and save-party identity.
|
|
- Battle-checkpoint tests prove scoped capture/restore and old-checkpoint
|
|
compatibility.
|
|
|
|
## Deprecation etiquette
|
|
|
|
Nothing is deprecated. The hook and optional constructor argument are
|
|
additive.
|