Files
gen1recomp/src/box/Events.lua
T

151 lines
7.6 KiB
Lua

local Store = require("src.box.Store")
local Context = require("src.box.GameContext")
local Events = {}
local WESTERN = { [2]=true,[3]=true,[4]=true,[5]=true,[7]=true }
local ALL = { [1]=true,[2]=true,[3]=true,[4]=true,[5]=true,[7]=true }
Events.ROWS = {
{ id="eon",name="Eon Ticket",item="ITEM_EON_TICKET",versions={ruby=ALL,sapphire=ALL,emerald=ALL},
card="rse_eon_ticket",route="Southern Island",method="Record mixing" },
{ id="aurora",name="AuroraTicket",item="ITEM_AURORA_TICKET",versions={firered=ALL,leafgreen=ALL,emerald=WESTERN},
card="aurora_ticket",rseCard="rse_aurora_ticket",route="Birth Island",method="Wonder Card" },
{ id="mystic",name="MysticTicket",item="ITEM_MYSTIC_TICKET",
versions={firered={[1]=true,[2]=true},leafgreen={[1]=true,[2]=true},emerald={[1]=true,[2]=true}},
card="mystic_ticket",rseCard="rse_mystic_ticket",route="Navel Rock",method="Wonder Card" },
{ id="oldSeaMap",name="Old Sea Map",item="ITEM_OLD_SEA_MAP",versions={emerald={[1]=true}},
card="rse_old_sea_map",route="Faraway Island",method="Wonder Card" },
}
Events.FAMILY={firered="frlg",leafgreen="frlg",emerald="rse",ruby="rs",sapphire="rs"}
Events._feeds,Events._jobs={},{}
function Events.setFeed(version,list) Events._feeds[version]=list end
function Events.poll(version,opts)
local family=Events.FAMILY[version]
if not family then return "error","no_family" end
if Events._feeds[version] then return "ok",Events._feeds[version] end
local Gift=require("src.core.game3.mystery_gift")
local job=Events._jobs[version]
if not job then
opts=opts or {}
job=Gift.fetchOnline({family=family,version=version,transport=opts.transport,client=opts.client})
Events._jobs[version]=job
end
local status,result=Gift.pollOnline(job)
if status=="pending" then return status end
Events._jobs[version]=nil
if status=="ok" then Events._feeds[version]=result end
return status,result
end
local function relayOffer(save,row)
local status,list=Events.poll(save.version)
if status=="pending" then return nil,"Checking the relay for tickets. Try again in a moment." end
if status~="ok" then return nil,"The relay could not be reached, so no tickets can be received." end
local Gift=require("src.core.game3.mystery_gift")
local item=require("src.core.game3.constants").of(save.version):require("items",row.item)
if Events.FAMILY[save.version]=="rs" then
for _,ev in ipairs(list.events or {}) do
if Gift.eventRecordMixingItem(ev.bytes)==item then return ev end
end
else
for _,entry in ipairs(list.cards or {}) do
if entry.card.gift and entry.card.gift.kind=="item" and entry.card.gift.item==item then return entry end
end
end
return nil,"The relay is not offering this ticket right now."
end
Events.relayOffer=relayOffer
function Events.allowed(id,version,language)
for _,row in ipairs(Events.ROWS) do
if row.id==id then return row.versions[version] and row.versions[version][language] and row or nil end
end
end
function Events.list(version,language)
local out={}
for _,row in ipairs(Events.ROWS) do if Events.allowed(row.id,version,language) then out[#out+1]=row end end
if #out>0 and Events.autoFetch~=false then pcall(Events.poll,version) end
return out
end
local function session(save)
local store={version=save.version,flags={},vars={}}
for id,on in pairs(save.flags or {}) do store.flags[tonumber(id) or id]=on end
for id,value in pairs(save.vars or {}) do store.vars[tonumber(id) or id]=value end
return {version=save.version,store=store,bag=save.bag,storage=save.storage,modData=save.modData or {}}
end
local function apply(s,save)
local snap=require("src.core.game3.scripting.flags").serialize(s.store)
save.flags,save.vars,save.bag,save.storage,save.modData=snap.flags,snap.vars,s.bag,s.storage,s.modData
end
function Events.status(save,row)
return Context.withItems(save.version,function()
local Gift=require("src.core.game3.mystery_gift")
local s=session(Store.copy(save))
local item=require("src.core.game3.constants").of(save.version):require("items",row.item)
if require("src.core.game3.bag").has(s.bag or {pockets={}},item,1) then return "Collected" end
local received=row.id=="eon" and (save.version=="ruby" or save.version=="sapphire") and "FLAG_SYS_HAS_EON_TICKET"
or row.id=="eon" and "FLAG_ENABLE_SHIP_SOUTHERN_ISLAND"
or row.id=="aurora" and "FLAG_RECEIVED_AURORA_TICKET"
or row.id=="mystic" and "FLAG_RECEIVED_MYSTIC_TICKET" or "FLAG_RECEIVED_OLD_SEA_MAP"
if Gift.getFlag(s,require("src.core.game3.constants").of(save.version):require("flags",received)) then return "Collected" end
if row.id=="eon" then return "Available" end
local family=save.version=="emerald" and "rse" or "frlg"
local key=family=="rse" and (row.rseCard or row.card) or row.card
for _,candidate in ipairs(Gift.builtins(family)) do
if candidate.key==key then
for _,flag in ipairs(candidate.card.gift and candidate.card.gift.haveFlags or {}) do
if Gift.getFlag(s,flag) then return "Event already completed" end
end
end
end
local card=Gift.getSavedCard(s)
if card and card.gift and card.gift.item==item then return "Ticket pending" end
return "Available"
end)
end
function Events.receive(save,id,language)
local row=Events.allowed(id,save.version,language)
if not row then return nil,"This event was not historically distributed for this game and language." end
local status,why=Events.status(save,row)
if not status then return nil,why end
if status~="Available" then return nil,"This event has already been received." end
return Context.withItems(save.version,function()
local offer,offerWhy=relayOffer(save,row)
if not offer then return nil,offerWhy end
local out=Store.copy(save)
local s=session(out)
local C=require("src.core.game3.constants").of(save.version)
local item=C:require("items",row.item)
if id=="eon" then
local leader={name="Box Events",giftItem=item}
local result
if save.version=="ruby" or save.version=="sapphire" then
result=require("src.core.game3.link.rs_record_mix").receiveGift(s,leader,2)
else result=require("src.core.game3.rse.record_mixing_gift").mixImport({leader,{}},s,2) end
if not result or result.item~=item then return nil,"Make room in the Key Items pocket before receiving the Eon Ticket." end
else
local Gift=require("src.core.game3.mystery_gift")
local existing=Gift.getSavedCard(s)
if existing then
local flag=Gift.receivedGiftFlag(existing.flagId,s)
if flag and not Gift.getFlag(s,flag) then return nil,"Collect your existing Wonder Card gift before receiving another card." end
end
if not Gift.receiveCard(s,offer.card) then return nil,"The game's ticket delivery card could not be prepared." end
end
apply(s,out);return out
end)
end
function Events.collect(save,id,language)
local row=Events.allowed(id,save.version,language)
if not row or id=="eon" then return nil,"Choose a pending ticket card." end
return Context.withItems(save.version,function()
local Gift=require("src.core.game3.mystery_gift")
local out=Store.copy(save);local s=session(out)
local card=Gift.getSavedCard(s)
local item=require("src.core.game3.constants").of(save.version):require("items",row.item)
if not card or not card.gift or card.gift.item~=item then return nil,"Receive this ticket's card first." end
local result=Gift.deliverGift(s,card)
if result~=Gift.DELIVER_GIVEN then
return nil,result==Gift.DELIVER_NO_ROOM and "The Key Items pocket is full." or "This ticket has already been collected."
end
Gift.claimCard(s,card);apply(s,out);return out
end)
end
return Events