-- Input abstraction: normalises keyboard (classic dual-track / modern simplified) -- and gamepad (always dual-stick) into a pair of track values in [-1, 1]. local Input = {} local SETTINGS_FILE = "oma-tank_settings.dat" local STICK_DEADZONE = 0.18 local mode = "modern" local joystick = nil local function clamp(v) if v < -1 then return -1 end if v > 1 then return 1 end return v end local function keyPair(positive, negative) local v = 0 if love.keyboard.isDown(positive) then v = v + 1 end if love.keyboard.isDown(negative) then v = v - 1 end return v end local function modernTracks() -- Up/Down drive both tracks, Left/Right split them local fwd = 0 if love.keyboard.isDown("up", "w") then fwd = fwd + 1 end if love.keyboard.isDown("down", "s") then fwd = fwd - 1 end local turn = 0 if love.keyboard.isDown("right", "d") then turn = turn + 1 end if love.keyboard.isDown("left", "a") then turn = turn - 1 end -- Reverse at 50% feel: matches the prior simplified control if fwd < 0 then fwd = fwd * 0.5 end local left = clamp(fwd + turn) local right = clamp(fwd - turn) return left, right end local function classicTracks() -- W/S = left track, I/K = right track local left = keyPair("w", "s") local right = keyPair("i", "k") return clamp(left), clamp(right) end local function applyDeadzone(v) if math.abs(v) < STICK_DEADZONE then return 0 end return v end local function gamepadTracks() if not joystick then return 0, 0 end -- Stick Y axis is positive down on most gamepads; flip so "forward" on the stick = +1 local left = -applyDeadzone(joystick:getGamepadAxis("lefty")) local right = -applyDeadzone(joystick:getGamepadAxis("righty")) return clamp(left), clamp(right) end function Input.tracks() local kl, kr if mode == "classic" then kl, kr = classicTracks() else kl, kr = modernTracks() end local gl, gr = gamepadTracks() -- If either source is pushing a stick, prefer gamepad values for that track local left = (gl ~= 0) and gl or kl local right = (gr ~= 0) and gr or kr return left, right end function Input.setMode(newMode) if newMode == "classic" or newMode == "modern" then mode = newMode Input.save() end end function Input.getMode() return mode end function Input.toggleMode() mode = (mode == "classic") and "modern" or "classic" Input.save() end function Input.label() return (mode == "classic") and "CLASSIC DUAL-TRACK" or "MODERN SIMPLIFIED" end function Input.save() pcall(function() love.filesystem.write(SETTINGS_FILE, "mode=" .. mode .. "\n") end) end function Input.load() if love.filesystem.getInfo(SETTINGS_FILE) then local ok, content = pcall(love.filesystem.read, SETTINGS_FILE) if ok and content then local m = content:match("mode=(%w+)") if m == "classic" or m == "modern" then mode = m end end end end function Input.attachJoystick() local joysticks = love.joystick.getJoysticks() for _, js in ipairs(joysticks) do if js:isGamepad() then joystick = js return end end joystick = nil end function Input.joystickAdded(js) if js:isGamepad() and not joystick then joystick = js end end function Input.joystickRemoved(js) if joystick == js then joystick = nil Input.attachJoystick() end end return Input