mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-21 13:09:54 +02:00
Merge pull request #1601 from bryanthaboi/dev
bug fixes and uncles neighbor
This commit is contained in:
@@ -41,12 +41,21 @@ end
|
||||
-- Mock isReady
|
||||
RomImporter.isReady = function(v)
|
||||
return v == "red" or v == "gold" or v == "blue" or v == "yellow"
|
||||
or v == "silver"
|
||||
end
|
||||
|
||||
local ok = RomImporter.syncAndroidShortcuts("gold")
|
||||
check(ok == true, "syncAndroidShortcuts returns true on Android")
|
||||
check(#capturedShortcuts == 4, "syncAndroidShortcuts caps at 4 items")
|
||||
check(capturedShortcuts[1] == "gold", "activeVersion 'gold' is placed first")
|
||||
check(capturedShortcuts[2] == "red" and capturedShortcuts[3] == "blue"
|
||||
and capturedShortcuts[4] == "yellow",
|
||||
"the rest follow GameVersion.ORDER until the cap")
|
||||
|
||||
capturedShortcuts = nil
|
||||
RomImporter.syncAndroidShortcuts("silver")
|
||||
check(#capturedShortcuts == 4, "a fifth ready game does not widen the payload")
|
||||
check(capturedShortcuts[1] == "silver", "activeVersion 'silver' is placed first")
|
||||
|
||||
-- Test with subset of ready games (e.g. only Red and Gold)
|
||||
RomImporter.isReady = function(v)
|
||||
@@ -78,4 +87,4 @@ end
|
||||
love.system.getLaunchGame = savedGetLaunchGame
|
||||
love.system.updateShortcuts = nil
|
||||
|
||||
print("8/8 checks passed (android_shortcuts_payload_test)")
|
||||
T.finish("android_shortcuts_payload_test")
|
||||
|
||||
@@ -23,6 +23,7 @@ T.eq(GameVersion.generation("red"), 1, "Red is Gen 1")
|
||||
T.eq(GameVersion.generation("blue"), 1, "Blue is Gen 1")
|
||||
T.eq(GameVersion.generation("yellow"), 1, "Yellow is Gen 1")
|
||||
T.eq(GameVersion.generation("gold"), 2, "Gold is Gen 2")
|
||||
T.eq(GameVersion.generation("silver"), 2, "Silver is Gen 2")
|
||||
|
||||
-- ------- 2. manifest: gen2compat is opt-in and defaults off
|
||||
|
||||
|
||||
@@ -39,45 +39,54 @@ end
|
||||
local edited = 0
|
||||
local hooks = { editTouchControls = function() edited = edited + 1 end }
|
||||
|
||||
local gold = LauncherSettings.open(hooks, "gold")
|
||||
check(has(gold, "TOUCH PAD"), "Gold's gear offers TOUCH PAD")
|
||||
check(has(gold, "VIBRATION"), "and VIBRATION")
|
||||
check(has(gold, "TOUCH CONTROLS"), "and the layout editor")
|
||||
check(has(gold, "VOID FILL"), "and VOID FILL")
|
||||
for _, version in ipairs({ "gold", "silver" }) do
|
||||
local model = LauncherSettings.open(hooks, version)
|
||||
check(has(model, "TOUCH PAD"), version .. " gear offers TOUCH PAD")
|
||||
check(has(model, "VIBRATION"), version .. " and VIBRATION")
|
||||
check(has(model, "TOUCH CONTROLS"), version .. " and the layout editor")
|
||||
check(has(model, "VOID FILL"), version .. " and VOID FILL")
|
||||
|
||||
local voidFill = findRow(gold, "VOID FILL")
|
||||
eq(voidFill.value(), "FADE ", "VOID FILL defaults to FADE")
|
||||
voidFill.step(1)
|
||||
eq(gold.opts.gold.voidFill, "water", "right stores water in the gold block")
|
||||
eq(voidFill.value(), "WATER", "and the row reads WATER")
|
||||
voidFill.step(-1)
|
||||
eq(gold.opts.gold.voidFill, "fade", "left restores fade")
|
||||
local voidFill = findRow(model, "VOID FILL")
|
||||
eq(voidFill.value(), "FADE ", version .. " VOID FILL defaults to FADE")
|
||||
voidFill.step(1)
|
||||
eq(model.opts.gold.voidFill, "water",
|
||||
version .. " right stores water in the gold block")
|
||||
eq(voidFill.value(), "WATER", version .. " and the row reads WATER")
|
||||
voidFill.step(-1)
|
||||
eq(model.opts.gold.voidFill, "fade", version .. " left restores fade")
|
||||
|
||||
-- Every write has to land in the gold block: the flat keys beside it are
|
||||
-- Red's, and Gold's boot never reads them (src/core/gen2/Save.lua:299).
|
||||
-- loadOptions seeds the flat Gen 1 defaults, so the check is that the Gold
|
||||
-- rows leave them exactly as they found them.
|
||||
local flatPad = gold.opts.touchControls
|
||||
local flatBuzz = gold.opts.haptics
|
||||
-- Every write has to land in the gen2 block: the flat keys beside it are
|
||||
-- Red's, and no Gen 2 boot reads them (src/core/gen2/Save.lua:299).
|
||||
-- loadOptions seeds the flat Gen 1 defaults, so the check is that the Gen 2
|
||||
-- rows leave them exactly as they found them.
|
||||
local flatPad = model.opts.touchControls
|
||||
local flatBuzz = model.opts.haptics
|
||||
|
||||
local pad = findRow(gold, "TOUCH PAD")
|
||||
local before = pad.value()
|
||||
pad.step(1)
|
||||
check(pad.value() ~= before, "stepping TOUCH PAD flips it")
|
||||
check(type(gold.opts.gold) == "table", "into the gold block")
|
||||
eq(gold.opts.gold.touchControls.enabled, false, "which now carries enabled")
|
||||
eq(gold.opts.touchControls, flatPad, "leaving the flat Gen 1 key alone")
|
||||
local pad = findRow(model, "TOUCH PAD")
|
||||
local before = pad.value()
|
||||
pad.step(1)
|
||||
check(pad.value() ~= before, version .. " stepping TOUCH PAD flips it")
|
||||
check(type(model.opts.gold) == "table", version .. " into the gold block")
|
||||
eq(model.opts.gold.touchControls.enabled, false,
|
||||
version .. " which now carries enabled")
|
||||
eq(model.opts.touchControls, flatPad,
|
||||
version .. " leaving the flat Gen 1 key alone")
|
||||
eq(model.opts.silver, nil,
|
||||
version .. " and inventing no second Gen 2 block beside it")
|
||||
|
||||
local buzz = findRow(gold, "VIBRATION")
|
||||
local buzzBefore = buzz.value()
|
||||
buzz.step(1)
|
||||
check(buzz.value() ~= buzzBefore, "stepping VIBRATION moves the level")
|
||||
eq(gold.opts.gold.haptics, TouchControls.normalizeHaptics(gold.opts.gold.haptics),
|
||||
"VIBRATION stores a level the shared module knows")
|
||||
eq(gold.opts.haptics, flatBuzz, "also without touching Red's")
|
||||
local buzz = findRow(model, "VIBRATION")
|
||||
local buzzBefore = buzz.value()
|
||||
buzz.step(1)
|
||||
check(buzz.value() ~= buzzBefore, version .. " stepping VIBRATION moves the level")
|
||||
eq(model.opts.gold.haptics,
|
||||
TouchControls.normalizeHaptics(model.opts.gold.haptics),
|
||||
version .. " VIBRATION stores a level the shared module knows")
|
||||
eq(model.opts.haptics, flatBuzz, version .. " also without touching Red's")
|
||||
|
||||
findRow(gold, "TOUCH CONTROLS").action()
|
||||
eq(edited, 1, "the editor row reaches the host hook")
|
||||
edited = 0
|
||||
findRow(model, "TOUCH CONTROLS").action()
|
||||
eq(edited, 1, version .. " the editor row reaches the host hook")
|
||||
end
|
||||
|
||||
-- The Gen 1 gear is untouched by the extraction: same three rows, still on
|
||||
-- the flat table.
|
||||
@@ -94,6 +103,8 @@ eq(findRow(red, "TOUCH PAD").value() ~= nil, true, "and reading it back")
|
||||
-- rather than dead, on both sides.
|
||||
eq(has(LauncherSettings.open(nil, "gold"), "TOUCH CONTROLS"), false,
|
||||
"no hook, no editor row on Gold")
|
||||
eq(has(LauncherSettings.open(nil, "silver"), "TOUCH CONTROLS"), false,
|
||||
"nor on Silver")
|
||||
eq(has(LauncherSettings.open(nil, "red"), "TOUCH CONTROLS"), false,
|
||||
"nor on Red")
|
||||
-- The Edit row hands the screen to the host, and the host has to know WHICH
|
||||
|
||||
@@ -155,28 +155,34 @@ modImp.mods = mods
|
||||
modImp._ensureMods = function() return mods end
|
||||
LauncherView.draw(modImp)
|
||||
LauncherView.draw(modImp)
|
||||
check((modImp._modScrollMax or 0) > 0,
|
||||
"60 mods overflow the list viewport inside the panel")
|
||||
local list = modImp._modListRect
|
||||
check(list.x + list.w
|
||||
<= modImp._tabRegionRect.x + modImp._tabRegionRect.w - Kit.scrollBarW(),
|
||||
"the rows stop short of the region's scrollbar gutter")
|
||||
pointer(list.x + 10, list.y + 10)
|
||||
local reg = modImp._tabRegionRect
|
||||
check((modImp._tabScrollMax.mods or 0) > reg.h,
|
||||
"60 installed mods are ONE continuous list: the region's travel spans "
|
||||
.. "the whole list, not one page of it")
|
||||
eq(modImp._pages.mods, nil, "and no page state is ever minted for it")
|
||||
pointer(reg.x + 10, reg.y + 40)
|
||||
modImp._wheelY = -1
|
||||
LauncherView.draw(modImp)
|
||||
check((modImp.modScroll or 0) > 0, "a notch over the mod list scrolls the list")
|
||||
eq(modImp._tabScroll.mods or 0, 0, "not the panel region around it")
|
||||
eq(modImp._pageScroll, 0, "and not the page behind that")
|
||||
check((modImp._tabScroll.mods or 0) > 0,
|
||||
"a notch over the region scrolls the list like any other tab")
|
||||
eq(modImp._pageScroll, 0, "without reaching the page behind it")
|
||||
|
||||
modImp._tabScroll.mods = modImp._tabScrollMax.mods
|
||||
LauncherView.draw(modImp)
|
||||
pointer(reg.x + 10, reg.y + reg.h * 0.5)
|
||||
modImp._wheelY = -1
|
||||
LauncherView.draw(modImp)
|
||||
eq(modImp._pages.mods, nil,
|
||||
"bottoming the list out never auto-advances any pager")
|
||||
eq(modImp._tabScroll.mods, modImp._tabScrollMax.mods,
|
||||
"the list just rests at its end")
|
||||
|
||||
modImp._modActions = "mod1"
|
||||
local shielded = modImp.modScroll
|
||||
local shieldedPage = modImp._pageScroll
|
||||
pointer(list.x + 10, list.y + 10)
|
||||
local shieldedAt = modImp._tabScroll.mods
|
||||
modImp._wheelY = -1
|
||||
LauncherView.draw(modImp)
|
||||
eq(modImp.modScroll, shielded, "a shielded mod list ignores the notch")
|
||||
eq(modImp._tabScroll.mods or 0, 0, "and so does the region under the scrim")
|
||||
eq(modImp._pageScroll, shieldedPage, "and the page behind that")
|
||||
eq(modImp._tabScroll.mods, shieldedAt,
|
||||
"a shielded mod list ignores the notch under the scrim")
|
||||
modImp._modActions = nil
|
||||
modImp._wheelY = 0
|
||||
LauncherView.draw(modImp)
|
||||
@@ -225,32 +231,27 @@ dragMods.mods = mods
|
||||
dragMods._ensureMods = function() return mods end
|
||||
LauncherView.draw(dragMods)
|
||||
LauncherView.draw(dragMods)
|
||||
local dlist = dragMods._modListRect
|
||||
local dListMax = dragMods._modScrollMax
|
||||
local dreg = dragMods._tabRegionRect
|
||||
local dRegionMax = dragMods._tabScrollMax.mods
|
||||
check(dListMax > 0 and dRegionMax > 0,
|
||||
"the mods tab has both an inner list and a region to scroll")
|
||||
LauncherView.touchpressed(dragMods, 7, dlist.x + 20, dlist.y + 30)
|
||||
LauncherView.touchmoved(dragMods, 7, dlist.x + 20, dlist.y + 30 - 60)
|
||||
eq(dragMods.modScroll, math.min(60, dListMax),
|
||||
"the first pixels of the drag move the list")
|
||||
eq(dragMods._tabScroll.mods or 0, 0, "and nothing else")
|
||||
LauncherView.touchmoved(dragMods, 7, dlist.x + 20,
|
||||
dlist.y + 30 - 60 - dListMax - dRegionMax * 2)
|
||||
eq(dragMods.modScroll, dListMax, "carrying on saturates the list")
|
||||
eq(dragMods._tabScroll.mods, dRegionMax,
|
||||
"then the same gesture walks the region to its bottom")
|
||||
check(dRegionMax > 0, "the mods region scrolls its overscan like any tab")
|
||||
LauncherView.touchpressed(dragMods, 7, dreg.x + 20, dreg.y + 30)
|
||||
LauncherView.touchmoved(dragMods, 7, dreg.x + 20, dreg.y + 30 - 60)
|
||||
eq(dragMods._tabScroll.mods, math.min(60, dRegionMax),
|
||||
"a drag moves the region by the finger's travel")
|
||||
LauncherView.touchmoved(dragMods, 7, dreg.x + 20,
|
||||
dreg.y + 30 - 60 - dRegionMax * 2)
|
||||
eq(dragMods._tabScroll.mods, dRegionMax, "carrying on saturates the region")
|
||||
check((dragMods._pageScroll or 0) > 0, "and only then reaches the page")
|
||||
LauncherView.touchreleased(dragMods, 7, dlist.x + 20, dlist.y - 900)
|
||||
LauncherView.touchreleased(dragMods, 7, dreg.x + 20, dreg.y - 900)
|
||||
|
||||
dragMods._skins = { { id = "s1", source = "user", controls = 8, pages = 1 } }
|
||||
for i = 2, 12 do
|
||||
dragMods._skins[i] = { id = "s" .. i, source = "user", controls = 8, pages = 1 }
|
||||
end
|
||||
dragMods._ensureSkins = function() return dragMods._skins end
|
||||
dragMods.modScroll = 0
|
||||
local heldModScroll = dragMods.modScroll
|
||||
local overList = dlist.y + 30
|
||||
local heldModsPage = dragMods._pages.mods or 1
|
||||
local heldModsAt = dragMods._tabScroll.mods
|
||||
local overList = dreg.y + 60
|
||||
dragMods:_switchTab("skins")
|
||||
LauncherView.draw(dragMods)
|
||||
LauncherView.draw(dragMods)
|
||||
@@ -260,8 +261,10 @@ LauncherView.touchpressed(dragMods, 9, sreg.x + 20, overList)
|
||||
LauncherView.touchmoved(dragMods, 9, sreg.x + 20, overList - 200)
|
||||
check((dragMods._tabScroll.skins or 0) > 0,
|
||||
"a drag on the skins tab scrolls the skins tab")
|
||||
eq(dragMods.modScroll, heldModScroll,
|
||||
"and leaves the mod list where the player parked it")
|
||||
eq(dragMods._pages.mods or 1, heldModsPage,
|
||||
"and leaves the mod list on the page the player parked it")
|
||||
eq(dragMods._tabScroll.mods, heldModsAt,
|
||||
"with its region offset held for the return trip")
|
||||
LauncherView.touchreleased(dragMods, 9, sreg.x + 20, sreg.y - 400)
|
||||
|
||||
love.graphics.polygon = love.graphics.polygon or function() end
|
||||
@@ -308,8 +311,8 @@ local view = read("src/import/LauncherView.lua")
|
||||
check(view:find("Kit.scrollBegin(", 1, true) ~= nil,
|
||||
"the panel dispatch opens a scroll region")
|
||||
check(view:find("Kit.scrollEnd(", 1, true) ~= nil, "and closes it")
|
||||
check(view:find("modListWantsWheel", 1, true) ~= nil,
|
||||
"the nested mod list is asked before the region takes a notch")
|
||||
check(view:find("modListWantsWheel", 1, true) == nil,
|
||||
"no nested list steals the wheel from the region any more")
|
||||
check(view:find("start.region", 1, true) ~= nil,
|
||||
"a touch drag that began in the region scrolls the region")
|
||||
check(view:find("Kit.scrollGutter(", 1, true) ~= nil,
|
||||
|
||||
@@ -32,11 +32,13 @@ do
|
||||
"a version id names exactly that game")
|
||||
eq(table.concat(ModTargets.expand("GEN1"), ","), "red,blue,yellow",
|
||||
"gen1 is every Gen 1 game, case-insensitive")
|
||||
eq(table.concat(ModTargets.expand("gen2"), ","), "gold",
|
||||
eq(table.concat(ModTargets.expand("gen2"), ","), "gold,silver",
|
||||
"gen2 is every Gen 2 game")
|
||||
eq(table.concat(ModTargets.expand("silver"), ","), "silver",
|
||||
"and each of them names itself")
|
||||
eq(table.concat(ModTargets.expand("all"), ","),
|
||||
table.concat(GameVersion.ORDER, ","), "all is the launcher order itself")
|
||||
eq(ModTargets.expand("silver"), nil, "a game this engine has no cache for")
|
||||
eq(ModTargets.expand("crystal"), nil, "a game this engine has no cache for")
|
||||
eq(ModTargets.expand("gen9"), nil, "a generation with no games is unknown")
|
||||
eq(ModTargets.expand(7), nil, "a non-string token is not a game")
|
||||
end
|
||||
@@ -56,7 +58,7 @@ end
|
||||
do
|
||||
eq(list(mf({})), "red,blue,yellow",
|
||||
"a manifest with no games key is Gen 1, which is what it was tested as")
|
||||
eq(list(mf({ gen2compat = true })), "red,blue,yellow,gold",
|
||||
eq(list(mf({ gen2compat = true })), "red,blue,yellow,gold,silver",
|
||||
"gen2compat keeps Gen 1 and adds Gen 2")
|
||||
eq(mf({}).gen2compat, false, "and the derived flag agrees")
|
||||
eq(mf({ gen2compat = true }).gen2compat, true, "both ways")
|
||||
@@ -67,14 +69,14 @@ end
|
||||
|
||||
do
|
||||
local gen2 = mf({ games = { "gen2" } })
|
||||
eq(list(gen2), "gold", "games can name Gen 2 alone")
|
||||
eq(list(gen2), "gold,silver", "games can name Gen 2 alone")
|
||||
eq(gen2.gen2compat, true, "which IS the gen2compat claim the gate reads")
|
||||
local both = mf({ games = { "gen1", "gen2" } })
|
||||
eq(list(both), "red,blue,yellow,gold", "or both generations")
|
||||
eq(list(both), "red,blue,yellow,gold,silver", "or both generations")
|
||||
local one = mf({ games = { "blue" } })
|
||||
eq(list(one), "blue", "or one single game")
|
||||
eq(one.gen2compat, false, "a Gen 1 game is not a Gen 2 claim")
|
||||
eq(list(mf({ games = { "red" }, gen2compat = true })), "red,gold",
|
||||
eq(list(mf({ games = { "red" }, gen2compat = true })), "red,gold,silver",
|
||||
"an old gen2compat beside a new games list still adds its game")
|
||||
end
|
||||
|
||||
@@ -224,10 +226,12 @@ do
|
||||
local bad = ModProfile.decode(require("src.core.SaveSerializer").encode({
|
||||
format = "g1rmodlist", formatVersion = 1,
|
||||
profile = { name = "P", enabledByVersion = {
|
||||
gold = { a = true }, silver = { a = true }, red = "nope" } },
|
||||
gold = { a = true }, silver = { a = true }, crystal = { a = true },
|
||||
red = "nope" } },
|
||||
}))
|
||||
eq(bad.enabledByVersion.gold.a, true, "a shared file's known game is kept")
|
||||
eq(bad.enabledByVersion.silver, nil, "an unknown game is dropped on read")
|
||||
eq(bad.enabledByVersion.silver.a, true, "every one of them, not just the first")
|
||||
eq(bad.enabledByVersion.crystal, nil, "an unknown game is dropped on read")
|
||||
eq(bad.enabledByVersion.red, nil, "and so is a bucket that is not a table")
|
||||
end
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ package.loaded["src.import.RomImporter"] = nil
|
||||
RomImporter = require("src.import.RomImporter")
|
||||
|
||||
local function clearSavesInbox()
|
||||
for _, ver in ipairs({ "red", "blue", "yellow", "gold" }) do
|
||||
for _, ver in ipairs({ "red", "blue", "yellow", "gold", "silver" }) do
|
||||
local dir = "imports/saves/" .. ver
|
||||
for _, name in ipairs(love.filesystem.getDirectoryItems(dir) or {}) do
|
||||
love.filesystem.remove(dir .. "/" .. name)
|
||||
@@ -137,6 +137,8 @@ check(createdDirs["imports/saves/yellow"] == true,
|
||||
"RES-01: ensureSavesInboxDir creates imports/saves/yellow/")
|
||||
check(createdDirs["imports/saves/gold"] == true,
|
||||
"RES-01: ensureSavesInboxDir creates imports/saves/gold/")
|
||||
check(createdDirs["imports/saves/silver"] == true,
|
||||
"RES-01: ensureSavesInboxDir creates imports/saves/silver/")
|
||||
|
||||
-- NXSAV-02: notice/hint includes save dir + per-game imports/saves/<version>/ MTP path
|
||||
ri = freshImporter()
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
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 ScreenPosition = require("src.core.ScreenPosition")
|
||||
local TouchSkin = require("src.core.TouchSkin")
|
||||
local Renderer = require("src.render.Renderer")
|
||||
local Chrome = require("src.ui.gen2.Chrome")
|
||||
local Zoom = require("src.render.Zoom")
|
||||
|
||||
eq(ScreenPosition.normalize(nil), "center", "no setting is CENTER")
|
||||
eq(ScreenPosition.normalize("junk"), "center", "garbage degrades to CENTER")
|
||||
eq(ScreenPosition.normalize("top"), "top", "top passes through")
|
||||
eq(ScreenPosition.label("upper"), "UPPER", "upper reads UPPER")
|
||||
|
||||
local seen, v = {}, "center"
|
||||
for _ = 1, 3 do
|
||||
seen[#seen + 1] = ScreenPosition.label(v)
|
||||
v = ScreenPosition.cycle(v, 1)
|
||||
end
|
||||
eq(table.concat(seen, ","), "CENTER,UPPER,TOP", "the row cycles CENTER,UPPER,TOP")
|
||||
eq(ScreenPosition.cycle("top", 1), "center", "and wraps back to CENTER")
|
||||
eq(ScreenPosition.cycle("center", -1), "top", "stepping back lands on TOP")
|
||||
|
||||
ScreenPosition.setMode("center")
|
||||
eq(ScreenPosition.lift(640, 288), 0, "CENTER never lifts")
|
||||
|
||||
ScreenPosition.setMode("top")
|
||||
eq(ScreenPosition.lift(640, 288), 176, "TOP lifts the centered origin to 0")
|
||||
eq(ScreenPosition.lift(288, 288), 0, "no slack, no lift")
|
||||
eq(ScreenPosition.lift(144, 288), 0, "negative slack, no lift")
|
||||
eq(ScreenPosition.lift(640, 288, 40), 136, "TOP stops at the safe-area inset")
|
||||
eq(ScreenPosition.lift(640, 288, 999), 0,
|
||||
"a safe inset past center degrades to centered")
|
||||
|
||||
ScreenPosition.setMode("upper")
|
||||
eq(ScreenPosition.lift(640, 288), 88, "UPPER lands halfway between")
|
||||
eq(ScreenPosition.lift(640, 288, 40), 88, "a small inset leaves UPPER alone")
|
||||
eq(ScreenPosition.lift(640, 288, 120), 56, "a large inset pushes UPPER down")
|
||||
|
||||
ScreenPosition.applyOptions({ screenPos = "top" })
|
||||
eq(ScreenPosition.mode, "top", "applyOptions takes the stored key")
|
||||
ScreenPosition.applyOptions(nil)
|
||||
eq(ScreenPosition.mode, "center", "applyOptions without options is CENTER")
|
||||
|
||||
local function setWindow(w, h)
|
||||
love.graphics.getDimensions = function() return w, h end
|
||||
love.graphics.getPixelDimensions = function() return w, h end
|
||||
end
|
||||
|
||||
setWindow(360, 640)
|
||||
TouchSkin.setActive(nil)
|
||||
Renderer:init()
|
||||
Zoom.offset = 0
|
||||
|
||||
ScreenPosition.setMode("center")
|
||||
local r = Renderer:frameRects()
|
||||
eq(r.Sp, 2, "360x640 fits two whole GB pixels")
|
||||
eq(r.lift, 0, "CENTER: no lift")
|
||||
eq(r.oy, 176, "CENTER: the letterbox is centered")
|
||||
local _, vhCenter = Renderer:worldViewSize()
|
||||
|
||||
ScreenPosition.setMode("top")
|
||||
r = Renderer:frameRects()
|
||||
eq(r.lift, 176, "TOP: the full centered slack lifts away")
|
||||
eq(r.oy, 0, "TOP: the letterbox sits at the top edge")
|
||||
eq(r.uoy, 0, "TOP: the UI letterbox follows")
|
||||
eq(r.ox, math.floor((360 - 320) / 2), "TOP: horizontal centering is untouched")
|
||||
local _, vhTop = Renderer:worldViewSize()
|
||||
eq(vhTop, vhCenter + 2 * math.ceil(176 / 2),
|
||||
"TOP: the world canvas grows to keep the bottom covered")
|
||||
|
||||
ScreenPosition.setMode("upper")
|
||||
r = Renderer:frameRects()
|
||||
eq(r.oy, 88, "UPPER: the letterbox centers in the upper half")
|
||||
|
||||
ScreenPosition.setMode("top")
|
||||
local ox, oy = Chrome.fitOrigin(360, 640)
|
||||
eq(oy, 0, "TOP: Gold's letterbox sits at the top edge")
|
||||
eq(ox, math.floor((360 - 320) / 2), "TOP: Gold's horizontal centering is untouched")
|
||||
ScreenPosition.setMode("center")
|
||||
local _, cy = Chrome.fitOrigin(360, 640)
|
||||
eq(cy, 176, "CENTER: Gold's letterbox is centered")
|
||||
|
||||
ScreenPosition.setMode("top")
|
||||
local skin = assert(TouchSkin.parse([[
|
||||
overlays = 1
|
||||
overlay0_name = "bezel"
|
||||
overlay0_full_screen = true
|
||||
overlay0_normalized = true
|
||||
overlay0_viewport = "0.1,0.1,0.8,0.4"
|
||||
overlay0_descs = 1
|
||||
overlay0_desc0 = "nul,0.5,0.5,rect,0.02,0.02"
|
||||
]]))
|
||||
TouchSkin.setActive(skin)
|
||||
TouchSkin.setOverlayLive(false)
|
||||
r = Renderer:frameRects()
|
||||
eq(r.cut, true, "the skin viewport cuts the playfield")
|
||||
eq(r.lift, 0, "a skin viewport disables the lift")
|
||||
eq(select(1, ScreenPosition.skinActive(360, 640)), true,
|
||||
"skinActive sees the viewport")
|
||||
local _, sy = Chrome.fitOrigin(360, 640)
|
||||
local _, cy2 = (function()
|
||||
ScreenPosition.setMode("center")
|
||||
return Chrome.fitOrigin(360, 640)
|
||||
end)()
|
||||
eq(sy, cy2, "with a skin the Gold origin ignores the mode")
|
||||
TouchSkin.setActive(nil)
|
||||
ScreenPosition.setMode("center")
|
||||
|
||||
T.finish("screen_position")
|
||||
@@ -81,7 +81,8 @@ local function importer(ready)
|
||||
}, RomImporter)
|
||||
end
|
||||
|
||||
local allReady = importer({ red = true, blue = true, yellow = true, gold = true })
|
||||
local allReady = importer({ red = true, blue = true, yellow = true, gold = true,
|
||||
silver = true })
|
||||
allReady:_queueBaseRomScan()
|
||||
eq(allReady.baseRomScan.state, "done", "ready launcher skips discovery")
|
||||
eq(listings, 0, "ready launcher does not enumerate baseroms")
|
||||
@@ -123,7 +124,8 @@ eq(picks, 0, "missing detected ROM does not open the picker unexpectedly")
|
||||
missing:choose("red")
|
||||
eq(picks, 1, "the next import attempt falls back to the native picker")
|
||||
|
||||
local rescanned = importer({ red = true, blue = true, yellow = true, gold = true })
|
||||
local rescanned = importer({ red = true, blue = true, yellow = true, gold = true,
|
||||
silver = true })
|
||||
rescanned.baseRoms.red = { path = "baseroms/z-red.gb", name = "z-red.gb" }
|
||||
rescanned:reimport("red")
|
||||
check(rescanned.baseRoms.red == nil, "re-import clears the detected ROM")
|
||||
|
||||
Reference in New Issue
Block a user