Files
gen1recomp/src/box/Records.lua
T
2026-10-06 11:00:16 -04:00

195 lines
7.2 KiB
Lua

local Store = require("src.box.Store")
local Records = {}
function Records.boxes(save, generation)
if generation == 3 then
return save.storage and save.storage.boxes or {}
end
return save.boxes or (save.box and { save.box }) or {}
end
function Records.list(save, generation, box)
local row = Records.boxes(save, generation)[box]
if type(row) ~= "table" then return {} end
return generation == 3 and (row.mons or {}) or row
end
function Records.at(save, generation, ref)
if type(ref) ~= "table" then return nil end
local list = ref.where == "party" and (save.party or {})
or Records.list(save, generation, ref.box)
return list[ref.index] or list[tostring(ref.index)]
end
function Records.candidates(save, generation)
local out = {}
for i, mon in ipairs(save.party or {}) do
out[#out + 1] = { where = "party", index = i, mon = mon, source = "Party" }
end
local count, size = generation == 1 and 12 or 14, generation == 3 and 30 or 20
for b = 1, count do
local row = Records.boxes(save, generation)[b]
local name = generation == 3 and row and row.name
or save.boxNames and save.boxNames[b] or "BOX " .. b
for i = 1, size do
local mon = Records.list(save, generation, b)[i]
or Records.list(save, generation, b)[tostring(i)]
if type(mon) == "table" then
out[#out + 1] = { where = "box", box = b, index = i, mon = mon, source = name }
end
end
end
return out
end
function Records.key(ref)
return table.concat({ ref.where or "box", ref.box or 0, ref.index or ref.slot or 0 }, ":")
end
function Records.identity(generation, mon)
if generation == 3 then
if type(mon.personality) ~= "number" then return nil end
return "3|" .. mon.personality .. "|" .. tostring(mon.otId or 0) .. "|" .. tostring(mon.otSecretId or 0)
end
if type(mon.dvs) ~= "table" or mon.otId == nil then return nil end
local dvs = mon.dvs
local ot = mon.otName or mon.ot
if ot == nil then ot = require("src.core.TrainerIdentity").monName(mon) end
return table.concat({ generation, mon.otId, ot or "",
dvs.attack or 0, dvs.defense or 0, dvs.speed or 0, dvs.special or 0 }, "|")
end
local function catalog(version)
return require("src.box.Catalog").get(version)
end
function Records.enterBox(version, generation, mon)
if type(mon) ~= "table" then return mon end
if generation == 2 then
require("src.core.gen2.Boxes").enterBox(mon, catalog(version))
elseif generation == 3 then
pcall(require("src.core.game3.storage").fullHealMon, mon, { version = version })
end
return mon
end
function Records.leaveBox(version, generation, mon)
if type(mon) ~= "table" then return mon end
if generation == 1 then
local data = catalog(version)
require("src.pokemon.Stats").ensure(data.pokemon and data.pokemon[mon.species], mon)
elseif generation == 2 then
mon.status, mon.statusTurns = nil, nil
if mon.isEgg then mon.hp = 0 else mon.hp = mon.maxHp or mon.hp end
end
return mon
end
function Records.registerReceived(save, generation, mon)
if mon.isEgg then return end
if generation == 3 then
save.dex = save.dex or {}
require("src.core.game3.dex").handleSetPokedexFlag(save.dex, mon.species, true, mon.personality)
else
save.pokedex = save.pokedex or {}
local dex = save.pokedex
dex.seen = dex.seen or {}
local key = generation == 2 and "caught" or "owned"
dex[key] = dex[key] or {}
dex.seen[mon.species], dex[key][mon.species] = true, true
if generation == 2 and mon.species == "UNOWN" then
local Unown = require("src.core.gen2.Unown")
local letter = Unown.monLetter(mon)
save.unownDex = save.unownDex or {}
local found = false
for _, value in ipairs(save.unownDex) do if value == letter then found = true end end
if letter and not found then save.unownDex[#save.unownDex + 1] = letter end
end
end
end
function Records.remove(save, generation, refs)
local nextSave = Store.copy(save)
local seen, party = {}, false
for _, ref in ipairs(refs) do
local key = Records.key(ref)
if seen[key] or not Records.at(nextSave, generation, ref) then return nil, "A selected Pokémon is missing." end
seen[key] = true
local mon = Records.at(nextSave, generation, ref)
local mail = tonumber(mon.mail)
if generation == 3 and mail and mail ~= 255 then return nil, "Remove held mail before depositing." end
if generation == 2 and (require("src.core.gen2.Mail").monHoldsMail(mon)
or ref.where == "party" and nextSave.mail and nextSave.mail.party
and nextSave.mail.party[ref.index]) then return nil, "Remove held mail before depositing." end
local list
if ref.where == "party" then list, party = nextSave.party, true
else
if generation ~= 3 and not nextSave.boxes then
nextSave.boxes = { nextSave.box or {} }; nextSave.box = nil
end
list = Records.list(nextSave, generation, ref.box)
end
list[ref.index], list[tostring(ref.index)] = nil, nil
end
local function compact(list)
local keys, values = {}, {}
for key, value in pairs(list) do
if type(value) == "table" then keys[#keys + 1] = tonumber(key) end
end
table.sort(keys)
for _, key in ipairs(keys) do values[#values + 1] = list[key] or list[tostring(key)] end
for key in pairs(list) do list[key] = nil end
for i, value in ipairs(values) do list[i] = value end
return keys
end
if party then
local oldSlots = compact(nextSave.party)
if generation == 2 and nextSave.mail and type(nextSave.mail.party) == "table" then
local oldMail, nextMail = nextSave.mail.party, {}
for index, oldIndex in ipairs(oldSlots) do nextMail[index] = oldMail[oldIndex] end
nextSave.mail.party = nextMail
end
local healthy = 0
for _, mon in ipairs(nextSave.party) do
if not mon.isEgg and (tonumber(mon.hp) or 0) > 0 then healthy = healthy + 1 end
end
if healthy == 0 then return nil, "Keep at least one Pokémon able to battle in the party." end
end
if generation < 3 then
for _, list in pairs(nextSave.boxes or {}) do compact(list) end
end
return nextSave
end
function Records.insert(save, generation, box, entries)
local count, capacity = generation == 1 and 12 or 14, generation == 3 and 30 or 20
if type(box) ~= "number" or box < 1 or box > count or box ~= math.floor(box) then
return nil, "Choose a valid destination PC box."
end
local nextSave = Store.copy(save)
local boxes
if generation == 3 then
nextSave.storage = nextSave.storage or { currentBox = 1, boxes = {} }
nextSave.storage.boxes = nextSave.storage.boxes or {}
boxes = nextSave.storage.boxes
boxes[box] = boxes[box] or { name = "BOX " .. box, mons = {} }
boxes[box].mons = boxes[box].mons or {}
else
nextSave.boxes = nextSave.boxes or { nextSave.box or {} }
nextSave.box = nil
boxes = nextSave.boxes
boxes[box] = boxes[box] or {}
end
local list = generation == 3 and boxes[box].mons or boxes[box]
for _, entry in ipairs(entries) do
local free
for i = 1, capacity do if not (list[i] or list[tostring(i)]) then free = i; break end end
if not free then return nil, "That PC box does not have enough room." end
list[free] = Store.copy(entry.mon)
Records.registerReceived(nextSave, generation, list[free])
end
return nextSave
end
return Records