mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 23:00:21 -04:00
379 lines
19 KiB
Lua
379 lines
19 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local Profile = require("src.core.game3.profile")
|
|
Profile.reset()
|
|
GameVersion.set("emerald")
|
|
|
|
local Dataset = require("src.core.game3.dataset")
|
|
local cache = Dataset.cache()
|
|
local function has(rel)
|
|
local src = cache and cache.read and cache:read(rel)
|
|
return type(src) == "string"
|
|
end
|
|
if not (has("data/generated/gba/frontier/trainers.lua") and has("data/generated/gba/rse/factory/manifest.lua")
|
|
and has("data/generated/gba/rse/pike/manifest.lua") and has("data/generated/gba/rse/frontier/manifest.lua")) then
|
|
print("emerald_factory_pike_test: skipped (no Emerald cache with rse/factory + rse/pike; set POKEPORT_IDENTITY)")
|
|
os.exit(0)
|
|
end
|
|
|
|
require("src.import.gba.versions").select("emerald")
|
|
local C = require("src.core.game3.constants").of("emerald")
|
|
local Pokemon = require("src.core.game3.pokemon")
|
|
Pokemon.install(nil)
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Rng = require("src.core.game3.rng")
|
|
|
|
local store = { flags = {}, vars = {} }
|
|
local Space = require("src.core.game3.scripting.space")
|
|
Space.store = store
|
|
|
|
local sess = { version = "emerald", name = "BRENDAN", trainerId = 12345, secretId = 4321, money = 1000, party = {},
|
|
gender = 0, bag = {}, flags = store.flags, vars = store.vars, map = "EM_BATTLE_FRONTIER_BATTLE_FACTORY_LOBBY" }
|
|
local prevGet = Runtime.getSession
|
|
Runtime.getSession = function() return sess end
|
|
|
|
local D = require("src.core.game3.rse.frontier.trainers")
|
|
local Util = require("src.core.game3.rse.frontier.util")
|
|
local Rse = require("src.core.game3.rse.init")
|
|
local Factory = require("src.core.game3.rse.frontier.factory")
|
|
local Pike = require("src.core.game3.rse.frontier.pike")
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
|
|
local function S(name) return C.species.byName[name] end
|
|
local function MV(name) return C:require("moves", name) end
|
|
local function setVar(name, v) Rse.setVar(name, v, sess) end
|
|
local function ctxWith(vars)
|
|
local ctx = { specialVars = {} }
|
|
function ctx:getVar(id) return self.specialVars[id] or 0 end
|
|
function ctx:setVar(id, v) self.specialVars[id] = v end
|
|
for id, v in pairs(vars or {}) do Rse.setSpecialVar(ctx, id, v) end
|
|
return ctx
|
|
end
|
|
local function result(ctx) return Rse.specialVar(ctx, Util.VAR_RESULT) end
|
|
|
|
local fm = Factory.manifest()
|
|
eq(table.concat(fm.requiredMoveCounts, ","), "3,3,3,2,2,2,2", "sRequiredMoveCounts (battle_factory.c:45)")
|
|
eq(#fm.moveStyles, 7, "seven factory move-style lists (battle_factory.c:113)")
|
|
eq(fm.moveStyles[1][1], MV("MOVE_SWORDS_DANCE"), "Total Preparation starts with Swords Dance")
|
|
eq(fm.moveStyles[7][5], MV("MOVE_WEATHER_BALL"), "Depends on the Battle's Flow ends with Weather Ball")
|
|
eq(#fm.fixedIvTable, 9, "sFixedIVTable rows plus the out-of-bounds row (battle_factory.c:750)")
|
|
eq(fm.fixedIvTable[9][1], 110, "row 8 reads sInitialRentalMonRanges' first byte")
|
|
eq(#fm.rentalRanges, 16, "sInitialRentalMonRanges has 16 rows (battle_factory.c:169)")
|
|
eq(fm.rentalRanges[1][1], 110, "level-50 challenge 1 rentals start at FRONTIER_MON_GRIMER")
|
|
eq(fm.rentalRanges[1][2], 199, "and end at FRONTIER_MON_FURRET_1")
|
|
eq(Factory.fixedIV(0, false), 3, "challenge 1 IVs are 3")
|
|
eq(Factory.fixedIV(0, true), 6, "the 7th trainer of challenge 1 uses 6")
|
|
eq(Factory.fixedIV(7, false), 31, "challenge 8 uses 31")
|
|
eq(Factory.fixedIV(8, false), 110, "challenge 9 reads past the table into random IVs")
|
|
eq(Factory.fixedIV(8, true), 0, "challenge 9's last battle reads 0")
|
|
eq(Factory.fixedIV(12, false), 31, "challenges past 9 clamp to the last row")
|
|
eq(Factory.moveBattleStyle(MV("MOVE_SWORDS_DANCE")), Factory.STYLE.PREPARATION, "Swords Dance is a preparation move")
|
|
eq(Factory.moveBattleStyle(MV("MOVE_TACKLE")), Factory.STYLE.NONE, "Tackle has no style")
|
|
|
|
setVar("VAR_FRONTIER_FACILITY", D.FACILITY.FACTORY)
|
|
setVar("VAR_FRONTIER_BATTLE_MODE", D.MODE.SINGLES)
|
|
Util.newGame(sess)
|
|
local f = Util.frontier(sess)
|
|
f.lvlMode = D.LVL.L50
|
|
Util.set2(f.factoryWinStreaks, 0, 0, 12)
|
|
Util.set2(f.factoryRentsCount, 0, 0, 30)
|
|
Factory.init(sess)
|
|
eq(Util.get2(f.factoryWinStreaks, 0, 0), 0, "InitFactoryChallenge clears an inactive streak (battle_factory.c:208)")
|
|
eq(Util.get2(f.factoryRentsCount, 0, 0), 0, "and the rents count")
|
|
eq(f.rentalMons[1].monId, 0xFFFF, "rental slots start empty")
|
|
eq(Factory.pastRentalsRank(sess, 0, 0), 0, "no rents -> rank 0")
|
|
Util.set2(f.factoryRentsCount, 0, 0, 22)
|
|
eq(Factory.pastRentalsRank(sess, 0, 0), 2, "22 rents -> rank 2 (battle_factory.c:868)")
|
|
Util.set2(f.factoryRentsCount, 0, 0, 0)
|
|
|
|
Rng.SeedRng(0x5eed)
|
|
Factory.generateInitialRentalMons(sess)
|
|
local mons = D.pack("mons").mons
|
|
local rOk, uniq, items = true, {}, {}
|
|
local dupItem = false
|
|
for i = 1, 6 do
|
|
local id = f.rentalMons[i].monId
|
|
if not (id and id >= 110 and id <= 199) then rOk = false end
|
|
local row = mons[id]
|
|
uniq[row.species] = (uniq[row.species] or 0) + 1
|
|
local it = D.heldItem(row.itemTableId)
|
|
if it ~= 0 and items[it] then dupItem = true end
|
|
items[it] = true
|
|
end
|
|
check(rOk, "six rentals drawn from the challenge-1 level-50 range")
|
|
check(not dupItem, "rentals never share a held item")
|
|
|
|
Factory.generateOpponentMons(sess)
|
|
eq(#sess.frontierTempParty, 3, "GenerateOpponentMons picks three mons")
|
|
local clash = false
|
|
for _, id in ipairs(sess.frontierTempParty) do
|
|
if uniq[mons[id].species] then clash = true end
|
|
end
|
|
check(not clash, "opponent mons never share a species with the rentals (battle_factory.c:341)")
|
|
check(tonumber(sess.frontierOpponentA) and f.trainerIds[1] == sess.frontierOpponentA, "opponent trainer id recorded")
|
|
local ty = Factory.opponentMostCommonType(sess)
|
|
check(ty >= 0 and ty <= Factory.NUMBER_OF_MON_TYPES, "most-common type is a type id or NUMBER_OF_MON_TYPES")
|
|
local style = Factory.opponentBattleStyle(sess)
|
|
check(style >= 0 and style <= Factory.NUM_STYLES, "battle style is a FACTORY_STYLE_* or FACTORY_NUM_STYLES")
|
|
|
|
local sel = Factory.selectableMons(sess)
|
|
eq(#sel, 6, "six selectable rentals")
|
|
eq(sel[1].mon.level, 50, "level-50 rentals are level 50 (battle_factory_screen.c:1750)")
|
|
eq(sel[1].mon.ivs.atk, 3, "challenge-1 rentals carry 3 IVs")
|
|
eq(sel[1].mon.friendship, 0, "rentals have 0 friendship")
|
|
eq(sel[1].mon.otName, "BRENDAN", "rentals carry the player's OT")
|
|
local hasReturn = false
|
|
for _, s in ipairs(sel) do
|
|
for _, m in ipairs(s.mon.moves) do if m == MV("MOVE_RETURN") then hasReturn = true end end
|
|
end
|
|
check(not hasReturn, "SetMonMoveAvoidReturn swaps Return for Frustration (battle_factory.c:913)")
|
|
|
|
Factory.copyMonsToPlayerParty(sess, sel, { 2, 4, 6 })
|
|
eq(#sess.party, 3, "three rentals copied to the party")
|
|
eq(sess.party[1].species, sel[2].mon.species, "first pick is party slot 1")
|
|
eq(f.rentalMons[1].monId, sel[2].monId, "rentalMons[0] records the rented monId")
|
|
eq(f.rentalMons[3].personality, sel[6].mon.personality, "rentalMons[2] records personality")
|
|
eq(f.rentalMons[2].ivs, sel[4].mon.ivs.atk, "rentalMons[1] records the ATK IV")
|
|
|
|
local enemy = Factory.fillTrainerParty(sess)
|
|
eq(#enemy, 3, "FillFactoryTrainerParty builds three mons")
|
|
eq(enemy[1].level, 50, "factory opponents are level 50")
|
|
eq(enemy[1].ivs.hp, 3, "opponent IVs follow the Battle Tower streak (battle_tower.c:1834)")
|
|
eq(enemy[1].species, mons[sess.frontierTempParty[1]].species, "opponent mons come from gFrontierTempParty")
|
|
sess.frontierEnemyParty = enemy
|
|
Factory.setRentalsToOpponentParty(sess)
|
|
eq(f.rentalMons[4].monId, sess.frontierTempParty[1], "SetRentalsToOpponentParty stores the opponent monIds")
|
|
eq(f.rentalMons[5].personality, enemy[2].personality, "and personalities")
|
|
|
|
local keep = {}
|
|
for i = 1, 3 do keep[i] = { species = sess.party[i].species, personality = sess.party[i].personality } end
|
|
sess.party[1].heldItem, sess.party[1].item = nil, nil
|
|
Factory.restorePlayerPartyHeldItems(sess)
|
|
eq(tonumber(sess.party[1].heldItem) or 0, D.heldItem(mons[f.rentalMons[1].monId].itemTableId),
|
|
"RestorePlayerPartyHeldItems puts the rental's item back")
|
|
sess.party = {}
|
|
local ctx = ctxWith({ [Util.VAR_0x8005] = 0 })
|
|
Factory.setPlayerAndOpponentParties(ctx, sess)
|
|
local same = true
|
|
for i = 1, 3 do
|
|
if sess.party[i].species ~= keep[i].species or sess.party[i].personality ~= keep[i].personality then same = false end
|
|
end
|
|
check(same, "factory_setparties 0 rebuilds the rental party from rentalMons (battle_factory.c:428)")
|
|
eq(sess.frontierEnemyParty[1].species, enemy[1].species, "and the last opponent party")
|
|
eq(sess.party[2].ivs.spd, f.rentalMons[2].ivs, "rebuilt rentals use the saved IV for every stat")
|
|
|
|
sess.party[1].species = enemy[2].species
|
|
check(Factory.alreadyHasSameSpecies(sess, 2, 2), "Swap_AlreadyHasSameSpecies spots a clash in another slot")
|
|
check(not Factory.alreadyHasSameSpecies(sess, 2, 1), "the slot being swapped away does not count")
|
|
Factory.copySwappedMonData(sess, 3, 1)
|
|
eq(sess.party[3].species, enemy[1].species, "CopySwappedMonData puts the enemy mon in the party")
|
|
eq(sess.party[3].friendship, 0, "the swapped mon has 0 friendship")
|
|
eq(f.rentalMons[3].monId, f.rentalMons[4].monId, "the rental slot takes the opponent's monId")
|
|
|
|
eq(Factory.aiFlags(sess), 0, "challenge 1 opponents run no AI scripts (battle_factory.c:904)")
|
|
Util.set2(f.factoryWinStreaks, 0, 0, 14)
|
|
local BP = require("src.core.game3.battle.profile")
|
|
eq(Factory.aiFlags(sess), BP.aiBit(BP.get(sess), "CHECK_BAD_MOVE"), "challenge 3 uses CHECK_BAD_MOVE only")
|
|
sess.frontierOpponentA = D.TRAINER_FRONTIER_BRAIN
|
|
check(Factory.aiFlags(sess) > BP.aiBit(BP.get(sess), "CHECK_BAD_MOVE"), "Noland uses the full AI")
|
|
local brain = Factory.fillBrainParty(sess)
|
|
eq(#brain, 3, "FillFactoryBrainParty builds three mons")
|
|
eq(brain[1].friendship, 0, "Noland's mons have 0 friendship (battle_factory.c:820)")
|
|
sess.frontierOpponentA = 0
|
|
Util.set2(f.factoryWinStreaks, 0, 0, 0)
|
|
|
|
local gctx = ctxWith({ [Util.VAR_0x8005] = Factory.DATA.WIN_STREAK_ACTIVE, [Util.VAR_0x8006] = 1 })
|
|
Factory.setData(gctx, sess)
|
|
Factory.getData(gctx, sess)
|
|
eq(result(gctx), 1, "FACTORY_DATA_WIN_STREAK_ACTIVE round-trips")
|
|
local sctx = ctxWith({ [Util.VAR_0x8005] = Factory.DATA.WIN_STREAK_SWAPS, [Util.VAR_0x8006] = 5 })
|
|
Factory.setData(sctx, sess)
|
|
eq(Util.get2(f.factoryRentsCount, 0, 0), 0, "rent count only moves after factory_setswapped (battle_factory.c:260)")
|
|
Factory.setPerformedSwap(sess)
|
|
Factory.setData(sctx, sess)
|
|
eq(Util.get2(f.factoryRentsCount, 0, 0), 5, "rent count set after a swap")
|
|
|
|
f.lvlMode = D.LVL.TENT
|
|
local Tents = require("src.core.game3.rse.frontier.tents")
|
|
Tents.generateRentalMons(sess)
|
|
local tsel = Factory.selectableMons(sess)
|
|
eq(tsel[1].mon.level, 30, "Slateport tent rentals are level 30 (battle_factory_screen.c:1784)")
|
|
eq(tsel[1].mon.ivs.hp, 0, "and carry 0 IVs")
|
|
Tents.generateOpponentMons(sess)
|
|
local tp = Factory.fillTrainerParty(sess)
|
|
eq(tp[1].level, 30, "tent opponents are level 30 (battle_tower.c:1891)")
|
|
eq(Factory.aiFlags(sess), 0, "tent battles run no AI scripts (battle_factory.c:893)")
|
|
f.lvlMode = D.LVL.L50
|
|
|
|
local pm = Pike.manifest()
|
|
eq(table.concat(pm.roomTypeHints, ","), "3,3,1,0,0,2,2,1,4", "sRoomTypeHints (battle_pike.c:517)")
|
|
eq(#pm.healBeforeQueen, 6, "sNumMonsToHealBeforePikeQueen has six rows")
|
|
eq(table.concat(pm.brainStreakAppearances[D.FACILITY.PIKE + 1], ","), "28,140,56,1", "Lucy appears at 28/140")
|
|
eq(#pm.npcTable, 25, "25 pike NPCs (battle_pike.c:267)")
|
|
eq(pm.npcTable[1].graphicsId, C:require("event_objects", "OBJ_EVENT_GFX_POKEFAN_F"), "first NPC is a Pokefan")
|
|
eq(#pm.npcSpeeches, 42, "42 NPC speeches")
|
|
eq(#pm.wildHeaders, 4, "four pike wild headers")
|
|
eq(pm.wildHeaders[1].land.rate, 10, "pike wild rooms use encounter rate 10")
|
|
eq(#pm.wildHeaders[1].land.slots, 12, "12 land slots")
|
|
eq(pm.wildMons[1][1][1].species, S("SPECIES_SEVIPER"), "level-50 pike wild mon 0 is Seviper")
|
|
eq(pm.wildMons[1][1][3].species, S("SPECIES_DUSCLOPS"), "set 1 mon 2 is Dusclops")
|
|
eq(pm.wildMons[2][4][3].moves[4], MV("MOVE_ENCORE"), "open-level Wobbuffet knows Encore")
|
|
|
|
setVar("VAR_FRONTIER_FACILITY", D.FACILITY.PIKE)
|
|
local function healthy(name, lv)
|
|
local m = D.createMon(S(name), lv or 50, 20, 7, 99)
|
|
m.otName = "BRENDAN"
|
|
return m
|
|
end
|
|
sess.party = { healthy("SPECIES_SWAMPERT"), healthy("SPECIES_BLAZIKEN"), healthy("SPECIES_SCEPTILE") }
|
|
local pf = Pike.frontier(sess)
|
|
Pike.init(sess)
|
|
eq(f.curChallengeBattleNum, 0, "InitPikeChallenge resets the battle number")
|
|
f.curChallengeBattleNum = 3
|
|
|
|
pf.pikeHintedRoomType = Pike.ROOM.STATUS
|
|
pf.pikeHintedRoomIndex = 1
|
|
pf.pikeHealingRoomsDisabled = 0
|
|
local seen, bad = {}, false
|
|
for seed = 1, 200 do
|
|
Rng.SeedRng(seed)
|
|
local c2 = ctxWith({ [0x8007] = 0 })
|
|
local t = Pike.nextRoomType(c2, sess)
|
|
seen[t] = true
|
|
if t == Pike.ROOM.STATUS or t == Pike.ROOM.HEAL_PART or t == Pike.ROOM.BRAIN then bad = true end
|
|
end
|
|
check(not bad, "the other paths never share the hinted room's hint (battle_pike.c:1040)")
|
|
check(seen[Pike.ROOM.SINGLE_BATTLE] and seen[Pike.ROOM.WILD_MONS], "other room types still come up")
|
|
pf.pikeHealingRoomsDisabled = 1
|
|
pf.pikeHintedRoomType = Pike.ROOM.NPC
|
|
bad = false
|
|
for seed = 1, 200 do
|
|
Rng.SeedRng(seed)
|
|
local t = Pike.nextRoomType(ctxWith({ [0x8007] = 0 }), sess)
|
|
if t == Pike.ROOM.HEAL_FULL or t == Pike.ROOM.HEAL_PART then bad = true end
|
|
end
|
|
check(not bad, "healing rooms are skipped after a full-health exit (battle_pike.c:1063)")
|
|
pf.pikeHealingRoomsDisabled = 0
|
|
pf.pikeHintedRoomType = Pike.ROOM.WILD_MONS
|
|
eq(Pike.nextRoomType(ctxWith({ [0x8007] = 1 }), sess), Pike.ROOM.WILD_MONS, "the hinted path is the hinted room")
|
|
|
|
for i = 1, 3 do sess.party[i].status = nil end
|
|
f.curChallengeBattleNum = 11
|
|
Rng.SeedRng(77)
|
|
check(Pike.tryInflictRandomStatus(sess), "TryInflictRandomStatus finds healthy mons")
|
|
local afflicted = 0
|
|
for i = 1, 3 do if Pike.hasAilment(sess.party[i]) then afflicted = afflicted + 1 end end
|
|
check(afflicted >= 1, "status room afflicts the party (" .. afflicted .. ")")
|
|
check(Pike.roomInflictedStatus(sess) ~= nil, "pike_getstatus reports the inflicted status")
|
|
check(Pike.typePreventsStatus(S("SPECIES_SKARMORY"), Pike.STATUS1.TOXIC_POISON), "Steel types dodge toxic")
|
|
check(Pike.typePreventsStatus(S("SPECIES_PIKACHU"), Pike.STATUS1.PARALYSIS), "Electric types dodge paralysis")
|
|
check(not Pike.typePreventsStatus(S("SPECIES_PIKACHU"), Pike.STATUS1.SLEEP), "nothing dodges sleep by type")
|
|
|
|
check(not Pike.isPartyFullHealed(sess), "an afflicted party is not fully healed")
|
|
sess.party[1].hp = 1
|
|
Rng.SeedRng(3)
|
|
local healed = Pike.healOneOrTwo(sess)
|
|
check(healed == 1 or healed == 2, "HealOneOrTwoMons heals one or two (" .. healed .. ")")
|
|
require("src.core.game3.party").healAll(sess.party)
|
|
check(Pike.isPartyFullHealed(sess), "a healed party is full health (battle_pike.c:1551)")
|
|
sess.party[2].hp = 0
|
|
sess.party[3].hp = 0
|
|
check(not Pike.atLeastTwoAliveMons(sess), "two fainted mons block the double battle room")
|
|
require("src.core.game3.party").healAll(sess.party)
|
|
sess.party[2].hp = sess.party[2].maxHp
|
|
|
|
f.curChallengeBattleNum = 5
|
|
Util.set1(f.pikeWinStreaks, 0, 27)
|
|
eq(Pike.queenFightType(sess, 0), Util.BRAIN.SILVER, "27 rooms cleared: Lucy is next (battle_pike.c:1515)")
|
|
eq(Pike.queenFightType(sess, 1), Util.BRAIN.NOT_READY, "the lookahead past Lucy is not ready")
|
|
Util.set1(f.pikeWinStreaks, 0, 26)
|
|
eq(Pike.queenFightType(sess, 1), Util.BRAIN.SILVER, "one room early the hint lady warns about Lucy")
|
|
Rng.SeedRng(9)
|
|
check(Pike.setHintedRoom(sess), "SetHintedRoom picks the Brain room when Lucy is next")
|
|
eq(pf.pikeHintedRoomType, Pike.ROOM.BRAIN, "hinted room type is PIKE_ROOM_BRAIN")
|
|
Util.set1(f.pikeWinStreaks, 0, 0)
|
|
pf.pikeHealingRoomsDisabled = 1
|
|
bad = false
|
|
for seed = 1, 100 do
|
|
Rng.SeedRng(seed)
|
|
Pike.setHintedRoom(sess)
|
|
if pf.pikeHintedRoomType == Pike.ROOM.HEAL_FULL or pf.pikeHintedRoomType == Pike.ROOM.HEAL_PART
|
|
or pf.pikeHintedRoomIndex > 2 then bad = true end
|
|
end
|
|
check(not bad, "no healing hint while healing rooms are disabled")
|
|
pf.pikeHealingRoomsDisabled = 0
|
|
|
|
eq(Pike.wildMonHeaderId(sess), 0, "wild header 0 for a fresh streak")
|
|
Util.set1(f.pikeWinStreaks, 0, 20 * 14 + 1)
|
|
eq(Pike.wildMonHeaderId(sess), 1, "wild header 1 past 280 rooms (battle_pike.c:1161)")
|
|
Util.set1(f.pikeWinStreaks, 0, 0)
|
|
local enc = Pike.tryGenerateWildMon(sess, { species = S("SPECIES_MILOTIC"), level = 5, personality = 1 }, false)
|
|
eq(enc.level, 46, "level-50 Milotic is 50 - 4 (battle_pike.c:1135)")
|
|
eq(enc.moves[4], MV("MOVE_SURF"), "Milotic knows Surf")
|
|
local enc2 = Pike.tryGenerateWildMon(sess, { species = S("SPECIES_DUSCLOPS"), level = 5, personality = 1 }, false)
|
|
eq(enc2.level, 45, "Dusclops is 50 - 5")
|
|
local got
|
|
for seed = 1, 400 do
|
|
Rng.SeedRng(seed)
|
|
got = Pike.standardWildEncounter(sess, 1, 1)
|
|
if got then break end
|
|
end
|
|
check(got ~= nil, "the pike wild room rolls encounters")
|
|
check(got and (got.species == S("SPECIES_SEVIPER") or got.species == S("SPECIES_MILOTIC")
|
|
or got.species == S("SPECIES_DUSCLOPS")), "pike wild mons come from gBattlePike_1")
|
|
check(got and got.moves and #got.moves == 4, "pike wild mons get their fixed moves")
|
|
|
|
f.selectedPartyMons = { 3, 1, 2, 0 }
|
|
sess.party = { healthy("SPECIES_SWAMPERT"), healthy("SPECIES_BLAZIKEN"), healthy("SPECIES_SCEPTILE") }
|
|
D.setHeldItem(sess.party[3], C.items.byName.ITEM_LEFTOVERS)
|
|
Pike.saveHeldItems(sess)
|
|
eq(pf.pikeHeldItemsBackup[1], C.items.byName.ITEM_LEFTOVERS, "SaveMonHeldItems follows selectedPartyMons")
|
|
D.setHeldItem(sess.party[3], 0)
|
|
Pike.restoreHeldItems(sess)
|
|
eq(tonumber(sess.party[3].heldItem) or 0, C.items.byName.ITEM_LEFTOVERS, "RestoreMonHeldItems puts it back")
|
|
|
|
Pike.rt(sess).roomType = Pike.ROOM.HEAL_FULL
|
|
Pike.setupRoomObjects(sess)
|
|
eq(Rse.var("VAR_OBJ_GFX_ID_0", sess), C:require("event_objects", "OBJ_EVENT_GFX_LINK_RECEPTIONIST"),
|
|
"full-heal room shows the receptionist (battle_pike.c:568)")
|
|
Pike.rt(sess).roomType = Pike.ROOM.STATUS
|
|
Pike.rt(sess).statusMon = Pike.STATUSMON.DUSCLOPS
|
|
Pike.setupRoomObjects(sess)
|
|
eq(Rse.var("VAR_OBJ_GFX_ID_0", sess), C:require("event_objects", "OBJ_EVENT_GFX_GENTLEMAN"), "status room gentleman")
|
|
eq(Rse.var("VAR_OBJ_GFX_ID_1", sess), C:require("event_objects", "OBJ_EVENT_GFX_DUSCLOPS"), "status room Dusclops")
|
|
f.curChallengeBattleNum = 4
|
|
Pike.clearTrainerIds(sess)
|
|
Pike.rt(sess).roomType = Pike.ROOM.DOUBLE_BATTLE
|
|
Pike.setupRoomObjects(sess)
|
|
check(sess.frontierOpponentA ~= sess.frontierOpponentB, "double battle room picks two trainers")
|
|
|
|
local cur = Pike.curtainFrameMetatiles(0, sess)
|
|
eq(#cur, 12, "the curtain covers 3x4 metatiles (field_specials.c:3827)")
|
|
eq(cur[1].metatile, C:require("metatile_labels", "METATILE_BattlePike_CurtainFrames_Start"), "frame 0 starts the strip")
|
|
eq(cur[1].x, -1, "the curtain starts one tile left of the player")
|
|
eq(cur[1].y, -3, "and three tiles up")
|
|
eq(Pike.curtainFrameMetatiles(1, sess)[1].metatile - cur[1].metatile, 32, "each frame is 4 rows of 8 further on")
|
|
|
|
Natives.bind("emerald")
|
|
for _, name in ipairs({ "CallBattleFactoryFunction", "CallBattlePikeFunction", "CloseBattlePikeCurtain" }) do
|
|
local id = C.specials.byName[name]
|
|
check(id ~= nil and Natives.ALLOW["special:" .. id] ~= nil, name .. " is bound on Emerald")
|
|
end
|
|
check(Rse.system("factory") == Factory and type(Factory.selectScreen) == "function", "the factory system is registered")
|
|
check(Rse.system("pike") == Pike and type(Pike.doSpecialBattle) == "function", "the pike system is registered")
|
|
local Screens = require("src.ui.game3.screens")
|
|
eq(Screens.path("factory_select", sess), "src.ui.game3.rse.factory_select", "factory select screen row")
|
|
eq(Screens.path("factory_swap", sess), "src.ui.game3.rse.factory_swap", "factory swap screen row")
|
|
local Caps = require("src.core.game3.capabilities")
|
|
check(not Caps.nativeAllowed({ version = "firered" }, "natives_factory"), "FireRed never binds natives_factory")
|
|
check(not Caps.nativeAllowed({ version = "firered" }, "natives_pike"), "FireRed never binds natives_pike")
|
|
Natives.bind("firered")
|
|
|
|
Runtime.getSession = prevGet
|
|
GameVersion.set("firered")
|
|
T.finish("emerald_factory_pike_test")
|