input remapping + mouse control
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.claude
|
||||
.local
|
||||
impostor.lua
|
||||
impostor.original.lua
|
||||
@@ -5,4 +6,4 @@ prompts
|
||||
docs
|
||||
minify.lua
|
||||
*.tic
|
||||
*.zip
|
||||
*.zip
|
||||
|
||||
@@ -65,6 +65,10 @@ globals = {
|
||||
"map",
|
||||
"time",
|
||||
"RLE",
|
||||
"mouse",
|
||||
"Mouse",
|
||||
"print",
|
||||
"musicator_generate_pattern",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ init/init.context.lua
|
||||
system/system.util.lua
|
||||
system/system.print.lua
|
||||
system/system.input.lua
|
||||
system/system.mouse.lua
|
||||
system/system.asciiart.lua
|
||||
system/system.rle.lua
|
||||
logic/logic.meter.lua
|
||||
|
||||
@@ -134,6 +134,7 @@ end
|
||||
--- @param decisions table A table of decision items.<br/>
|
||||
--- @param selected_decision_index number The current index of the selected decision.<br/>
|
||||
--- @return number selected_decision_index The updated index of the selected decision.
|
||||
--- @return boolean mouse_confirmed True if the user clicked the center to confirm.
|
||||
function Decision.update(decisions, selected_decision_index)
|
||||
if Input.left() then
|
||||
Audio.sfx_beep()
|
||||
@@ -142,5 +143,27 @@ function Decision.update(decisions, selected_decision_index)
|
||||
Audio.sfx_beep()
|
||||
selected_decision_index = Util.safeindex(decisions, selected_decision_index + 1)
|
||||
end
|
||||
return selected_decision_index
|
||||
|
||||
if Mouse.clicked() then
|
||||
local mx = Mouse.x()
|
||||
local my = Mouse.y()
|
||||
local bar_height = 16
|
||||
local bar_y = Config.screen.height - bar_height
|
||||
if my >= bar_y then
|
||||
if mx < 15 then
|
||||
Audio.sfx_beep()
|
||||
Mouse.consume()
|
||||
selected_decision_index = Util.safeindex(decisions, selected_decision_index - 1)
|
||||
elseif mx > Config.screen.width - 15 then
|
||||
Audio.sfx_beep()
|
||||
Mouse.consume()
|
||||
selected_decision_index = Util.safeindex(decisions, selected_decision_index + 1)
|
||||
else
|
||||
Mouse.consume()
|
||||
return selected_decision_index, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return selected_decision_index, false
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ Map = {}
|
||||
UI = {}
|
||||
Print = {}
|
||||
Input = {}
|
||||
Mouse = {}
|
||||
Sprite = {}
|
||||
Audio = {}
|
||||
Focus = {}
|
||||
|
||||
@@ -240,9 +240,12 @@ Screen.register({
|
||||
end
|
||||
end
|
||||
elseif state == STATE_CHOICE then
|
||||
selected_choice = UI.update_menu(MysteriousManScreen.choices, selected_choice)
|
||||
local menu_x = (Config.screen.width - 60) / 2
|
||||
local menu_y = (Config.screen.height - 20) / 2
|
||||
local confirmed
|
||||
selected_choice, confirmed = UI.update_menu(MysteriousManScreen.choices, selected_choice, menu_x, menu_y)
|
||||
|
||||
if Input.select() then
|
||||
if Input.select() or confirmed then
|
||||
Audio.sfx_select()
|
||||
if selected_choice == 1 then
|
||||
MysteriousManScreen.wake_up()
|
||||
|
||||
@@ -16,7 +16,7 @@ Screen.register({
|
||||
end,
|
||||
update = function()
|
||||
if not Context.stat_screen_active then return end
|
||||
if Input.select() or Input.player_interact() then
|
||||
if Input.select() or Input.select() then
|
||||
Focus.stop()
|
||||
Context.stat_screen_active = false
|
||||
Meter.show()
|
||||
|
||||
@@ -3,12 +3,9 @@ local INPUT_KEY_UP = 0
|
||||
local INPUT_KEY_DOWN = 1
|
||||
local INPUT_KEY_LEFT = 2
|
||||
local INPUT_KEY_RIGHT = 3
|
||||
local INPUT_KEY_A = 4
|
||||
local INPUT_KEY_B = 5
|
||||
local INPUT_KEY_Y = 7
|
||||
local INPUT_KEY_SPACE = 48
|
||||
local INPUT_KEY_BACKSPACE = 51
|
||||
local INPUT_KEY_ENTER = 50
|
||||
|
||||
--- Checks if Up is pressed.
|
||||
--- @within Input
|
||||
@@ -22,22 +19,9 @@ function Input.left() return btnp(INPUT_KEY_LEFT) end
|
||||
--- Checks if Right is pressed.
|
||||
--- @within Input
|
||||
function Input.right() return btnp(INPUT_KEY_RIGHT) end
|
||||
--- Checks if Space is pressed.
|
||||
--- @within Input
|
||||
function Input.space() return keyp(INPUT_KEY_SPACE) end
|
||||
|
||||
--- Checks if Select is pressed.
|
||||
--- @within Input
|
||||
function Input.select() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_SPACE) end
|
||||
--- Checks if Menu Confirm is pressed.
|
||||
function Input.select() return btnp(INPUT_KEY_Y) or keyp(INPUT_KEY_SPACE) or Mouse.clicked() end
|
||||
--- Checks if Back is pressed.
|
||||
--- @within Input
|
||||
function Input.menu_confirm() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_ENTER) end
|
||||
--- Checks if Player Interact is pressed.
|
||||
--- @within Input
|
||||
function Input.player_interact() return btnp(INPUT_KEY_B) or keyp(INPUT_KEY_ENTER) end
|
||||
--- Checks if Menu Back is pressed.
|
||||
--- @within Input
|
||||
function Input.menu_back() return btnp(INPUT_KEY_Y) or keyp(INPUT_KEY_BACKSPACE) end
|
||||
--- Checks if Toggle Popup is pressed.
|
||||
--- @within Input
|
||||
function Input.toggle_popup() return keyp(INPUT_KEY_ENTER) end
|
||||
function Input.back() return keyp(INPUT_KEY_BACKSPACE) end
|
||||
|
||||
@@ -17,6 +17,7 @@ end
|
||||
--- @within Main
|
||||
function TIC()
|
||||
init_game()
|
||||
Mouse.update()
|
||||
|
||||
local now = time()
|
||||
if Context.last_frame_time == 0 then
|
||||
|
||||
43
inc/system/system.mouse.lua
Normal file
43
inc/system/system.mouse.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--- @section Mouse
|
||||
local _mx, _my = 0, 0
|
||||
local _mleft, _mleft_prev = false, false
|
||||
local _consumed = false
|
||||
|
||||
--- Updates mouse state. Call once per frame.
|
||||
--- @within Mouse
|
||||
function Mouse.update()
|
||||
_mleft_prev = _mleft
|
||||
_consumed = false
|
||||
local mt = {mouse()}
|
||||
_mx, _my, _mleft = mt[1], mt[2], mt[3]
|
||||
end
|
||||
|
||||
--- Returns current mouse X position.
|
||||
--- @within Mouse
|
||||
function Mouse.x() return _mx end
|
||||
|
||||
--- Returns current mouse Y position.
|
||||
--- @within Mouse
|
||||
function Mouse.y() return _my end
|
||||
|
||||
--- Returns true if the mouse button was just pressed this frame (and not yet consumed).
|
||||
--- @within Mouse
|
||||
function Mouse.clicked() return _mleft and not _mleft_prev and not _consumed end
|
||||
|
||||
--- Returns true if the mouse button is held down.
|
||||
--- @within Mouse
|
||||
function Mouse.held() return _mleft end
|
||||
|
||||
--- Marks the current click as consumed so Mouse.clicked() won't fire again this frame.
|
||||
--- @within Mouse
|
||||
function Mouse.consume() _consumed = true end
|
||||
|
||||
--- Returns true if the mouse is within the given rectangle.
|
||||
--- @within Mouse
|
||||
--- @param x number Left edge.
|
||||
--- @param y number Top edge.
|
||||
--- @param w number Width.
|
||||
--- @param h number Height.
|
||||
function Mouse.in_rect(x, y, w, h)
|
||||
return _mx >= x and _mx < x + w and _my >= y and _my < y + h
|
||||
end
|
||||
@@ -38,8 +38,12 @@ end
|
||||
--- @within UI
|
||||
--- @param items table A table of menu items.<br/>
|
||||
--- @param selected_item number The current index of the selected item.<br/>
|
||||
--- @param[opt] x number Menu x position (required for mouse support).<br/>
|
||||
--- @param[opt] y number Menu y position (required for mouse support).<br/>
|
||||
--- @param[opt] centered boolean Whether the menu is centered horizontally.<br/>
|
||||
--- @return number selected_item The updated index of the selected item.
|
||||
function UI.update_menu(items, selected_item)
|
||||
--- @return boolean mouse_confirmed True if the user clicked on a menu item.
|
||||
function UI.update_menu(items, selected_item, x, y, centered)
|
||||
if Input.up() then
|
||||
Audio.sfx_beep()
|
||||
selected_item = selected_item - 1
|
||||
@@ -53,7 +57,29 @@ function UI.update_menu(items, selected_item)
|
||||
selected_item = 1
|
||||
end
|
||||
end
|
||||
return selected_item
|
||||
|
||||
if x ~= nil and y ~= nil and Mouse.clicked() then
|
||||
local mx = Mouse.x()
|
||||
local my = Mouse.y()
|
||||
local menu_x = x
|
||||
if centered then
|
||||
local max_w = 0
|
||||
for _, item in ipairs(items) do
|
||||
local w = print(item.label, 0, -10, 0, false, 1, false)
|
||||
if w > max_w then max_w = w end
|
||||
end
|
||||
menu_x = (Config.screen.width - max_w) / 2
|
||||
end
|
||||
for i, _ in ipairs(items) do
|
||||
local item_y = y + (i - 1) * 10
|
||||
if my >= item_y and my < item_y + 10 and mx >= menu_x - 8 then
|
||||
Mouse.consume()
|
||||
return i, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return selected_item, false
|
||||
end
|
||||
|
||||
--- Draws a bordered textbox with scrolling text.
|
||||
|
||||
@@ -107,9 +107,9 @@ function AudioTestWindow.update()
|
||||
AudioTestWindow.menuitems = AudioTestWindow.generate_menuitems(
|
||||
AudioTestWindow.list_func, AudioTestWindow.index_func
|
||||
)
|
||||
elseif Input.menu_confirm() then
|
||||
elseif Input.select() then
|
||||
AudioTestWindow.menuitems[AudioTestWindow.index_menu].decision()
|
||||
elseif Input.menu_back() then
|
||||
elseif Input.back() then
|
||||
AudioTestWindow.back()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -65,7 +65,7 @@ end
|
||||
--- Updates configuration window logic.
|
||||
--- @within ConfigurationWindow
|
||||
function ConfigurationWindow.update()
|
||||
if Input.menu_back() then
|
||||
if Input.back() then
|
||||
GameWindow.set_state("menu")
|
||||
return
|
||||
end
|
||||
@@ -94,7 +94,7 @@ function ConfigurationWindow.update()
|
||||
control.set(new_value)
|
||||
end
|
||||
elseif control.type == "action_item" then
|
||||
if Input.menu_confirm() then
|
||||
if Input.select() then
|
||||
control.action()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,7 +26,7 @@ end
|
||||
--- @within ContinuedWindow
|
||||
function ContinuedWindow.update()
|
||||
ContinuedWindow.timer = ContinuedWindow.timer - 1
|
||||
if ContinuedWindow.timer <= 0 or Input.select() or Input.menu_confirm() then
|
||||
if ContinuedWindow.timer <= 0 or Input.select() or Input.select() then
|
||||
Window.set_current("menu")
|
||||
MenuWindow.refresh_menu_items()
|
||||
end
|
||||
|
||||
@@ -52,7 +52,7 @@ function EndWindow.update()
|
||||
end
|
||||
end
|
||||
|
||||
if Input.menu_confirm() then
|
||||
if Input.select() then
|
||||
Audio.sfx_select()
|
||||
if Context._end.selection == 1 then
|
||||
Context._end.state = "ending"
|
||||
@@ -69,7 +69,7 @@ function EndWindow.update()
|
||||
end
|
||||
end
|
||||
elseif Context._end.state == "ending" then
|
||||
if Input.menu_confirm() then
|
||||
if Input.select() then
|
||||
Window.set_current("menu")
|
||||
MenuWindow.refresh_menu_items()
|
||||
end
|
||||
|
||||
@@ -38,7 +38,7 @@ end
|
||||
--- @within GameWindow
|
||||
function GameWindow.update()
|
||||
Focus.update()
|
||||
if Input.menu_back() then
|
||||
if Input.back() then
|
||||
Window.set_current("menu")
|
||||
MenuWindow.refresh_menu_items()
|
||||
return
|
||||
@@ -60,7 +60,7 @@ function GameWindow.update()
|
||||
_selected_decision_index = 1
|
||||
end
|
||||
|
||||
local new_selected_decision_index = Decision.update(
|
||||
local new_selected_decision_index, mouse_confirmed = Decision.update(
|
||||
_available_decisions,
|
||||
_selected_decision_index
|
||||
)
|
||||
@@ -69,7 +69,7 @@ function GameWindow.update()
|
||||
_selected_decision_index = new_selected_decision_index
|
||||
end
|
||||
|
||||
if Input.select() then
|
||||
if Input.select() or mouse_confirmed then
|
||||
local selected_decision = _available_decisions[_selected_decision_index]
|
||||
if selected_decision and selected_decision.handle then
|
||||
Audio.sfx_select()
|
||||
|
||||
@@ -31,7 +31,7 @@ function BriefIntroWindow.update()
|
||||
lines = lines + 1
|
||||
end
|
||||
|
||||
if BriefIntroWindow.y < -lines * 8 or Input.select() or Input.menu_confirm() then
|
||||
if BriefIntroWindow.y < -lines * 8 or Input.select() or Input.select() then
|
||||
Window.set_current("menu")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ end
|
||||
--- @within TitleIntroWindow
|
||||
function TitleIntroWindow.update()
|
||||
TitleIntroWindow.timer = TitleIntroWindow.timer - 1
|
||||
if TitleIntroWindow.timer <= 0 or Input.select() or Input.menu_confirm() then
|
||||
if TitleIntroWindow.timer <= 0 or Input.select() or Input.select() then
|
||||
Window.set_current("intro_ttg")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -28,12 +28,12 @@ function TTGIntroWindow.update()
|
||||
end
|
||||
|
||||
-- Count menu_back presses during the intro
|
||||
if Input.menu_back() then
|
||||
if Input.back() then
|
||||
TTGIntroWindow.space_count = TTGIntroWindow.space_count + 1
|
||||
end
|
||||
|
||||
TTGIntroWindow.timer = TTGIntroWindow.timer - 1
|
||||
if TTGIntroWindow.timer <= 0 or Input.menu_confirm() then
|
||||
if TTGIntroWindow.timer <= 0 or Input.select() then
|
||||
-- Evaluate exactly 3 presses at the end of the intro
|
||||
if TTGIntroWindow.space_count == 3 then
|
||||
Context.test_mode = true
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
--- @section MenuWindow
|
||||
local _menu_items = {}
|
||||
local _click_timer = 0
|
||||
|
||||
--- Draws the menu window.
|
||||
--- @within MenuWindow
|
||||
@@ -22,9 +23,28 @@ end
|
||||
--- Updates the menu window logic.
|
||||
--- @within MenuWindow
|
||||
function MenuWindow.update()
|
||||
Context.current_menu_item = UI.update_menu(_menu_items, Context.current_menu_item)
|
||||
local menu_h = #_menu_items * 10
|
||||
local y = 10 + (Config.screen.height - 10 - 10 - menu_h) / 2
|
||||
|
||||
if Input.menu_confirm() then
|
||||
if _click_timer > 0 then
|
||||
_click_timer = _click_timer - Context.delta_time
|
||||
if _click_timer <= 0 then
|
||||
_click_timer = 0
|
||||
local selected_item = _menu_items[Context.current_menu_item]
|
||||
if selected_item and selected_item.decision then
|
||||
selected_item.decision()
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local new_item, mouse_confirmed = UI.update_menu(_menu_items, Context.current_menu_item, 0, y, true)
|
||||
Context.current_menu_item = new_item
|
||||
|
||||
if mouse_confirmed then
|
||||
Audio.sfx_select()
|
||||
_click_timer = 0.5
|
||||
elseif Input.select() then
|
||||
local selected_item = _menu_items[Context.current_menu_item]
|
||||
if selected_item and selected_item.decision then
|
||||
Audio.sfx_select()
|
||||
@@ -115,4 +135,5 @@ function MenuWindow.refresh_menu_items()
|
||||
table.insert(_menu_items, {label = "Exit", decision = MenuWindow.exit})
|
||||
|
||||
Context.current_menu_item = 1
|
||||
_click_timer = 0
|
||||
end
|
||||
|
||||
@@ -355,6 +355,17 @@ function MinigameDDRWindow.update()
|
||||
right = Input.right()
|
||||
}
|
||||
|
||||
if Mouse.clicked() then
|
||||
local mx = Mouse.x()
|
||||
local my = Mouse.y()
|
||||
for _, target in ipairs(mg.target_arrows) do
|
||||
if mx >= target.x and mx < target.x + mg.arrow_size and
|
||||
my >= mg.target_y and my < mg.target_y + mg.arrow_size then
|
||||
input_map[target.dir] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for dir, pressed in pairs(input_map) do
|
||||
if pressed and mg.input_cooldowns[dir] == 0 then
|
||||
mg.input_cooldowns[dir] = mg.input_cooldown_duration
|
||||
|
||||
@@ -83,7 +83,14 @@ function MinigameButtonMashWindow.update()
|
||||
return
|
||||
end
|
||||
|
||||
if Input.select() then
|
||||
local mouse_on_button = false
|
||||
if Mouse.clicked() then
|
||||
local dx = Mouse.x() - mg.button_x
|
||||
local dy = Mouse.y() - mg.button_y
|
||||
mouse_on_button = (dx * dx + dy * dy) <= (mg.button_size * mg.button_size)
|
||||
end
|
||||
|
||||
if Input.select() or mouse_on_button then
|
||||
Audio.sfx_drum_high()
|
||||
|
||||
mg.bar_fill = mg.bar_fill + mg.fill_per_press
|
||||
|
||||
@@ -95,7 +95,14 @@ function MinigameRhythmWindow.update()
|
||||
if mg.press_cooldown > 0 then
|
||||
mg.press_cooldown = mg.press_cooldown - 1
|
||||
end
|
||||
if Input.select() and mg.press_cooldown == 0 then
|
||||
local mouse_on_button = false
|
||||
if Mouse.clicked() then
|
||||
local dx = Mouse.x() - mg.button_x
|
||||
local dy = Mouse.y() - mg.button_y
|
||||
mouse_on_button = (dx * dx + dy * dy) <= (mg.button_size * mg.button_size)
|
||||
end
|
||||
|
||||
if (Input.select() or mouse_on_button) and mg.press_cooldown == 0 then
|
||||
mg.button_pressed_timer = mg.button_press_duration
|
||||
mg.press_cooldown = mg.press_cooldown_duration
|
||||
local target_left = mg.target_center - (mg.target_width / 2)
|
||||
|
||||
@@ -28,7 +28,7 @@ end
|
||||
--- @within PopupWindow
|
||||
function PopupWindow.update()
|
||||
if Context.popup.show then
|
||||
if Input.menu_confirm() or Input.menu_back() then
|
||||
if Input.select() or Input.back() then
|
||||
PopupWindow.hide()
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user