evee fix and some other junk

This commit is contained in:
bryanthaboi
2026-07-25 15:21:49 -04:00
parent 3069b2e2a9
commit f6b29e6caa
9 changed files with 243 additions and 22 deletions
+1
View File
@@ -783,5 +783,6 @@ end
-- test / debug helpers
DiscordPresence._state = state
DiscordPresence.locationName = locationName
DiscordPresence.handleJoinRequest = handleJoinRequest
return DiscordPresence
+5 -1
View File
@@ -9,6 +9,7 @@
-- opts.onCancel: fired when the menu closes without a pick (B)
-- Pops itself on B.
local Assets = require("src.render.Assets")
local Font = require("src.render.Font")
local Logger = require("src.core.Logger")
local Runtime = require("src.mods.Runtime")
@@ -96,7 +97,10 @@ local function drawIcon(game, mon, x, y, selected, counter)
end
if not path then return end
if iconImages[path] == nil then
local ok, img = pcall(love.graphics.newImage, path)
-- resolve through Assets so an overrides/ or transform-derived icon
-- (e.g. a per-species image at assets/generated/icons/<name>.png) is
-- picked up the same way battle sprites are
local ok, img = pcall(love.graphics.newImage, Assets.resolve(path))
iconImages[path] = ok and img or false
end
local img = iconImages[path]
+9
View File
@@ -3323,10 +3323,19 @@ function OverworldState:startWarpTo(mapId, x, y, facing, onDone, opts)
-- outdoor. Auto-walk leaves the mat, so the arrival disable
-- (warpEntryCell / justWarped) is unnecessary -- and would let you
-- stand on the door without re-entering if you hold back into it.
-- The walk-out is a simulated d-pad press (wSimulatedJoypadStates),
-- not a forced move, so it obeys collision: on a landing with a
-- solid cell south of the door (the mansion stair landings back
-- onto shelves) the step bumps and the player stays on the door,
-- arrival disable intact, instead of clipping into the wall.
if self.map:isDoorTileCell(self.player.cellX, self.player.cellY) then
if Collision.canMove(self.map, self.entities, self.player, "down") then
self.warpEntryCell = nil
self.justWarped = false
self:scriptMove(self.player, "down", 1)
else
self.player.facing = "down"
end
end
end
end, function()
+75
View File
@@ -0,0 +1,75 @@
-- Driver: Celadon Mansion back-stair landings. The 2F/3F/1F west and
-- middle stair landings are door tiles with a solid shelf cell directly
-- south; the door walk-out step must bump there (simulated d-pad press),
-- not force the player through the wall (the Eevee-house stairwell
-- stuck-in-shelves bug). East stairs keep the normal walk-out.
return function(game)
local U = dofile("tests/drivers/util.lua")
local ow
local fails = 0
local function expect(cond, ...)
if not cond then fails = fails + 1 end
U.log(cond and "PASS" or "FAIL", ...)
end
local function settle(mapId)
for _ = 1, 300 do
ow = game.overworld
if ow and ow.map.id == mapId and not ow.transitioning
and #ow.scriptMoves == 0 and not ow.player.moving then
break
end
U.wait(1)
end
U.wait(4)
ow = game.overworld
end
-- climb the west back stairs: 1F (2,1) -> 2F landing (2,1), whose south
-- cell is the solid shelf row
U.teleport(game, "CELADON_MANSION_1F", 4, 1, "left")
U.hold(game, "left", 70)
settle("CELADON_MANSION_2F")
expect(ow.map.id == "CELADON_MANSION_2F", "west stairs arrive 2F, map:", ow.map.id)
expect(ow.player.cellX == 2 and ow.player.cellY == 1,
"player stays on landing (2,1), got:", ow.player.cellX, ow.player.cellY)
expect(ow.map:isWalkableCell(ow.player.cellX, ow.player.cellY),
"standing cell walkable, tile:",
string.format("%02x", ow.map:cellTile(ow.player.cellX, ow.player.cellY)))
-- the landing is not a trap: one step east onto the walkway works
-- (short tap: (4,1) beyond it is the middle-stairs warp)
U.hold(game, "right", 4)
U.wait(24)
ow = game.overworld
expect(ow.map.id == "CELADON_MANSION_2F" and ow.player.cellX == 3,
"stepped east off the landing, at:", ow.map.id,
ow.player.cellX, ow.player.cellY)
-- stepping back onto the stairs still takes them down to 1F
U.hold(game, "left", 4)
settle("CELADON_MANSION_1F")
expect(ow.map.id == "CELADON_MANSION_1F", "stairs back down, map:", ow.map.id)
expect(ow.player.cellX == 2 and ow.player.cellY == 1,
"1F landing holds too (2,1), got:", ow.player.cellX, ow.player.cellY)
-- east stairs land on (7,1) with open floor south: the vanilla
-- walk-out step must still fire
U.teleport(game, "CELADON_MANSION_1F", 7, 3, "up")
U.hold(game, "up", 70)
settle("CELADON_MANSION_2F")
expect(ow.map.id == "CELADON_MANSION_2F", "east stairs arrive 2F, map:", ow.map.id)
expect(ow.player.cellX == 7 and ow.player.cellY == 2,
"walk-out stepped south to (7,2), got:", ow.player.cellX, ow.player.cellY)
-- a save already stuck inside the shelf (pre-fix) escapes north onto
-- the stairs, which warp back down
U.teleport(game, "CELADON_MANSION_2F", 2, 2, "up")
U.hold(game, "up", 24)
settle("CELADON_MANSION_1F")
expect(ow.map.id == "CELADON_MANSION_1F", "stuck save escapes via stairs, map:",
ow.map.id)
if fails > 0 then error(fails .. " check(s) failed") end
U.log("all checks passed")
end
+124
View File
@@ -0,0 +1,124 @@
-- Unit coverage for event:discord.join_requested (DiscordPresence Ask-to-Join).
-- Mods subscribe through Runtime; the engine emits before pushing JoinOnline.
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.modkit")
local Runtime = require("src.mods.Runtime")
local Events = require("src.mods.Events")
local DiscordPresence = require("src.core.DiscordPresence")
local savedLink = package.loaded["src.link.LinkState"]
local savedTour = package.loaded["src.link.Tournament"]
package.loaded["src.link.LinkState"] = {
newJoinOnline = function(_game, code)
return { tag = "link", code = code, stage = true, net = {} }
end,
}
package.loaded["src.link.Tournament"] = {
newJoinOnline = function(_game, code)
return { tag = "tournament", code = code, stage = true, net = {} }
end,
}
local function freshGame()
local items = {}
return {
stack = {
items = items,
top = function(self) return self.items[#self.items] end,
push = function(self, screen) self.items[#self.items + 1] = screen end,
},
}
end
local bus = Events.new()
local savedEvents, savedHooks = Runtime.events, Runtime.hooks
Runtime.events = bus
local function listen()
local seen = {}
bus:on("discord.join_requested", function(ev)
seen[#seen + 1] = ev
end, 0, "discord_join_test")
return seen
end
do
local game = freshGame()
local st = DiscordPresence._state
st.game = game
st.activity = "exploring"
local seen = listen()
DiscordPresence.handleJoinRequest("m:HOST01")
T.eq(#seen, 1, "match join emits discord.join_requested")
T.eq(seen[1].code, "HOST01", "payload carries the match code")
T.eq(seen[1].kind, "m", "payload carries kind tag m")
T.eq(game.stack:top().tag, "link", "pushes LinkState.newJoinOnline")
T.eq(game.stack:top().code, "HOST01", "join screen gets the code")
bus:removeOwner("discord_join_test")
end
do
local game = freshGame()
local st = DiscordPresence._state
st.game = game
st.activity = "menu"
local seen = listen()
DiscordPresence.handleJoinRequest("t:TOUR99")
T.eq(#seen, 1, "tournament join emits discord.join_requested")
T.eq(seen[1].kind, "t", "payload carries kind tag t")
T.eq(seen[1].code, "TOUR99", "payload carries the tournament code")
T.eq(game.stack:top().tag, "tournament", "pushes Tournament.newJoinOnline")
bus:removeOwner("discord_join_test")
end
do
local game = freshGame()
local st = DiscordPresence._state
st.game = game
st.activity = "exploring"
local seen = listen()
DiscordPresence.handleJoinRequest("PLAIN42")
T.eq(#seen, 1, "plain secret still emits discord.join_requested")
T.eq(seen[1].kind, "m", "plain secret defaults to match kind")
T.eq(seen[1].code, "PLAIN42", "plain secret is the whole code")
bus:removeOwner("discord_join_test")
end
do
local game = freshGame()
local st = DiscordPresence._state
st.game = game
st.activity = "battle"
local seen = listen()
DiscordPresence.handleJoinRequest("m:NOPE")
T.eq(#seen, 0, "battle activity suppresses join dispatch")
T.eq(game.stack:top(), nil, "battle activity pushes no join screen")
bus:removeOwner("discord_join_test")
end
do
local game = freshGame()
game.stack:push({ stage = true, net = {} }) -- already in a link session
local st = DiscordPresence._state
st.game = game
st.activity = "exploring"
local seen = listen()
DiscordPresence.handleJoinRequest("m:NOPE")
T.eq(#seen, 0, "active link session suppresses join dispatch")
T.eq(#game.stack.items, 1, "active link session is not replaced")
bus:removeOwner("discord_join_test")
end
DiscordPresence._state.game = nil
DiscordPresence._state.activity = "menu"
Runtime.events, Runtime.hooks = savedEvents, savedHooks
package.loaded["src.link.LinkState"] = savedLink
package.loaded["src.link.Tournament"] = savedTour
T.finish("discord_join_requested")
+3 -4
View File
@@ -1,10 +1,9 @@
-- Bill's PC vs player's PC top-menu origin/size (#176).
-- ROM-free: uses the fixture dataset so CI (no data/generated/) stays green.
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local T = require("tests.harness")
local Data = require("src.core.Data")
if not (Data.pokemon and next(Data.pokemon)) then Data:load() end
local T = require("tests.modkit")
local Data = T.fixtures.load()
local SaveData = require("src.core.SaveData")
local BoxMenu = require("src.ui.BoxMenu")
+9 -8
View File
@@ -1,10 +1,10 @@
-- Headless regression: two Bill's PC releases in one list session (#171).
-- ROM-free: fixture species only (CI has no data/generated/).
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local T = require("tests.harness")
local Data = require("src.core.Data")
if not (Data.pokemon and Data.pokemon.RATTATA) then Data:load() end
local T = require("tests.modkit")
local Data = T.fixtures.load()
local ids = T.fixtures.ids
require("src.render.Font").load(Data)
local Pokemon = require("src.pokemon.Pokemon")
@@ -45,10 +45,11 @@ local game = {
game.save.options = game.save.options or {}
game.save.options.textSpeed = 1
local a, b, c = ids.species[1], ids.species[2], ids.species[3]
local box = Boxes.active(game.save)
box[1] = Pokemon.new(Data, "RATTATA", 5)
box[2] = Pokemon.new(Data, "PIDGEY", 6)
box[3] = Pokemon.new(Data, "CATERPIE", 4)
box[1] = Pokemon.new(Data, a, 5)
box[2] = Pokemon.new(Data, b, 6)
box[3] = Pokemon.new(Data, c, 4)
local function press(btn)
pressed = { [btn] = true }
@@ -86,7 +87,7 @@ releaseCurrent()
releaseCurrent()
T.eq(#box, 1, "two releases leave one mon")
T.check(topMt() == ListMenu, "still on RELEASE list after the second")
T.eq(box[1].species, "CATERPIE", "remaining mon is the third seeded one")
T.eq(box[1].species, c, "remaining mon is the third seeded one")
Sound.playCry, Sound.play = realCry, realPlay
T.finish("pc_release")
+8 -1
View File
@@ -51,10 +51,17 @@ local function fresh()
end
-- ---- crosswalk data + synthetic 32KB save (built the way the codec tests do)
-- Gen1 encode/decode needs Red species/item indices from data/generated/,
-- which CI never has. Skip cleanly so the ROM-free T1/T2 tier stays green.
local loadPokemon = loadfile("data/generated/pokemon.lua")
if not loadPokemon then
print("save_file_io skipped (needs data/generated/ for Gen1 save codec)")
os.exit(0)
end
GenSave.setCharmap(loadfile("src/save_convert/data/charmap.lua")())
local data = {
pokemon = loadfile("data/generated/pokemon.lua")(),
pokemon = loadPokemon(),
moves = loadfile("data/generated/moves.lua")(),
items = loadfile("data/generated/items.lua")(),
maps = loadfile("data/generated/maps.lua")(),
+6 -5
View File
@@ -1,10 +1,11 @@
-- TradeAnim InternalClockTradeFuncSequence completes under A-skip and
-- exposes the cable-trade phases (engine/movie/trade.asm).
-- ROM-free: fixture species only (CI has no data/generated/).
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local Data = require("src.core.Data")
if not (Data.maps and Data.maps.PALLET_TOWN) then Data:load() end
local T = require("tests.modkit")
local Data = T.fixtures.load()
local ids = T.fixtures.ids
local S = require("tests.harness").suite("trade anim")
local check, eq = S.check, S.eq
@@ -22,8 +23,8 @@ Game.stack = StateStack; StateStack:init()
Game.save = SaveData.newGame()
require("src.render.Font").load(Data)
local sent = Pokemon.new(Data, "SPEAROW", 10)
local recv = Pokemon.new(Data, "FARFETCHD", 10)
local sent = Pokemon.new(Data, ids.species[1], 10)
local recv = Pokemon.new(Data, ids.species[2], 10)
recv.nickname = "DUX"
recv.ot = "TRAINER"
recv.otId = 8193