mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
cbf622f4aa
Bring feat/switch-nx up to date with origin/dev (72 commits). Resolve Input/RomImporter conflicts by keeping GamepadMap (NX face remap + dual-path gate) while adopting upstream joyBindings rebinds (#632) and Enable-all mods (#647). Gate shoulder GAME SPEED hotkeys when Select is held so Select+L display chords still work. Co-authored-by: Cursor <cursoragent@cursor.com>
172 lines
5.7 KiB
Lua
172 lines
5.7 KiB
Lua
-- Select+face chords fire Game:keypressed digits (NXMOD-06..10).
|
|
-- Spec: Select held + A/B/Y/X/L → keys 2/3/5/6/7; without Select, face stays GB.
|
|
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 check = T.check
|
|
local eq = T.eq
|
|
|
|
local Game = require("src.core.Game")
|
|
local Input = require("src.core.Input")
|
|
local GamepadMap = require("src.core.GamepadMap")
|
|
|
|
local joy = {
|
|
isGamepad = function() return true end,
|
|
isGamepadDown = function(_, button) return false end,
|
|
}
|
|
|
|
local digits = {}
|
|
local padForwarded = {}
|
|
local wroteOptions = false
|
|
|
|
local origKeypressed = Game.keypressed
|
|
local origPad = Input.gamepadpressed
|
|
local origWrite = Game.writeOptions
|
|
|
|
function Game:keypressed(key)
|
|
digits[#digits + 1] = key
|
|
-- Mimic digit persistence side-effect for keys that write options.
|
|
if key == "2" or key == "3" or key == "5" or key == "6" or key == "7" then
|
|
wroteOptions = true
|
|
end
|
|
end
|
|
|
|
function Input:gamepadpressed(joystick, button)
|
|
padForwarded[#padForwarded + 1] = button
|
|
return origPad(self, joystick, button)
|
|
end
|
|
|
|
local function resetSpies()
|
|
digits = {}
|
|
padForwarded = {}
|
|
wroteOptions = false
|
|
end
|
|
|
|
local function holdSelect()
|
|
Input:init()
|
|
-- Press Select (SDL back) into Input so isDown("select") is true.
|
|
origPad(Input, joy, "back")
|
|
Input:step()
|
|
check(Input:isDown("select"), "Select held via Input")
|
|
end
|
|
|
|
-- --- Without Select: face buttons keep normal GB path (NXMOD-09) ---
|
|
GamepadMap._setForceNXForTests(false)
|
|
Input:init()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, "a")
|
|
eq(#digits, 0, "no digit without Select")
|
|
eq(#padForwarded, 1, "face reaches Input without Select")
|
|
eq(padForwarded[1], "a", "Input receives face a")
|
|
check(not wroteOptions, "no options write without Select chord")
|
|
|
|
-- --- Select + face → same digit path as PC keys (NXMOD-06..08, NXMOD-10) ---
|
|
local chordCases = {
|
|
{ button = "a", digit = "2", label = "Select+A -> 2" },
|
|
{ button = "b", digit = "3", label = "Select+B -> 3" },
|
|
{ button = "y", digit = "5", label = "Select+Y -> 5" },
|
|
{ button = "x", digit = "6", label = "Select+X -> 6" },
|
|
{ button = "leftshoulder", digit = "7", label = "Select+L -> 7" },
|
|
}
|
|
|
|
for _, case in ipairs(chordCases) do
|
|
holdSelect()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, case.button)
|
|
eq(#digits, 1, case.label .. " fires keypressed once")
|
|
eq(digits[1], case.digit, case.label)
|
|
eq(#padForwarded, 0, case.label .. " does not forward face to Input")
|
|
check(wroteOptions, case.label .. " uses digit options path")
|
|
end
|
|
|
|
-- --- NX Nintendo UX: physical A (SDL b) → 2, physical B (SDL a) → 3 ---
|
|
GamepadMap._setForceNXForTests(true)
|
|
holdSelect()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, "b") -- physical Nintendo A
|
|
eq(digits[1], "2", "NX Select+physical A (SDL b) -> key 2")
|
|
eq(#padForwarded, 0, "NX chord A does not forward face")
|
|
check(wroteOptions, "NX chord A options path")
|
|
|
|
holdSelect()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, "a") -- physical Nintendo B
|
|
eq(digits[1], "3", "NX Select+physical B (SDL a) -> key 3")
|
|
eq(#padForwarded, 0, "NX chord B does not forward face")
|
|
|
|
-- Without Select on NX, face still goes to Input (no accidental cycle).
|
|
Input:init()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, "b")
|
|
eq(#digits, 0, "NX no digit without Select")
|
|
eq(#padForwarded, 1, "NX face reaches Input without Select")
|
|
|
|
-- Dual-path Select: joystick isGamepadDown("back") also counts as held.
|
|
GamepadMap._setForceNXForTests(false)
|
|
Input:init()
|
|
resetSpies()
|
|
local joySelectDown = {
|
|
isGamepad = function() return true end,
|
|
isGamepadDown = function(_, button) return button == "back" end,
|
|
}
|
|
Game:gamepadpressed(joySelectDown, "y")
|
|
eq(digits[1], "5", "Select via isGamepadDown(back) + Y -> 5")
|
|
eq(#padForwarded, 0, "isGamepadDown Select chord does not forward face")
|
|
|
|
-- Edge: face chords without Select must not cycle digits (NXMOD-09).
|
|
-- leftshoulder without Select is the GAME SPEED hotkey (upstream), so it
|
|
-- does not reach Input — only face buttons do.
|
|
GamepadMap._setForceNXForTests(false)
|
|
for _, btn in ipairs({ "a", "b", "y", "x" }) do
|
|
Input:init()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, btn)
|
|
eq(#digits, 0, "edge: no cycle without Select for " .. btn)
|
|
eq(#padForwarded, 1, "edge: " .. btn .. " still reaches Input without Select")
|
|
check(not wroteOptions, "edge: no options write without Select for " .. btn)
|
|
end
|
|
|
|
-- leftshoulder alone cycles speed (does not forward / does not digit).
|
|
do
|
|
local sped = 0
|
|
local origCycle = Game._cycleSpeed
|
|
function Game:_cycleSpeed(dir) sped = sped + (dir or 0) end
|
|
Input:init()
|
|
resetSpies()
|
|
Game:gamepadpressed(joy, "leftshoulder")
|
|
eq(#digits, 0, "edge: L alone does not fire display digit")
|
|
eq(#padForwarded, 0, "edge: L alone does not forward to Input (speed hotkey)")
|
|
eq(sped, -1, "edge: L alone cycles GAME SPEED down")
|
|
Game._cycleSpeed = origCycle
|
|
end
|
|
|
|
-- Select+L still wins over the speed hotkey.
|
|
holdSelect()
|
|
resetSpies()
|
|
do
|
|
local sped = 0
|
|
local origCycle = Game._cycleSpeed
|
|
function Game:_cycleSpeed(dir) sped = sped + (dir or 0) end
|
|
Game:gamepadpressed(joy, "leftshoulder")
|
|
eq(digits[1], "7", "Select+L still fires display digit 7")
|
|
eq(sped, 0, "Select+L does not cycle GAME SPEED")
|
|
eq(#padForwarded, 0, "Select+L does not forward L to Input")
|
|
Game._cycleSpeed = origCycle
|
|
end
|
|
|
|
-- Edge: Select alone (no face) does not synthesize a digit
|
|
holdSelect()
|
|
resetSpies()
|
|
-- pressing back again while held is not a display chord partner
|
|
Game:gamepadpressed(joy, "back")
|
|
eq(#digits, 0, "edge: Select alone does not fire a display digit")
|
|
eq(#padForwarded, 1, "edge: Select alone still forwards to Input")
|
|
|
|
GamepadMap._setForceNXForTests(false)
|
|
Game.keypressed = origKeypressed
|
|
Input.gamepadpressed = origPad
|
|
Game.writeOptions = origWrite
|
|
|
|
T.finish()
|