mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-22 13:36:14 +02:00
CLOSES #1570
This commit is contained in:
+96
-23
@@ -18,6 +18,7 @@ local Chrome = require("src.ui.gen2.Chrome")
|
|||||||
local Clock = require("src.core.gen2.Clock")
|
local Clock = require("src.core.gen2.Clock")
|
||||||
local FixedStep = require("src.core.FixedStep")
|
local FixedStep = require("src.core.FixedStep")
|
||||||
local Font = require("src.render.Font")
|
local Font = require("src.render.Font")
|
||||||
|
local GamepadMap = require("src.core.GamepadMap")
|
||||||
local Input = require("src.core.Input")
|
local Input = require("src.core.Input")
|
||||||
local Music = require("src.core.Music")
|
local Music = require("src.core.Music")
|
||||||
local Save = require("src.core.gen2.Save")
|
local Save = require("src.core.gen2.Save")
|
||||||
@@ -57,20 +58,6 @@ Game2.__index = Game2
|
|||||||
|
|
||||||
local function noop() end
|
local function noop() end
|
||||||
|
|
||||||
for _, name in ipairs({
|
|
||||||
"joystickpressed", "joystickreleased", "joystickaxis", "joystickhat",
|
|
||||||
"joystickadded",
|
|
||||||
}) do
|
|
||||||
Game2[name] = noop
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Not a noop, because the overlay has to come back on its own: a player who
|
|
||||||
-- unplugs the only controller would otherwise have to tap a blind screen to
|
|
||||||
-- get the pad back (src/core/Game.lua:869 does the same).
|
|
||||||
function Game2:joystickremoved()
|
|
||||||
TouchControls:joystickremoved()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- THE FRAME AND INPUT SEAMS.
|
-- THE FRAME AND INPUT SEAMS.
|
||||||
--
|
--
|
||||||
-- Gold composites its own frame (Game2:draw / drawScene) and pumps its own pad
|
-- Gold composites its own frame (Game2:draw / drawScene) and pumps its own pad
|
||||||
@@ -1993,6 +1980,13 @@ function Game2:applyOptions()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Game2:_cycleSpeed(dir)
|
||||||
|
local GameSpeed = require("src.core.GameSpeed")
|
||||||
|
self.options.speed = GameSpeed.cycle(self.options.speed, dir)
|
||||||
|
if self.save then self.save.options = self.options end
|
||||||
|
self:persistOptions()
|
||||||
|
end
|
||||||
|
|
||||||
-- `back` -- SDL's name for the small left-hand menu button: Xbox VIEW, the PS
|
-- `back` -- SDL's name for the small left-hand menu button: Xbox VIEW, the PS
|
||||||
-- CREATE/SHARE beside the touchpad, the Switch MINUS -- is SELECT, and has been
|
-- CREATE/SHARE beside the touchpad, the Switch MINUS -- is SELECT, and has been
|
||||||
-- since src/core/GamepadMap.lua's DEFAULT_GAMEPAD_BINDINGS was written
|
-- since src/core/GamepadMap.lua's DEFAULT_GAMEPAD_BINDINGS was written
|
||||||
@@ -2003,27 +1997,49 @@ end
|
|||||||
-- the PACK's move-item, the party menu's reorder and half the soft-reset chord
|
-- the PACK's move-item, the party menu's reorder and half the soft-reset chord
|
||||||
-- (A+B+SELECT+START) were all unreachable from a pad, and pressing the button
|
-- (A+B+SELECT+START) were all unreachable from a pad, and pressing the button
|
||||||
-- to find out killed the process. It reaches Input like every other button now.
|
-- to find out killed the process. It reaches Input like every other button now.
|
||||||
function Game2:gamepadpressed(_joystick, button)
|
function Game2:gamepadpressed(joystick, button)
|
||||||
-- a controller is being used: the touch overlay steps aside until the next
|
-- a controller is being used: the touch overlay steps aside until the next
|
||||||
-- screen touch (mobile only; a no-op elsewhere)
|
-- screen touch (mobile only; a no-op elsewhere)
|
||||||
TouchControls:noteGamepad()
|
TouchControls:noteGamepad()
|
||||||
-- The shoulders cycle GAME SPEED, as they do in the Gen 1 path.
|
local selectHeld = Input:isDown("select")
|
||||||
if button == "rightshoulder" or button == "leftshoulder" then
|
if not selectHeld and joystick and joystick.isGamepadDown then
|
||||||
local GameSpeed = require("src.core.GameSpeed")
|
local ok, down = pcall(function()
|
||||||
local dir = button == "rightshoulder" and 1 or -1
|
return joystick:isGamepadDown("back")
|
||||||
self.options.speed = GameSpeed.cycle(self.options.speed, dir)
|
end)
|
||||||
if self.save then self.save.options = self.options end
|
selectHeld = ok and down == true
|
||||||
self:persistOptions()
|
end
|
||||||
|
-- shoulders and triggers cycle GAME SPEED, as in src/core/Game.lua:881
|
||||||
|
if not selectHeld then
|
||||||
|
if button == "rightshoulder" or button == "righttrigger" then
|
||||||
|
self:_cycleSpeed(1)
|
||||||
|
return
|
||||||
|
elseif button == "leftshoulder" or button == "lefttrigger" then
|
||||||
|
self:_cycleSpeed(-1)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local top = self.stack and self.stack:top()
|
||||||
|
if top and top.onGamepadPressed then
|
||||||
|
top:onGamepadPressed(button)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if selectHeld then
|
||||||
|
local digit = GamepadMap.displayChordDigit(button)
|
||||||
|
if digit then
|
||||||
|
self:keypressed(digit)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
-- START opens the start menu in the overworld; it used to quit, from before
|
-- START opens the start menu in the overworld; it used to quit, from before
|
||||||
-- there was a menu to open.
|
-- there was a menu to open.
|
||||||
|
|
||||||
Input:gamepadpressed(_joystick, button)
|
Input:gamepadpressed(joystick, button)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Game2:gamepadreleased(joystick, button)
|
function Game2:gamepadreleased(joystick, button)
|
||||||
Input:gamepadreleased(joystick, button)
|
Input:gamepadreleased(joystick, button)
|
||||||
|
local top = self.stack and self.stack:top()
|
||||||
|
if top and top.onGamepadReleased then top:onGamepadReleased(button) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Game2:gamepadaxis(joystick, axis, value)
|
function Game2:gamepadaxis(joystick, axis, value)
|
||||||
@@ -2032,4 +2048,61 @@ function Game2:gamepadaxis(joystick, axis, value)
|
|||||||
Input:gamepadaxis(joystick, axis, value)
|
Input:gamepadaxis(joystick, axis, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- The raw joystick road, same bodies as src/core/Game.lua:935 (#620, #632, #1570).
|
||||||
|
local function isRawStick(joystick)
|
||||||
|
return not (joystick and joystick.isGamepad and joystick:isGamepad())
|
||||||
|
end
|
||||||
|
|
||||||
|
function Game2:joystickpressed(joystick, button)
|
||||||
|
if GamepadMap.isAccelerometer(joystick) then return end
|
||||||
|
TouchControls:noteGamepad()
|
||||||
|
local top = self.stack and self.stack:top()
|
||||||
|
if isRawStick(joystick) and top and top.onJoystickPressed then
|
||||||
|
top:onJoystickPressed(button)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
Input:joystickpressed(joystick, button)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Game2:joystickreleased(joystick, button)
|
||||||
|
if GamepadMap.isAccelerometer(joystick) then return end
|
||||||
|
Input:joystickreleased(joystick, button)
|
||||||
|
local top = self.stack and self.stack:top()
|
||||||
|
if isRawStick(joystick) and top and top.onJoystickReleased then
|
||||||
|
top:onJoystickReleased(button)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Game2:joystickaxis(joystick, axis, value)
|
||||||
|
if GamepadMap.isAccelerometer(joystick) then return end
|
||||||
|
if math.abs(value) > 0.5 then TouchControls:noteGamepad() end
|
||||||
|
Input:joystickaxis(joystick, axis, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Game2:joystickhat(joystick, hat, direction)
|
||||||
|
if GamepadMap.isAccelerometer(joystick) then return end
|
||||||
|
if direction ~= "c" then TouchControls:noteGamepad() end
|
||||||
|
Input:joystickhat(joystick, hat, direction)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- src/core/Game.lua:1015 (#799)
|
||||||
|
function Game2:recoverInput()
|
||||||
|
Input:reset()
|
||||||
|
Input:reconcile()
|
||||||
|
TouchControls:reset()
|
||||||
|
if self.mods and self.mods.releaseModInput then self.mods:releaseModInput() end
|
||||||
|
self:cancelPointers()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Game2:joystickadded()
|
||||||
|
self:recoverInput()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The overlay comes back on its own when the last pad is unplugged
|
||||||
|
-- (src/core/Game.lua:1044).
|
||||||
|
function Game2:joystickremoved()
|
||||||
|
self:recoverInput()
|
||||||
|
TouchControls:joystickremoved()
|
||||||
|
end
|
||||||
|
|
||||||
return Game2
|
return Game2
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
-- Gold noop'd the raw joystick road, so a stick with no SDL game-controller-db
|
||||||
|
-- entry pressed nothing in Gold while working in Gen 1 (#1570).
|
||||||
|
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 Game2 = require("src.core.Game2")
|
||||||
|
local Input = require("src.core.Input")
|
||||||
|
|
||||||
|
local CALLBACKS = {
|
||||||
|
"keypressed", "keyreleased",
|
||||||
|
"gamepadpressed", "gamepadreleased", "gamepadaxis",
|
||||||
|
"joystickpressed", "joystickreleased", "joystickaxis", "joystickhat",
|
||||||
|
"joystickadded", "joystickremoved",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name in ipairs(CALLBACKS) do
|
||||||
|
eq(type(Game[name]), "function", "Gen 1 routes " .. name)
|
||||||
|
eq(type(Game2[name]), "function", "Gold routes " .. name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local rawJoy = { isGamepad = function() return false end }
|
||||||
|
local gamepadJoy = { isGamepad = function() return true end }
|
||||||
|
|
||||||
|
local function newGold(top)
|
||||||
|
return setmetatable({
|
||||||
|
options = {},
|
||||||
|
stack = { top = function() return top end },
|
||||||
|
}, Game2)
|
||||||
|
end
|
||||||
|
|
||||||
|
Input:init()
|
||||||
|
local gold = newGold(nil)
|
||||||
|
|
||||||
|
gold:joystickpressed(rawJoy, 1)
|
||||||
|
Input:step()
|
||||||
|
check(Input:wasPressed("a"), "raw stick button 1 presses GB A in Gold")
|
||||||
|
check(Input:isDown("a"), "raw stick hold survives the step in Gold")
|
||||||
|
gold:joystickreleased(rawJoy, 1)
|
||||||
|
Input:step()
|
||||||
|
check(not Input:isDown("a"), "raw stick release clears the hold in Gold")
|
||||||
|
|
||||||
|
gold:joystickhat(rawJoy, 1, "l")
|
||||||
|
Input:step()
|
||||||
|
check(Input:wasPressed("left"), "raw hat left presses GB LEFT in Gold")
|
||||||
|
gold:joystickhat(rawJoy, 1, "c")
|
||||||
|
Input:step()
|
||||||
|
check(not Input:isDown("left"), "raw hat centre clears GB LEFT in Gold")
|
||||||
|
|
||||||
|
gold:joystickaxis(rawJoy, 2, 1)
|
||||||
|
Input:step()
|
||||||
|
check(Input:wasPressed("down"), "raw axis 2 presses GB DOWN in Gold")
|
||||||
|
gold:joystickaxis(rawJoy, 2, 0)
|
||||||
|
Input:step()
|
||||||
|
check(not Input:isDown("down"), "raw axis 2 back to centre clears GB DOWN")
|
||||||
|
|
||||||
|
-- A recognized pad raises BOTH roads for one press; the raw half must not
|
||||||
|
-- re-assert the factory map underneath a rebind (#620, #632).
|
||||||
|
Input:init()
|
||||||
|
gold = newGold(nil)
|
||||||
|
gold:gamepadpressed(gamepadJoy, "a")
|
||||||
|
gold:joystickpressed(gamepadJoy, 1)
|
||||||
|
gold:joystickpressed(gamepadJoy, 2)
|
||||||
|
Input:step()
|
||||||
|
check(Input:wasPressed("a"), "recognized pad A reaches Input in Gold")
|
||||||
|
check(not Input:wasPressed("b"), "raw must not stack B onto a recognized pad")
|
||||||
|
|
||||||
|
-- src/ui/BindingsMenu.lua's capture slots: Gold now hands the top state first
|
||||||
|
-- refusal on both roads, the way src/core/Game.lua does.
|
||||||
|
Input:init()
|
||||||
|
local captured = {}
|
||||||
|
local capturingTop = {
|
||||||
|
onJoystickPressed = function(_, button) captured.joy = button end,
|
||||||
|
onGamepadPressed = function(_, button) captured.pad = button end,
|
||||||
|
}
|
||||||
|
gold = newGold(capturingTop)
|
||||||
|
gold:joystickpressed(rawJoy, 3)
|
||||||
|
gold:gamepadpressed(gamepadJoy, "y")
|
||||||
|
Input:step()
|
||||||
|
eq(captured.joy, 3, "an armed CONTROLS row captures the raw button")
|
||||||
|
eq(captured.pad, "y", "an armed CONTROLS row captures the pad button")
|
||||||
|
check(not Input:wasPressed("a"), "a captured press never reaches gameplay")
|
||||||
|
|
||||||
|
-- Hotplug: the reset+reconcile Gen 1 runs, so a pad that vanished mid-hold
|
||||||
|
-- cannot strand a direction down (#799).
|
||||||
|
Input:init()
|
||||||
|
gold = newGold(nil)
|
||||||
|
gold:joystickpressed(rawJoy, 1)
|
||||||
|
Input:step()
|
||||||
|
check(Input:isDown("a"), "held before the hotplug")
|
||||||
|
gold:joystickadded(rawJoy)
|
||||||
|
Input:step()
|
||||||
|
check(not Input:isDown("a"), "joystickadded drops stranded holds in Gold")
|
||||||
|
|
||||||
|
gold:joystickpressed(rawJoy, 1)
|
||||||
|
Input:step()
|
||||||
|
gold:joystickremoved(rawJoy)
|
||||||
|
Input:step()
|
||||||
|
check(not Input:isDown("a"), "joystickremoved drops stranded holds in Gold")
|
||||||
|
|
||||||
|
T.finish()
|
||||||
Reference in New Issue
Block a user