From 863c614a4ca9982784cd4f895c6d45907c6ef557 Mon Sep 17 00:00:00 2001 From: nightmareci Date: Sun, 8 Nov 2020 12:55:06 -0800 Subject: [PATCH 1/3] Implemented joystick input. I had to redo how input is done entirely, so more than one source of input can be used for game inputs. I added new inputs, menu_decide and menu_back. Return and escape still have their reserved status, sending menu_decide and menu_back, respectively. Other keys are reserved too, like arrows, to ensure users can always reconfigure input. --- main.lua | 116 +++++++++++++++++++++++++++++++- scene.lua | 3 +- scene/config.lua | 2 +- scene/exit.lua | 2 +- scene/game.lua | 68 ++++++++++--------- scene/game_config.lua | 14 ++-- scene/input_config.lua | 148 ++++++++++++++++++++++++++++++++--------- scene/mode_select.lua | 13 ++-- scene/title.lua | 10 +-- 9 files changed, 291 insertions(+), 85 deletions(-) diff --git a/main.lua b/main.lua index cd043d6..4c390da 100644 --- a/main.lua +++ b/main.lua @@ -23,7 +23,6 @@ function love.load() end if not config.input then - config.input = {} scene = InputConfigScene() else if config.current_mode then current_mode = config.current_mode end @@ -110,16 +109,127 @@ function love.draw() love.graphics.pop() end -function love.keypressed(key, scancode, isrepeat) +function love.keypressed(key, scancode) -- global hotkeys if scancode == "f4" then config["fullscreen"] = not config["fullscreen"] love.window.setFullscreen(config["fullscreen"]) + -- reserved keys, so the user can always get back to configure input + elseif scancode == "return" then + scene:onInputPress({input="menu_decide", type="key", key=key, scancode=scancode}) + elseif scancode == "escape" then + scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode}) + elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then + scene:onInputPress({input=scancode, type="key", key=key, scancode=scancode}) + -- other keys can be configured else - scene:onKeyPress({key=key, scancode=scancode, isRepeat=isrepeat}) + local input_pressed = nil + if config.input and config.input.keys then + input_pressed = config.input.keys[scancode] + end + scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode}) end end +function love.keyreleased(key, scancode) + -- reserved keys, so the user can always get back to configure input + if scancode == "return" then + scene:onInputRelease({input="menu_decide", type="key", key=key, scancode=scancode}) + elseif scancode == "escape" then + scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode}) + elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then + scene:onInputRelease({input=scancode, type="key", key=key, scancode=scancode}) + -- other keys can be configured + else + local input_released = nil + if config.input and config.input.keys then + input_released = config.input.keys[scancode] + end + scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode}) + end +end + +function love.joystickpressed(joystick, button) + local input_pressed = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_pressed = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button}) +end + +function love.joystickreleased(joystick, button) + local input_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_released = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button}) +end + +function love.joystickaxis(joystick, axis, value) + local input_pressed = nil + local positive_released = nil + local negative_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].axes and + config.input.joysticks[joystick:getName()].axes[axis] + then + if math.abs(value) >= 0.5 then + input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"] + end + positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive + negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative + end + if math.abs(value) >= 0.5 then + scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + else + scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + end +end + +function love.joystickhat(joystick, hat, direction) + local input_pressed = nil + local has_hat = false + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].hats and + config.input.joysticks[joystick:getName()].hats[hat] + then + if direction ~= "c" then + input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction] + end + has_hat = true + end + if input_pressed then + scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + elseif has_hat then + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + elseif direction ~= "c" then + scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + else + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + end +end + function love.focus(f) if f then resumeBGM() diff --git a/scene.lua b/scene.lua index f2b7a51..809a2df 100644 --- a/scene.lua +++ b/scene.lua @@ -5,7 +5,8 @@ Scene = Object:extend() function Scene:new() end function Scene:update() end function Scene:render() end -function Scene:onKeyPress() end +function Scene:onInputPress() end +function Scene:onInputRelease() end ExitScene = require "scene.exit" GameScene = require "scene.game" diff --git a/scene/config.lua b/scene/config.lua index 630cf63..3de9d0b 100644 --- a/scene/config.lua +++ b/scene/config.lua @@ -17,7 +17,7 @@ function ConfigScene:changeOption(rel) self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1 end -function ConfigScene:onKeyPress(e) +function ConfigScene:onInputPress(e) end return ConfigScene diff --git a/scene/exit.lua b/scene/exit.lua index ba0f849..bd1fd16 100644 --- a/scene/exit.lua +++ b/scene/exit.lua @@ -16,7 +16,7 @@ end function ExitScene:changeOption(rel) end -function ExitScene:onKeyPress(e) +function ExitScene:onInputPress(e) end return ExitScene diff --git a/scene/game.lua b/scene/game.lua index 5f796c8..f896d60 100644 --- a/scene/game.lua +++ b/scene/game.lua @@ -2,9 +2,23 @@ local GameScene = Scene:extend() require 'load.save' function GameScene:new(game_mode, ruleset) + self.retry_mode = game_mode + self.retry_ruleset = ruleset self.game = game_mode() self.ruleset = ruleset() self.game:initialize(self.ruleset) + self.inputs = { + left=false, + right=false, + up=false, + down=false, + rotate_left=false, + rotate_left2=false, + rotate_right=false, + rotate_right2=false, + rotate_180=false, + hold=false, + } DiscordRPC:update({ details = self.game.rpc_details, state = self.game.name, @@ -13,18 +27,11 @@ end function GameScene:update() if love.window.hasFocus() then - self.game:update({ - left = love.keyboard.isScancodeDown(config.input.left), - right = love.keyboard.isScancodeDown(config.input.right), - up = love.keyboard.isScancodeDown(config.input.up), - down = love.keyboard.isScancodeDown(config.input.down), - rotate_left = love.keyboard.isScancodeDown(config.input.rotate_left), - rotate_left2 = love.keyboard.isScancodeDown(config.input.rotate_left2), - rotate_right = love.keyboard.isScancodeDown(config.input.rotate_right), - rotate_right2 = love.keyboard.isScancodeDown(config.input.rotate_right2), - rotate_180 = love.keyboard.isScancodeDown(config.input.rotate_180), - hold = love.keyboard.isScancodeDown(config.input.hold), - }, self.ruleset) + local inputs = {} + for input, value in pairs(self.inputs) do + inputs[input] = value + end + self.game:update(inputs, self.ruleset) end self.game.grid:update() @@ -59,24 +66,25 @@ function GameScene:render() end -function GameScene:onKeyPress(e) - if (self.game.completed) and - (e.scancode == "return" or e.scancode == "escape") and e.isRepeat == false then - highscore_entry = self.game:getHighscoreData() - highscore_hash = self.game.hash .. "-" .. self.ruleset.hash - submitHighscore(highscore_hash, highscore_entry) - scene = ModeSelectScene() - elseif (e.scancode == config.input.retry) then - -- fuck this, this is hacky but the way this codebase is setup prevents anything else - -- it seems like all the values that get touched in the child gamemode class - -- stop being linked to the values of the GameMode superclass because of how `mt.__index` works - -- not even sure this is the actual problem, but I don't want to have to rebuild everything about - -- the core organisation of everything. this hacky way will have to do until someone figures out something. - love.keypressed("escape", "escape", false) - love.keypressed("return", "return", false) - elseif e.scancode == "escape" then - scene = ModeSelectScene() - end +function GameScene:onInputPress(e) + if self.game.completed and (e.input == "menu_decide" or e.input == "menu_back") then + highscore_entry = self.game:getHighscoreData() + highscore_hash = self.game.hash .. "-" .. self.ruleset.hash + submitHighscore(highscore_hash, highscore_entry) + scene = ModeSelectScene() + elseif e.input == "retry" then + scene = GameScene(self.retry_mode, self.retry_ruleset) + elseif e.input == "menu_back" then + scene = ModeSelectScene() + elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = true + end +end + +function GameScene:onInputRelease(e) + if e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = false + end end function submitHighscore(hash, data) diff --git a/scene/game_config.lua b/scene/game_config.lua index 37c8a84..0fa2585 100644 --- a/scene/game_config.lua +++ b/scene/game_config.lua @@ -51,26 +51,26 @@ function ConfigScene:render() end end -function ConfigScene:onKeyPress(e) - if e.scancode == "return" and e.isRepeat == false then +function ConfigScene:onInputPress(e) + if e.input == "menu_decide" then playSE("mode_decide") saveConfig() scene = TitleScene() - elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then + elseif e.input == "up" then playSE("cursor") self.highlight = Mod1(self.highlight-1, optioncount) - elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then + elseif e.input == "down" then playSE("cursor") self.highlight = Mod1(self.highlight+1, optioncount) - elseif (e.scancode == config.input["left"] or e.scancode == "left") and e.isRepeat == false then + elseif e.input == "left" then playSE("cursor_lr") local option = ConfigScene.options[self.highlight] config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[3]) - elseif (e.scancode == config.input["right"] or e.scancode == "right") and e.isRepeat == false then + elseif e.input == "right" then playSE("cursor_lr") local option = ConfigScene.options[self.highlight] config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[3]) - elseif e.scancode == "escape" then + elseif e.input == "menu_back" then loadSave() scene = TitleScene() end diff --git a/scene/input_config.lua b/scene/input_config.lua index a16aa23..bcc4263 100644 --- a/scene/input_config.lua +++ b/scene/input_config.lua @@ -5,6 +5,8 @@ ConfigScene.title = "Input Config" require 'load.save' local configurable_inputs = { + "menu_decide", + "menu_back", "left", "right", "up", @@ -18,10 +20,18 @@ local configurable_inputs = { "retry", } +local function newSetInputs() + local set_inputs = {} + for i, input in ipairs(configurable_inputs) do + set_inputs[input] = false + end + return set_inputs +end + function ConfigScene:new() - -- load current config - self.config = config.input self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} DiscordRPC:update({ details = "In menus", @@ -41,40 +51,118 @@ function ConfigScene:render() ) love.graphics.setFont(font_3x5_2) - for i, input in pairs(configurable_inputs) do + for i, input in ipairs(configurable_inputs) do love.graphics.printf(input, 40, 50 + i * 20, 200, "left") - if config.input[input] then - love.graphics.printf( - love.keyboard.getKeyFromScancode(config.input[input]) .. " (" .. config.input[input] .. ")", - 240, 50 + i * 20, 200, "left" - ) - end - end + if self.set_inputs[input] then + love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left") + end + end if self.input_state > table.getn(configurable_inputs) then - love.graphics.print("press enter to confirm, delete to retry") + love.graphics.print("press return to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) else - love.graphics.print("press key for " .. configurable_inputs[self.input_state]) + love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0) + love.graphics.print("return, delete, backspace, tab, arrows, and escape can't be changed", 0, 20) end end -function ConfigScene:onKeyPress(e) - if self.input_state > table.getn(configurable_inputs) then - if e.scancode == "return" then - -- save, then load next scene - saveConfig() - scene = TitleScene() - elseif e.scancode == "delete" or e.scancode == "backspace" then - self.input_state = 1 - end - else - if e.scancode == "escape" then - loadSave() - scene = TitleScene() - else - config.input[configurable_inputs[self.input_state]] = e.scancode - self.input_state = self.input_state + 1 - end - end +local function addJoystick(input, name) + if not input.joysticks then + input.joysticks = {} + end + if not input.joysticks[name] then + input.joysticks[name] = {} + end +end + +function ConfigScene:onInputPress(e) + if e.type == "key" then + -- return, delete, backspace, tab, arrows, and escape are reserved and can't be remapped + if e.scancode == "escape" and config.input then + scene = TitleScene() + elseif self.input_state > table.getn(configurable_inputs) then + if e.scancode == "return" then + -- save new input, then load next scene + config.input = self.new_input + saveConfig() + scene = TitleScene() + elseif e.scancode == "delete" or e.scancode == "backspace" then + -- retry + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} + elseif e.scancode == "escape" and config.input then + -- cancel only if there was an input config already + scene = TitleScene() + end + elseif + e.scancode ~= "delete" and + e.scancode ~= "backspace" and + e.scancode ~= "return" and + e.scancode ~= "left" and + e.scancode ~= "right" and + e.scancode ~= "up" and + e.scancode ~= "down" + then + if e.scancode == "tab" then + self.set_inputs[configurable_inputs[self.input_state]] = "skipped" + self.input_state = self.input_state + 1 + else + if not self.new_input.keys then + self.new_input.keys = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" + self.new_input.keys[e.scancode] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end + elseif string.sub(e.type, 1, 3) == "joy" then + if self.input_state <= table.getn(configurable_inputs) then + if e.type == "joybutton" then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].buttons then + self.new_input.joysticks[e.name].buttons = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jbtn " .. + e.button .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + elseif e.type == "joyaxis" then + if math.abs(e.value) >= 0.5 then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].axes then + self.new_input.joysticks[e.name].axes = {} + end + if not self.new_input.joysticks[e.name].axes[e.axis] then + self.new_input.joysticks[e.name].axes[e.axis] = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jaxis " .. + (e.value >= 0.5 and "+" or "-") .. e.axis .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + elseif e.type == "joyhat" then + if e.direction ~= "c" then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].hats then + self.new_input.joysticks[e.name].hats = {} + end + if not self.new_input.joysticks[e.name].hats[e.hat] then + self.new_input.joysticks[e.name].hats[e.hat] = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jhat " .. + e.hat .. " " .. e.direction .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end + end + end end return ConfigScene diff --git a/scene/mode_select.lua b/scene/mode_select.lua index e810bd3..51ee21e 100755 --- a/scene/mode_select.lua +++ b/scene/mode_select.lua @@ -58,8 +58,8 @@ function ModeSelectScene:render() end end -function ModeSelectScene:onKeyPress(e) - if e.scancode == "return" and e.isRepeat == false then +function ModeSelectScene:onInputPress(e) + if e.input == "menu_decide" then current_mode = self.menu_state.mode current_ruleset = self.menu_state.ruleset config.current_mode = current_mode @@ -67,17 +67,16 @@ function ModeSelectScene:onKeyPress(e) playSE("mode_decide") saveConfig() scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset]) - elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then + elseif e.input == "up" then self:changeOption(-1) playSE("cursor") - elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then + elseif e.input == "down" then self:changeOption(1) playSE("cursor") - elseif (e.scancode == config.input["left"] or e.scancode == "left") or - (e.scancode == config.input["right"] or e.scancode == "right") then + elseif e.input == "left" or e.input == "right" then self:switchSelect() playSE("cursor_lr") - elseif e.scancode == "escape" then + elseif e.input == "menu_back" then scene = TitleScene() end end diff --git a/scene/title.lua b/scene/title.lua index a21ce24..b688eb7 100644 --- a/scene/title.lua +++ b/scene/title.lua @@ -57,17 +57,17 @@ function TitleScene:changeOption(rel) self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1 end -function TitleScene:onKeyPress(e) - if e.scancode == "return" and e.isRepeat == false then +function TitleScene:onInputPress(e) + if e.input == "menu_decide" then playSE("main_decide") scene = main_menu_screens[self.main_menu_state]() - elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then + elseif e.input == "up" then self:changeOption(-1) playSE("cursor") - elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then + elseif e.input == "down" then self:changeOption(1) playSE("cursor") - elseif e.scancode == "escape" and e.isRepeat == false then + elseif e.input == "menu_back" then love.event.quit() end end From 347937468629ac95e29fe319f0c7dac96fbb3bb4 Mon Sep 17 00:00:00 2001 From: nightmareci Date: Sun, 8 Nov 2020 13:06:29 -0800 Subject: [PATCH 2/3] Forgot that the code used "enter" instead of "return" in the input config scene before, so changed it back. --- scene/input_config.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scene/input_config.lua b/scene/input_config.lua index bcc4263..1b4ae0f 100644 --- a/scene/input_config.lua +++ b/scene/input_config.lua @@ -58,10 +58,10 @@ function ConfigScene:render() end end if self.input_state > table.getn(configurable_inputs) then - love.graphics.print("press return to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) + love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) else love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0) - love.graphics.print("return, delete, backspace, tab, arrows, and escape can't be changed", 0, 20) + love.graphics.print("enter, delete, backspace, tab, arrows, and escape can't be changed", 0, 20) end end @@ -76,7 +76,7 @@ end function ConfigScene:onInputPress(e) if e.type == "key" then - -- return, delete, backspace, tab, arrows, and escape are reserved and can't be remapped + -- enter, delete, backspace, tab, arrows, and escape are reserved and can't be remapped if e.scancode == "escape" and config.input then scene = TitleScene() elseif self.input_state > table.getn(configurable_inputs) then From 6834e92674fa99714b3b54771b367962c9756e68 Mon Sep 17 00:00:00 2001 From: nightmareci Date: Sun, 8 Nov 2020 13:19:01 -0800 Subject: [PATCH 3/3] Changed indentation to hard tabs. --- main.lua | 192 ++++++++++++++++++------------------ scene/game.lua | 66 ++++++------- scene/game_config.lua | 8 +- scene/input_config.lua | 216 ++++++++++++++++++++--------------------- scene/title.lua | 2 +- 5 files changed, 242 insertions(+), 242 deletions(-) diff --git a/main.lua b/main.lua index 4c390da..f683fe1 100644 --- a/main.lua +++ b/main.lua @@ -46,10 +46,10 @@ function love.load() end --sort mode/rule lists local function padnum(d) return ("%03d%s"):format(#d, d) end - table.sort(game_modes, function(a,b) - return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end) + table.sort(game_modes, function(a,b) + return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end) table.sort(rulesets, function(a,b) - return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end) + return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end) end @@ -114,120 +114,120 @@ function love.keypressed(key, scancode) if scancode == "f4" then config["fullscreen"] = not config["fullscreen"] love.window.setFullscreen(config["fullscreen"]) - -- reserved keys, so the user can always get back to configure input - elseif scancode == "return" then - scene:onInputPress({input="menu_decide", type="key", key=key, scancode=scancode}) - elseif scancode == "escape" then - scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode}) - elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then - scene:onInputPress({input=scancode, type="key", key=key, scancode=scancode}) - -- other keys can be configured + -- reserved keys, so the user can always get back to configure input + elseif scancode == "return" then + scene:onInputPress({input="menu_decide", type="key", key=key, scancode=scancode}) + elseif scancode == "escape" then + scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode}) + elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then + scene:onInputPress({input=scancode, type="key", key=key, scancode=scancode}) + -- other keys can be configured else - local input_pressed = nil - if config.input and config.input.keys then - input_pressed = config.input.keys[scancode] - end + local input_pressed = nil + if config.input and config.input.keys then + input_pressed = config.input.keys[scancode] + end scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode}) end end function love.keyreleased(key, scancode) - -- reserved keys, so the user can always get back to configure input - if scancode == "return" then - scene:onInputRelease({input="menu_decide", type="key", key=key, scancode=scancode}) - elseif scancode == "escape" then - scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode}) - elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then - scene:onInputRelease({input=scancode, type="key", key=key, scancode=scancode}) - -- other keys can be configured + -- reserved keys, so the user can always get back to configure input + if scancode == "return" then + scene:onInputRelease({input="menu_decide", type="key", key=key, scancode=scancode}) + elseif scancode == "escape" then + scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode}) + elseif scancode == "left" or scancode == "right" or scancode == "up" or scancode == "down" then + scene:onInputRelease({input=scancode, type="key", key=key, scancode=scancode}) + -- other keys can be configured else - local input_released = nil - if config.input and config.input.keys then - input_released = config.input.keys[scancode] - end + local input_released = nil + if config.input and config.input.keys then + input_released = config.input.keys[scancode] + end scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode}) end end function love.joystickpressed(joystick, button) - local input_pressed = nil - if - config.input and - config.input.joysticks and - config.input.joysticks[joystick:getName()] and - config.input.joysticks[joystick:getName()].buttons - then - input_pressed = config.input.joysticks[joystick:getName()].buttons[button] - end - scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button}) + local input_pressed = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_pressed = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button}) end function love.joystickreleased(joystick, button) - local input_released = nil - if - config.input and - config.input.joysticks and - config.input.joysticks[joystick:getName()] and - config.input.joysticks[joystick:getName()].buttons - then - input_released = config.input.joysticks[joystick:getName()].buttons[button] - end - scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button}) + local input_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_released = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button}) end function love.joystickaxis(joystick, axis, value) - local input_pressed = nil - local positive_released = nil - local negative_released = nil - if - config.input and - config.input.joysticks and - config.input.joysticks[joystick:getName()] and - config.input.joysticks[joystick:getName()].axes and - config.input.joysticks[joystick:getName()].axes[axis] - then - if math.abs(value) >= 0.5 then - input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"] - end - positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive - negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative - end - if math.abs(value) >= 0.5 then - scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) - else - scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) - scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) - end + local input_pressed = nil + local positive_released = nil + local negative_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].axes and + config.input.joysticks[joystick:getName()].axes[axis] + then + if math.abs(value) >= 0.5 then + input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"] + end + positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive + negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative + end + if math.abs(value) >= 0.5 then + scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + else + scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + end end function love.joystickhat(joystick, hat, direction) - local input_pressed = nil - local has_hat = false - if - config.input and - config.input.joysticks and - config.input.joysticks[joystick:getName()] and - config.input.joysticks[joystick:getName()].hats and - config.input.joysticks[joystick:getName()].hats[hat] - then - if direction ~= "c" then - input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction] - end - has_hat = true - end - if input_pressed then - scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) - elseif has_hat then - for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do - scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) - end - elseif direction ~= "c" then - scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) - else - for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do - scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) - end - end + local input_pressed = nil + local has_hat = false + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].hats and + config.input.joysticks[joystick:getName()].hats[hat] + then + if direction ~= "c" then + input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction] + end + has_hat = true + end + if input_pressed then + scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + elseif has_hat then + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + elseif direction ~= "c" then + scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + else + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + end end function love.focus(f) diff --git a/scene/game.lua b/scene/game.lua index f896d60..416045a 100644 --- a/scene/game.lua +++ b/scene/game.lua @@ -2,23 +2,23 @@ local GameScene = Scene:extend() require 'load.save' function GameScene:new(game_mode, ruleset) - self.retry_mode = game_mode - self.retry_ruleset = ruleset + self.retry_mode = game_mode + self.retry_ruleset = ruleset self.game = game_mode() self.ruleset = ruleset() self.game:initialize(self.ruleset) - self.inputs = { - left=false, - right=false, - up=false, - down=false, - rotate_left=false, - rotate_left2=false, - rotate_right=false, - rotate_right2=false, - rotate_180=false, - hold=false, - } + self.inputs = { + left=false, + right=false, + up=false, + down=false, + rotate_left=false, + rotate_left2=false, + rotate_right=false, + rotate_right2=false, + rotate_180=false, + hold=false, + } DiscordRPC:update({ details = self.game.rpc_details, state = self.game.name, @@ -27,10 +27,10 @@ end function GameScene:update() if love.window.hasFocus() then - local inputs = {} - for input, value in pairs(self.inputs) do - inputs[input] = value - end + local inputs = {} + for input, value in pairs(self.inputs) do + inputs[input] = value + end self.game:update(inputs, self.ruleset) end @@ -67,24 +67,24 @@ function GameScene:render() end function GameScene:onInputPress(e) - if self.game.completed and (e.input == "menu_decide" or e.input == "menu_back") then - highscore_entry = self.game:getHighscoreData() - highscore_hash = self.game.hash .. "-" .. self.ruleset.hash - submitHighscore(highscore_hash, highscore_entry) - scene = ModeSelectScene() - elseif e.input == "retry" then - scene = GameScene(self.retry_mode, self.retry_ruleset) - elseif e.input == "menu_back" then - scene = ModeSelectScene() - elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then - self.inputs[e.input] = true - end + if self.game.completed and (e.input == "menu_decide" or e.input == "menu_back") then + highscore_entry = self.game:getHighscoreData() + highscore_hash = self.game.hash .. "-" .. self.ruleset.hash + submitHighscore(highscore_hash, highscore_entry) + scene = ModeSelectScene() + elseif e.input == "retry" then + scene = GameScene(self.retry_mode, self.retry_ruleset) + elseif e.input == "menu_back" then + scene = ModeSelectScene() + elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = true + end end function GameScene:onInputRelease(e) - if e.input and string.sub(e.input, 1, 5) ~= "menu_" then - self.inputs[e.input] = false - end + if e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = false + end end function submitHighscore(hash, data) diff --git a/scene/game_config.lua b/scene/game_config.lua index 0fa2585..beef971 100644 --- a/scene/game_config.lua +++ b/scene/game_config.lua @@ -5,10 +5,10 @@ ConfigScene.title = "Game Settings" require 'load.save' ConfigScene.options = { - -- this serves as reference to what the options' values mean i guess? - {"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}}, - {"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}}, - {"world_reverse","World Reverse", {"No" ,"SRS only" ,"Always"}}, + -- this serves as reference to what the options' values mean i guess? + {"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}}, + {"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}}, + {"world_reverse","World Reverse", {"No" ,"SRS only" ,"Always"}}, } local optioncount = #ConfigScene.options diff --git a/scene/input_config.lua b/scene/input_config.lua index 1b4ae0f..16efcad 100644 --- a/scene/input_config.lua +++ b/scene/input_config.lua @@ -5,8 +5,8 @@ ConfigScene.title = "Input Config" require 'load.save' local configurable_inputs = { - "menu_decide", - "menu_back", + "menu_decide", + "menu_back", "left", "right", "up", @@ -21,17 +21,17 @@ local configurable_inputs = { } local function newSetInputs() - local set_inputs = {} - for i, input in ipairs(configurable_inputs) do - set_inputs[input] = false - end - return set_inputs + local set_inputs = {} + for i, input in ipairs(configurable_inputs) do + set_inputs[input] = false + end + return set_inputs end function ConfigScene:new() self.input_state = 1 - self.set_inputs = newSetInputs() - self.new_input = {} + self.set_inputs = newSetInputs() + self.new_input = {} DiscordRPC:update({ details = "In menus", @@ -53,116 +53,116 @@ function ConfigScene:render() love.graphics.setFont(font_3x5_2) for i, input in ipairs(configurable_inputs) do love.graphics.printf(input, 40, 50 + i * 20, 200, "left") - if self.set_inputs[input] then - love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left") - end - end + if self.set_inputs[input] then + love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left") + end + end if self.input_state > table.getn(configurable_inputs) then love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) else love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0) - love.graphics.print("enter, delete, backspace, tab, arrows, and escape can't be changed", 0, 20) + love.graphics.print("enter, delete, backspace, tab, arrows, and escape can't be changed", 0, 20) end end local function addJoystick(input, name) - if not input.joysticks then - input.joysticks = {} - end - if not input.joysticks[name] then - input.joysticks[name] = {} - end + if not input.joysticks then + input.joysticks = {} + end + if not input.joysticks[name] then + input.joysticks[name] = {} + end end function ConfigScene:onInputPress(e) - if e.type == "key" then - -- enter, delete, backspace, tab, arrows, and escape are reserved and can't be remapped - if e.scancode == "escape" and config.input then - scene = TitleScene() - elseif self.input_state > table.getn(configurable_inputs) then - if e.scancode == "return" then - -- save new input, then load next scene - config.input = self.new_input - saveConfig() - scene = TitleScene() - elseif e.scancode == "delete" or e.scancode == "backspace" then - -- retry - self.input_state = 1 - self.set_inputs = newSetInputs() - self.new_input = {} - elseif e.scancode == "escape" and config.input then - -- cancel only if there was an input config already - scene = TitleScene() - end - elseif - e.scancode ~= "delete" and - e.scancode ~= "backspace" and - e.scancode ~= "return" and - e.scancode ~= "left" and - e.scancode ~= "right" and - e.scancode ~= "up" and - e.scancode ~= "down" - then - if e.scancode == "tab" then - self.set_inputs[configurable_inputs[self.input_state]] = "skipped" - self.input_state = self.input_state + 1 - else - if not self.new_input.keys then - self.new_input.keys = {} - end - self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" - self.new_input.keys[e.scancode] = configurable_inputs[self.input_state] - self.input_state = self.input_state + 1 - end - end - elseif string.sub(e.type, 1, 3) == "joy" then - if self.input_state <= table.getn(configurable_inputs) then - if e.type == "joybutton" then - addJoystick(self.new_input, e.name) - if not self.new_input.joysticks[e.name].buttons then - self.new_input.joysticks[e.name].buttons = {} - end - self.set_inputs[configurable_inputs[self.input_state]] = - "jbtn " .. - e.button .. - " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") - self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state] - self.input_state = self.input_state + 1 - elseif e.type == "joyaxis" then - if math.abs(e.value) >= 0.5 then - addJoystick(self.new_input, e.name) - if not self.new_input.joysticks[e.name].axes then - self.new_input.joysticks[e.name].axes = {} - end - if not self.new_input.joysticks[e.name].axes[e.axis] then - self.new_input.joysticks[e.name].axes[e.axis] = {} - end - self.set_inputs[configurable_inputs[self.input_state]] = - "jaxis " .. - (e.value >= 0.5 and "+" or "-") .. e.axis .. - " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") - self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state] - self.input_state = self.input_state + 1 - end - elseif e.type == "joyhat" then - if e.direction ~= "c" then - addJoystick(self.new_input, e.name) - if not self.new_input.joysticks[e.name].hats then - self.new_input.joysticks[e.name].hats = {} - end - if not self.new_input.joysticks[e.name].hats[e.hat] then - self.new_input.joysticks[e.name].hats[e.hat] = {} - end - self.set_inputs[configurable_inputs[self.input_state]] = - "jhat " .. - e.hat .. " " .. e.direction .. - " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") - self.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state] - self.input_state = self.input_state + 1 - end - end - end - end + if e.type == "key" then + -- enter, delete, backspace, tab, arrows, and escape are reserved and can't be remapped + if e.scancode == "escape" and config.input then + scene = TitleScene() + elseif self.input_state > table.getn(configurable_inputs) then + if e.scancode == "return" then + -- save new input, then load next scene + config.input = self.new_input + saveConfig() + scene = TitleScene() + elseif e.scancode == "delete" or e.scancode == "backspace" then + -- retry + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} + elseif e.scancode == "escape" and config.input then + -- cancel only if there was an input config already + scene = TitleScene() + end + elseif + e.scancode ~= "delete" and + e.scancode ~= "backspace" and + e.scancode ~= "return" and + e.scancode ~= "left" and + e.scancode ~= "right" and + e.scancode ~= "up" and + e.scancode ~= "down" + then + if e.scancode == "tab" then + self.set_inputs[configurable_inputs[self.input_state]] = "skipped" + self.input_state = self.input_state + 1 + else + if not self.new_input.keys then + self.new_input.keys = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" + self.new_input.keys[e.scancode] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end + elseif string.sub(e.type, 1, 3) == "joy" then + if self.input_state <= table.getn(configurable_inputs) then + if e.type == "joybutton" then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].buttons then + self.new_input.joysticks[e.name].buttons = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jbtn " .. + e.button .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + elseif e.type == "joyaxis" then + if math.abs(e.value) >= 0.5 then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].axes then + self.new_input.joysticks[e.name].axes = {} + end + if not self.new_input.joysticks[e.name].axes[e.axis] then + self.new_input.joysticks[e.name].axes[e.axis] = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jaxis " .. + (e.value >= 0.5 and "+" or "-") .. e.axis .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + elseif e.type == "joyhat" then + if e.direction ~= "c" then + addJoystick(self.new_input, e.name) + if not self.new_input.joysticks[e.name].hats then + self.new_input.joysticks[e.name].hats = {} + end + if not self.new_input.joysticks[e.name].hats[e.hat] then + self.new_input.joysticks[e.name].hats[e.hat] = {} + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jhat " .. + e.hat .. " " .. e.direction .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end + end + end end return ConfigScene diff --git a/scene/title.lua b/scene/title.lua index b688eb7..0a7dc52 100644 --- a/scene/title.lua +++ b/scene/title.lua @@ -26,7 +26,7 @@ function TitleScene:new() self.main_menu_state = 1 DiscordRPC:update({ details = "In menus", - state = mainmenuidle[math.random(#mainmenuidle)], + state = mainmenuidle[math.random(#mainmenuidle)], }) end