mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
256 lines
9.8 KiB
Lua
256 lines
9.8 KiB
Lua
-- ../pokecrystal/engine/events/map_name_sign.asm:3
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
love = love or require("tests.love_stub")
|
|
|
|
local engine = "crystal"
|
|
package.loaded["src.core.GameVersion"] = {
|
|
engine = function() return engine end,
|
|
}
|
|
package.loaded["src.render.Assets"] = {
|
|
register = function() end,
|
|
resolve = function(path) return path end,
|
|
exists = function() return false end,
|
|
image = function() error("no sheet in the fixture cache") end,
|
|
}
|
|
local withCalls = {}
|
|
package.loaded["src.render.GbcPalette"] = {
|
|
available = function() return true end,
|
|
with = function(colors, body)
|
|
withCalls[#withCalls + 1] = colors
|
|
body()
|
|
return true
|
|
end,
|
|
}
|
|
package.loaded["src.render.Font"] = {
|
|
ttfActive = function() return false end,
|
|
encode = function(text)
|
|
local out = {}
|
|
for i = 1, #tostring(text) do out[i] = string.byte(text, i) end
|
|
return out
|
|
end,
|
|
width = function(text) return #tostring(text) * 8 end,
|
|
draw = function() end,
|
|
}
|
|
package.loaded["src.world.gen2.MapNameSign"] = nil
|
|
local Sign = require("src.world.gen2.MapNameSign")
|
|
|
|
local NAMES = {
|
|
LANDMARK_NEW_BARK_TOWN = "NEW BARK\nTOWN",
|
|
LANDMARK_ROUTE_29 = "ROUTE 29",
|
|
LANDMARK_ROUTE_35 = "ROUTE 35",
|
|
LANDMARK_SPECIAL = "SPECIAL",
|
|
LANDMARK_RADIO_TOWER = "RADIO TOWER",
|
|
LANDMARK_LAV_RADIO_TOWER = "RADIO TOWER",
|
|
LANDMARK_UNDERGROUND_PATH = "UNDERGROUND",
|
|
LANDMARK_INDIGO_PLATEAU = "INDIGO\nPLATEAU",
|
|
LANDMARK_POWER_PLANT = "POWER PLANT",
|
|
}
|
|
|
|
local World = {}
|
|
World.__index = World
|
|
|
|
function World.new(prev)
|
|
return setmetatable({ mapSignState = { prev = prev } }, World)
|
|
end
|
|
|
|
function World:go(mapId, landmark, environment, via)
|
|
self.map = { id = mapId,
|
|
def = { landmark = landmark, environment = environment or "ROUTE" } }
|
|
Sign.init(self, via)
|
|
return self.mapSign
|
|
end
|
|
|
|
function World:currentLandmarkId()
|
|
return self.map and self.map.def and self.map.def.landmark or nil
|
|
end
|
|
|
|
function World:landmarkName()
|
|
return NAMES[self:currentLandmarkId()]
|
|
end
|
|
|
|
local w = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
local sign = w:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
if check(sign ~= nil, "crossing into a new landmark raises the sign") then
|
|
eq(sign.timer, 60, "wLandmarkSignTimer starts at 60")
|
|
eq(sign.name, "ROUTE 29", "the town-map name is what is placed")
|
|
end
|
|
eq(w.mapSignState.prev, "LANDMARK_ROUTE_29", "wPrevLandmark takes wCurLandmark")
|
|
|
|
eq(w:go("ROUTE_29", "LANDMARK_ROUTE_29"), nil,
|
|
"a second load inside the same landmark shows nothing")
|
|
|
|
local nb = World.new("LANDMARK_ROUTE_29")
|
|
local sign2 = nb:go("NEW_BARK_TOWN", "LANDMARK_NEW_BARK_TOWN")
|
|
if check(sign2 ~= nil, "walking back into New Bark raises the sign") then
|
|
eq(sign2.name, "NEW BARK TOWN", "<BSP> prints as a space, not a line break")
|
|
end
|
|
|
|
local gate = World.new("LANDMARK_ROUTE_29")
|
|
eq(gate:go("ROUTE_43_GATE", "LANDMARK_ROUTE_43", "GATE"), nil,
|
|
"a GATE environment takes wCurLandmark to -1")
|
|
eq(gate.mapSignState.prev, false, "and -1 is still stamped into wPrevLandmark")
|
|
|
|
for _, mapId in ipairs({ "ROUTE_35_NATIONAL_PARK_GATE",
|
|
"ROUTE_36_NATIONAL_PARK_GATE" }) do
|
|
local park = World.new("LANDMARK_ROUTE_29")
|
|
eq(park:go(mapId, "LANDMARK_ROUTE_35", "INDOOR"), nil,
|
|
mapId .. " is forced to -1 by name, not by environment")
|
|
end
|
|
|
|
for _, id in ipairs({ "LANDMARK_SPECIAL", "LANDMARK_RADIO_TOWER",
|
|
"LANDMARK_LAV_RADIO_TOWER", "LANDMARK_UNDERGROUND_PATH",
|
|
"LANDMARK_INDIGO_PLATEAU", "LANDMARK_POWER_PLANT" }) do
|
|
local quiet = World.new("LANDMARK_ROUTE_29")
|
|
eq(quiet:go("SOMEWHERE", id), nil, id .. " gets no pop-up sign")
|
|
eq(quiet.mapSignState.prev, id, id .. " is still stamped into wPrevLandmark")
|
|
end
|
|
|
|
local fromSpecial = World.new("LANDMARK_SPECIAL")
|
|
eq(fromSpecial:go("ROUTE_29", "LANDMARK_ROUTE_29"), nil,
|
|
"a previous landmark of LANDMARK_SPECIAL suppresses the next sign")
|
|
|
|
-- ../pokecrystal/engine/menus/intro_menu.asm:467-468
|
|
for _, via in ipairs({ "boot", "continue" }) do
|
|
local booted = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
eq(booted:go("ROUTE_29", "LANDMARK_ROUTE_29", "ROUTE", via), nil,
|
|
"the first map load after " .. via .. " shows no sign")
|
|
eq(booted.mapSignState.prev, "LANDMARK_ROUTE_29",
|
|
"but .dont_do_map_sign still stamps wPrevLandmark")
|
|
end
|
|
|
|
-- ../pokecrystal/engine/overworld/events.asm:177-191
|
|
local ticker = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
ticker:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
eq(ticker.mapSign.shown, false, "the sign is armed hidden (hWY untouched)")
|
|
for _ = 1, 3 do Sign.frame(ticker) end
|
|
eq(ticker.mapSign.shown, false, "still hidden after 3 real frames (a = 60)")
|
|
Sign.frame(ticker)
|
|
eq(ticker.mapSign.shown, true, "shown on the 4th (second HandleMap, a = 59)")
|
|
for _ = 5, 121 do Sign.frame(ticker) end
|
|
check(ticker.mapSign ~= nil, "the sign is still up after 121 real frames")
|
|
Sign.frame(ticker)
|
|
eq(ticker.mapSign, nil, "and gone on the 122nd (61st call, a = 0)")
|
|
|
|
local stepped = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
stepped:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
for _ = 1, 30 do Sign.tick(stepped) end
|
|
eq(stepped.mapSign.timer, 60, "the logic step never counts the sign down")
|
|
stepped.mapSetup = { phase = "in" }
|
|
for _ = 1, 30 do Sign.frame(stepped) end
|
|
eq(stepped.mapSign.timer, 60, "nor does a real frame under the map setup fade")
|
|
stepped.mapSetup = nil
|
|
Sign.frame(stepped)
|
|
Sign.frame(stepped)
|
|
eq(stepped.mapSign.timer, 59, "the countdown resumes once the setup is done")
|
|
|
|
-- ../pokecrystal/home/window.asm:42
|
|
local talked = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
talked:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
talked.textbox = true
|
|
Sign.tick(talked)
|
|
eq(talked.mapSign, nil, "a text box takes the sign down")
|
|
|
|
-- ../pokecrystal/engine/overworld/events.asm:284-285
|
|
for _, site in ipairs({ "a battle", "the START menu", "a trainer sighting" }) do
|
|
local pushed = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
check(pushed:go("ROUTE_29", "LANDMARK_ROUTE_29") ~= nil,
|
|
"the sign is up when " .. site .. " arrives")
|
|
Sign.cancel(pushed)
|
|
eq(pushed.mapSign, nil, site .. " clears wLandmarkSignTimer")
|
|
Sign.tick(pushed)
|
|
eq(pushed.mapSign, nil, "and it does not come back after the state pops")
|
|
end
|
|
|
|
local idle = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
Sign.cancel(idle)
|
|
eq(idle.mapSign, nil, "cancelling with no sign up is a no-op")
|
|
Sign.cancel(nil)
|
|
|
|
local frozen = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
local held = frozen:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
if check(held ~= nil, "a sign raised before a push starts at 60") then
|
|
for _ = 1, 20 do Sign.frame(frozen) end
|
|
eq(held.timer, 50, "twenty real frames are ten HandleMap calls: ten off the timer")
|
|
Sign.cancel(frozen)
|
|
eq(frozen.mapSign, nil,
|
|
"and the remaining 50 are dropped rather than frozen under the push")
|
|
end
|
|
|
|
eq(Sign.textX("NEW BARK TOWN"), 24, "a 13-character name starts at column 3")
|
|
eq(Sign.textX("ROUTE 29"), 48, "an 8-character name starts at column 6")
|
|
eq(Sign.textX("CHERRYGROVE CITY"), 16, "the longest name starts at column 2")
|
|
|
|
local rows = Sign.tiles()
|
|
eq(rows[0][0], 1, "top left is MAP_NAME_SIGN_START + 1")
|
|
eq(rows[0][19], 4, "top right is + 4")
|
|
eq(rows[1][0], 5, "left of the first line is + 5")
|
|
eq(rows[1][19], 11, "right of the first line is + 11")
|
|
eq(rows[2][0], 6, "left of the second line is + 6")
|
|
eq(rows[2][19], 12, "right of the second line is + 12")
|
|
eq(rows[3][0], 7, "bottom left is + 7")
|
|
eq(rows[3][19], 10, "bottom right is + 10")
|
|
eq(rows[1][9], 13, ".FillMiddle lays + 13 across the interior")
|
|
eq(rows[2][9], 13, "on both interior rows")
|
|
local top = {}
|
|
for col = 1, 18 do top[col] = rows[0][col] end
|
|
eq(table.concat(top, ","), "3,3,2,2,3,3,2,2,3,3,2,2,3,3,2,2,3,3",
|
|
".FillTopBottom writes +3,+3 then four runs of +2,+2,+3,+3")
|
|
local bottom = {}
|
|
for col = 1, 18 do bottom[col] = rows[3][col] end
|
|
eq(table.concat(bottom, ","), "9,9,8,8,9,9,8,8,9,9,8,8,9,9,8,8,9,9",
|
|
"and the same pattern off + 8 along the bottom")
|
|
|
|
-- ../pokecrystal/engine/events/map_name_sign.asm:181
|
|
-- ../pokecrystal/gfx/tilesets/bg_tiles.pal:9
|
|
local TEXT_ROW = {
|
|
{ 255, 255, 132 }, { 255, 255, 132 }, { 115, 74, 0 }, { 0, 0, 0 },
|
|
}
|
|
local fakeSheet = { getDimensions = function() return 14 * 8, 8 end }
|
|
local assets = package.loaded["src.render.Assets"]
|
|
assets.exists = function() return true end
|
|
assets.image = function() return fakeSheet end
|
|
local drawn = 0
|
|
love.graphics.draw = function() drawn = drawn + 1 end
|
|
love.graphics.newQuad = love.graphics.newQuad or function() return {} end
|
|
love.graphics.push = love.graphics.push or function() end
|
|
love.graphics.pop = love.graphics.pop or function() end
|
|
love.graphics.translate = love.graphics.translate or function() end
|
|
love.graphics.scale = love.graphics.scale or function() end
|
|
love.graphics.setColor = love.graphics.setColor or function() end
|
|
local cw = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
cw.palettes = { bg = { [8] = TEXT_ROW } }
|
|
cw.fitScale = function() return 1 end
|
|
cw:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
Sign.draw(cw, 160, 144, 0)
|
|
eq(drawn, 0, "nothing is drawn before PlaceMapNameSign's second call")
|
|
for _ = 1, 4 do Sign.frame(cw) end
|
|
Sign.draw(cw, 160, 144, 0)
|
|
eq(#withCalls, 1, "the sign blits through one GbcPalette.with")
|
|
if check(withCalls[1] ~= nil, "with a palette") then
|
|
eq(withCalls[1][1][1], 255, "PAL_BG_TEXT color 0 is cream")
|
|
eq(withCalls[1][1][3], 132, "not white")
|
|
eq(withCalls[1][3][1], 115, "color 2 is the brown frame line")
|
|
eq(withCalls[1][4][1], 0, "color 3 is black")
|
|
end
|
|
check(drawn >= 80, "all 80 frame tiles were drawn inside the fold")
|
|
local noPal = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
noPal.fitScale = function() return 1 end
|
|
noPal:go("ROUTE_29", "LANDMARK_ROUTE_29")
|
|
for _ = 1, 4 do Sign.frame(noPal) end
|
|
drawn = 0
|
|
Sign.draw(noPal, 160, 144, 0)
|
|
eq(#withCalls, 1, "no palette table means a plain blit")
|
|
check(drawn >= 80, "and the sign still draws")
|
|
|
|
engine = "gold"
|
|
local gold = World.new("LANDMARK_NEW_BARK_TOWN")
|
|
eq(gold:go("ROUTE_29", "LANDMARK_ROUTE_29"), nil,
|
|
"Gold never raises a map name sign")
|
|
engine = "crystal"
|
|
|
|
T.finish("crystal map name sign bug 1943")
|