mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
c93f035359
- Hidden Items & Itemfinder (fixes #2314): * Extract BG_EVENT_HIDDEN_ITEM (kind 7) from GBA ROM with proper flag calculation (0x3E8 + id), underfoot flags, and quantities. * Implement overworld Itemfinder scan logic (7-tile radius, directional response, underfoot detection, SFX 65, and OEM text). * Wire up Bag Menu Itemfinder dispatch to overworld field runtime. - Opponent Battle HUD Caught Marker (fixes #2313): * Add authentic Pokédex caught Poké Ball icon (B_INTERFACE_GFX_BALL_CAUGHT / tile 70) to opponent healthbox. * Match pokefirered parity in TryAddPokeballIconToHealthbox (wild encounters only, non-tutorial, non-ghost, checked against Dex). * Ensure status ailment icons (PSN, PAR, SLP, FRZ, BRN) take rendering priority over the caught ball marker. - Level-Up Learnset & Movepool Assignment (fixes #2315): * Fix wild and generated Pokémon moveset assignment to assign the 4 most recent level-up moves up to the current level instead of getting stuck on basic moves (e.g. Tackle). - Easy Chat / Profile Quick Chat: * Extract full word groups, categories, and dictionary entries from ROM. * Build Easy Chat interface with group selection, paginated word lists, and alphabetized filtering. * Fix dialog text overflowing when exiting profile / quick chat prompts. - Nurse Joy & PC Storage / Map Polishing: * Implement Nurse Joy healing tray animation flow and audio cues in standard scripts. * Fix PC storage box header/wallpaper rendering and storage data extraction. * Correct Sevii Islands / Island 1 map section lookups and region map coordinate handling. * Fix circular dependency in battle residual handlers (partialTrap). fixes #2325 fixes #2322 fixes #2315 fixes #2314 fixes #2313
188 lines
6.2 KiB
Lua
188 lines
6.2 KiB
Lua
-- Unit test for Game 3 Easy Chat system, Profile Screen, Specials 0x60/0x61,
|
|
-- and the Pewter City Pokemon Center MysteryEventClub woman script behavior.
|
|
|
|
local function test(name, fn)
|
|
local ok, err = pcall(fn)
|
|
if ok then
|
|
print("[ok] " .. name)
|
|
else
|
|
print("[FAIL] " .. name .. ": " .. tostring(err))
|
|
error(err)
|
|
end
|
|
end
|
|
|
|
local EasyChatData = require("src.core.game3.easy_chat_data")
|
|
local Schema = require("src.core.game3.save_schema_firered")
|
|
local Std = require("src.core.game3.scripting.stdscripts")
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
local Adapters = require("src.core.game3.scripting.adapters")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
|
|
test("decodes authentic word IDs and passphrases", function()
|
|
-- Default profile
|
|
local defText = EasyChatData.formatPhrase(EasyChatData.DEFAULT_PROFILE, 2, 2)
|
|
assert(defText:find("I AM A"), "Default profile line 1")
|
|
assert(defText:find("POKéMON FRIEND"), "Default profile line 2")
|
|
|
|
-- Mystery Event passphrase
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_MYSTERY_EVENT[1]) == "MYSTERY")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_MYSTERY_EVENT[2]) == "EVENT")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_MYSTERY_EVENT[3]) == "IS")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_MYSTERY_EVENT[4]) == "EXCITING")
|
|
|
|
-- Questionnaire passphrase
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_QUESTIONNAIRE[1]) == "LINK")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_QUESTIONNAIRE[2]) == "TOGETHER")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_QUESTIONNAIRE[3]) == "WITH")
|
|
assert(EasyChatData.getWord(EasyChatData.PASSPHRASE_QUESTIONNAIRE[4]) == "ALL")
|
|
end)
|
|
|
|
test("persists easyChatProfile in save schema", function()
|
|
local session = Schema.newGame()
|
|
assert(session.easyChatProfile ~= nil)
|
|
assert(#session.easyChatProfile == 4)
|
|
|
|
-- Modify profile
|
|
session.easyChatProfile = { 5178, 6167, 4107, 8207 }
|
|
local save = Schema.toSaveTable(session)
|
|
assert(save.easyChatProfile ~= nil)
|
|
assert(save.easyChatProfile[1] == 5178)
|
|
|
|
-- Restore
|
|
local loaded = Schema.fromSaveTable(save)
|
|
assert(loaded.easyChatProfile ~= nil)
|
|
assert(loaded.easyChatProfile[1] == 5178)
|
|
assert(loaded.easyChatProfile[4] == 8207)
|
|
end)
|
|
|
|
test("handles ShowEasyChatScreen special with custom profile (VAR_RESULT=1, VAR_0x8004=1, flag 0x82D)", function()
|
|
local session = Schema.newGame()
|
|
local store = Flags.newStore()
|
|
session.store = store
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
}
|
|
|
|
local ctx = {
|
|
vars = {},
|
|
specialVars = { [0x8004] = 0 }, -- EASY_CHAT_TYPE_PROFILE
|
|
}
|
|
|
|
local customWords = { 2601, 4128, 526, 2611 } -- standard "I AM A POKéMON FRIEND"
|
|
local adapters = Adapters.stub({
|
|
openEasyChat = function(opts, done)
|
|
assert(opts.type == 0)
|
|
done(true, customWords)
|
|
end,
|
|
})
|
|
|
|
local yielded = Natives.ALLOW["special:" .. Std.SPECIAL.ShowEasyChatScreen](ctx, adapters)
|
|
-- Poll until done
|
|
if ctx.nativePoll then
|
|
while not ctx.nativePoll() do end
|
|
end
|
|
|
|
-- Assertions:
|
|
-- 1. VAR_RESULT (0x800D) = 1 (TRUE)
|
|
assert(Flags.getVar(nil, ctx, 0x800D) == 1)
|
|
-- 2. VAR_0x8004 = 1 (custom phrase, does not match MYSTERY EVENT IS EXCITING)
|
|
assert(Flags.getVar(nil, ctx, 0x8004) == 1)
|
|
-- 3. FLAG_SYS_SET_TRAINER_CARD_PROFILE (0x82D) is set
|
|
assert(Flags.getFlag(store, ctx, 0x82D) == true)
|
|
assert(session.flags[0x82D] == true)
|
|
-- 4. session.easyChatProfile is updated
|
|
assert(session.easyChatProfile[1] == customWords[1])
|
|
end)
|
|
|
|
test("handles ShowEasyChatScreen special with mystery event passphrase (VAR_0x8004=0)", function()
|
|
local session = Schema.newGame()
|
|
local store = Flags.newStore()
|
|
session.store = store
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
}
|
|
|
|
local ctx = {
|
|
vars = {},
|
|
specialVars = { [0x8004] = 0 }, -- EASY_CHAT_TYPE_PROFILE
|
|
}
|
|
|
|
local mysteryWords = EasyChatData.PASSPHRASE_MYSTERY_EVENT
|
|
local adapters = Adapters.stub({
|
|
openEasyChat = function(opts, done)
|
|
done(true, mysteryWords)
|
|
end,
|
|
})
|
|
|
|
Natives.ALLOW["special:" .. Std.SPECIAL.ShowEasyChatScreen](ctx, adapters)
|
|
if ctx.nativePoll then
|
|
while not ctx.nativePoll() do end
|
|
end
|
|
|
|
-- VAR_RESULT = 1 (TRUE)
|
|
assert(Flags.getVar(nil, ctx, 0x800D) == 1)
|
|
-- VAR_0x8004 = 0 (matches special passphrase!)
|
|
assert(Flags.getVar(nil, ctx, 0x8004) == 0)
|
|
assert(Flags.getFlag(store, ctx, 0x82D) == true)
|
|
end)
|
|
|
|
test("handles ShowEasyChatScreen special when cancelled (VAR_RESULT=0)", function()
|
|
local session = Schema.newGame()
|
|
local store = Flags.newStore()
|
|
session.store = store
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
}
|
|
|
|
local ctx = {
|
|
vars = {},
|
|
specialVars = { [0x8004] = 0 },
|
|
}
|
|
|
|
local adapters = Adapters.stub({
|
|
openEasyChat = function(opts, done)
|
|
done(false, opts.words)
|
|
end,
|
|
})
|
|
|
|
Natives.ALLOW["special:" .. Std.SPECIAL.ShowEasyChatScreen](ctx, adapters)
|
|
if ctx.nativePoll then
|
|
while not ctx.nativePoll() do end
|
|
end
|
|
|
|
-- VAR_RESULT = 0 (FALSE)
|
|
assert(Flags.getVar(nil, ctx, 0x800D) == 0)
|
|
-- VAR_0x8004 = 1 (not 0, so doesn't take special phrase branch)
|
|
assert(Flags.getVar(nil, ctx, 0x8004) == 1)
|
|
-- FLAG_SYS_SET_TRAINER_CARD_PROFILE not set
|
|
assert(not Flags.getFlag(store, ctx, 0x82D))
|
|
end)
|
|
|
|
test("formats and displays phrase with ShowEasyChatMessage", function()
|
|
local session = Schema.newGame()
|
|
session.easyChatProfile = { 5178, 6167, 4107, 8207 }
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
}
|
|
|
|
local openedMsg = nil
|
|
local adapters = Adapters.stub({
|
|
openMessage = function(text)
|
|
openedMsg = text
|
|
end,
|
|
})
|
|
|
|
Natives.ALLOW["special:" .. Std.SPECIAL.ShowEasyChatMessage]({}, adapters)
|
|
assert(openedMsg ~= nil)
|
|
assert(openedMsg:find("MYSTERY EVENT"), "Contains line 1 words")
|
|
assert(openedMsg:find("IS EXCITING"), "Contains line 2 words")
|
|
end)
|
|
|
|
test("extracts easy chat data from ROM via EasyChatExtract", function()
|
|
local EasyChatExtract = require("src.import.gba.easy_chat_extract")
|
|
assert(EasyChatExtract.extractFromRom ~= nil)
|
|
assert(EasyChatExtract.run ~= nil)
|
|
end)
|
|
|
|
print("[test] All Easy Chat tests passed!")
|