Files
gen1recomp/src/battle/gen2/BattleAPI.lua
T
2026-08-16 01:32:23 +02:00

120 lines
4.1 KiB
Lua

-- Read-only Gen 2 battle state with the same shape as mod.battle on Gen 1.
local BattleAPI = {}
BattleAPI.__index = BattleAPI
function BattleAPI.new(game)
return setmetatable({ game = game, revision = 0, signature = nil }, BattleAPI)
end
local function activeBattle(game)
local states = game and game.stack and game.stack.states or {}
local battle
for i = #states, 1, -1 do
local state = states[i]
if state.screenId == "Gen2BattleState" or state.isGen2BattleState then
battle = state
break
end
end
return battle, states[#states]
end
local function monCopy(data, mon, active)
if not mon then return nil end
local def = data and data.pokemon and data.pokemon[mon.species]
return { species = mon.species,
name = mon.nickname or (def and def.name) or mon.species,
level = mon.level, hp = mon.hp,
maxHp = mon.maxHp or (mon.stats and mon.stats.hp) or mon.hp,
status = mon.status, active = active and true or false }
end
local function messageCopy(screen)
if not screen.message then return nil end
local lines = {}
for line in tostring(screen.message):gmatch("[^\n]+") do
lines[#lines + 1] = line
end
return #lines > 0 and lines or nil
end
local function signature(game, screen, top)
if not screen then return "none" end
local battle = screen.battle or {}
local parts = { tostring(screen), tostring(top), tostring(screen.phase),
tostring(screen.message), tostring(screen.messageTimer),
tostring(screen.menuIndex), tostring(screen.moveIndex),
tostring(battle.turn), tostring(battle.over), tostring(battle.outcome) }
for _, mon in ipairs({ battle.player, battle.enemy }) do
parts[#parts + 1] = tostring(mon)
parts[#parts + 1] = tostring(mon and mon.hp)
parts[#parts + 1] = tostring(mon and mon.status)
end
for _, mon in ipairs((game.save and game.save.party) or battle.party or {}) do
parts[#parts + 1] = tostring(mon)
parts[#parts + 1] = tostring(mon.hp)
parts[#parts + 1] = tostring(mon.status)
end
return table.concat(parts, "|")
end
function BattleAPI:_revision(screen, top)
local nextSignature = signature(self.game, screen, top)
if nextSignature ~= self.signature then
self.signature = nextSignature
self.revision = self.revision + 1
end
return self.revision
end
local function moveCopies(game, battle)
local out = {}
for slot, move in ipairs((battle.player and battle.player.moves) or {}) do
local def = (game.data.moves or {})[move.id] or {}
out[slot] = { slot = slot, id = move.id, name = def.name or move.id,
pp = move.pp, maxPp = move.maxPp or def.pp or move.pp,
type = def.type, power = def.power, accuracy = def.accuracy,
disabled = battle:moveDisabled(battle.player, move.id) }
end
return out
end
local function battleKind(screen)
if screen.tutorial then return "oldman" end
return screen.battle and screen.battle.wild and "wild" or "trainer"
end
function BattleAPI:snapshot()
local game = self.game
local screen, top = activeBattle(game)
if not screen or not screen.battle then return nil end
local battle = screen.battle
local prompt = "locked"
if top == screen and screen.phase == "menu" then
prompt = "menu"
elseif top == screen and screen.phase == "moves" then
prompt = "moves"
elseif top == screen and screen.message then
prompt = "advance"
elseif top and top.screenId == "Gen2PartyMenu" then
prompt = "party"
end
local party = {}
for i, mon in ipairs((game.save and game.save.party) or battle.party or {}) do
party[i] = monCopy(game.data, mon, mon == battle.player)
party[i].slot = i
end
return { revision = self:_revision(screen, top), kind = battleKind(screen),
catchable = battle.wild and not screen.tutorial, prompt = prompt,
message = messageCopy(screen), turn = battle.turn or 0,
player = monCopy(game.data, battle.player, true),
enemy = monCopy(game.data, battle.enemy, true),
party = party, moves = moveCopies(game, battle),
-- Gold's PACK is pocketed and target selection is screen-owned. Omit it
-- until the engine can expose the same semantic item records as Gen 1.
items = {} }
end
return BattleAPI