mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 08:11:35 +02:00
238af263d6
# Conflicts: # src/core/Checkpoint.lua
99 lines
4.0 KiB
Lua
99 lines
4.0 KiB
Lua
-- Shared settled supported player-decision predicate. Checkpoint capture and
|
|
-- the public auxiliary action deliberately use this one engine-owned rule so
|
|
-- a tool cannot open at a phase that it could not subsequently checkpoint.
|
|
-- It exposes no controller; callers receive only the result/reason.
|
|
|
|
local BattleSafety = {}
|
|
|
|
local BATTLE_BUSY_FIELDS = {
|
|
"current", "afterQueue", "nextInsert", "pendingHit", "waitingUI",
|
|
"waitingSound", "waitFrames", "draining", "animPlaying", "growIn",
|
|
"introSlide", "ghostReveal", "mimicCtx", "mimicMoves", "result",
|
|
}
|
|
|
|
local function nonempty(value)
|
|
return type(value) == "table" and next(value) ~= nil
|
|
end
|
|
|
|
local function running(runner)
|
|
return runner and runner.isRunning and runner:isRunning()
|
|
end
|
|
|
|
local function scriptsBusy(overworld)
|
|
return running(overworld and overworld.runner)
|
|
or nonempty(overworld and overworld.parallelRunners)
|
|
or nonempty(overworld and overworld.pendingScripts)
|
|
or nonempty(overworld and overworld.parallelQueue)
|
|
or nonempty(overworld and overworld.scriptMoves)
|
|
end
|
|
|
|
function BattleSafety.inspect(game, battle)
|
|
if type(game) ~= "table" or type(game.save) ~= "table"
|
|
or type(game.save.version) ~= "string" then
|
|
return nil, "not_in_playthrough", "A checkpoint requires an identified active playthrough."
|
|
end
|
|
if type(battle) ~= "table" then
|
|
return nil, "not_battle", "No battle is active."
|
|
end
|
|
if battle.kind == "link" then
|
|
return nil, "link_battle_unsupported", "Network battles cannot be checkpointed."
|
|
end
|
|
if battle.safari or battle.ghost or battle.scopeReveal or battle.demo or battle.noCatch then
|
|
return nil, "battle_variant_unsupported",
|
|
"This battle variant does not have a checkpoint contract."
|
|
end
|
|
if battle.kind ~= "wild" and battle.kind ~= "trainer" then
|
|
return nil, "battle_variant_unsupported",
|
|
"This battle kind does not have a checkpoint contract."
|
|
end
|
|
local origin = battle.checkpointOrigin
|
|
local ordinaryOrigin = battle.kind == "wild" and "wild_encounter"
|
|
or "trainer_encounter"
|
|
local scriptedOrigin = type(origin) == "table"
|
|
and origin.kind == "script_battle"
|
|
if type(origin) ~= "table"
|
|
or (origin.kind ~= ordinaryOrigin and not scriptedOrigin) then
|
|
return nil, "battle_origin_unsupported",
|
|
"The battle completion path cannot be reconstructed safely."
|
|
end
|
|
local overworld = game.overworld or {}
|
|
local scriptedRunner = scriptedOrigin and (battle.checkpointScriptContinuation
|
|
or (overworld.runner
|
|
and overworld.runner.isCheckpointBattle
|
|
and overworld.runner:isCheckpointBattle(battle)))
|
|
local otherScriptWork = nonempty(overworld.parallelRunners)
|
|
or nonempty(overworld.pendingScripts) or nonempty(overworld.parallelQueue)
|
|
or nonempty(overworld.scriptMoves)
|
|
if (scriptedOrigin and (not scriptedRunner or otherScriptWork))
|
|
or (not scriptedOrigin and scriptsBusy(overworld)) then
|
|
return nil, "script_busy", "A suspended or queued script cannot be checkpointed."
|
|
end
|
|
if battle.phase ~= "menu" or nonempty(battle.queue) then
|
|
return nil, "battle_phase_busy",
|
|
"Wait for the player command menu before creating a checkpoint."
|
|
end
|
|
for _, field in ipairs(BATTLE_BUSY_FIELDS) do
|
|
if battle[field] ~= nil and battle[field] ~= false then
|
|
return nil, "battle_phase_busy", "Wait for the current battle action to finish."
|
|
end
|
|
end
|
|
if not battle.player or not battle.enemy or not battle.player.mon
|
|
or battle.player.mon.hp <= 0
|
|
or (battle.menuLockedAction and battle:menuLockedAction(battle.player)) then
|
|
return nil, "battle_phase_busy",
|
|
"Wait for a supported player decision before creating a checkpoint."
|
|
end
|
|
for _, battler in ipairs({ battle.player, battle.enemy }) do
|
|
if not battler.mon or battler.shownHP ~= battler.mon.hp
|
|
or battler.shownStatus ~= battler.mon.status
|
|
or battler.drainFloor ~= nil or battler.drainHold ~= nil
|
|
or battler.faintQueued then
|
|
return nil, "battle_phase_busy",
|
|
"Wait for battle status and HP presentation to settle."
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
return BattleSafety
|