From c751da37ac460a61fd065bfef5b4a77d3c64fe65 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Sun, 14 Apr 2024 17:56:55 -0700 Subject: [PATCH 01/16] Reworking control input prompt icons to be based on button/key name instead of virtual button name. Adding new icons. --- .../Sprites/Controls/Nintendo Switch/Down.png | Bin 0 -> 525 bytes .../Nintendo Switch/{confirm.png => East.png} | Bin .../Sprites/Controls/Nintendo Switch/Left.png | Bin 0 -> 514 bytes .../{copyfile.png => LeftShoulder.png} | Bin .../Controls/Nintendo Switch/LeftStick.png | Bin 0 -> 668 bytes .../Controls/Nintendo Switch/LeftTrigger.png | Bin 0 -> 394 bytes .../Controls/Nintendo Switch/LeftX.png | Bin 0 -> 675 bytes .../Controls/Nintendo Switch/LeftY.png | Bin 0 -> 741 bytes .../{createfile.png => North.png} | Bin .../Controls/Nintendo Switch/Right.png | Bin 0 -> 507 bytes .../{deletefile.png => RightShoulder.png} | Bin .../Controls/Nintendo Switch/RightStick.png | Bin 0 -> 694 bytes .../Controls/Nintendo Switch/RightTrigger.png | Bin 0 -> 435 bytes .../Controls/Nintendo Switch/RightX.png | Bin 0 -> 708 bytes .../Controls/Nintendo Switch/RightY.png | Bin 0 -> 778 bytes .../Controls/Nintendo Switch/Select.png | Bin 0 -> 445 bytes .../Nintendo Switch/{cancel.png => South.png} | Bin .../Controls/Nintendo Switch/Start.png | Bin 0 -> 451 bytes .../Sprites/Controls/Nintendo Switch/Up.png | Bin 0 -> 519 bytes .../Sprites/Controls/Nintendo Switch/West.png | Bin 0 -> 515 bytes .../Controls/Nintendo Switch/pause.png | Bin 746 -> 0 bytes Content/Sprites/Controls/PC/A.png | Bin 0 -> 398 bytes Content/Sprites/Controls/PC/Apostrophe.png | Bin 0 -> 270 bytes Content/Sprites/Controls/PC/B.png | Bin 0 -> 347 bytes Content/Sprites/Controls/PC/Backslash.png | Bin 0 -> 373 bytes Content/Sprites/Controls/PC/Backspace.png | Bin 0 -> 304 bytes Content/Sprites/Controls/PC/C.png | Bin 0 -> 396 bytes Content/Sprites/Controls/PC/Capslock.png | Bin 0 -> 307 bytes Content/Sprites/Controls/PC/Comma.png | Bin 0 -> 303 bytes Content/Sprites/Controls/PC/Command.png | Bin 0 -> 466 bytes Content/Sprites/Controls/PC/D.png | Bin 0 -> 367 bytes Content/Sprites/Controls/PC/D0.png | Bin 0 -> 382 bytes Content/Sprites/Controls/PC/D1.png | Bin 0 -> 274 bytes Content/Sprites/Controls/PC/D2.png | Bin 0 -> 358 bytes Content/Sprites/Controls/PC/D3.png | Bin 0 -> 371 bytes Content/Sprites/Controls/PC/D4.png | Bin 0 -> 276 bytes Content/Sprites/Controls/PC/D5.png | Bin 0 -> 342 bytes Content/Sprites/Controls/PC/D6.png | Bin 0 -> 380 bytes Content/Sprites/Controls/PC/D7.png | Bin 0 -> 352 bytes Content/Sprites/Controls/PC/D8.png | Bin 0 -> 368 bytes Content/Sprites/Controls/PC/D9.png | Bin 0 -> 384 bytes Content/Sprites/Controls/PC/Delete.png | Bin 0 -> 339 bytes Content/Sprites/Controls/PC/Down.png | Bin 0 -> 307 bytes Content/Sprites/Controls/PC/E.png | Bin 0 -> 262 bytes Content/Sprites/Controls/PC/End.png | Bin 0 -> 377 bytes Content/Sprites/Controls/PC/Enter.png | Bin 0 -> 378 bytes Content/Sprites/Controls/PC/Equals.png | Bin 0 -> 258 bytes Content/Sprites/Controls/PC/Escape.png | Bin 0 -> 385 bytes Content/Sprites/Controls/PC/Exclamation.png | Bin 0 -> 281 bytes Content/Sprites/Controls/PC/F.png | Bin 0 -> 262 bytes Content/Sprites/Controls/PC/F1.png | Bin 0 -> 290 bytes Content/Sprites/Controls/PC/F10.png | Bin 0 -> 387 bytes Content/Sprites/Controls/PC/F11.png | Bin 0 -> 302 bytes Content/Sprites/Controls/PC/F12.png | Bin 0 -> 373 bytes Content/Sprites/Controls/PC/F2.png | Bin 0 -> 366 bytes Content/Sprites/Controls/PC/F3.png | Bin 0 -> 379 bytes Content/Sprites/Controls/PC/F4.png | Bin 0 -> 291 bytes Content/Sprites/Controls/PC/F5.png | Bin 0 -> 350 bytes Content/Sprites/Controls/PC/F6.png | Bin 0 -> 389 bytes Content/Sprites/Controls/PC/F7.png | Bin 0 -> 356 bytes Content/Sprites/Controls/PC/F8.png | Bin 0 -> 379 bytes Content/Sprites/Controls/PC/F9.png | Bin 0 -> 396 bytes Content/Sprites/Controls/PC/Function.png | Bin 0 -> 346 bytes Content/Sprites/Controls/PC/G.png | Bin 0 -> 414 bytes Content/Sprites/Controls/PC/H.png | Bin 0 -> 258 bytes Content/Sprites/Controls/PC/Home.png | Bin 0 -> 382 bytes Content/Sprites/Controls/PC/I.png | Bin 0 -> 255 bytes Content/Sprites/Controls/PC/Insert.png | Bin 0 -> 380 bytes Content/Sprites/Controls/PC/J.png | Bin 0 -> 313 bytes Content/Sprites/Controls/PC/K.png | Bin 0 -> 372 bytes Content/Sprites/Controls/PC/Keypad0.png | Bin 0 -> 382 bytes Content/Sprites/Controls/PC/Keypad1.png | Bin 0 -> 274 bytes Content/Sprites/Controls/PC/Keypad2.png | Bin 0 -> 358 bytes Content/Sprites/Controls/PC/Keypad3.png | Bin 0 -> 371 bytes Content/Sprites/Controls/PC/Keypad4.png | Bin 0 -> 276 bytes Content/Sprites/Controls/PC/Keypad5.png | Bin 0 -> 342 bytes Content/Sprites/Controls/PC/Keypad6.png | Bin 0 -> 380 bytes Content/Sprites/Controls/PC/Keypad7.png | Bin 0 -> 352 bytes Content/Sprites/Controls/PC/Keypad8.png | Bin 0 -> 368 bytes Content/Sprites/Controls/PC/Keypad9.png | Bin 0 -> 384 bytes Content/Sprites/Controls/PC/KeypadColon.png | Bin 0 -> 269 bytes Content/Sprites/Controls/PC/KeypadGreater.png | Bin 0 -> 337 bytes Content/Sprites/Controls/PC/KeypadLess.png | Bin 0 -> 337 bytes Content/Sprites/Controls/PC/KeypadPlus.png | Bin 0 -> 265 bytes Content/Sprites/Controls/PC/KeypadPower.png | Bin 0 -> 331 bytes Content/Sprites/Controls/PC/L.png | Bin 0 -> 258 bytes Content/Sprites/Controls/PC/Left.png | Bin 0 -> 315 bytes Content/Sprites/Controls/PC/LeftAlt.png | Bin 0 -> 320 bytes Content/Sprites/Controls/PC/LeftBracket.png | Bin 0 -> 273 bytes Content/Sprites/Controls/PC/LeftControl.png | Bin 0 -> 379 bytes Content/Sprites/Controls/PC/LeftShift.png | Bin 0 -> 363 bytes Content/Sprites/Controls/PC/M.png | Bin 0 -> 370 bytes Content/Sprites/Controls/PC/Minus.png | Bin 0 -> 257 bytes Content/Sprites/Controls/PC/Mouse/mouse.png | Bin 0 -> 435 bytes .../Controls/PC/Mouse/mouse_horizontal.png | Bin 0 -> 428 bytes .../Sprites/Controls/PC/Mouse/mouse_left.png | Bin 0 -> 492 bytes .../Sprites/Controls/PC/Mouse/mouse_move.png | Bin 0 -> 494 bytes .../Sprites/Controls/PC/Mouse/mouse_right.png | Bin 0 -> 474 bytes .../Controls/PC/Mouse/mouse_scroll.png | Bin 0 -> 487 bytes .../Controls/PC/Mouse/mouse_scroll_down.png | Bin 0 -> 562 bytes .../Controls/PC/Mouse/mouse_scroll_up.png | Bin 0 -> 533 bytes .../PC/Mouse/mouse_scroll_vertical.png | Bin 0 -> 605 bytes .../Sprites/Controls/PC/Mouse/mouse_small.png | Bin 0 -> 365 bytes .../Controls/PC/Mouse/mouse_vertical.png | Bin 0 -> 429 bytes Content/Sprites/Controls/PC/N.png | Bin 0 -> 332 bytes Content/Sprites/Controls/PC/Numlock.png | Bin 0 -> 438 bytes Content/Sprites/Controls/PC/O.png | Bin 0 -> 405 bytes Content/Sprites/Controls/PC/Option.png | Bin 0 -> 349 bytes Content/Sprites/Controls/PC/P.png | Bin 0 -> 347 bytes Content/Sprites/Controls/PC/PageDown.png | Bin 0 -> 476 bytes Content/Sprites/Controls/PC/PageUp.png | Bin 0 -> 417 bytes Content/Sprites/Controls/PC/Period.png | Bin 0 -> 270 bytes Content/Sprites/Controls/PC/PrintScreen.png | Bin 0 -> 457 bytes Content/Sprites/Controls/PC/Question.png | Bin 0 -> 378 bytes Content/Sprites/Controls/PC/Quote.png | Bin 0 -> 269 bytes Content/Sprites/Controls/PC/Return.png | Bin 0 -> 341 bytes Content/Sprites/Controls/PC/Right.png | Bin 0 -> 313 bytes Content/Sprites/Controls/PC/RightAlt.png | Bin 0 -> 320 bytes Content/Sprites/Controls/PC/RightBracket.png | Bin 0 -> 274 bytes Content/Sprites/Controls/PC/RightControl.png | Bin 0 -> 379 bytes Content/Sprites/Controls/PC/RightShift.png | Bin 0 -> 363 bytes Content/Sprites/Controls/PC/Semicolon.png | Bin 0 -> 295 bytes Content/Sprites/Controls/PC/Slash.png | Bin 0 -> 366 bytes Content/Sprites/Controls/PC/Space.png | Bin 0 -> 415 bytes Content/Sprites/Controls/PC/Tab.png | Bin 0 -> 353 bytes Content/Sprites/Controls/PC/Tilde.png | Bin 0 -> 341 bytes Content/Sprites/Controls/PC/Up.png | Bin 0 -> 307 bytes Content/Sprites/Controls/PC/cancel.png | Bin 2480 -> 0 bytes Content/Sprites/Controls/PC/confirm.png | Bin 2330 -> 0 bytes Content/Sprites/Controls/PC/copyfile.png | Bin 2438 -> 0 bytes Content/Sprites/Controls/PC/createfile.png | Bin 2440 -> 0 bytes Content/Sprites/Controls/PC/deletefile.png | Bin 2319 -> 0 bytes Content/Sprites/Controls/PC/pause.png | Bin 1644 -> 0 bytes Content/Sprites/Controls/PC/q.png | Bin 0 -> 393 bytes Content/Sprites/Controls/PC/r.png | Bin 0 -> 360 bytes Content/Sprites/Controls/PC/s.png | Bin 0 -> 405 bytes Content/Sprites/Controls/PC/t.png | Bin 0 -> 261 bytes Content/Sprites/Controls/PC/u.png | Bin 0 -> 338 bytes Content/Sprites/Controls/PC/v.png | Bin 0 -> 395 bytes Content/Sprites/Controls/PC/w.png | Bin 0 -> 401 bytes Content/Sprites/Controls/PC/x.png | Bin 0 -> 429 bytes Content/Sprites/Controls/PC/y.png | Bin 0 -> 370 bytes Content/Sprites/Controls/PC/z.png | Bin 0 -> 345 bytes .../Controls/PlayStation 4/copyfile.png | Bin 384 -> 0 bytes .../Controls/PlayStation 4/deletefile.png | Bin 445 -> 0 bytes .../Sprites/Controls/PlayStation 4/pause.png | Bin 617 -> 0 bytes .../Sprites/Controls/PlayStation 5/cancel.png | Bin 569 -> 0 bytes .../Controls/PlayStation 5/confirm.png | Bin 554 -> 0 bytes .../Controls/PlayStation 5/copyfile.png | Bin 384 -> 0 bytes .../Controls/PlayStation 5/createfile.png | Bin 561 -> 0 bytes .../Controls/PlayStation 5/deletefile.png | Bin 445 -> 0 bytes .../Sprites/Controls/PlayStation 5/pause.png | Bin 475 -> 0 bytes Content/Sprites/Controls/PlayStation/Down.png | Bin 0 -> 417 bytes .../cancel.png => PlayStation/East.png} | Bin Content/Sprites/Controls/PlayStation/Left.png | Bin 0 -> 438 bytes .../Controls/PlayStation/LeftShoulder.png | Bin 0 -> 328 bytes .../Controls/PlayStation/LeftStick.png | Bin 0 -> 668 bytes .../Controls/PlayStation/LeftTrigger.png | Bin 0 -> 410 bytes .../Sprites/Controls/PlayStation/LeftX.png | Bin 0 -> 675 bytes .../Sprites/Controls/PlayStation/LeftY.png | Bin 0 -> 741 bytes .../createfile.png => PlayStation/North.png} | Bin .../Controls/PlayStation/PS3_Select.png | Bin 0 -> 381 bytes .../Controls/PlayStation/PS3_Start.png | Bin 0 -> 420 bytes .../Controls/PlayStation/PS4_Select.png | Bin 0 -> 419 bytes .../Controls/PlayStation/PS4_Start.png | Bin 0 -> 431 bytes .../Controls/PlayStation/RIghtTrigger.png | Bin 0 -> 471 bytes .../Sprites/Controls/PlayStation/RIghtX.png | Bin 0 -> 708 bytes .../Sprites/Controls/PlayStation/Right.png | Bin 0 -> 439 bytes .../Controls/PlayStation/RightShoulder.png | Bin 0 -> 403 bytes .../Controls/PlayStation/RightStick.png | Bin 0 -> 694 bytes .../Sprites/Controls/PlayStation/RightY.png | Bin 0 -> 778 bytes .../Sprites/Controls/PlayStation/Select.png | Bin 0 -> 433 bytes .../confirm.png => PlayStation/South.png} | Bin .../Sprites/Controls/PlayStation/Start.png | Bin 0 -> 374 bytes Content/Sprites/Controls/PlayStation/Up.png | Bin 0 -> 427 bytes Content/Sprites/Controls/PlayStation/West.png | Bin 0 -> 453 bytes Content/Sprites/Controls/Xbox Series/Down.png | Bin 0 -> 268 bytes .../Xbox Series/{cancel.png => East.png} | Bin Content/Sprites/Controls/Xbox Series/Left.png | Bin 0 -> 273 bytes .../{copyfile.png => LeftShoulder.png} | Bin .../Controls/Xbox Series/LeftStick.png | Bin 0 -> 668 bytes .../Controls/Xbox Series/LeftTrigger.png | Bin 0 -> 350 bytes .../Sprites/Controls/Xbox Series/LeftX.png | Bin 0 -> 675 bytes .../Sprites/Controls/Xbox Series/LeftY.png | Bin 0 -> 741 bytes .../Xbox Series/{createfile.png => North.png} | Bin .../Sprites/Controls/Xbox Series/Right.png | Bin 0 -> 273 bytes .../{deletefile.png => RightShoulder.png} | Bin .../Controls/Xbox Series/RightStick.png | Bin 0 -> 694 bytes .../Controls/Xbox Series/RightTrigger.png | Bin 0 -> 413 bytes .../Sprites/Controls/Xbox Series/RightX.png | Bin 0 -> 708 bytes .../Sprites/Controls/Xbox Series/RightY.png | Bin 0 -> 778 bytes .../Sprites/Controls/Xbox Series/Select.png | Bin 0 -> 485 bytes .../Xbox Series/{confirm.png => South.png} | Bin .../Sprites/Controls/Xbox Series/Start.png | Bin 0 -> 447 bytes Content/Sprites/Controls/Xbox Series/Up.png | Bin 0 -> 272 bytes Content/Sprites/Controls/Xbox Series/West.png | Bin 0 -> 560 bytes .../Sprites/Controls/Xbox Series/pause.png | Bin 725 -> 0 bytes Source/Data/Controls.cs | 50 +++++++++--------- .../ControlsConfigBinding_V01.cs | 26 +++++++++ 199 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 Content/Sprites/Controls/Nintendo Switch/Down.png rename Content/Sprites/Controls/Nintendo Switch/{confirm.png => East.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/Left.png rename Content/Sprites/Controls/Nintendo Switch/{copyfile.png => LeftShoulder.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftStick.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftTrigger.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftX.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftY.png rename Content/Sprites/Controls/Nintendo Switch/{createfile.png => North.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/Right.png rename Content/Sprites/Controls/Nintendo Switch/{deletefile.png => RightShoulder.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightStick.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightTrigger.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightX.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightY.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/Select.png rename Content/Sprites/Controls/Nintendo Switch/{cancel.png => South.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/Start.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/Up.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/West.png delete mode 100644 Content/Sprites/Controls/Nintendo Switch/pause.png create mode 100644 Content/Sprites/Controls/PC/A.png create mode 100644 Content/Sprites/Controls/PC/Apostrophe.png create mode 100644 Content/Sprites/Controls/PC/B.png create mode 100644 Content/Sprites/Controls/PC/Backslash.png create mode 100644 Content/Sprites/Controls/PC/Backspace.png create mode 100644 Content/Sprites/Controls/PC/C.png create mode 100644 Content/Sprites/Controls/PC/Capslock.png create mode 100644 Content/Sprites/Controls/PC/Comma.png create mode 100644 Content/Sprites/Controls/PC/Command.png create mode 100644 Content/Sprites/Controls/PC/D.png create mode 100644 Content/Sprites/Controls/PC/D0.png create mode 100644 Content/Sprites/Controls/PC/D1.png create mode 100644 Content/Sprites/Controls/PC/D2.png create mode 100644 Content/Sprites/Controls/PC/D3.png create mode 100644 Content/Sprites/Controls/PC/D4.png create mode 100644 Content/Sprites/Controls/PC/D5.png create mode 100644 Content/Sprites/Controls/PC/D6.png create mode 100644 Content/Sprites/Controls/PC/D7.png create mode 100644 Content/Sprites/Controls/PC/D8.png create mode 100644 Content/Sprites/Controls/PC/D9.png create mode 100644 Content/Sprites/Controls/PC/Delete.png create mode 100644 Content/Sprites/Controls/PC/Down.png create mode 100644 Content/Sprites/Controls/PC/E.png create mode 100644 Content/Sprites/Controls/PC/End.png create mode 100644 Content/Sprites/Controls/PC/Enter.png create mode 100644 Content/Sprites/Controls/PC/Equals.png create mode 100644 Content/Sprites/Controls/PC/Escape.png create mode 100644 Content/Sprites/Controls/PC/Exclamation.png create mode 100644 Content/Sprites/Controls/PC/F.png create mode 100644 Content/Sprites/Controls/PC/F1.png create mode 100644 Content/Sprites/Controls/PC/F10.png create mode 100644 Content/Sprites/Controls/PC/F11.png create mode 100644 Content/Sprites/Controls/PC/F12.png create mode 100644 Content/Sprites/Controls/PC/F2.png create mode 100644 Content/Sprites/Controls/PC/F3.png create mode 100644 Content/Sprites/Controls/PC/F4.png create mode 100644 Content/Sprites/Controls/PC/F5.png create mode 100644 Content/Sprites/Controls/PC/F6.png create mode 100644 Content/Sprites/Controls/PC/F7.png create mode 100644 Content/Sprites/Controls/PC/F8.png create mode 100644 Content/Sprites/Controls/PC/F9.png create mode 100644 Content/Sprites/Controls/PC/Function.png create mode 100644 Content/Sprites/Controls/PC/G.png create mode 100644 Content/Sprites/Controls/PC/H.png create mode 100644 Content/Sprites/Controls/PC/Home.png create mode 100644 Content/Sprites/Controls/PC/I.png create mode 100644 Content/Sprites/Controls/PC/Insert.png create mode 100644 Content/Sprites/Controls/PC/J.png create mode 100644 Content/Sprites/Controls/PC/K.png create mode 100644 Content/Sprites/Controls/PC/Keypad0.png create mode 100644 Content/Sprites/Controls/PC/Keypad1.png create mode 100644 Content/Sprites/Controls/PC/Keypad2.png create mode 100644 Content/Sprites/Controls/PC/Keypad3.png create mode 100644 Content/Sprites/Controls/PC/Keypad4.png create mode 100644 Content/Sprites/Controls/PC/Keypad5.png create mode 100644 Content/Sprites/Controls/PC/Keypad6.png create mode 100644 Content/Sprites/Controls/PC/Keypad7.png create mode 100644 Content/Sprites/Controls/PC/Keypad8.png create mode 100644 Content/Sprites/Controls/PC/Keypad9.png create mode 100644 Content/Sprites/Controls/PC/KeypadColon.png create mode 100644 Content/Sprites/Controls/PC/KeypadGreater.png create mode 100644 Content/Sprites/Controls/PC/KeypadLess.png create mode 100644 Content/Sprites/Controls/PC/KeypadPlus.png create mode 100644 Content/Sprites/Controls/PC/KeypadPower.png create mode 100644 Content/Sprites/Controls/PC/L.png create mode 100644 Content/Sprites/Controls/PC/Left.png create mode 100644 Content/Sprites/Controls/PC/LeftAlt.png create mode 100644 Content/Sprites/Controls/PC/LeftBracket.png create mode 100644 Content/Sprites/Controls/PC/LeftControl.png create mode 100644 Content/Sprites/Controls/PC/LeftShift.png create mode 100644 Content/Sprites/Controls/PC/M.png create mode 100644 Content/Sprites/Controls/PC/Minus.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_horizontal.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_left.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_move.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_right.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll_down.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll_up.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll_vertical.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_small.png create mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_vertical.png create mode 100644 Content/Sprites/Controls/PC/N.png create mode 100644 Content/Sprites/Controls/PC/Numlock.png create mode 100644 Content/Sprites/Controls/PC/O.png create mode 100644 Content/Sprites/Controls/PC/Option.png create mode 100644 Content/Sprites/Controls/PC/P.png create mode 100644 Content/Sprites/Controls/PC/PageDown.png create mode 100644 Content/Sprites/Controls/PC/PageUp.png create mode 100644 Content/Sprites/Controls/PC/Period.png create mode 100644 Content/Sprites/Controls/PC/PrintScreen.png create mode 100644 Content/Sprites/Controls/PC/Question.png create mode 100644 Content/Sprites/Controls/PC/Quote.png create mode 100644 Content/Sprites/Controls/PC/Return.png create mode 100644 Content/Sprites/Controls/PC/Right.png create mode 100644 Content/Sprites/Controls/PC/RightAlt.png create mode 100644 Content/Sprites/Controls/PC/RightBracket.png create mode 100644 Content/Sprites/Controls/PC/RightControl.png create mode 100644 Content/Sprites/Controls/PC/RightShift.png create mode 100644 Content/Sprites/Controls/PC/Semicolon.png create mode 100644 Content/Sprites/Controls/PC/Slash.png create mode 100644 Content/Sprites/Controls/PC/Space.png create mode 100644 Content/Sprites/Controls/PC/Tab.png create mode 100644 Content/Sprites/Controls/PC/Tilde.png create mode 100644 Content/Sprites/Controls/PC/Up.png delete mode 100644 Content/Sprites/Controls/PC/cancel.png delete mode 100644 Content/Sprites/Controls/PC/confirm.png delete mode 100644 Content/Sprites/Controls/PC/copyfile.png delete mode 100644 Content/Sprites/Controls/PC/createfile.png delete mode 100644 Content/Sprites/Controls/PC/deletefile.png delete mode 100644 Content/Sprites/Controls/PC/pause.png create mode 100644 Content/Sprites/Controls/PC/q.png create mode 100644 Content/Sprites/Controls/PC/r.png create mode 100644 Content/Sprites/Controls/PC/s.png create mode 100644 Content/Sprites/Controls/PC/t.png create mode 100644 Content/Sprites/Controls/PC/u.png create mode 100644 Content/Sprites/Controls/PC/v.png create mode 100644 Content/Sprites/Controls/PC/w.png create mode 100644 Content/Sprites/Controls/PC/x.png create mode 100644 Content/Sprites/Controls/PC/y.png create mode 100644 Content/Sprites/Controls/PC/z.png delete mode 100644 Content/Sprites/Controls/PlayStation 4/copyfile.png delete mode 100644 Content/Sprites/Controls/PlayStation 4/deletefile.png delete mode 100644 Content/Sprites/Controls/PlayStation 4/pause.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/cancel.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/confirm.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/copyfile.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/createfile.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/deletefile.png delete mode 100644 Content/Sprites/Controls/PlayStation 5/pause.png create mode 100644 Content/Sprites/Controls/PlayStation/Down.png rename Content/Sprites/Controls/{PlayStation 4/cancel.png => PlayStation/East.png} (100%) create mode 100644 Content/Sprites/Controls/PlayStation/Left.png create mode 100644 Content/Sprites/Controls/PlayStation/LeftShoulder.png create mode 100644 Content/Sprites/Controls/PlayStation/LeftStick.png create mode 100644 Content/Sprites/Controls/PlayStation/LeftTrigger.png create mode 100644 Content/Sprites/Controls/PlayStation/LeftX.png create mode 100644 Content/Sprites/Controls/PlayStation/LeftY.png rename Content/Sprites/Controls/{PlayStation 4/createfile.png => PlayStation/North.png} (100%) create mode 100644 Content/Sprites/Controls/PlayStation/PS3_Select.png create mode 100644 Content/Sprites/Controls/PlayStation/PS3_Start.png create mode 100644 Content/Sprites/Controls/PlayStation/PS4_Select.png create mode 100644 Content/Sprites/Controls/PlayStation/PS4_Start.png create mode 100644 Content/Sprites/Controls/PlayStation/RIghtTrigger.png create mode 100644 Content/Sprites/Controls/PlayStation/RIghtX.png create mode 100644 Content/Sprites/Controls/PlayStation/Right.png create mode 100644 Content/Sprites/Controls/PlayStation/RightShoulder.png create mode 100644 Content/Sprites/Controls/PlayStation/RightStick.png create mode 100644 Content/Sprites/Controls/PlayStation/RightY.png create mode 100644 Content/Sprites/Controls/PlayStation/Select.png rename Content/Sprites/Controls/{PlayStation 4/confirm.png => PlayStation/South.png} (100%) create mode 100644 Content/Sprites/Controls/PlayStation/Start.png create mode 100644 Content/Sprites/Controls/PlayStation/Up.png create mode 100644 Content/Sprites/Controls/PlayStation/West.png create mode 100644 Content/Sprites/Controls/Xbox Series/Down.png rename Content/Sprites/Controls/Xbox Series/{cancel.png => East.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/Left.png rename Content/Sprites/Controls/Xbox Series/{copyfile.png => LeftShoulder.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/LeftStick.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftTrigger.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftX.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftY.png rename Content/Sprites/Controls/Xbox Series/{createfile.png => North.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/Right.png rename Content/Sprites/Controls/Xbox Series/{deletefile.png => RightShoulder.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/RightStick.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightTrigger.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightX.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightY.png create mode 100644 Content/Sprites/Controls/Xbox Series/Select.png rename Content/Sprites/Controls/Xbox Series/{confirm.png => South.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/Start.png create mode 100644 Content/Sprites/Controls/Xbox Series/Up.png create mode 100644 Content/Sprites/Controls/Xbox Series/West.png delete mode 100644 Content/Sprites/Controls/Xbox Series/pause.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Down.png b/Content/Sprites/Controls/Nintendo Switch/Down.png new file mode 100644 index 0000000000000000000000000000000000000000..970817efbf50c4e04f6ca49477f37a08d7e456a5 GIT binary patch literal 525 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS&)=`Nm!GfS|DJz+{C);a)^FMj42+qcE{-7)hu==W zna8Zi<2qCEjrX7b@wblC#0L@f|1YE+j1WomdaT>H1r;lx{$DX8xzO5eioLFNTw5oY#Qnv zCDS++8Us4nD+Eq&Zct!n;ajldz*jCec}AI5`G%_uI;<{V0{W)SbvBjbJh0)k$935@ zhF4+@i()tzY(5>naQ+LHhUOzj8Q$Mu(8-KDx{5*L?oE@MjK?h8E-?A=SZr_DlQVzG z)n{Lg`%JyLd+m~Eynpzjkzq#Vf#p9xG^R;CJO92$-8r#JS9h8E=G8`)Hb)9B2lQP( zq?n`8_gcF3*@pn_G|^Y<6N>k4+Z=oIr1h-F?A}x7t>1icTI%!9Ia^M)eKwfadu(2T z+EEQ&u8kUQ=@VCYDygkr$-|fZSEtPvII(k{DSlS&)>I~ub;2KzW+Uc{Cucha-!rBJb07ZNYZX6b7vq2F2hs2DpE~Q!Xm`7C z;@LQcj#`CR6FFC83V2Or&Pbi0mCJ8&Ea*6&z%jQ(-i+kc+n5Zlop0e*5aV0m!WD2f z;baKY1omJ__8$kQxihA)_g-szv-Fnu2MgmG-vV1q7~N z�^bWp5cKfl^^e=q}sufl&@{RL(WGkj0%Iz5rSnww#EHUFz{?sftDP@FB2972#sY(EtPvII(k{DSTC{pZKu?_V#kf4=@b|9%D^&)C@v42(ZKT^vIq4!@oL za@`sQo`#Ew?MmmTOo4yvH_Dzt?ou24yjA4t(`c3w0xIu4BK_SA-2CY;V?V< zn#9|V&zn`=Wead>tgYPtKT~NUuPH~vQr>QP=0B6-4pccX zyyx??6QA_CbgUpNG$9d$guC@hs?+%xBG zP)Kb3ge2bO+kA7@ufLoSxbKywdc(1@S=@8YY)?Mz6^Pb;%W!e?qWhZj&QB@59^uWn z%Zh8I^`pGzS!a`u*1UCOobddEs#-bub!w>*56woPw0)1_nD@7606R1OLy!$fy;hp;dXJYRE`L6A^g1K$A z@vk4V+L`0-2-nLu9J{!eA%XqWD)Z^NS5=d)sJm@1H3;>;%yzF{f5II*9rgS9%k&fU b{xfW7fAhMw`mHK3eK2^s`njxgN@xNAHAX&u literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftTrigger.png b/Content/Sprites/Controls/Nintendo Switch/LeftTrigger.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8a4f632d11f10d468c91f27b0d9c2590332ee0 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@K^Y7cQf6sqjUO#?*|9*z;X*Ik+xo4g(jv*0;-(J7X z*Q_AG5|FVr*iBz$V?J`7WnW8yHWRDwq@B4%ys-3uMZo4@#M(5P~`A? zqTVHLMqv#>eMT|Ymp(QL&(G8q>0AglQ)ahFI>a!|pyB>}_A@<nU}|J!72#^>W{u`_*v{y8mzCjl9REjc#SMDDFRoy|_xpKPg4zA5Rg7`J zzXQo#$$LW?zLjh`%~+kcJn4Yz+c2IZpOzopr0PDiBH2?qr literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftX.png b/Content/Sprites/Controls/Nintendo Switch/LeftX.png new file mode 100644 index 0000000000000000000000000000000000000000..7d3ea538a3e48f38b833b1b14d550f95b96b9734 GIT binary patch literal 675 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+ux7R?_V!p&wu{C{(gp&T8jJ(42=IhT^vIq4!@oL zdedSBo`$tb+f}Z7ufG+V*Tk}B_vYfXb0+&mPKFmPzx-Q1^%ql}se`}UPK{GOza$;j zZ-`|H`)imGCas4S;S9&bbA=|s0bI}4Dhrn}W#|cc{rGSwbpOZ3!-p@jW`wBW-%jL%}CH5fU#c_o+^M0^&sXIQuVAj2wCamF9p z8G0B3>q?Uww6D7qEz&S~BB9W2TG(c|^P{K4#8WO^E#bJkyFytlN@@2SIzSwhSW zf2MsopY-Wu#L`smj+5akMUlPLmNTzJ+>AP6S}vQO&vv?JtzC^tgvLxYJ=>FKugmg2 zxUn&*?A+{>Q<^2uBb2{P%h;zJ`Yu&f^-MQohR@;U>*pU6D^j4ze%F;)X z?p+(3LqY>(4v5WT4>VlS!*wH0VkMWo`P^vp_%`jF?M#awN*zD!F=y}2g)=tp`}sax zCZ3&p{l1R=^_4ac4%&Wv&bUVYE;ECn?8@Nhb5EO@Hb%U-nR|DZ*6M>dp8pqrcE|3? hpTFn7u=YIVFJARlPlU7O7BHDGc)I$ztaD0e0swj6Lqq@o literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftY.png b/Content/Sprites/Controls/Nintendo Switch/LeftY.png new file mode 100644 index 0000000000000000000000000000000000000000..b7277227c3b12c8dd1d5ce607353453ba78503bd GIT binary patch literal 741 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB-PAT^vIq4!@m# zbKPSFp0-S<8w>aRzdWx+HaX+c;)@we9xe*?{(E%BeeaXMr+5EJY`EC;hb>{w_j5J; z8_vw{zM0P$_H)COzkCzkUTFs<5!;%@l^g@*$zF`bovLLxZ`5mVdy)=WfSt^qh<^) zMFDFWwPb^M8nUl5aI+NDreFHaQE{Jn&vb^3Y#sd#xx6=~HE6TVUtcKLEW6`Fp80C# z-y#bf?IjpirRj2YSO!@Ou^e#{5Ec>*Iwh!mG3E?wXjO=ZVSBLd60VhOndiT3-OAvU zlBIoLa!38Gtu_1k8!9#}yC+$>HsnGVs8 z&u=fCVVm=QrS0ZR%{4o}Em62I=QyMDv}!%}F8-@O)|m8JxH&j&6@PYZg6O9OLS44E z^ZP4rw%b1U4R_9CQfdtSeY|0o;VpaCj=l}1x)0S9j{o=4uKw}zh57ucyv?GyVd`mz xw@uwUWohld`o<@br*ogY|NHhg{||Ep`*{IxN~_NBM*$NWgQu&X%Q~loCIEa}U@QOt literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/createfile.png b/Content/Sprites/Controls/Nintendo Switch/North.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/createfile.png rename to Content/Sprites/Controls/Nintendo Switch/North.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Right.png b/Content/Sprites/Controls/Nintendo Switch/Right.png new file mode 100644 index 0000000000000000000000000000000000000000..304a73ee14c7e0b267d153434022ed79a20d5d33 GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS&)>I~uh*a7zn=en{C)hzUf?7o#TtH1iURiELL`| zyhzLXXGHmzq?4C^oLRd~t9$*OtjW61Gi{}NZ5R4<1xkse1ooU$N}Sx{6BaBfbLm;6 z-JNaw4Q9#bPcmU!9z5eM^IawRsNMG;eYZV#=t literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/deletefile.png b/Content/Sprites/Controls/Nintendo Switch/RightShoulder.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/deletefile.png rename to Content/Sprites/Controls/Nintendo Switch/RightShoulder.png diff --git a/Content/Sprites/Controls/Nintendo Switch/RightStick.png b/Content/Sprites/Controls/Nintendo Switch/RightStick.png new file mode 100644 index 0000000000000000000000000000000000000000..bdeaf51fa6bb30feb966d0cd3f96b68f1526a4f6 GIT binary patch literal 694 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSBE+vmsM?_V#kUw{5R|9*zjO)S<73`|0vE{-7)hu=;Q z?|W>(*kUoym65SHi9clrD+i0iuUR`-Wb6(cvWQrqS9>5$^wg?Tp4UVZybqX} zF6CMvn^k>vQA3RKy(SwCvnOs7xP^R|1S!kuKUbc&)+j;gsgz!Bb@_*Vp^M$k84`BR zz2=m@e4fawfR8s9@-S>lb>4q@(X%PswQEG#zxHi9EBkS6^S)U}XC1%U#JJ$rhsgW+ z$=->+SLfViP1`2Bo9WWE-S<_J+NT8vA7IGhn3pQ-+#gt&WqRw2NL`NA_KTY(*4;W9 zJ@ftiYwhRz^DS2LS=7zl+&{n4;=w`dkKY+r$RB2Am=@q?Uzw9F z&=ER6V(+!RGplBq{`>jAb?-KQ^>6R%m+3!<`p394`1Rj_!-Z17l*8cZ>gTe~DWM4f D`y5Os literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/RightTrigger.png b/Content/Sprites/Controls/Nintendo Switch/RightTrigger.png new file mode 100644 index 0000000000000000000000000000000000000000..e871088a2c390e5d5f1d0329db589661e4bb7f88 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@K^Y8Q9zdtV@zkYuIetm`_`T8^l21b5Q7srr@!*8#9 z^R+1OFa)qpwEy;R`CLI+(ZxX-K535AZ|zfH?7HjHvyPFsf;r$!1%LLBe2cYS4RU%- z)~&2EcUt&091hgZU}U_(&fqqe-NMFgKC6Q8G_HnaOyW+825d?UMG8z0RxoI2C9FJ< z$syXXm}w4|!vdxrt{E~0sR9114@wmxi&-4b^?#YB-=fL<=oqhOT|AS{*W_96KRVb{ zO{7Q)J-}TVmad~Z?zk$VpdB2{_i`g*c z>(xWtQ>zne7jJtP&AH(%QxNBgNv&UGwl^HVdVjvhxEtPvII(k{DS@G$J^iU&zE0c&wu{?etm|{eOo#i7?>11T^vIq4!@oL za@`sQo(9>J_*L)!Zwa61Bv^3r}k7EEn~gZ0=31?Lb+;R`4%jR z_J6dbif6{xTcWo1Ob!w4LJ!0eT94n2nXNMG@htIgYz^D8!`^P;Ia@THp*rXBrESNe zD(5)g=5Da*tJFAS*_UQDh41r|shrXWSH`KBbU!Rj|9g!6;QKzd>uv|$M;~n8$lr2% z-=eZwLykvj968Tt&wasYcia6_aJ=2|_jdMz4ZSagMyD)4f|OtJbhPe`@xd%<@$x`I{xRxEyovNz{yYVk Pju<>${an^LB{Ts5(vnVO literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/RightY.png b/Content/Sprites/Controls/Nintendo Switch/RightY.png new file mode 100644 index 0000000000000000000000000000000000000000..95d07d35fd3a4b0fb3c7d30195d3c9c15f45fc67 GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB%irH$e||o{{(FX{lc(h~FfgTgx;TbJ9DY0f z=DNoUJPw|Rq^5oPA76dA@8FWm^=^wNwzYe;{y1WG&na$y%oBd*HPfD$GrZnY{;j$} z@L$xS8g7H-{jW{#Gj{#4eaIH@RR54U!`t0U?b$W>r~P6{xcT*QduguWZ;k}LyOzrs z_v;wGXKatwl$r3Zg56`?;YIo`s*n6Q42-O0nKzWEot2v4?Ed*jyN2%4;-D;7-}Z(? zSG7v_U@5ByE^e!v6&icKxqt57_17x1wB;D1$tm_`2EJI0i-4>F8`++N-WL4FMdS&355>zUr{+hnKlpq25?wb>7Trw2A1nR7!g zXdmkvj)rY}|B4CJG{h#SGw%O-kTLYcZX4Ff;0F;*CU4j)%d;Sn%O zzGBLR427pMhFoWl1_exYXV!dLu&(us%c{n=wyV?~zW8K6ZEtuqscG8#e$ELxuV2j# z)e%=aXl8fiZdl-n8$L(hIwT#vkt5yk-8FgRHoJMt7Dd(87sbq(@3CI(g-hW~$3}71 zx6OZIzOcUAB_X4=`?b;CkD=L{*GaRrX=E_msN}rX=zP*dVcMa$K|Xak?|0gE-)gSe z`%T8txp*EsPw4xdQd8nqeT>YMD_kSP=^J;;-8t+`v)hVKk1A}QiOTj(GM5s&>E7TX z;QKGx;k3kCdsYvJ8@s1{5D54qf9aILewn}5Hg6J5c8$K;d38gs2v2IN-Tyd+)N4i7 jKda~0{%8Ep_JCc==ymhmyIMTJ)X3oJ>gTe~DWM4fJIrx( literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/Select.png b/Content/Sprites/Controls/Nintendo Switch/Select.png new file mode 100644 index 0000000000000000000000000000000000000000..31b5c644379e32955af1149989cb10f7459ad8af GIT binary patch literal 445 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S&)>J#=dYKa|Gt0y{&!qye4^%2%JYAR+r|B-(SdsP4|5(g{a^`tKKYf+@nd~Ch zB~4~$2;VXB(Ub#|c23@t!O(TbcS&->)5L4a3LhK~NhsLy^fDa%TfLAe<_g2buMMe5 zq05#stAwd-Wjz1thnm0_hYZF8OxwH-eh9Caf5<*T@PO9=LlN}`X|_8o6ATr&7bG|c z9{85^o+0<|GbS^KBMm=(>xbg=;5 zX*~1QeqUU6r{jin?yiS>q|dXhR9`zO=|Gc`R@XtTNjjd3QUpT^W|`(2Jl3gQl<{xR zwuGcT)mUzba@6u<_cQPHJzyM_MboFyt=akR{0M^je AcmMzZ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/cancel.png b/Content/Sprites/Controls/Nintendo Switch/South.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/cancel.png rename to Content/Sprites/Controls/Nintendo Switch/South.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Start.png b/Content/Sprites/Controls/Nintendo Switch/Start.png new file mode 100644 index 0000000000000000000000000000000000000000..c4476c0d0c42fa329a3d7a81a5c0c17595ef45b7 GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS@7tf(ub1b4Kfizd{&@{`^j1s;wzJ49QOxA{B&tnHqIR(%5R~wj}ZKh6^ z_4t(V^4h^mTQ9P0`?{dl>~=w&#QB54{!1na&0%c~o$_F{#~zi9lUmm`DPP;OLcjk< z=c1pVXN&AUH%TV-_o1?j`uBGAf327IKKj}IGN(^5tMBYjch&Rk{eZ#9;OXk;vd$@? F2>^ND(>VYD literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/Up.png b/Content/Sprites/Controls/Nintendo Switch/Up.png new file mode 100644 index 0000000000000000000000000000000000000000..86129c7d36d87bcc814a93f013894e50c5131383 GIT binary patch literal 519 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS@7tf(ubi7#Nd1T^vIq4!@m# zyXde2kBi~-0^yeb|8H%(>=P8tJ?+v=yOKTYXEZw~tUdd8x{>&UdgdbEzY9Y)i%pm; zYkhNyXu}2e0DdP2?c_z5R2saJwN^cExE=ATjIHCbOCj%y$04Px0%z=n${HMm7+NJ4 z{8XHjFYF-Yq{?%`c?}PvMzh_4YDqx`R)_iCJ4-pzDw($5bYNoOHv2GFWJUuXKY zv7}VCAwt|DuZfXkd1Y8`=3KY_sE+vMhI)PiF>NOpc5_HGncR^7knCi;=IGbtU6%to zT3B5J!r~d0Gg^d%?5?S6552ip_`tf2A}{|KW#=Apxv*yI$yuKl+DiA@I;tJj;N{w^ z;g&vehi4N1{#87DTPn-!?q1t(Fe|=Xs7m&|NLqDr;1u8N@7XoS9wzVoH&gFGko=-4 WAIo(otDFT!1%s!npUXO@geCwOMC#lC literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/West.png b/Content/Sprites/Controls/Nintendo Switch/West.png new file mode 100644 index 0000000000000000000000000000000000000000..737632d430e900dc55644e6a382345bb80581d39 GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S?eELi_pg7ie}4ab{&)tpH+iNE42IE--pT!8KjS>7zhMgbtUoq< za?Jj~=CF<@WV6r)_jelaq!?7+X8pWNczjZXV-4Fia)5Rzn}Ye#)pq( z-VSbgKY!&o%AIB^NdDqhIqz5Jd2_~&3;DlimA$yA!65ouH~q~;Ee7S|O8wdl>oXTg zEoZdhW!GKBWWy&c&MDh)+@G%@g?Y(O!#>7O60>OMkDP^MOg99_Re`{a=Mcnc8<;e!GryLd7Hg|?=$+aE+Z`0+LUi^B#gt6@x!-c3% V4q^4rY=P0h;OXk;vd$@?2>>1K_dfst literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/pause.png b/Content/Sprites/Controls/Nintendo Switch/pause.png deleted file mode 100644 index 67c6b5b015f318b309122231db46d93830372d7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 746 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0)I(FK~#8N?V62I z!!Qhm8y28U08CIeUgC zV(IzCb(4$?!!QiPFmke9uV>iau}PU@oABZN1O-shDR{-U&!;UPBzyavb{@(V0?D1! zIcDdTyG%mGF$yI0gm6^vb;dzeRd3u5W`|=iG$aUJ7f-Cv^^DuWL^*(q-!=<4;hfuQ zf(0m~_=YJ&xZ$>nAOTSOJHoi$D~2P8@WO2|>Nx<#FA+*Bo_OY{LgfGyPph+_j=BOa zP}QV$K+(k$7$ns%gIFz`c#bfw_u_Dk68cCov1(kPaX^ydyMPBvgh&9btqMRqSR$*W zvSvf>OMp2=H}~9jGGqZh(9IsVop>(+(+N{U<{gz?;v|F99zm0LOpJ&;@wl=p?xSG)ej3ul|BR zZiT-prF#Jifi2z;|O9j7x-kYQn0WLWX60ZPI@sXQ-W5KZ%(W(t|PtxZAuGLw< zBkm3oo0~+9j zWX}p?LGi(L1RqF11iI@gT5;tfrg%bq3H$_o(`zZ)asl1&j4GapK0yQAkZc(%AnL`a zY(Rr65+XCZ++DdK$z`2uQjYob{Q*f|)VT-qgsuD$mw-Yh*ys)NHh0ixCwz!u7=~dO cMn*=XFGgTsFoYs8*Z=?k07*qoM6N<$g7afM!2kdN diff --git a/Content/Sprites/Controls/PC/A.png b/Content/Sprites/Controls/PC/A.png new file mode 100644 index 0000000000000000000000000000000000000000..d845fa44901c564f62ae11d1c2cc4491a76c6afe GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu@=r_3Qih%jfgox1Z1O#KE8%DDlnH#WBR=_}i<7d`$)- zYzcf1ME5kF^Si^~?v~dud9(WijyntPF$gDfFz;~{)SPtB)#LHvZR@Yf{$J|6e}cX5 zy~EA=AD^*w)oN^MnH|BH?fAs3F=hg%fK28Gmx4u({R&GR+Z`f|;xE+hkz$N$XcjJL zIKpYvaEepH;U$x-$i_>TSahE>0!f*3+)I~o8b!oSou-!X;JTMLGmmU*K$O&i)^35- zE0;3vn6vE&ml3Cyc7o6pvkQCGt+qCV)!7`LX7yl`-0^8v688#imTkYn*qmV_mGg7H zFR#m&+U5lBX6q(dUb+42ld7(MJGD)}_Vd29&%br8J~0JWO@16c!8HaL0t}w6elF{r G5}E)E3a}Rd literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Apostrophe.png b/Content/Sprites/Controls/PC/Apostrophe.png new file mode 100644 index 0000000000000000000000000000000000000000..ca275d4dfd00982736cd25ab36ae8f2b9d7becc7 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh1F{QUL%?fdf?rYK3N0Y#fUT^vI^jwjFXWH9JaVVxZ1 z6uz)AfZtbzHE8vQhE@*N%i)QvQwvxlZ;0wNYi~HTF2OK{QM`t3=Foa+;P62YYl*|VeoYIb6Mw<&;$T#S8SL7 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/B.png b/Content/Sprites/Controls/PC/B.png new file mode 100644 index 0000000000000000000000000000000000000000..2f42d8a420512f66b25687472d38b56e9f568ae7 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=(S`SbP9ub*GPU;cf+J;T9E>sWwNyFFbTLp+WrSGY46 z^r*0|Ka=*)o!NNubw$k=|NB}0IA~OSme;mm4=<44-L$`e_3I7Mns)66$JaezjyYH_ zldwc<1#{uMdB@f=Ok$GzC>-$N-0TTW;uRtcop;LDf6)HXm8G<->3)kyPR;igA@`<6 zGey>aEh2jkzCRJMr*DauMa>cED_1z%!#`Sxo@f+}=>M^%J@{bFn@{!+xy~hre_&si zU|YtzzeB%kqxjbQ6TN|ho BqnZE! literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Backslash.png b/Content/Sprites/Controls/PC/Backslash.png new file mode 100644 index 0000000000000000000000000000000000000000..ae3724dd33200422603b046ba54bd0e1605ec134 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DRNt>-)#w=YKE1zP^9H{eA}bBNZ=!au+>a977@wzrF4# z)U3e68n8ChQQ_IY!Yt_pZ`toE8_w5RnS%N)OCU*;d?2hPedNV7gj4`<^OxgN;G zq@@+0uyB_qpD3SXEvr{bSvaf9GdB zzqalBbA|Kg%Iz5{S$|F5F{eht<-op=i4(p$Jvpq9qh`nB)WF}oW$sObj^~WxY=#V1 z<0ktoIm-3KAR;Yk%iiX~4K~~ick2`!E-*GS__6Q!y?)oK-B~*E-zQJc{hs;9nD@bQ ZyFH2DCcZwmI~V9V22WQ%mvv4FO#n6#t-JsL literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Backspace.png b/Content/Sprites/Controls/PC/Backspace.png new file mode 100644 index 0000000000000000000000000000000000000000..f71ec7aa07011e08a11ab28811d8ef8428441f06 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezu@=z>+jpw@0XA7pU)7Qw}ulaKF8C=F~s9|@(o`GgB~r3 zO0I3(OXoT=XLeon;7U4|!00Z>RW|P+SK49G9|_?FEb9_@%UG8`;L6#cZNU>>z{W1Y z!MeOmIAFu9hNj@%oEj0n4hJ=tcpO`mV5-P^w?$-*!V-oQmb!Qlox#G$s$RxlQ}Q@u zLUZgtiI{^jZ@BypiCzI3Jm<%n_Pc$PPu#R;2%fjKYRep%&;~|^-z)wZ>If}N1GEtPvII(k{DSNK(*sW9l>(}y}O>1cp?dA8HFE(l3n@d5<*5$X&ILsp@Dzz*RA64f6u_3is*>pQpuS;&WjkN9!;RN-4|8m=DXooRYdHOR-{w<{ zx5R7(8uPzJiC?HZJH_P8`A42SGxj`tH{I{?0q-|gkFo4y%$fi3<45KmhG^B_mzcWG z2M5P>rWPH!)3(rL>K>u~hgaolY8lQ>%r8iBKKNJ8hA%HOfTPV)T&+M#A<{0iVJhP` xrbRp*^X*@Com+Lm?%ihV>F+B38T&p^&6AP%x=Bk(cLUJR44$rjF6*2UngAj&yo>+< literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Capslock.png b/Content/Sprites/Controls/PC/Capslock.png new file mode 100644 index 0000000000000000000000000000000000000000..188e6d2b4d56a250806202b13a22771dc2c8c202 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWjRo{r&S9ex$br07aL3x;Tb-98aF%$zaf$3$3vSxppw=z2Oo&Agb`%$&7b) z(>ci>qH7!q1;kkA8mFH-usnfv)qDfdlBNpd0__OK&iQ(CxU3Yp(jJ5`bSHfhb!hp} zc6dTS1J{W_gO1vXt+92IF^-~TtfwDxtpQr$Q}gcFyy|cTQH9{W22ZEE^obo+_Ge^Z Y`uJ(@FYV`RfKF!cboFyt=akR{0DNG3<^TWy literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Comma.png b/Content/Sprites/Controls/PC/Comma.png new file mode 100644 index 0000000000000000000000000000000000000000..d54e596784ca6bafb67d468076ad3f76b7202951 GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu@}w@$c`?UoUT;-@l*Xgx(h;pu}`f7sn8f(NB8`#z@5Z~P-UBJ5YhGBM!V9e(H;a?>;#kYi&9St;z?CNy#9-1qfk~Q)E9u+={`TEg?Q9yGYB)6y z1a{nQ(~ba|pu3|f>J8UA;dqhc?T@vBGV7JZg8xOGKe1ZuBLl;RoeR%AyS3E@=tKrj LS3j3^P6NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!>3p_1Et|-_M_4f8SpIJwvpt@^uCVMk7xb#}JR>Pp4XQ z9dZz8+uO|kfz8aU%?IOGWh^<8QKbyWEDG2anwiBIm}Pb_ z9uWDO*>KIx*_p#|!RxkV0xk_{cQ=^q5MX}u;mq3?A6O44runHG>+4*u>tN*Hlo(p{ z>5vwOP(gvbyv0U4CX1B(7KW=6!f!0{_~d>`?Ed|e$(y+NeKstrz1Nz*{0`5M0 z&%9+>d+;o;#S22*95s8rcIdRr7(aB63cj+U)Wp>@F~pw1Ol$G8D22C+mYZogR^Qj~ zSK*iuD6DwGjaA7p;eL!l>YjSW1&z$%3~3e*_U!Na7@A#p`<~8;znlNn??2j7#Z=MO V9_ZxK`yUvv44$rjF6*2UngB!o(VYMQ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D.png b/Content/Sprites/Controls/PC/D.png new file mode 100644 index 0000000000000000000000000000000000000000..2436d62fc59292aab203fe9a9bf2746e8d8c7948 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@U&*#U#ub02S-hTf6etw3H1#kI*a;H6A977@wzrB8& z?~noyTY_1_9IuzZ?bj|UzoZc>u0Q2}R^*}S2A3|)T-FnLU_IkOHHKdT4Jpk0GA47I znYB2B+!ZEkR5En&XfO+;I>;~xr7`|zw7H*mGh{tum4RmCwK-xBv~sx=ZXHaj_eyW9 zuE|eW!I0s;E}pZ&o&AiILQ(YuhA;1?>|i=zdR@cAsud(g}Rr3|a-_#u6 SMtuN!i^0>?&t;ucLK6TK7^xWm literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D0.png b/Content/Sprites/Controls/PC/D0.png new file mode 100644 index 0000000000000000000000000000000000000000..a3b22463e26c499f7d8b8945440010181818cf60 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~C^Uw3o*I(Z+Uw{AoetU+@*}_afxm%ttjv*0;-(J7X z*JQxMmXNTa`1QU2nR7J~Zk)N6wdcaW@RqcAr%R>DJNC?UY=~#Rlfn?B%#c=8dSLmx zA5sazirZKWCN{BdxX`eafr*!cbwY=rLqnZ{lV1XJ;;!k(4lqC3bM@H?rVlfuPB5Oa zdMa@JXR5@38S$^)db_c0;OG3h=?>dD|Nk5HWqtjR1a30B{*+M-j%?6pa){<NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0a{(5=){{8bA#AY1d0u*iYba4#vIG#Milfj@zg*AA} z>F|Y(MaupvtU;?cG_-QCUJgrSoms#dctcdDRr|%EbqTC7jN)ai+z+_I9x^QE(g?U< zSu7UEdf>;w^$R9XXqqXa9kI12WPgReu3p#Ng@b=d#Wzp$PyajBjrM literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D2.png b/Content/Sprites/Controls/PC/D2.png new file mode 100644 index 0000000000000000000000000000000000000000..b82cfe17b900c3c954d03d2c7e489583d297f365 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S>)+o$ug~9aA1^EtPvII(k{DSrU^{eFi0^jDjJa_2o=977@wzrB8& zuUUbIErEXy|J3jGw^q)+y(!7<^rNGf{s%qbUU=!jhLSXa2lpFZh&cQdVtAS)>#@{w zCEEPa4$UH5E-CX@!qs=~iQ|;49sGHZC z`t0pN#fpUQ&6)O|QL|PtTxWEc&Cg+AazH`hQp1nmtMy*4%X)qN@0wf7R_pxtVXAq; YHiPdQzr@7JpkQV2boFyt=akR{0K{;zasU7T literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D4.png b/Content/Sprites/Controls/PC/D4.png new file mode 100644 index 0000000000000000000000000000000000000000..98388efefc3fa99efa8ae1781b406f2edc63e37e GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFPQ&+eg1s=_451s8Qx9)nF17U@pN$v@i?9w;mTmpqr!Un ztX0|K#=a+7Dy+A5Z*1`8VAU>9X5IXNYtcsS8(iTJdSefY?O@7$!)10z^vy9wH_-`e z8IHI- literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D5.png b/Content/Sprites/Controls/PC/D5.png new file mode 100644 index 0000000000000000000000000000000000000000..77edaf82fbbcf048fe9febf0fc84280d9a45dd96 GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSr0$DjAl=dWLX-(J3d{(go_v3<5cxlNufjv*0;-(Ej0 z)U3e68W8QO&^Y1$|66^ReQz7+8uoF|-aXA&>d@hplE#(=rVP$XkK`4-7=JrFd3Z!F zAY!5tV?w9{LnwO)V~Xqq)&r+39vp}~aC_g!;|)7I+|Mu_GMc^IaMo{y=*FWLPF3DM z7=AixN93=B-`_TT=e-csJY9Ip#dT75Zci`HU(r!oYiIm>*{cJY3@?vOX6WM6U~-Uc uI38abT7LD`{&&t&((?}dpDFX>1hY-gw_{8E`EtPvII(k{DSrU4pShVElXlQR%MaEkdFlR}#2f&;w{ayM=;-Z=k#5ATVK%|!>6wr*U^-oJ&R zh~fK+PmHYxBx^2fF~_~MUBF^+d;5uehGSP4RGzOse1$EtPvII(k{DSq*$JhJwzt6Y7KYzXa{(c6p+_~~VxjmjPjv*0;-(Ej0 zbVz}R^};RjDJm!a*RN&PHZ@S|z1;dNPc!{uBezd^vKo6G?*Rsvr_LP;3GxwL7T)|P zTqmAsj0oxE@vu@bd~ku0ow>`1&!Rx^Ly&Ymm(BZV6Nbcq@+1cKTxHe;eQVoVw_G!{ z;D1w^VXX7?+W&(L4>oK_J+QVm=|=D8A14GEe}~mStdq-lemzHHN?FsS>8qH-nU>7< z=Q&}eV9Zd;Q1^e;>Rqds{VTO^%CT~(H@5sRjs3XMw literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D8.png b/Content/Sprites/Controls/PC/D8.png new file mode 100644 index 0000000000000000000000000000000000000000..eb418fefacc55e4ade78b5162cf880c2942531af GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=|t=imF^m+!A%uRq^@Kf~g#{WpP97d%}YLp+WrSGY46 z^r*0&S9$->ow;27nWE;4|NX3g95gEa$!o7@*0$)6Jt)7U>F*8EKW*9_$Jag3jyYH_ zlMupqlgsY=p6X(u`AwNCI+>jh#uo@xc1Iu7-_R7kL-bGecd02HA2cg|{WrE_Wm(&> zC z-ri`FS^6i!3*>kIiQmyw^@eNTVbLea;U9W`ERv`W{4Kq5OTDpt@W1CfCx+`jVr2Lo Xv+C^wR`X_{-xxey{an^LB{Ts5cHFPs literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/D9.png b/Content/Sprites/Controls/PC/D9.png new file mode 100644 index 0000000000000000000000000000000000000000..a20ac2e3b85c280538576335bd5c564a4a1ee31d GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=nQ_3Qc9=g+?{zrX*zJwv+wp+`We2c9mDAs)w*E8H0j zdQ@2TgTw#2Gp|1MOi^>g|9;jQH;szF^4d4p!wckhH|;NA{dz;Rrd|8R@pTW_V-D8K zB!n>DTu~o@*S?aebpiIzu&3mvHrie_t$^H zlb#VGdw%?9pWih9{k*yVzrE8{bhkVD*wk3Y zZ};;bqCfV2KDe4;#_b;;wHTgV|GM~RQw{6uji>)NY2WCNJ($0v>E{j6KPvk)j>TQ6 pbJu!%|5);=`n~3#R=L_RFf7==q>{5crV{8^22WQ%mvv4FO#p|9z+?ab literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Delete.png b/Content/Sprites/Controls/PC/Delete.png new file mode 100644 index 0000000000000000000000000000000000000000..96ec55b9d7e0c88612891f801a2964c9da3e18e8 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!>3n=k@dJ`PbjKm!IFipW)i!x>-P}&7LlfAs)w*E8H0j zdQ@1~-+BMfow?lmnxbaM|9;jQSB;9#^4b>c;Rf=%o8}j={@$qlgE#y_f9yg29Zml& z4y<6hrBSgxh(qbi|GU+1xbE%U?eF2pR>zwENzUm>fo4Vhdr3yt|MwnlZ{p(mb?;&M zVeZ}RKScLbe;3PQog}cT=`V|j#NXqq6HG4haj|~ic=~^7|ux!}_b#fzD^}boFyt=akR{0D0S?82|tP literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Down.png b/Content/Sprites/Controls/PC/Down.png new file mode 100644 index 0000000000000000000000000000000000000000..08f49a62a3dab9e7c07618c88a566c82c5719d39 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0b{d{@*_51td89vm5W{oXiy?8@3r&W8yv2_W?F^uMAtkMs-${sT)hcl|> zhcH@lCCqHCVco3oNxM+%24|pw^mgU+g%S;}2mM5tH&hmjZDPD3^2WuCA$!v7t&<#P z-Lb4TdHpafpf|S8I>r%bn)L&&JsY)eIMoF9>|JrUC*+p?*<(}gizopr0RJ<8t^fc4 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/E.png b/Content/Sprites/Controls/PC/E.png new file mode 100644 index 0000000000000000000000000000000000000000..18d44a796712dc9a619e1c0b141dacf74c69c0a3 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g6_6x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYZT0j5=NH zVT_LMmmCjfSny0Mka$_SnS1vit{qKUZ@8u%7IjGs-!SFJB8lq2-8?I|%zx9Wx&KJf elhE!828OKpY_|gLJT?Hjg2B_(&t;ucLK6T42Wl+< literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/End.png b/Content/Sprites/Controls/PC/End.png new file mode 100644 index 0000000000000000000000000000000000000000..42bc15ff219c7d695d2aabd7cdc4e50e9c4c639c GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS?@zt7i?uV2r9-@add{(goUQ7c)X+*MB($B>A_Z?E6v zYgQ0o4Jc2Me)fO=wg}xxPDy4WQq;GLYKR$Ekaf4-JL50MI+NY8mUYRMp ze%!`#!?Z<`?UCP4rWub!9;hCPRBy<>yDlzi&R5-rP3a6L<~`%NFrT5yw_#pVc?sun z#VM;=n43>CoVWO3tMgQu&X%Q~loCIGsiuh0Mh literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Enter.png b/Content/Sprites/Controls/PC/Enter.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a7ca1f54c0a4ff89bd3e621972f5633f7c485a GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U$FlD_x1Vf_uKc+=Z}|Xcw=T;50ts*>EamTas2I7TfQa( z5%vPVN32(rUp#xYWVQ0*)y)^BAMifmxZ}X*5cDWv5!3ok!#aUi*3BggCVXOX=lwH% z`m+5`OnpCRIr#RdHD;tN5-UE$mC)g`&eB3r(!0@=SB~q3Nr&i*3lA1C)Om2%39B&V zl|MYSso9`$DPJ5zA1nJru?B_M-qHhtH$_rdcit*uVtBUT{At}gJPsaPC!95&FfXzH zs_wZ!-Unya*)hxikeVR=U}5_qN4Ca-s=D8c{)wD<`FA&yw3LnLhfIZi@<+d{=;glr k&qDkC{jjsY#k4=MDa@3KNS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g9G+x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYX9k*!&oE zX7Vm+x>z9LJGt4_QM~M@XaQ>|P<6X@2T--tDnm{r-UW|6|-il literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Escape.png b/Content/Sprites/Controls/PC/Escape.png new file mode 100644 index 0000000000000000000000000000000000000000..968d5bfe07c74020b6cd42417c3fcf1a32a152b5 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSNA$B>A_Z?E6v zYgQ0o4RE=cc>Zsc=3tQDNqS9kmfnjrGiL95kOcdv&tiW_PiR zUBv!_XG(tKjD=mi2?hsD91b*GV35>dllW1&K#J2yuQQ~lE5PBlsc&*+pD@P>-J{Dg z_pryE%;{Y5dzP|7NHW8Qo)w$2B*PT0+Wrc^Id-8zYouwSA6pheqI0XFZ&~)M;Sa_{an^LB{Ts5h!M7P literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Exclamation.png b/Content/Sprites/Controls/PC/Exclamation.png new file mode 100644 index 0000000000000000000000000000000000000000..fb54c793f1bcb3220d76863760c4b573e6e5c810 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezhHj-`}y_je{T(_V3K-2;mlNB%Na^#@!f8?-H0!VB2gB@S|3 zuvpC1wuR}`W#?*9M%GKWIW$h(b8u+<-gj|Ld-Or6H=mY2;Chx2ULdqifqi#V@)7Z) sH@a^Ldo2C?O~U8r;;YK*qmD2$gdCINwR<zopr0JRK!WdHyG literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F.png b/Content/Sprites/Controls/PC/F.png new file mode 100644 index 0000000000000000000000000000000000000000..5ea2b7eb0aeb12088cc7764383267ca092eae71b GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g6_6x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYZT0j5=NH zVT_LMmmCjfSn!CkD%<9lB~FiL3=e3HJy^7(N#hOIG@*ErWc{q^ic`N$-fQr5dPLuz dEJ1z-hVV%oMZXrF*bH<9gQu&X%Q~loCIBS!Ww`(V literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F1.png b/Content/Sprites/Controls/PC/F1.png new file mode 100644 index 0000000000000000000000000000000000000000..3b37c4cab8fc3dbbe8964fc342687cb940d7c49f GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0a{(5=){{8bA#AY1d0u-I*>EamTaXfj3Cxbzc3TyC` z)8PvniPtM-dS>k?RF7{$w2xgT(aJ!DwSbs~5} zk=m5Imc?RmtOqO(tzR&CLetD0qGy^oABQ(2OjyToN-ltP%I~BHqCIIcONS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=hkc;Tz<3H^mpQe&4A5gF9THKlWhwj;8+> z2Uai{i8L(!W~=d|(a|RRs#3KK*SkiG%ME9y-wkVp zXwUfm?(Mtc1ZxA)hL`)wpZ~9~`p&eSiABC!pDlv1OaI@4&#m`%Z$F?=-xA#@dt=w~ z9io3)o~O%j{hQ9%dg=e;zz>n{?mGXz*yG&S^!LWo`op4gj<0*bALD3W#%kZ8-?dSE rYyCv8-{Jpee2Tx;yC+MKpMl|F{d^tY))SY2-evG~^>bP0l+XkKXehcQ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F11.png b/Content/Sprites/Controls/PC/F11.png new file mode 100644 index 0000000000000000000000000000000000000000..f08c03337cc41b1961f8662dac37b5e32a3ac93a GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWjRo{r&S9ex$br07Vyhx;Tb-98aF%$zafFeobc*{7DMMD%OzS3o7h4apYD^W zU|lTP&cPaaJ=^#A|> literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F12.png b/Content/Sprites/Controls/PC/F12.png new file mode 100644 index 0000000000000000000000000000000000000000..2a206159d421dda0d687b091688c51fe57d1a695 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S>)+o$ug~9aFCV{u{d@-52{SGLw};CH<;f4-!eNb@y4tdGjI34+&L*>Kg$(1`Ikv@YgTe~DWM4fcEtPvII(k{DS@S>+iomug`DaFF!wi|9S=%&u4Rha;H39977@wzrB8w zuUSEWHNbqrQOO_w*T0=~ZH05RUT*xEJLbLLT>?4EUY;)Dn#0RsEBusS@sZt>M#b=S z4MscWk3t2KUBV7W8Z;UNncWyu47fBtlqVS9et-N;4p*Mx+5=WUSMo+YkDaw#En#z= zF2e@hBL=FDzz|8X?;8q?&x^S1P^|9JDhZnZ?hp+X+R17{ZTGcL6=>WF#8?BKK1 z?uX*u%5#&McCFC5z$b7`ow0)F0~3dYK;8bUt>0E{+;g`)COm!le;+QHBF54+U*9EtPvII(k{DSrU&&RKS-#^{eFgdr+0k>%3b$#aSVw#{Py~7 zp(X_Zwgmn;kzx1#XBvBL-f%H?Rd?Ed?ZPLM6I&1FW%;Nd*w1)T^GJ<=%hN}83_nW} z_zh+X1T$++o}_i)5<@g&BU=mCi6a~e2d+1s&C<_(dr4;bPKOWMv*jxeT&lmfk%{|- z{Mv~OHrr(uRezqAoUog510%x@JBgX8G4CCeAC$i4(2-`)aP80ybtn^km%KeE;j`*D zorH+%hfF>^OAxe4d#3Vg;~Ev+*{c}r875ql*FJE8A((L@+mZ9~rJm`byX)`xzltfJ g`eeRm!}J)2nKEA|XYH4Z1bUId)78&qol`;+04jvCEdT%j literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F4.png b/Content/Sprites/Controls/PC/F4.png new file mode 100644 index 0000000000000000000000000000000000000000..b216eb44e81c2052c4990b4486089975b97e0049 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFPQ&+eg1s=_451s8Qx9)nF17^?CIhd;&D7V!j-|GM}_tD zS*x66wKaYccdQ4ms<}}}(=p1t}k_O#x*C34RK^{Yx!*)OxGwt2iPd5s85kCF_AdK;cEtPvII(k{DR->$DjAl=dWLX-(J3d{(c6PMRH$(a=ScT977@wzrFsJ ztJ#2u^+I0M@43(Z&MylQIFfQ^%PEJV|DtaklYLjOY&PVw;q|!2{GgwqVs^!Whc7Mo zPH1>6b8rb%V(jA4VBs)Q5MXExbZFe&c=vdnL{Ye{_<{9@?HSjm9&>f>Z3#?x z$GA=JmekKn!AEq{Qe?NJZ{J%!VOQ3H{3W8hvOcW4^G#hdDe{_j++?#*)_3dEtPvII(k{DS@U`Qy*eug_n9f4_bIdwGUaJP&k$at}RS977@wzrB8t zuUUbIEn&GvM8?y<^UDMmA9gf~`nqY0I{ydN>|6G0qV>X-AK1^BBJ1!ckl|dA?2M#h zUsDAaw^pGK6GQhgxXBra9XP}MjH%;HkVE6~#+=)mcP`~_Si8oW+k>;E=)l@|=FRLs zZ`JRpItC;8B|GIxBk5)0zvkacDelF{r5}E)Kg1EZ? literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F7.png b/Content/Sprites/Controls/PC/F7.png new file mode 100644 index 0000000000000000000000000000000000000000..8216aa6b0ec2ce0aa678b142c1eb7fec335182d5 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSq*`^VSwzt6vKzka^_{(gpaiyzzv${p}@aSVw#{Pwyh z-(dwF)(a-gEeEfBx6ft08!|(yW>T5p&-Xe9qZJYlf3cbA*|?kWVwI8|$HeU$dDq;T zyOmXiZIa3Zi7sJ>0}Todvdm?S1`@0yKTJOq-dw$D>#KbSrvH}qXV{iiZ6L6E-Q{|= z_djCJ+3=m&`Q>rL$*ad6JIrJjW9aJ>V3kYN>}T$lu@y+zR@0IuqfwmmuyBD-(4}Ro z4%jms`Zk$Ch)spjg{R}Xed)sOSsC`<=f1!FZtlOCA}c;I?dblNVJ~~(C(thpp00i_ I>zopr0RM!kj{pDw literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/F8.png b/Content/Sprites/Controls/PC/F8.png new file mode 100644 index 0000000000000000000000000000000000000000..b91adf2dec50a9819dfda1e53a877f6942ec6db1 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=|y=kwp+m#<&1-#_1eKf}@Nz865L+nz3tAs)xyUOmlu z$U%VZ!IV@(C#wr=Ec{L32bpvntuL%rU#svV?21KJ&-ocW7L9ioY+n3i)|sdFZ`g09 zrkRWV(a`ozh%ET9cutfiNS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=nQ_3PL3&(FW#FTel2J;Uk0SMCF)-gvq=hIkxLu5f2C z=uu%^?^X8Soq6}&>x!Bi{`a%ixM@`Ul-HiY9$p~7yJ>#`>(3jaHO<;Dj<0*b9&@l> zCLx3|lI!2zW`qA{_Li6P*|Dy5_>^g%$6EizVG3U!>x7ao604iOE4;eC+x_Rh_i+!y zKD@vC`oH`_Ckv51KmN0~GZ}oozWe#}{rjuEPfYaxP+`pHa`Z8$hNeJh|LuwY|6e(H z*|LoF|NrlMtG~#vZ`xIU{)2W$wRm$lqrvfyk3$*GZ2s+T%vZ_vEqVHX-f#n;6XzGO zzTT+)!?h-`XYY!?Z6UYze?30se^LIE(C!Kb29tdYDlckP#RC1!;OXk;vd$@?2>{D$ B#g700 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Function.png b/Content/Sprites/Controls/PC/Function.png new file mode 100644 index 0000000000000000000000000000000000000000..b7aa56236966333cc8af4ccf5692318c385cfac0 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~C-=DA7&$qwNzg~WR|9*xFCWcKwxow^kbjsHwPd|}ysFi^o&b;FK8o;&yBmS;A4 z9}Q;6vu*Qa_Q~8^>ULBy&-BL<#uNMRrl~vlaUWU2!m;&0nR0ZX>4V>lQ`Wk(g-8ZS xPDpk5SF>9CRjBvwyZjfn%QXEpmi#cuIAZCymcySPJp=lH!PC{xWt~$(696!Ip;7<< literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/G.png b/Content/Sprites/Controls/PC/G.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1eaac8a3b103b4889b58d915fed67ce5f924a4 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@K*PrKqpC7M3zh8d;eR~G2omMM>a=$!X977@wzrB81 zs9AxBHNeHOh2_Wp^=tdfx>_ao+z9n9vnp~?LuX$_S69Z{o?^l zIV^{sHS`Dk;E6CuILUB~;amfU8~Z=@gtyx-++q7*eUZhS!A3RG-jGM5Sj&c)=f&S+ z%z`(!GMxRO{O0DfD}@Sae^m2?XB?Y;?Sp8{+GAH5-cH%Yz2ti8=Yx$6%r)#E&U>oY zax*{sI>oZkm@UBL*bS$<>-C=Q{W>F8vsdkj@CxSTDK+b}6y_e^(z$!%!UZavxgpV> zix;z3zp7ox9L{*?STI`z&j!f{1_x^ES98A&o&Krp{^{()OW*(Zk^RxZF52={|MbI^ R4Zu)f@O1TaS?83{1OU7j#JKNS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZg`@eEaqJ^8Nc6_#fY30*aP-x;Tb-98aF%$zaf)}YlJ8d^D6gToV9Cl;_q-VoJk)?RUFU4mr{qj(uB_XDo5hYZT0j4iEa zL;Tr>n=(zbX1YKUJqGua7#y Z%wXZh(Y(&X?EtPvII(k{DRNd-;dANUq64pfB$=Xd47g4pFQZz=9dl~xP7d-;-^l9a_nH_F3+_ z#?!F!`r5!WhKMzHe@O;MrIv75f3SL5wxJ>D9^=%_ReXs%ncnyxJ?F@8P&|SAfUZM+ z_tED9ZAA?`MOS#c*LE7b|6X9hZY0er@IdZC<=+qzB3 icXKDzt1<3-#Mt5R^_$GUjYomLWbkzLb6Mw<&;$UbcCh#W literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/I.png b/Content/Sprites/Controls/PC/I.png new file mode 100644 index 0000000000000000000000000000000000000000..0e58a398b30b9c38a6fbce6a179263c6727f0056 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g4uTx;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYZRQj8f?# z2Uj#Ph8ryUoF-oOQ?!6J6sWXay920H^P{Wbw?$==L7Db9xr6IEpPpDP_K|@>{Wtfb UVEKb?KEtPvII(k{DRNx`{(o5uYVukKVRN{|9u8K=4Kh7+zn3`$B>A_Z?E6x zYgXW4O9*l4oBF-}7N@Z9k(56>X6wFfUAeH1GgR>CF9R0l|7<%vTLtW0II@bqACQ@y zypP$3<6q*h)FxxXcx%^hZOV0DRccAbC?|nN~t>E-{Uvcj1 zEzTWJPvrXZU$TlUdc~~rw8n?`A`5f$^U`yzchp<%9ZT+Lo01`NV|TsYVgrXyGEr3x z-_>8NkSkQMZ(16~C37Qvo;KSf)>cL~sfLDFd94Ep4J#Si8Q=Ymj?Gw~^?v*BxUI44 fZ2lV?7Icc&WPIa_*Zj=}^dp0(tDnm{r-UW|E2gi< literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/J.png b/Content/Sprites/Controls/PC/J.png new file mode 100644 index 0000000000000000000000000000000000000000..417836f4801b1aa28b72303235370a3beedc53c5 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=h0``7F9=igs1-)}#EKf|RrHw1xFGd*1#Lp+WrSGY46 z^r*1v8^8PK&Rl-`nWE-~|NX2rZW>fb})dAl7gLpsDkZh#$Steaqfs>EG9NK0oDuyTxtoU}s?1Wwow-Z?ybU Qpd%SPUHx3vIVCg!06d+Tpa1{> literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/K.png b/Content/Sprites/Controls/PC/K.png new file mode 100644 index 0000000000000000000000000000000000000000..52ba37d7e7c798124767c4bf60ea36926b169edf GIT binary patch literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=!0u6zn=enJ%h%cHSd8^S3F%DLp+WrSGY46 z^r*1ARa*FCW3 zGYArOh?HFIS`2J1cK=RXa%NF2V_nYa z`n}wVtAR6VNxJPEu4l>9|8s_406K+#2UGnUu6+XWBFXw$_R3Sg`Cm^y^}kEH@~V;? a14Dr9GP?=)1(pH*$KdJe=d#Wzp$PyDhpD>& literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad0.png b/Content/Sprites/Controls/PC/Keypad0.png new file mode 100644 index 0000000000000000000000000000000000000000..a3b22463e26c499f7d8b8945440010181818cf60 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~C^Uw3o*I(Z+Uw{AoetU+@*}_afxm%ttjv*0;-(J7X z*JQxMmXNTa`1QU2nR7J~Zk)N6wdcaW@RqcAr%R>DJNC?UY=~#Rlfn?B%#c=8dSLmx zA5sazirZKWCN{BdxX`eafr*!cbwY=rLqnZ{lV1XJ;;!k(4lqC3bM@H?rVlfuPB5Oa zdMa@JXR5@38S$^)db_c0;OG3h=?>dD|Nk5HWqtjR1a30B{*+M-j%?6pa){<NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0a{(5=){{8bA#AY1d0u*iYba4#vIG#Milfj@zg*AA} z>F|Y(MaupvtU;?cG_-QCUJgrSoms#dctcdDRr|%EbqTC7jN)ai+z+_I9x^QE(g?U< zSu7UEdf>;w^$R9XXqqXa9kI12WPgReu3p#Ng@b=d#Wzp$PyajBjrM literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad2.png b/Content/Sprites/Controls/PC/Keypad2.png new file mode 100644 index 0000000000000000000000000000000000000000..b82cfe17b900c3c954d03d2c7e489583d297f365 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S>)+o$ug~9aA1^EtPvII(k{DSrU^{eFi0^jDjJa_2o=977@wzrB8& zuUUbIErEXy|J3jGw^q)+y(!7<^rNGf{s%qbUU=!jhLSXa2lpFZh&cQdVtAS)>#@{w zCEEPa4$UH5E-CX@!qs=~iQ|;49sGHZC z`t0pN#fpUQ&6)O|QL|PtTxWEc&Cg+AazH`hQp1nmtMy*4%X)qN@0wf7R_pxtVXAq; YHiPdQzr@7JpkQV2boFyt=akR{0K{;zasU7T literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad4.png b/Content/Sprites/Controls/PC/Keypad4.png new file mode 100644 index 0000000000000000000000000000000000000000..98388efefc3fa99efa8ae1781b406f2edc63e37e GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFPQ&+eg1s=_451s8Qx9)nF17U@pN$v@i?9w;mTmpqr!Un ztX0|K#=a+7Dy+A5Z*1`8VAU>9X5IXNYtcsS8(iTJdSefY?O@7$!)10z^vy9wH_-`e z8IHI- literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad5.png b/Content/Sprites/Controls/PC/Keypad5.png new file mode 100644 index 0000000000000000000000000000000000000000..77edaf82fbbcf048fe9febf0fc84280d9a45dd96 GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSr0$DjAl=dWLX-(J3d{(go_v3<5cxlNufjv*0;-(Ej0 z)U3e68W8QO&^Y1$|66^ReQz7+8uoF|-aXA&>d@hplE#(=rVP$XkK`4-7=JrFd3Z!F zAY!5tV?w9{LnwO)V~Xqq)&r+39vp}~aC_g!;|)7I+|Mu_GMc^IaMo{y=*FWLPF3DM z7=AixN93=B-`_TT=e-csJY9Ip#dT75Zci`HU(r!oYiIm>*{cJY3@?vOX6WM6U~-Uc uI38abT7LD`{&&t&((?}dpDFX>1hY-gw_{8E`EtPvII(k{DSrU4pShVElXlQR%MaEkdFlR}#2f&;w{ayM=;-Z=k#5ATVK%|!>6wr*U^-oJ&R zh~fK+PmHYxBx^2fF~_~MUBF^+d;5uehGSP4RGzOse1$EtPvII(k{DSq*$JhJwzt6Y7KYzXa{(c6p+_~~VxjmjPjv*0;-(Ej0 zbVz}R^};RjDJm!a*RN&PHZ@S|z1;dNPc!{uBezd^vKo6G?*Rsvr_LP;3GxwL7T)|P zTqmAsj0oxE@vu@bd~ku0ow>`1&!Rx^Ly&Ymm(BZV6Nbcq@+1cKTxHe;eQVoVw_G!{ z;D1w^VXX7?+W&(L4>oK_J+QVm=|=D8A14GEe}~mStdq-lemzHHN?FsS>8qH-nU>7< z=Q&}eV9Zd;Q1^e;>Rqds{VTO^%CT~(H@5sRjs3XMw literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad8.png b/Content/Sprites/Controls/PC/Keypad8.png new file mode 100644 index 0000000000000000000000000000000000000000..eb418fefacc55e4ade78b5162cf880c2942531af GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=|t=imF^m+!A%uRq^@Kf~g#{WpP97d%}YLp+WrSGY46 z^r*0&S9$->ow;27nWE;4|NX3g95gEa$!o7@*0$)6Jt)7U>F*8EKW*9_$Jag3jyYH_ zlMupqlgsY=p6X(u`AwNCI+>jh#uo@xc1Iu7-_R7kL-bGecd02HA2cg|{WrE_Wm(&> zC z-ri`FS^6i!3*>kIiQmyw^@eNTVbLea;U9W`ERv`W{4Kq5OTDpt@W1CfCx+`jVr2Lo Xv+C^wR`X_{-xxey{an^LB{Ts5cHFPs literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Keypad9.png b/Content/Sprites/Controls/PC/Keypad9.png new file mode 100644 index 0000000000000000000000000000000000000000..a20ac2e3b85c280538576335bd5c564a4a1ee31d GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=nQ_3Qc9=g+?{zrX*zJwv+wp+`We2c9mDAs)w*E8H0j zdQ@2TgTw#2Gp|1MOi^>g|9;jQH;szF^4d4p!wckhH|;NA{dz;Rrd|8R@pTW_V-D8K zB!n>DTu~o@*S?aebpiIzu&3mvHrie_t$^H zlb#VGdw%?9pWih9{k*yVzrE8{bhkVD*wk3Y zZ};;bqCfV2KDe4;#_b;;wHTgV|GM~RQw{6uji>)NY2WCNJ($0v>E{j6KPvk)j>TQ6 pbJu!%|5);=`n~3#R=L_RFf7==q>{5crV{8^22WQ%mvv4FO#p|9z+?ab literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/KeypadColon.png b/Content/Sprites/Controls/PC/KeypadColon.png new file mode 100644 index 0000000000000000000000000000000000000000..9112f83b7793983a1a5f0ed9f302dc2362dd5cf9 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh1_eEIeL`|a}?j%l_o28uR%x;Tb-98aF%$zafIQU4mc?qj(uB_XDo5hYZT$2fI$a zjI9t|Gsm*{nuB(PVR72^jFjGE&pHAow8qv+#yEBU%GHK}!A5~=%R_h5UqHt&c)I$ztaD0e0sybfZL0tP literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/KeypadGreater.png b/Content/Sprites/Controls/PC/KeypadGreater.png new file mode 100644 index 0000000000000000000000000000000000000000..2897392cf8b0e1433379dddca25b9afe6d7ce478 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azWjRo{r&Ot8SXv5nFSO+=;`7Z;&J@#Ra>DZ0|C~A zs{Vx6np-x1WxI8`f_ZP_PR1!c$v3=?+Z*ka2|K;cX4AQdL)(5nOFhv%VWQ#984g=d zJih+q^-_k<9M7&bdbboOY&iVj1QU%!4n3@%)uxY$9;n=mqE~Des7cq5F z#)dwJ{*_7s0fHYEq_D8CPV{a(@A>12m=QynB6EVc5kvXIwR&?dwwm8-Kjtfc&OV|4 zdOS~`#2(2t20Q-Oi9TL!)^Ypao|o(Gw>|!?tG0|aNVNaNIq8;3K+iCEy85}Sb4q9e E0G1`1?*IS* literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/KeypadLess.png b/Content/Sprites/Controls/PC/KeypadLess.png new file mode 100644 index 0000000000000000000000000000000000000000..b89852ba4300378950f1aab81c482274e8e5abca GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azWjRo{r&Ot8SXv5nFSO+=;`7Z;&J@#Ra>DZ0|C~A zs{Vx6np-x1WxH{?f_X3F9R{ysg4-^A)Snr{x5{+3jd`E$9<%#4Z8;p0s*`*9;K8W_wI_K*5@xfksFsbWFX6c2GL`LElV5F% z27`kbg93MwfXI;p0$+dmP5Z=fTww*ndQEMH38ERRPhZjTNfJwToo>OuY?l3;{|6b@ z@0XZkP+@!{q2T{ttz+S9zvlh^tQS}RNS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZjLv{Pp?w>-Wp|GhF28<^&2?db&7%(SJ@%alH~9W%|8}N?3T5jxVo9er*hl6 eiQ&4B7#SV~P4b)hQ+prK5e%NLelF{r5}E+?hi_#7 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/KeypadPower.png b/Content/Sprites/Controls/PC/KeypadPower.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a4905c29b0b1b86ffb137e03fa0042e296ab1c GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azWjRo{r&Ot8SXv5nFSQy?djqe;&D7V!j-|GM}@UJ z^itX4MiX^y71m3;H#YQgu%0eYW(_T1y?8@3r&W7KZ|p(89ZY#|xXccSzB$I|Cd#v- zY3^oDjTu{o_BYMd=w$A0id-GG_Q>)C^{iiqLJYW%M0Z9rUT6@F^>9njV34}7m-!?| z39ABg*?Tu5rdY;+V)LFOd9K&FSUN)w_T{ly&QfDv*_89<)9nXbt2S!i;0sRxTAB8! uJL!$QNS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g9G+x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYZT0jJqxc zvMR?ivhXZvnmEsV_lDE!8?;vdm089(ij=W>cj|X-6yJJ!g4gepaWg)7>$t~l?O3Fra_Pgg&ebxsLQ04}>_n*aa+ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Left.png b/Content/Sprites/Controls/PC/Left.png new file mode 100644 index 0000000000000000000000000000000000000000..88bdf43de8055b40998a44f4e3feceafceee62a7 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azP$bV{{8Xu8ETz>8Uck@d%8G=cpQIw)sU~rL4Y-& zs?XuA>I1eLH>;Q}8CuOhaAdFCc*AS)1HW%Y4i6o^=+B=JaWMb+Q}Nj+b5cAPsWzTo z_9b4k{3U~m+>?vVv)e5-ZX|sODmdmKazx^e=nsc51Njcs0|E-u7@Qkw%uHE$7^4K3 z+8TwK`x^HtvB)sT9{u5M#deE}X-@3*f9oG~JkMukW!u`s)BOBPaF735o^^jq|68yB f^t85HIg=rLc3*8zSMh70vl%>H{an^LB{Ts51T>0e literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/LeftAlt.png b/Content/Sprites/Controls/PC/LeftAlt.png new file mode 100644 index 0000000000000000000000000000000000000000..1f664cdae1cde638a809bbb51177c27e5e4a7a9e GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U-0{U{`u$q@7M3QUoYR!a8qY0J5Xkcr;B5V$MNJH-V6pk zS`t}YdETXaoS9|0zbk33sBUMqao5=KnNQn-JKTVOchmF&*0LL-Hf`D`4zGJ48FSED zCP6?e!piv7-Drj1x-lG~2ZitMp8n^9CPV9On;Ncr_hL)G--|Z*{cdl0gy^2d5eH*$ zX)BzY=#ZSTEFoiwh7H%R4X5`vXj`<$9+ckERC_~okDA@@VO9gjT&x|hMz)z4*}Q$iB}-qDbY literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/LeftBracket.png b/Content/Sprites/Controls/PC/LeftBracket.png new file mode 100644 index 0000000000000000000000000000000000000000..cccd4d242bd66849079288d2062db1760fc49cbb GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFF5{we!cyA`T70(8KgA+R|AC`JzX3_JdP(vxH1^@sIZ<6 zNq^_YY}~wQf=I;sV@zhsB5Q8+ik2J{tw;{vz`AaM)b6IY1+15Dh~~6t-{@uTiD3=Z zu+iZPyXefw=-#KbU@_AycXM$?R%Pq_bI0`d3$I%sy}L=afb}L&hw?s+V{upV+_m0L lcS$~#|5d8;s*)T7gTV5Mhf?0SbOIg2;OXk;vd$@?2>`~za6SM4 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/LeftControl.png b/Content/Sprites/Controls/PC/LeftControl.png new file mode 100644 index 0000000000000000000000000000000000000000..13810938225c6d0df3f58f4f383babbf63ffba8a GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=?w_t*2+=kK3y|Gqz7owx^3@h{y4_SFE`X zIS8;NyNx0i&hn2I3r1ky7~!wkm{OlXm2mKdIBvpCOkVmdInZdRyC{ zvxnZXZ|2z@+@P=dn0ym-6EGbFwc~kpU|G;#!_XoL%^W&fw0EM1b+t8lS(`M zbmlZlH?;!{(R1!N&$g_3W2}>{{ED5tYW!( h@BDA2`B!H$o3ApMto?Amw>Hq544$rjF6*2UngELusY?I= literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/LeftShift.png b/Content/Sprites/Controls/PC/LeftShift.png new file mode 100644 index 0000000000000000000000000000000000000000..58940419d22e878d9ae8e44ef8978b3492628213 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu@)n@7veU&)?tAFCWkFLe2gMP~x(ui(`n#@wZoOxeghK zuz&EIci^J-j$M`&4EYI;1!eD^@P6U2byzTO!CNJcYx{KSrfqqzr>1m1Y2M1@ga4L4 zdCIP@s3K=__mwa${jL_UB4CE+jZ3#n8b$Zlsc(4b=$LSt`Rnh?kE=z#KDXa^{deGZ|FQ$8 Zn9J_e?|*xW=R44Q44$rjF6*2UngIDvsks0E literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/M.png b/Content/Sprites/Controls/PC/M.png new file mode 100644 index 0000000000000000000000000000000000000000..7ae6cad362c7e0f186d305fb702029abae65be90 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu^1z`SSMj_xJ0c_g~MTIExi%EW<5N7sn8f<4>>d6>M@4 zU`>$Pz@oi@^{s=qf$C=Fw+vPdd$FO!z5W@}S zQxc6WD_Rz4KXkq@)k85sKbdEe5X0;H&)oL!m)>ys;NgZ=zIFfCC)HjJYtF6rv44Mi eY3+X33F7(Brp{elIh`BmO9oF@KbLh*2~7ZM>72Fz literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Minus.png b/Content/Sprites/Controls/PC/Minus.png new file mode 100644 index 0000000000000000000000000000000000000000..2ed42b8dd9104e680cd6c4fe89810027728ab6db GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g9G-x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYX9k+_o`A z1j&1_E-o}&#o$tsI6a;*JfJo9V9|~yjW=A=gyKb#^|PicPW?7{uffyl5q*2I1o;^l YA|-jWw0N>F0v*8M>FVdQ&MBb@0AQD5$N&HU literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse.png b/Content/Sprites/Controls/PC/Mouse/mouse.png new file mode 100644 index 0000000000000000000000000000000000000000..f9acb4530b283a51bc74e8669928e92ab0a2c425 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS-K>+k!o*O!mapU=Pl{CftW-C92w7#R6IT^vIq4!@m# zo3B}cr_EO3xLD=?<+6FNj)g=Ss>NN9c3wK)cWeDdN&To`M$rQ91H250TTgzDWo%f) zz;}54(uRyUK?dnh4GEkM^WVtb^O?WIfnn0#UympMv)7b6aQf&>fgcTdyLc1sT9mmq zMC9AXJ{AjQi3pc2XSI>t(7sziV>)Bq`u{gfBdQd>ZPC_B%1INy%KP+=@blX@*II>N zJI9#*H#kB~!;oEga>23opabhd5Bz0V@@OIhk4S<7LmQI>(*g|!(|aqG6f`xI_yx8o zIqJztOuF`rLDyZF_rIu2$12;d?J=QdZ=TDa-1Y7Dho?u5%;qloY`MV3GNPpD!Ryk4 nDMDp_%xhQt=NA1?a)7&U-N$dD>YkOrU}Nxf^>bP0l+XkKOMt}8 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_horizontal.png b/Content/Sprites/Controls/PC/Mouse/mouse_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..0b38e0eb9dbb7d3478a49c215bfbd7baec6f27bb GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_UvR$tdj5X>`t$qc-^b5qxD|0Of`Nfiz|+Ms#N+teE4F-1 z1|kdzdXGe7=H7|@!nVumWzwT(k8*4pIN$ME?Rd?bVZtJ~&?hV4ly$R1w72u>&Q57x ziBrFS{fcL<*K}jm`kjcfn{j3Fas+?uIdhs4Pi|>E?MqV40Rzy}AGZ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_left.png b/Content/Sprites/Controls/PC/Mouse/mouse_left.png new file mode 100644 index 0000000000000000000000000000000000000000..9ca5d22b7d8b73f79375ef23447d0d1dc28463e6 GIT binary patch literal 492 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCilW1AIbU zpBuS7Gjw`xYIFK)85Fps7FufeNDJB9{R< z(j`HD!S(X<_2ciKukT-Pe}Dgb{`LO)^6~Te_vfE~&oFDks?Q7zjFO%%jv*0;-(JrY zZc-3nd+_cs-_+St|Npn1>?tcT)m3WttVH{~x5A!#e58MDFq1rSKL zI2;WgRA$}z)VR&Wu_0ENjmNoRv3dPg-DP`K6&kGnS?sCas(ysIzxMu@mWl)WN(7q< z8;XTCur4Tj#N;rkA(8pd+!F`n8R~rdYD6ytKiB86h~H+gTe~DWM4ftr+1^ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_move.png b/Content/Sprites/Controls/PC/Mouse/mouse_move.png new file mode 100644 index 0000000000000000000000000000000000000000..8219b0ba831ea666dfefda841cc4c9f015a04c50 GIT binary patch literal 494 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_UvR$tdj5X>`t$qc-^b5qxD|0Of`NfC$kW9!#N+tgtG0fJ z4MZ3c;#;&g7;W5qfcMlX7H%PFZsS*s6Hc9TVE^`vZR3hXL0xZs8oVCwF&0p-EB!Nj zA+!B7Bb9%D{(OHUU>I;Bo+ZbOVUrfG!~q>nqXsS3Sqym`kJt*FZ!p~2#Qo#vUW-{w zS5yx?Q{#!d!Xv_9!PjKYEZ6K1dUCI2s1Db;-SZYD#M<2LDrBm$F=w{%ZK%4*Ys|1| z7weCXO`8}m_ikJ3eMY)z=A*_{{1MVuUoi#uC#?Fpz^I||-?y)~d_KqRFHwv-AXp>z zJ19osgs=FP>lxC1-;Ny+JaMv1>BR5LOQc>bid(Xk?+*LUy;rt~c{8tb)%<(*5!;i4 zcVi?BxYEB$yuLnh%YNq%0*u|6;rk_z`dxEm*IVqq-Xiep`}U8UcUm#;nDyt=?yB$6 zeyPG~UIGQ_>;F0inKy9nkUlV5Z7TEY1E2qYNd9`te0|p2sS*ro7l7f;;OXk;vd$@? F2>`a$=0X4f literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_right.png b/Content/Sprites/Controls/PC/Mouse/mouse_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1c95913424fd7060492ab345ffa8ab21124086 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCij)0(?ST zpBuToG<5&}|NnC%S0D)l&kUV_ffts~eMBBK z@Fw%b$UNxzH2K1*9T5+bRUiCjNch{ppv$&}V}XH#BEw;Zwx^6TyIHaq++>%snRp~_ zzkc$_Mu8Xe54x@Rw6@OAH`Vpu|Fsd*)9%{sHN5z(wd$*dLv2Cw#Dm=TW8L2P m@X9Y|+~awloAXEM15WShA>Y5(n6Lo@lEKr}&t;ucLK6UVU*Jgq literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_scroll.png b/Content/Sprites/Controls/PC/Mouse/mouse_scroll.png new file mode 100644 index 0000000000000000000000000000000000000000..440c2fa51f9fee410c1dbc53b46d6f36b2cc2d0f GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijA1AIbU zpBcG5Gjx4v=>FWu?YWWba|00fov{m0{682xH*|$C@RLCEfF=Ode3SBg59COe1o;K8 zKd)auKmI*`f4%+w`|JJn><#WEy zDBkl}=FWurV;`AVuO}1=-uiWb^s@P|@3-IHaOqv{w@=E(Q$aZ^f;0ENrGj;)S4PF0}0)R#WO#te+`nBs4kRw$R7hdm z@owr2*K(QX_%f)>y4&N^JZ%EQf}M}}IID(l5G||G;kM0^f$cZJ&%DSiM;9%1|?9Kl_2>_ZHVM?+B^=|CO^qn?0a! zkN4+YJO>`@pY~?>da3LxE5rVpzB_@RGSxRTOx$fHxoFWu?YV*5b0b$E_nol|Q2e=}>wlsF&^(|CK;;*@+=PJ~$&w(y;PvPA z>*MFY=kMRY-roOyyng-u`T6qi`Oh;jo+*`QU|{s}ba4!cIQ;hd%e-a-9)<^bcW)J` zo|XOckAGJHU*WNX89~b*#_JxE-zaVQyAjMPey-E$~X z>caEmtsDkV*c+KVBwBsgbM#nRj@c&)`M)>iP&8rN(%Q~%(EV=GMUD%4G3(bStes&Q z@O8WXVpU$IE$5?e*PdPXChH(0gX#J3#c4|zVrBbve(&>_p2XMUS9euWuJ->oriamg zyN*5;t|(8CVs@B&s=YCKa{X=Ao-W?WUv4ox6!Xqf`uuO+)vw2wfA3+LkvJpTndw03 zXMgJjj0qtTEum~H4rI+a@Sd6PbUDX_WQRTmE@ly?44wmhhxM zTq0_?z++~o)?f7-603@|}hy22WQ%mvv4FO#sOi^!We) literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_scroll_vertical.png b/Content/Sprites/Controls/PC/Mouse/mouse_scroll_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..2c1ed1d53e0a7cd27f32c932cae6453044712e56 GIT binary patch literal 605 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCij=0(?ST zpBcHmG<1Jv==$8q?YV*5b0b$E`<<~1Q2hV@|IZCwfh3UtXe7`OpyK+UA9aBosgfYS z;Pv|F>*MFY=kM>|@4tS3ynTNCeSLoU_vhy`G;{1a#lXPW=jq}Y5^?zL^qaGq6?j^$ zqs>zTBhUWc|NKEzf%1jf=giMeU23~u;PT{(P5#GTUS;f6d?V?wm?2~`zkunE6|Q;? z884i>Z4NB4SCe5#+pGM9fu|zz14Ez?lio*BmcU5uMggVdhKCQ{F^L)KX-YEkNKe0Q zeZ%UEP=LRE{PBhm!2<>R*S>nas>sG$hT*{Us&}f)%o67d_ujA9OLY3cF#Y8FYe!2@ z#cLg?&H5doyPt7AA4f9VlU<)KHxw_oS7$sF^zRkJ@;gEMBCB_9fBU?B>-G|c^u}_} zu%(PReSyg$?%;@{Ryyy3JXAqyCP44$rj JF6*2UngDO?8aDs{ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_small.png b/Content/Sprites/Controls/PC/Mouse/mouse_small.png new file mode 100644 index 0000000000000000000000000000000000000000..730389335947f6ed6c289ee011ba6c17f61a39cb GIT binary patch literal 365 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_UvR#C{CfU={rdCs_shR$Ff)7Y0hGDu>EamTaXfj4H-kZs zmPDw-x~3Jy@9*v1`~BVB*+*}P#?*i3TlC=W?ua#9?-WGl99_kr@-^t&Bby0EbGWh; z%^rq)c-8gk)b7_GG%Cs%UmUQp;ktLP!9sX@Q}qv#10oN3v-WUtL^<{}UEkht?@qh> z!Oz-d`tPqjVcG#qu#e25$u!e zTa`C`J0LRW*un?5EIaNS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_UvR$tdj5X>`t$qc-^b5qxD|0Of`Nfi(9^{+#N+tgtJ-{r z90V9H#I0~ z^VDy~lVi`G=XfiA@Y)%MFpp;422Un#g(VIl4tfhuvOW>&XUO}=_oGJNi|v3agGKq( zgoFME7#$)x%{V2r8T~ijIrET*m3N~MSKqrO&%bkSnC~XNM)1KVk=sWc9U3JjhWj?1 zQJu%QJhbGDA|qekyq~_WR{0wKvPk$fEAN_Z9Ls5zk|_tg8`iRXW(m2v_r>v_%9qwS z^0;x#kXEW+m-JSTQ$o$4LV6ZWGy85}Sb4q9e02AfHYybcN literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/N.png b/Content/Sprites/Controls/PC/N.png new file mode 100644 index 0000000000000000000000000000000000000000..41f13363f311d16affce9787e745aa6ed9a5780d GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezu@}y@8|R9-EtPvII(k{DRNlulLvAKYx9GKfipu{dpUjV5cpoLz z!Q@a9ZNp@fHP@QE!AXI;qI}xPr^gvKSZwEET)%ZaGaq9c!)Ke9dJOlTGQPaiJt01@ z@?Y2#=M3SyEY;o5?VD%4kjlBb?=?$+P;9gAq{ED}WLk86g#_0zEj@TaAwi$nYpLhL z$Be3{OfT-cd&qEt)}BQ%!h5$xTi8tu+PgSLnD^d!`DweECtcUKKJba*Hsd_@AOH8i s+VpN!*8g4dUw4+tKCfTK`Ddkk?Sn62^KY+H0EQfcr>mdKI;Vst01+6@umAu6 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/O.png b/Content/Sprites/Controls/PC/O.png new file mode 100644 index 0000000000000000000000000000000000000000..ec18de8c0cab88499e2438a3bb36eb2655055917 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U-0|$@%8!q^7q&G&);v);A%F{94PbC)5S5w9(hR(pA{VRPKCZ3T@F^#-1H?mjP&vDbu z=?C7`7(8&6C}rBcu08)D?{Coyj!Jr}77CK`pOYm=_qNnYMsETz(8Q| MboFyt=akR{0K6EodH?_b literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Option.png b/Content/Sprites/Controls/PC/Option.png new file mode 100644 index 0000000000000000000000000000000000000000..bea912fc298eed976b53cdecfae3efba8e0e2935 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezu@}&^7Gf*@8^G?-_LM3o#`Y{{G_LgV~EG`r&l-f9x@PM zy})yTBZonG14EEmgO#ZA2FEBXHxDh9mKJG+2BuE|EZ#EzPCoCux4$R;rt={mJo#mG9%ON^5xubV z$ZA8D{s1S&T#bc$+u!bPVcWpM7}3O_b1;ojRiZ(N$AOb=0n1+gLQXEP<-FQc3>>l> z*R?PT{WA;y^G9#Nvj>_9rw%^-A9^M{S2*`~t)0z&y-UA!wJI4W92G82lXv?E^b~`q LtDnm{r-UW|%z~7) literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/P.png b/Content/Sprites/Controls/PC/P.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc24045e691766253c6f23e3355995ebc535820 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DRNx`^V?sujgMsU;h1m`+kPMQ@ZSda@##!977@wzrB8& z>#zb3Tf*)vTi3I{?cYXmHS2Dgxhx>!bA09F_6sh-ms9%d$aycY;~BuNnpYBqXHY&AG)^7 zlVQQnvO|Il`s|-}eGy8yr{(xda<#yRLr$OkLQd74W1sDLh8MdF{23~KH!@6R z4`EV~n{ZCPG;(v+oBrRbJ-Pg@|7VK)I3Zl?^liG!ee+2`FEDtz`njxgN@xNAw^gJz literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/PageDown.png b/Content/Sprites/Controls/PC/PageDown.png new file mode 100644 index 0000000000000000000000000000000000000000..79ee37297048e9f1a7dc5bc1df50585960898884 GIT binary patch literal 476 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=?p{p;uV?|;v4pTAx{o}p-;kP!m|qm8GFV~EG`r&q20 z4m$|2J($C=gHec=Rn>N)1;ZVM5>3x$7x6rS=^-lY4o0>U3%pZRtR^_A#2r-o<1M1j z_wm@_brYv?q|N;@FD>P4`ujH#anm;_c)2qD{jBx3^VL#&_ESfWd=TFwAT7!qW%I)* zVLtmr#@99y5)RWeR4O=jeY`6vn_FSL;537R45PSci{^s@g{GSQLUqzB6Q(NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U$FoE`uY3U_w(n!myfq+DBha%n}LCm)zif>#N+tWtG0QE z90XVs{3aeg~md)i?jpsd$uwsy?s(8Wn#Y66c+kctH zBf^tnj_bUSV0kWUeX#PlNS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh1F{QUL%?fdf?rYK3N0Y#fUT^vI^jwjFXWH9JaVVxZ1 z6uz)AfZtbzHE8vQhE@*N%i)QvQwvxlZ;0wNYi~HTF2OK{QM`a6sWUZ`vOp>;73=(Z;Q$dgEH;U jatGIWK0C2m>?6>-6L_?ACQhpZx`x5i)z4*}Q$iB}``>F_ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/PrintScreen.png b/Content/Sprites/Controls/PC/PrintScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..e65ba4a1883cb965319858da7d8e7ce650798068 GIT binary patch literal 457 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!>3w_v`ns@8^G?A3xt-o?-t%HeCh=Momu_#}JR>Pp@wD zJ8U4p_Fx}p{{iU>ORa<1m+f<`WZtB7r7U^%Ej!203?65>M4JqSI}=ufO!_k|%3P|9EaY-*?%;)#Me+q}O79yRJoUV4tOO8wB$&NxA_=PbU4Cg`O7+ zCmm3K_o?b)q2L9PIL3J=nL7Gs=WWv1*wnad#}ik!c|1SX^}2T$mkOP7cs#Xg$5lW3 zFDKVO-Cn8HzhAOIubH3ON%FEtPvII(k{DR~C&+F&kujik?{(ZmvetU+iNxP>3<*s?UIEF+VetZ2j zUy}h3Yr>Sf+pq2We_1PI(GE$Q)t#O1{wO8ZoJ@Fqsw5~)>cD!&qb^D}IRj0W@>*0{ zuVYPNoRrWcUn@PIQ^oN5ee}88d=EZEm_1`*E{v{_ z;nDd$^>I}5w9`%g4>SI(-52=U?vvzXu^GRXZIHb7QE2<&noEpNHM9<>Tx3{vcLm$N z_y8v3l?^*LvMD~e#91NwAa35S$1xHP!U}IHS2gr7?quR(n{s~pu7LGYx8DBys&m)> h$;b014a?^+zMb(c{k!VygFqiLc)I$ztaD0e0szmHxP<@! literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Quote.png b/Content/Sprites/Controls/PC/Quote.png new file mode 100644 index 0000000000000000000000000000000000000000..86cc155ae3b09c2e94a35305ad8ef0a2aab890b3 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh1_eEIeL`|a}?j%l_o28uR%x;Tb-98aF%$zafIQU4mc?qj(uB_XDo5hYZfaj=#@v zX*4=B&geWPKatBS{ak~Pv*j*#(H;)g$Qw_m9~5;-4BsHK?f}>BrlUv1kKX9M!Xe^Gc@&b$}sG|{}kvL22WQ%mvv4FO#nWRZ2|xQ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Return.png b/Content/Sprites/Controls/PC/Return.png new file mode 100644 index 0000000000000000000000000000000000000000..4cbc61d3241c29017f9f94a755242b43f134a023 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azP{~YvZvhNf+ac|b_mDUTC7>Za- zm^7Kb2nLke7qBs~Iuy_T)tJTa%5;t)AwEGTH_+y{tmlDktGgFOGBI>Bh;kGtf47bJ z{P$|JD8HWEnTmo*$L*@ROt0^LV0d5W(LWo>PunG)^65L&ozR|iNS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFZh0azP$bV{{8Xu8ETz>8Uck@db&7}TxJJE-yCCf6Af6z zV41W*JHpe0agv~g$eJT78K(KA3kPkOG=XV{poQofl_d$RimZ28MAj%gIg!W2xV0(3 zqf9tpLsLLXX}?;vl-7!4di!P9DM;^b$}M2M2DCNS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U-0{U{`u$q@7M3QUoYR!a8qY0J5Xkcr;B5V$MNJH-V6pk zS`t}YdETXaoS9|0zbk33sBUMqao5=KnNQn-JKTVOchmF&*0LL-Hf`D`4zGJ48FSED zCP6?e!piv7-Drj1x-lG~2ZitMp8n^9CPV9On;Ncr_hL)G--|Z*{cdl0gy^2d5eH*$ zX)BzY=#ZSTEFoiwh7H%R4X5`vXj`<$9+ckERC_~okDA@@VO9gjT&x|hMz)z4*}Q$iB}-qDbY literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/RightBracket.png b/Content/Sprites/Controls/PC/RightBracket.png new file mode 100644 index 0000000000000000000000000000000000000000..f64d1f635617d34d2c3c803e15503b0ac02f42f2 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|&0G|-o z|9AmV6;NLF((NiBi@PMqFF5{we!cyA`T70(8KgA+R|AEcJY5_^JdP(vxH1^@sIZ<6 zNq^_YY}~wQf=I;sV@zhsB5Q8+ik2J{tw;{vz`AaM)b6IY1+15Dh~~6t-{@uTiD7j( zSLDPMb}@p{qaftqg8+y27i>jhJ!!UcxYClR-{%a!&>MS@Z%0$k8?J4F@gm9kS=*JT ne)C>r_;h=^gr2V=EbPa>2tDnm{r-UW|9BXtk literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/RightControl.png b/Content/Sprites/Controls/PC/RightControl.png new file mode 100644 index 0000000000000000000000000000000000000000..13810938225c6d0df3f58f4f383babbf63ffba8a GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=?w_t*2+=kK3y|Gqz7owx^3@h{y4_SFE`X zIS8;NyNx0i&hn2I3r1ky7~!wkm{OlXm2mKdIBvpCOkVmdInZdRyC{ zvxnZXZ|2z@+@P=dn0ym-6EGbFwc~kpU|G;#!_XoL%^W&fw0EM1b+t8lS(`M zbmlZlH?;!{(R1!N&$g_3W2}>{{ED5tYW!( h@BDA2`B!H$o3ApMto?Amw>Hq544$rjF6*2UngELusY?I= literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/RightShift.png b/Content/Sprites/Controls/PC/RightShift.png new file mode 100644 index 0000000000000000000000000000000000000000..58940419d22e878d9ae8e44ef8978b3492628213 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu@)n@7veU&)?tAFCWkFLe2gMP~x(ui(`n#@wZoOxeghK zuz&EIci^J-j$M`&4EYI;1!eD^@P6U2byzTO!CNJcYx{KSrfqqzr>1m1Y2M1@ga4L4 zdCIP@s3K=__mwa${jL_UB4CE+jZ3#n8b$Zlsc(4b=$LSt`Rnh?kE=z#KDXa^{deGZ|FQ$8 Zn9J_e?|*xW=R44Q44$rjF6*2UngIDvsks0E literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Semicolon.png b/Content/Sprites/Controls/PC/Semicolon.png new file mode 100644 index 0000000000000000000000000000000000000000..971c10af283314f969c61acaf56483fa1b34216c GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezu@=r_4n7y&)?r~pU=Q1x8@E|e6pvDV~EG`G??(+4Ly=xLhW><4md^S;Jy~84sBJ5>wNt!)7=UT#ad%o}s z&9MhLcQi@7;p!8L7fII7>Q|il&AQg$Y5y6y%BxCp3=ECg5|g*TU8n?f9)qW=pUXO@ GgeCx4W_*wU literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Slash.png b/Content/Sprites/Controls/PC/Slash.png new file mode 100644 index 0000000000000000000000000000000000000000..535aa23b68f7c22ab052172d1391b37ba9544faa GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DRNt>-)#w=YKE1zP^9H{eA}bBNZ=!a;H39977@wzrB7? zs9AxBC19@FJSp48o>0IOQW%lRUkpT zxFLq|fvk%3Yqkc4NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U$FoE`t|$y=fBVIx0jD+c*D-5%)r3N?CIhd;&D8Ahc|;k zkCsHJ!>*>=XZ7A+Xy`r~r@~tGenW#h2dnx0MAqVmT-OrAKX9#6;NRVpUcg#(L)4~4 zyP};rAky*r-Qx88xz%-9XLrvEeSYuG-fBKy#tTOa%irItsQjLH|ITjndrXxXT=(Lb zKh3{eTYK}{y|~A_^WP^%eEg;~;lGT==WqA!ma}irs3JBog}x3~2u@A~)mDz}Sz9NpWu zde`nhre@|B%r^bmaN536dq#WgLGK++wKqifsM+02-u_s%=vwgcDf+jpquhG67Bn(3 ZOz-$nvg>_LHZY(VJYD@<);T3K0RS3_#h(BG literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Tab.png b/Content/Sprites/Controls/PC/Tab.png new file mode 100644 index 0000000000000000000000000000000000000000..a9124b6943a103b35b6bf96bff5e44d4df73721a GIT binary patch literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSr4^Y8P|ulIj{e!u+setU+W0%d|gxxJn)jv*0;-(EW{ z)U3e68nF6=@sU6OuWz%uu~GQ8P~kzPaz^Kt%?SaL(~j|QX)HMK*Fj3r?bl?9M4#sk zOJChER+y|Xli6dD0&|+AfpNklMqy?T3D!Es(+ipSE;?#HQub&}xOT5)?~FYH2fi!n zs)p}m|NY@Ab58Ttnf7T{nc9z;Gu_Uy44C&Z{GU{VE`uZg?2g_B&fEs>Uyd(jJ2rit z$Qa3%!loiQ;obke-7SBfb|u%I&B~vAPgpcyf%5~-k1St=^9^@Y06oIs>FVdQ&MBb@ E0H`aX?EnA( literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/Tilde.png b/Content/Sprites/Controls/PC/Tilde.png new file mode 100644 index 0000000000000000000000000000000000000000..ec91525690dbad7ac9926cd376c89bee360269a3 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu^1z@6YGU_phJNZ@-`6f2q3swNI0pq#@V!NAm z7qFJQi}KjA#;y+g`Y3pV=#-l8kHQLM=XmrpORoNw6w2V&l1yxp zS+K9++TA2=c;HAhrzz`lbN%L?89n+kANS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWjRo{r&S9ex$br07aL3x;Tb-98aF%$zafwExoGJ~h9pUXO@geCx9ZgzJ7 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/cancel.png b/Content/Sprites/Controls/PC/cancel.png deleted file mode 100644 index 170b55c530620a8370c3345b81f0bae297a95a8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2480 zcmV;h2~YNkP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2}ManK~#8N?V9^j zRo4~AzxM@~ha#yDe1Jp*j2#eP!8f2LMi7CBsZGX5C!Og`JJZ)s?N8}{kc_{y)Bcd8 zwzV2j6crVSfT(#?MTL?oqC`{#l}8AV`|Nj}bI51}&bhz^GTx7~J)C{c*?aA^*IsMw za}NRp2oNAZfB-KnChh1~yk75I9@1G-v@#UcS}8Y~OpQv-4-pwO%lj<1S%!-|D{Y7Z ze;82MMJ#7oMjL5!k=D(`gTh6y91%(VjPwzqbvrSjK)YGmM7l9T`r55^KfX|q_Y{%F zhxarw#s>=Up(@9?@}VZq*usv*>?aCiyBwrLwciQFu$16)BE*g)6qU0~Q7R@5?JVg` zp028=#_&l29K3`d8N6OLH(p2vDN5*2PxbLt0q^thTlMUDdV8F3IQw{?R-s|BSYQth zg4JfxYV>itJ?QOq!0mFW?NL%iSpH|T*$@&EEN27p0Tu8&?QdNSD}aNSbo7pT_B>9f z2N%xQp`@e)9i6mBuSuR^4<g$6q5U zIbNwBgpa6zpJ{&&3H7RvHv5APUNDp!gSvM0I*t{U zpt13RV%`Jc;Y{DX+l+#OB9xbxqo=z^42X?;VX<0~kdTO-yWYlvSLUe?49*@+W?c*^ zfDF3spT=&tVdbjDR6;)H#>Bu%C5YLIp>=h2p@M@dE2~7?lMZ!xJcXRMJ^2QomR&?y zNjW+@J6R|7CJJfB%&3{j%gsh=YBGI*AzxxhW}^zo)sDJ^hT5^=wKdrGW*(wu&V<<_ z3ZMaVG%YQyICA&|swyvWcAe@28shLSU#h{$6Q^z~MGYRe8};?|*#EBrE{U6p z-w4abxODjv_U-#O8t*(%YTF+7pz!c1R92ivcem#BsI(x4 z&c#cXV0->nBqYv-)oMJ9YUs-D7X=8x6h0|=0dlrxVL?IyY!<6BqcXF-y}hVBTY*Jz9jlAN&pbKHi6i51OeU&F=Z%jOjCwxp^bjrM-&DlMS!? z@1rZb?tT#S~^LG%>&^ip${|@E@LypmC6c{$*v}Vnoiu`R`khX3O!a~C+6$2Xw>T$c!)71^P z$E7$=FO?M>WJBt*<#_9@Jj{=e9?{^9;CBTGX66I2adVKrJr9c(B_qgclZmEvNV+V^ zk{mr;_e^#Y6Y-OG@~~w20@#AAS_}STOcWs4f-Fc`x&T>QHX-syFDWrzbqIt<6Rl$U zwCT$A)oYgdedhZaGX)5;sc~_4CxbV8%#a+3<5sLema3!$Zl@dGK~iOZU_=4(qG7~1 z`ds+p^J^$7D#qhSPt+wqA1nhGAw0B#*47q=M9Bv}XTCtEIC6AlH=+P}$uJ^3oY98* zCKMhyj{nxx(Fz*^MY*(02evkip+; zYC*v#MX0L!3_aiWFxu1HWeHepj0$!oKadnaLZid!z|||4QE;FTH|p*%Egq32=*sR_ z1<35SwzT8;(Gr|0KEssvvEm10wiy@@6Eg>yS#KaNK8{O49+0Qho#Xkc3n)HWiu?Cl zlx^}b85IQ-YDb^x>gqw&xi6J<-_+E^fyiu1zURT@Nt3XZ8RBn#{|oHiwG&ZMQK}LY zxN~f6#hFv3C@;H!j`l9C-e+`W*Hr+Wl)Pp2*%9_JySr9hhvUbJaq~vK;@uTE{q|rx z)}^Om+x9J(`|>RA95+xI+1&OrJSsO)MNE=zH#DH=Xfdw*rxv|E4&{muv}>{ti4hAB zKGKecaJ%UAZZ+Z9(bKqcsTvOD^%#dn6PHYH>9VERxoZbvxMLI|r-mYD+Z$NBcD0%* zN{HaS4yOw>+#VMkJch4o8+`Q#hGaIX0K>~ba+^o39Vk9=78ReKLwkD%$HGdE$!xJ; ze%yTQcsn1-DGA^0?PdEMmk^EIyiEK!DG62^cYa(Ca&>luU5e?AeOK#9N5N?Ck8onbV~xE-FL&<4)~~A(5|3L}p!#T7d8;?Kmj%TI*uf zWgIwg2u)u%!R=;NCuuIP$(x<^85!8HF`cP!geX;gNJGx2yfg_J8&_f@?-3^{i1kP` zdD#4r{-6k-RaL|3(9I8YW$nkX0yK>dYF6@E>qhMz9Nb@suj>BCnRhD#mtv*q%O)r* z`!z(zMkyvg5V9oZM9-je+=>h;D=aj$-yJBHbn8|F{`rsnsH?449~hWIqq8qOI}JK; zHsz-=iLKAQXpn@b@%DXGS6{<7ovN8Crcdcb0rTVMbA2Zw+`tbbjy`6DH}0UewnlqJ z#s{>vg6+XroRWfsg)b}jeh-OO@}r1~1o;(qKo2YCt~x0xPow4h#$RYEZHehC z4)ht+cBH)l*u(mdwZHubg&WVWLIz`OzZPMK6XENSe#Y%9k%?dlPH9P9~oCpmE u4nWrHa6Xs!e^L`5K!5-N0t9$L0sar{>$_&uugTQ_0000QP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2(L**K~#8N?V1a4 zRMi>B|92nRBpVWv@TdudkcWT<6O1#Zs31^D6a+ebpzT=Ds_l%{rnJLY#M%liZLvz? z)R{WdqC;mKhuUODp<^jYFo|P3VFD#sijpM{3zC?GB%5Skx&43lUOIhc@7?X1tmFP> z&z^hko;~OLzVrIdxfcl%BuJ1TL4r>#iV=ULsH(bv(QOQ6MhM4ABQz?C(y86~I3h|j zJj>u=h!**;lpzNEctBxG85$U3jg(nxR1<$txD19`k@O=*>c}vvjSnc$R)ztQZiFBIfSO{D4JNkfe3fdU-R<(O6u7~)JVtXR5zyfC%HK`PYijVq!uLd1>`E0U$C zkzuBGBSOZ<{1_b_h2QT-FcgHMQV5#@hr@~F{;1Zyl4r^%1f~L zxfXe@y+21^|7EC}VhRla*r~p>z7k^Euz;d<2QiG% zHAE`@P8-4Qv|;6~w_?xkU6_@Z$@zje&3TaqxX-u_izNd@()xa107qVHMD^3ZKu=FM z^VDRE+WH2)$%J?@tGCawd*@5 zF3GbfwY6Sg)c}^qeoNy??EA?x+JrX|3h@pNAU{wUJFT!FZvpPyupXs179)M;4A>nG zt_)+i(mR6J4(A?09pZ@q6 zbY5WNaahc<8|gao;z-2v@S{#CU-QSZG{Nis^`=^0MxmDjy1}I9&HS zn%`<>id~pfygkU`see{hCaS*q2!2+x3poqY|66&1`BG9{xPAT2c)DgUmX(*mW^-_! z0FqrUwt5~`tXPhcrAz2DSn?C{4cWtD+5=d~w;1i$QBkd~{QylZZ&7eD0gXWE z#j&~jo_p}f_N_?Ia2vVJX+L=$&)2-bf@~3ZCJ%W_;_QUoP3AE}DHpxU^O4jRDH z9{=d?ThwKXSF1(y%GILW8`Z+xa9RkGERhj>%FXUl@+(svs);Wf5cpqI~%j+&SZ~@;?Fv! zvRg5L9A<`PWWcWw&AgIb;Y+iraz0qI`O24sHAk zvVq~=2K7hl>DIol-<*0(Ww&Ag(_NtS{NlxhD89B3ibJ0OwJi|6wljY_ha-oN!#gsr zXST?P?}xDM%T>60^Vf0w=wA>B1hoA{gqX@669WjvMY*V0R|%KHskOcweuz`#9U8`O zUw#Fzz1oN|Z@|bsIkKndIM;)nJ0C|&a|=$ip1=cNyB~M1{R*Dne-LNeJDA7vkcx=` z>Wnxn(()TNt;MpN%JnoGOWI3it6jWw5!E#{_~mm4(doIU{r>tDTyrutScyK>hOrm|ad(Kw+EFtT(CeC&-j?Afy$-50tL;&Lbl z8&ZiJZX`RCQB+)jwQE+R@{UR@D#_6#7#&ja_S>zfJyeI*);9F@_t9`vl8Vb}B9^o{ z6s)>sCBFCl?I>83YsIx5#Q(kLYIS#XFUEk?+ zqO7bGPyOieNR$_>4P7HPg}tDGk?H2*Dx)I-v^4!0&sD#m9gnGWm$e=s#-Ng71gTzz zhNQKXgI{7Gt>u|Fjs8VNWhL(2_9ZMWD`XDK$lE2Wjq9*PVt`eQJF{J^0N_ zze8>9s~8&gaz0VxU=&Ecse}j{ot}T&fRIL$h{^P1w{)n`%`H~ z&ZrRASB}FiKN^b|8X+E^3}0nx9+R`8>3l0>GN$%z5mp!vZ--oE+TIe0hn_I)?+H!k zoDer}iir_Cnn+WF)D<7fUxfmFa$l7ES18;nhBlEj#z>h_dq-0ah26vuiyk3mY%+?C zIT3k+(Lx1eyhii7{7c%M1PKx(NRS{wf|vvR108~Xd+*6PjQ{`u07*qoM6N<$f{zqz A`v3p{ diff --git a/Content/Sprites/Controls/PC/copyfile.png b/Content/Sprites/Controls/PC/copyfile.png deleted file mode 100644 index 7bbde29b032caefff616aef491950239912aecc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2438 zcmV;133>L3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2^&d7K~#8N?ORK4 z6h{yq+q?`o4j>S+lVHRFjO>5}_`o$GXTTOB79hmM2VN2f1Q*~$5?dlDLP6pH*9hVK z0TL8);34s_K*qd;lK=)81jZ&j4EE&v%3YnFWp;LUXBLp`Pbzh9cXjnw)zvdSyR+UH z#xRCajS^E99lq~#u9D&5;SzvNTC&d+zE@gW$`3yJq_Nm2S^(5hI?fU@Y`S6r<4PG2 zjB^8%I#LgS5(nXc!)U8Qu>gUY3#UFq{Zo`vOy9pK`cU4(xNg+1qpyd33XCg7Ti$`p zh13E7@?0wLFC8*XY@@?#K>9044VpfIR6xqu9|DdYfb?VRUy$En?>NR@mtFw&$`}O5 zd)Xqfz|}ET)+<505#=eAuOVR=hP;KmF~U0A!tmPIqRmP(O<>Ls3J{Ui1i>=YzeRb5 ztR2v?AtS73bCl42SKq}MGl$HnbAJ#F4Gl5nWeb7Gm#DXsp@FVwl(TW6c4$-4jydZ& zH|izi!uopyCba1X0_#DhS7?oZD_1O7+nf`!-p~keDk^lM&dyHW(_0N6B5EI}i9j}x z1G%`|iUyqk^Oj@cV+V0N}1v@`EUAb~a zGa>zJf*QqK-*G}9;5-QU&FYN%&0;e|uLnGydXFDJ_WJw#y|S`0Y16(56DD|7RaK%B7izPo zr^kEs>J^XG($2QGZ{K=TrcCi>&z>!94wMt`NMB>jRpl`cj*bq|;q@Q`);Kvs-};a@U_+J)26(pD<89~_O^KX1 zaY9I9m3^#?2tSvXm-{DAo)jH*Fbrzv=FOY_ym|9v?D+BH#ooAa)W#Fkr9@!r;|n&N+N!0=iO?R6|395H)FMgRo)42J4{eXF~h2WddW>R%Kq z+S&q6YY?VQo95rRaYJ;%0+<2iO73+SZ+(gdkdc(ZM0>?d4(AoRFOMEQ8gN{lm^g8w zb;4amt@riy`PJ3cfiW70ojZ4m4&jcCfGEL-eHfqLHo!Ph#-P(Q0^|%ip~Rj%dEzf$ zzC7T7I<#riCed*(Vp>0N;6OlE1BiRRfBEud(Q(J+fO7s5HmpxM0Yy#!D#+guB31wh zC3xu2At6tpL+Z@TnKS*XSFef=Q(1%d?AbGa;lhOh$F;;gUvy%mz6(|U2T~0?@wNdb z(e(cY1NcQH5i92ib?C*57k*t`UBD5|hAmsRhz^7G=FP|@=HS7D(npC3SRPQ$ee?yk ztZ$Kk1A6#r!C*BKI{<_dJ#yrTb&8@+;b?3RGsL4ukNjoJmPudcmceOIbn-}jh2>6P zV9WXz2@Du#%6&5Y|5S<%Oe7_s{jahIQ}zi zzTW^4x^E93J{)jTW!9`&{^G@prLK-^rflE7UB(g#G9do|s1nLVTYzx0VCmAO0S8@C z=QTjQ@?W@cLB8eF|jvw>QoO0AZasGgkt5&l^(7Ok}1rf6u=)^>5KI( z64243a5aR-NFv!%I9V`v?p#@Ela7J<$K2)hPw5Pyrm zkMb|moCwSU*pe*3yB$@QSuMn=voxac~)?)(!lmK9G z&acJu0qjZn@Zm#wEau+7c=4jNrL_0e$XRlCeaRazpogNYKa3OtO>_SEv1-*Ssi&Fx z1UNUlJ`@Dl(TiajL|=hPg(<-=LOMG;&8JkL+{jfNM;UqX%Xwu)1i61ug#S3220${6 z`+h+`j>dwf5e%<~C=zc4*tOS$gm8_>dqc`OHNdbe5e)w@GLKA}3j2hxJjl)EnksOG z7NZ><9Utv0GM6r05{}9>b-=Lfd(1cbUXoJi1f%jbIfXkBIE=0rB^8)(^u8+V0z~u{ zsV_^PB|`@!&y}O(3X1l-`WCRy)99NW&tCXnghkadsaBwj7 z*X2`79T4P};K?iV4-;!~%HtmPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2^~p9K~#8N?ORP~ z6;~9#`B6xdnk+P;X^Ih%gfvBQqpi5m_y>a6lv42rTu2E>a4D!XpwOR<(1o=q=}uzQ zx^f{j;>x&EF(!=&8j>`r6}646kl*R|oi}H^FK^zwnfK(#5KamhbxWaYk(e3;^#RHi(53FNf1&<@9zwszDEHymFpnwFuMl;S z6PXFIB>?0(RN!AY4d!w^zD(FBmKTJa=Arr2!%sM}exwdGt+;x-W^Q{6zWHdpr2<6?- zH_6%p1DkS%<#d4(dfaYrkRBU+`?xCuE;XBZ*U9p^kcbdU#F$-sM9Ct>ZY6 zG#ki)Tx@Q6gF1lU5;*=jK|zquQBMbZHjqn+%`tYsuw?nxty>)VwuEbMeZDPt{>kay zy?Z(n;y)*-QTY0X4uQ16gN%drk%j%TfSrVIU5@c40EYEax0jAwqzyh7OiWBjG9tou zy4U8M2^lj5L)_g#O*dfo^((3>Sq({9YjDo3su>*}H6tSks86dTe-{8Gzhc~L+~#*BV^S9`3%DCs&8Z%ISJs>rAy|}p+ly!vQp|Y zK@+fO(IQh@TWfag*kLwq+$hHo1n(=P90JPi7YMiDoJtY{4@L%@OQ6u)eJRq;aZX?2 z%$YNEn6;FZl{q_i?sNtR2gP25CE;-+XV?n86jA^il6Dy2-d?x2flM?3=gyszK<3Y% z&%2}0g4rX&zLeFgS36IhJQ17VAvy$g*#xx?!s!)iE^1#8 zND{4A*uPoka-kp@vXt)JxnqtVJ?b3~334RYb>QB}ilDx}0fB4*NXW?pom-?bWbi>C zk(mjx%OEW6^fz(!>Qyr^Fd#|Mx)2bqXfNCu3*dXc^9@Rgz`#c+e=0w60Lc^0&CRB_ zx7T39;>rE{_f2PKr`f!Db5asC*k{k4nHx85NSTR=0@(V5F}P)^n+e|ppp&$Q!zQR= zRzdtNL_k$lm8q+%GYt(5p48XZ%NhU5l`Ce=nl%!*CX5&#A2&~*K6QVE2Dy@RF=F_f z6&lk_1kM2H#I-14EN3tnLf5(qPM)T;wA3^<%98a)UlZ~C`E$`)9}?0SHYA47Gk}=_ zc*$l6j|Tx=dbd}yv+yC%mqDNH~`MTOb0VS`s60or&0VyS0AW3!P`fks6jH3j_@ z9R7$Zw&74@^gcN`DZyYLU=AKUC}q}ZFuQi`GEGfQGVK+-+zky48El?Re}BK%R{OF& zcb4EI$%+8w40BF1`u?P`$D)mOqQeS;7Y&l4al&*S zJ$fWIL0)u3Xs54Xk1?g}3jNLjs&)D&Dq;Xfm!s$>I`Y&U?e*)|%O0SnrbcEA>$8CF zWy)NgVk9L2>Ihn1S^%*oAV_RHc<{iqwYABWgUdt*CL*+x#*%_aiz*i|K#r_^`LjjW zxXuDz`%j)cY4+^dBS~OgmPrUi&=TP5Dk7`7XG6)aSh2!v-@e^!+qTUU{@$`>i&?pH zr6hr1TU{1B0iHNH-6hH!Rpr1$UNFKyY5 zOM{og!NEb()zu~SF1;{dL(Tw(^oLaV^bJY?-_r6$Wo%Faoa!vw!fQUky#m4MPiUXV zk4Yzy7_AElzG#)s&?y~L65vi(>K>@SSq36`Ob6RP%eE-E86xaDLeCEopaw<}OD_u= zn~jtNAoK9;@Ll}x&CG(!l~ZZ*Jn)h zf|tFpqJe2&J?XW!wweP64oCoO7ZTE0xic2V#BylBp)f+{$dAQOpFS;9Hy5d|uXj2+ zI>a6U9&RZklw%jU!Dd*S#!!jH&{9VG2IDHqA;PD_gn`^AVdK9B~@7{f9Kash8`?hdYuCW7#W!=Ny z?E6Scp$=x{XL1VL5jf1Q4NuN@`Q zunfnl@tc2{c@LTi`v>KhI5v!9e1Q2Iey99phIVn&l>64!Lf%duAdDE~(UxdPB;x2N z0iz$(|L9Ls>A*xl$(4f%v9ui5K&jc>)pMA`9OjTm81o;9qS^tqhWfAo0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2&73wK~#8N?ORJ| zRaX=}`KXw*8YdyOP1K2|riSB0^!l9Wqug4x~Ox$H8a8HlmbL#G(oTk`DV!b zWbFbS8?%Y|AV&$Ucei)rzO^AX)%KKNY;25EUX~Du)FR(Oh88-aVa{d>)kB?%4%l2l z+sGG?3-gl(7<8r|2m!&a*Q>;)!Jv}|Vr?*)?MA$lx5))UPqQMWCl7n=5h*pu5vf zH|KOn8!0H_=?-Fi1x{bTqo|z4NX}Y=Q65pv>C>mpjvYHpd3iZ!j43M0?KV9)IB5F& z`+1zUB}p4)Wo2f;f(5q31Led!QUm&SD|e~Q1yH2Zz6eS0^X~hxV01KDR9#)2sIRY2 zyn6LYuC+WJm$rE=`;|bxP_(pa#iRXKn7wL8lQU zPhSep9980L*RGYHvg_8ZOFVn_Ov*+^c+$-b+VcK~(51a~eMxV4x zA@G&~9h^R6P%t0U`#W3A=@b}Iv=xavh1s-eleu^Ao+&OamgSHQX3d%$jkm%(3)HgRg0RTa11hE8y4>9uwo#W_h5SV}b__5i%d9%5D_pV%PyBILf`r`QJMpyto zp+Mq&%hNGal$4an`JJQ8(IzzC*VkvZY}sNuIyz`iQiPx~MwBj9NP&-jzdb;uPXC;S zMMt%wqC$QoEnBus);k?15zTW$Y-wpRXU?2)PJ9edM9{O$M^<_w;5P$Q%1a9%uX#yF zc`Uwl>y}x)dbM2Bh6aIw;#pzezJ2EK;lt7=gClRIQ10rB2c7`Lfe#-(m_>^gncKH- zo2^^7I-4GYz`V|u*49>Y=+Gha_U&7_*4Y>*!j=GER}pzHOm&cZ!R5=B&ECCx<(jrw z#~|p;J9+Y?Iez@O2E2p z`rQZ%0N>K`MP;PW(PrYYm_L{G5t=R)OCc)oMJs)Ad~?GS0FaPIkUbE(3?gNuBg~O+ zXlO7uZ{9S^moImgLqt%{@1XM!X4E$~Jl42Q0KSXogT3drIC3xube1E(YSk)pW4Ro;AXjo8wLUmLr6P0&pi?*U_vIpH zFbH&*vaPL6o*mHneD(!$rw=wSWvTGh41;{EEOk)ulN8!>br_T=onRueA(YQ6$+gRJ5A7Eg0B{&DLgWUZ=x1BZ_8xE4KwVv({OaSb z&cs{Wnl)>({&7QnOxzdh>+9u*R838d6W|bs$W44AXL6?x^o3{t6KM=t$M-^z}JKc3Z$Q9HJ4)!V#$|<^+qY5a}XzoH% z#53dp0Ee*G?rtvf-H>vQ3{Why1&V)6+7Y9Z8iW8iJjl(>HBun@qV&)h*Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1_4P#K~#8N?VD+= zUPBni?`?HaYpY2~ENxK~u|$FoQi24H*h$0(A;JeDNGyq6ED7p^F9eAw5rWk210p19 zEw%5l6ExCItF-m|o%ft;?!5D!<+h~vzVAQzW#*jDnRDiunP;Av_qMO6o_gwP_2+4+ z)~;PUnPjil)v(aQ{{H^o@_eZ}8h}RUxxPc-QJ9!r4G;P855u{T83Kctv?+NvZ@j%e zA9jRVBV_~BQn(oI@FHb|P6n{?AHbCC#_-lMI0jx!8DLbN#<~nfLgUq@aCa-)t~Qh8 zz5fkN$Zm`b{RPt)0Y9`Z|5a)P=

R|w-`W;g|=9x zn+%Xt&j5MawdxrlPrFt<1LSEZtpPU_i(yF(EN9eJCF@-Q)}5;3Zzz+yHJ>k7ncr)y zR49BX$@8tNzK`J=SPrhEWiPQVKW2Zp97aPd8~z+rsHjDtd+OugC44w54@ELZ4Bc&C*uS5pJn_*393(20e70YAe$ z2#4_N@O~?s$p+4XHy~BVuW%=XPV__2(-*Sgr@==#=RjEAvQ8D9ZmF6Y!16~z+;d?M z#y-Oag+t#SI~(?ctst($d$AAD^M}*I^NKTJXP6EbLfjS)KPsnOQv>)BE?Z4xgTwdO zD=+71UB%z2fi`JnGi?rWV|9v^YH9$z`Tg)3yaF~P*0J~)>h5tiQ)&VZxgSU4CCho&nSH4lyho`%gJUUSQs3Sk_u0%k+1Y(I>LnQ$wt zgp}sM7$}~b1oI)3amKQorLY=eHI4%Y_v z=KeiZUZ-cI7iuPihBi73ztwYx+rV&I+-1hT#|SZwD654xuZjak!PpM?@4LeiDD(hK z0N4Dmtn0da_^@u70`VHZ08;UYb*Ac=3~xiMp~nG%9F9hFDO9`+I%@14?}ufJ`>}Mg z`?RtH+7nVssCB05I365Dm8vp;FNhmdrIZ6KbBcv@j;F(o5c?Vb%^hM@9N~L*f=eLW zl6O><0rdL5T$!&z6=@-_t;3HC%Z3=eT?uzVrzLb-cnCZdDk8n&dF!_h_X5v?F-I-6 z^-MlbibGMot0y_G&2=1#o_TL@c`J--%;38IBNWCg<6h^3}Dnamnbm%)A>-{VgR?_ zH?*>Yl`??C#8Z}$CVw_>Q=0+uVdBAOd`vZ*-z_rR9P=}rB09l0000EtPvII(k{DSNA-|PFIUw^+pUY>vde0zq?yH*te<(_)FIEF+VetZ2U zU$cS$Yd}nd?6N=quZyk7%w2e~yLQzb^`@evk_eIQlLcjem>=Nn(s*YPLC$>CIX2BK9 zN+tWHVh0;~YrW?!s_OLRX3m^aWfHn6A>sD-w^i(XOqmDsn5J#5x_0_Uy3bUb-t*Gw z5+}~TO<8y1*1pa5Gk@fY=QDf~saTrmc(F#PEtPvII(k{DS@Y!Wm=7IEHsBhK=+{_5}>&CJP?hR&4W-JeWZYs%;7hqc9x`81} z@K}sQ1DDF}e<}@0%v}tdcu&mV|7zB|RgU}Lxxc#YSNO-6_km{mGmmd>8WNxP0R6+@ M>FVdQ&MBb@0F-g4ivR!s literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/s.png b/Content/Sprites/Controls/PC/s.png new file mode 100644 index 0000000000000000000000000000000000000000..2c16d711b28c5da5343afb9e36964b128d6cc089 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS?@>&MUMuV0^ke}BKd{CkE5L9q;=+(%Cr$B>A_Z>Jv= zYF6NJ5fyN1IPt$ew|nbiv1raOS2nrJ-t&2s)_M5OiiON|yaERlj&UnWaXe>`?OuAG zLC@$(QA5AZPo4!83{x3(_!EpBQdTklV|6&E-zIu5koSP!?GwJ!_!SB}cv}lGEV~#`BwrA38D_$JD+95ub;R?fzSubAKI9N-E{8Z@s{Y5+^Idz78j8spe z(Mk4&sZz(w=l^6%coJn1%6MgO`=^UFk)cd7?Vj6zCd^xLmOXJzm&wl>_ABpO`7~G* z-rJ-x9B1CaBT&)s;cw{lt*cjkF1zDCWT;%h&U^=NUX*{an^L HB{Ts5ps&2~ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/t.png b/Content/Sprites/Controls/PC/t.png new file mode 100644 index 0000000000000000000000000000000000000000..c122913f570243d24d5063438d295518ae89bf36 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g6_7x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYZT0j5=NH zL5vYS4f<}PJsPaaR{3R#)8iS#16pGb7VT)#c*8YKC|)F4KWn<;)Nhmb8a$mI(YGf{ cke`9!{T42+(j`WXKu0imy85}Sb4q9e0I5@CKL7v# literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/u.png b/Content/Sprites/Controls/PC/u.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc351c144894c6fc0562e792c6d5b3ec7ae16c7 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=h0``72|ujlWVzdwJ!J%f)%TQg8yB z9u-#oyXXG6Gp7eVQ`Fq>zn`_nO{3zYy!MM`?H&EG2jh1%{k=D<$!5)W#|`Lu22WQ%mvv4FO#pNHrF8%R literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/v.png b/Content/Sprites/Controls/PC/v.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe6d9eb872d7a53c8b7a0dab9ddb2ab2d1699b7 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu@}y{P*+Y-`mfZ-`~%Wn0RLuP~x+vi(`n#@wZp^3pN>u z94{2#u(_1QeM13*djYfC0p1ekmbocb+KTY3$%o3^T(yteC z`;zMB%=A<#bgrj*Cqpvpvo{Ak51y1uFm>HU_HCC;e;o+h-r1k=$BFl z7hjvYNRS~`Q;P8dGNYEi>hQF^@;?7I1~PVdm?#BI&Tv_vdU3_S>dnkXHG5Mx9Di^! xq5a_F?~5hmxAt1R?Os{`SBU@p_8Z3f%D*Ok{d{5KbfEVcJYD@<);T3K0RTb5xD)^Y literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/w.png b/Content/Sprites/Controls/PC/w.png new file mode 100644 index 0000000000000000000000000000000000000000..c79a453712f67507c0aa63fe42ba396a70e16ecb GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}@0G|-o z|AYWgAyCOe`RR*+ES{1ezumFpAV`#F4`3-~h0X_xe7Cr^TfVz2&|C!?D7w09#P}tY)iUi&o>$J`-%Bf6l_a4+Ps_9Yerp@`ZuqgA~Gxsraud0 z2}oW(#o6&tlb8O}JfV#XSg!F;Zpar*u4G;+kkxi$_kt%(A11yEUN)K2;d+6CCriNI z_f9GepLm%v#ec055h;vRoDl5tfLYR&#dJb|%Ytl|(BMV9CA|xBybRQ}^n6?do~bE) zFrFM2zn5>rgZ=Tk5uYC;INr`&TFV_5Jo6hWZ9g9QjeZ)|CJQ Og2B_(&t;ucLK6U=`LGxO literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/x.png b/Content/Sprites/Controls/PC/x.png new file mode 100644 index 0000000000000000000000000000000000000000..fdf7e5d676ba0ed34b73c469b6d5c9aba06aceee GIT binary patch literal 429 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@K*XPUMx7Xi){(XEu|9pnq^Up{#Ffej@x;TbJ9DY0f zu2i!EN1OK65B-(@!*^fOtzM>GV14V!38VWwKMu6rZZ|7Au%2~Fo3oLZk5AF+;*niXr*^(x`mp`u$7eex8*xmrX^8o;KzHJYHBl3d z0+(oBoO7xoNKdoj$+1=3o(xat7sqX72-5mlB^Ai9vb3S@a+x0EZix+At=8}=XX}O6`p^UF8Xk-VaGjjs|FT^dsP|?ee4CS4xbo4{dSMN7AgAr_}|J! jy7Qm?JAZ{yzl{Bp`BzzC1BL6r0AuiU^>bP0l+XkKFon-g literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/y.png b/Content/Sprites/Controls/PC/y.png new file mode 100644 index 0000000000000000000000000000000000000000..e8469b0277ef58d3f6cb746d8536b9de05572499 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=yB z9u-#qn^yl8H}5l3B`YP`mZJXQ=mbb_k z9$}SA4>{;@uF696OY-#pjNt}AC(JKk{Rnh|>OPHQaaaDiYQ2?zo_wl)vvlQEB{>F$ YvMI})FQ~qV0s4-?)78&qol`;+04;vDe*gdg literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/z.png b/Content/Sprites/Controls/PC/z.png new file mode 100644 index 0000000000000000000000000000000000000000..575a424bf5a8306302af38199e0e6ede793f67ef GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR}}=lkoQm$!dEzkdIE{(gq4y{lFM<+ggdIEF+VetUhl z*kJ_@wuH%Q_Y9_eufH|Vs)QrxU|QCXaK8IZj*sWrACvr$-w@Buz{eC2cAwp-YjU-N ztE(0((<&j32_+6n2Np4lF)c7+yTfczzpb3bPIK*_8EoGk$KHLUBM|*xaQXRz*Sdax zaV&bXZ4%?m`0Gjyk_{3M*c4cAFnTbSF*qHl-LKc?Aa`f_HvTtp1`Ui3*ZEmiSS=7b w@S36iZ*ch6FyFt=>ohif6M8fMWJ7S=nhoEa&v2JL0(yYK)78&qol`;+0Kqn(?f?J) literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation 4/copyfile.png b/Content/Sprites/Controls/PlayStation 4/copyfile.png deleted file mode 100644 index 931dfb2d291cc7bc2869e3ca0908bb05e283f086..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=+R$F{m=8Se?MP-KZEmP;SE5k2c9mDAs)xyUbW>q z nr`fQ6anz0X*Xyq>Kgj$Gl?XndUl}}I{an^LB{Ts5@++-B diff --git a/Content/Sprites/Controls/PlayStation 4/deletefile.png b/Content/Sprites/Controls/PlayStation 4/deletefile.png deleted file mode 100644 index 4e91c3a1aabb2c47991cb707e3c9d66351cdc8bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~2>+kpL+pj;*?=L_9{eFfmstuDF7#JlzT^vIq4!^yA zo3F`$hb^Jcy8O%E`C%eA86v~oJoenEcfRt*d+n67X}e}FV-l?pyRdBXKjE7*UmtkE zVBUBzj;ZDN{EE|TUmDUI8##My)gGC$Z)iBF!L~qDsIbyOX{I9kmKmK38D~fLCwLx6 zZ%mf{*5Kf#!)U?x;8KHISc#B23g_s*;!{ZGY_(6;St!t*TUeR{xXpR{#T$!PC{xWt~$(699UJ&PD(L diff --git a/Content/Sprites/Controls/PlayStation 4/pause.png b/Content/Sprites/Controls/PlayStation 4/pause.png deleted file mode 100644 index e489e99717dc3944dd4b51f80f6a2b6eedf68005..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 617 zcmV-v0+#)WP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0scuuK~#8N?V62I z!!Qhm8y0Applr}%0@wsLV1$lPHs}bjN!b9HpfEv^?U$VG#Lf?Pnq)X)#gZMH zgf0jngb+dqiE}!g9^_+lgiHB+Vm`&e@|Aile$2NvO%6I{QV`f@AMtJBI~vpB#r~eH zd&J_$d^&zo5V#!d(pc``m9BtU*$OlT+n|8{}!wEhb|0S0WGMRU&UrIC32lx5wFJ5 ztfUBf|4E7|Znqg~0$rRwXljfBv(;xKO&jB>`$7y_0TREg@DF5C{t^Efa`65WM3=SB z#`fus0no+igC^Yu)u%B&%-HwxY={#0&BS*%8fD8TdiFN;@!Lf26yLU?+vGhB2qA=! z;m9$yH>Xt%b)2oyZF)#@)t{*?q<@)lX(XxY8NMUaDgu(~OZq3eOCX7a?)g>_;<`aD zLwQ1&Y!r~$P+347!bedQ_t3L2_5!FkK3T_@ zEtPvII(k{DSlQ@B7Q2f3IK9Zy!H@{eFfiZ;$jcFfdN_ba4!cIQ(|{ z&A!75Jgzs(HU9tKdO5`{H)nI!61$L{`MeJwJlOi?qyI+f4|f?vD}M_2XNfP^vBIHg zHE)CN)`dypjCR-iHpMf#1n)K~#_DsNB%kKa zkMQX?%(>FLrPVKIHq}c`6*XHh(dWahdj1K|=LxOsOp6Ne5bn9$B-Ey>bMcOntElL? znwRoouCAG3PaTdiR+b6qpFALNt5 Yskrx7mlm7v21Xu(r>mdKI;Vst0Ln-Ry#N3J diff --git a/Content/Sprites/Controls/PlayStation 5/confirm.png b/Content/Sprites/Controls/PlayStation 5/confirm.png deleted file mode 100644 index 2dc8d2156193145b179a7b1e4dbd4f9a4bce4c97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 554 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S@7K%QukY7?zd!yw|9plm97g9D7#Q0;T^vIq4!@m# zJFmrn$A!7&4$sQ}|Ff%ay0X}?xljES@NoOpM~ffan0K)DkI^0GANLvjH||lM^q%#H z#V5sMFRU3>8gxwRX)xU&l(>~aW3$xEcZ|aE$4b~&)Chl-a;T9mVKsO%pOf9;l$e8` zR6^_xk<+Ufl%$oD8uH~Nk0ef8`17ISf^DT%`_En9$a!z6GrL0Ig!$LiN?6*p0?w<} zPF=f5>rKPN(54g51DPh}+~`&KJaaMw&l2E+RA$DOknbCS6^nI`BTlN0##*L2_e^+`>8j&*%Lm?E2hLbK|^ z7k(8V^TQ=C>|G`tE?MztWxc9myuQfA|4j{Ir}q4}?Oql3F(b$T_tNLHUl{Zr3xC@BQFV{c3JG9rF?hQA KxvXNS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=+R$F{m=8Se?MP-KZEmP;SE5k2c9mDAs)xyUbW>q z nr`fQ6anz0X*Xyq>Kgj$Gl?XndUl}}I{an^LB{Ts5@++-B diff --git a/Content/Sprites/Controls/PlayStation 5/createfile.png b/Content/Sprites/Controls/PlayStation 5/createfile.png deleted file mode 100644 index 4bed134aabbc472216dcb0b801cc8d00435ee57d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS&-dHw-(N33zn*{p`*?;sH~u#=FfjIdx;TbJ9DY0f zW>K>Nk85wa^zD!T>vO$>gdD=-mKoQ+Sg@U?L?C>U>XFCO)$$JfXZx|}Qvb?F>5OqV ztBh9vVL7mbOJ}Czfmd3|d9sXCVj@p3BStUN~7xH76?9Onr zpdqyBN%N!$+ROnD3Xe6|i?UU$u{_n?&QOs4kFV_P*_f_0hKbs`{0t6^zjq}?Yt=A3 zF#Ee}QREjvhAU;iO)t!AV_>NZT)WYxi9seTz-!H7<%X7^9j3>_ewj?|WJoxl(`Wr6 zDb}H?T`sX9w&7>T^T0_}4FwfBPObMCZQ^Tg*6TXBGo3JL{T5RGJmguK)OxvzSFC)K zcbFYCeD+*A^Tq|Hv&`-t52My>yyy>K|G&Hm#=6Q9W09yyB& z6RVJ5*=;QTskVFgTe~DWM4f384u8 diff --git a/Content/Sprites/Controls/PlayStation 5/deletefile.png b/Content/Sprites/Controls/PlayStation 5/deletefile.png deleted file mode 100644 index 4e91c3a1aabb2c47991cb707e3c9d66351cdc8bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~2>+kpL+pj;*?=L_9{eFfmstuDF7#JlzT^vIq4!^yA zo3F`$hb^Jcy8O%E`C%eA86v~oJoenEcfRt*d+n67X}e}FV-l?pyRdBXKjE7*UmtkE zVBUBzj;ZDN{EE|TUmDUI8##My)gGC$Z)iBF!L~qDsIbyOX{I9kmKmK38D~fLCwLx6 zZ%mf{*5Kf#!)U?x;8KHISc#B23g_s*;!{ZGY_(6;St!t*TUeR{xXpR{#T$!PC{xWt~$(699UJ&PD(L diff --git a/Content/Sprites/Controls/PlayStation 5/pause.png b/Content/Sprites/Controls/PlayStation 5/pause.png deleted file mode 100644 index 5887078ba0a4adfd91bf349f5a1152972e27fe11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmV<10VMv3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0dPq~K~#8N?b+c? z!!Qs9;FJaE1|0!5U<5`f8?XW!lnv+xWrL~{v>N~uz+L@*p%#+Z?_?+Mld8KPO_Xze zZY*~qA|fJlwLlE>ZIJe|Fi0tG5JhH6YXG9iOlb{36cG`T81^c#vd@RV6I`&z*QUt| z+@w1H^^8lV!;0Fc+IrjI()L*~>r~TVcen*b*j~UZK{^<7KM=AP$o&=V`W4bPSphqr z0U360dyJMf57_8sJZlbTnrFJ6a1^?YBs)##{ql5OcgE($J1gmE{-7)hu>a5E!3>Q;}95iziWZU|NpDsE^@fg(7>H; zb@Jc5)>&sxY@2>^?}YumT;Eou%nkLD-^;GG zu$HOH{_k=zpA3Ho zbG9n=25s{)P4=hPtrb5j-L%u%FvU)dg>hf?;mwRMnT@1x@H;awx*m9|zj0M!eE661 cE)F?%tL~aCV|x9>4(MwJPgg&ebxsLQ0F@oVqW}N^ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation 4/cancel.png b/Content/Sprites/Controls/PlayStation/East.png similarity index 100% rename from Content/Sprites/Controls/PlayStation 4/cancel.png rename to Content/Sprites/Controls/PlayStation/East.png diff --git a/Content/Sprites/Controls/PlayStation/Left.png b/Content/Sprites/Controls/PlayStation/Left.png new file mode 100644 index 0000000000000000000000000000000000000000..208343320c1a705273db594860e90300fdbe7a7f GIT binary patch literal 438 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCim50(?ST zpBXwmGj#nA1}_cWpBuV9H*|Yu<=TnOYy zlmz(&%fIKZ*SEjF{=9y^{rdd=^Y8uR=iiT?&(P{8lMht$-qXb~B;xSf>o>WY4Fp&N zcJI!fwe;lw{}~G>_^Qw9;dh!@sr%jG<(-RR^P7VOKU{aXK0D#pI*A!RCc%aYV$KYV z&l!^E$e+Hw;?SN$S0bN2F@N89>O}Q}kC)0`nTh4h^F2^o;IOv2vc2i7_Xj%*hu19( z&;FjD#W3fBNkN@>fs@jH{v(I9<}iUbQRxu95GPcr&k~*|SH#zKJHE5pne$tGQo{=SO)?Q* y+C`a_*jQ|1I4#&M_H;Ub(fROq`F|f4htI65%S%Fyva&!i#Ng@b=d#Wzp$Pyo!OTMd literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/LeftShoulder.png b/Content/Sprites/Controls/PlayStation/LeftShoulder.png new file mode 100644 index 0000000000000000000000000000000000000000..b737fcacd2cca3bf329243eb8a88fe7d16516888 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U+{bW{`2+g1lCs1aMr;B5V$MNJH-V6pk zS_{@U&0f3u-onOE!QzP`KlUDGnx`NVQ`Ii|;*jW-#PAO?>mJCIvF1PE`Ud1kt$QHL zXCNW!AeldbWrLQ5x5L5NyIDl`ERA4nlH19pFsCu3!P-^uj5tg2HI_GA77w}BC4@id z){sB-YK)2wd#d7OHAo-_OQ=A66F^*hl%~= jYty%jzaCu>!oU!-PVm`>M@uq+?q=|G^>bP0l+XkK&GC}T literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/LeftStick.png b/Content/Sprites/Controls/PlayStation/LeftStick.png new file mode 100644 index 0000000000000000000000000000000000000000..e04bbf3969d9e21278bdbbd6f52e4ad2916bc70a GIT binary patch literal 668 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC{pZKu?_V#kf4=@b|9%D^&)C@v42(ZKT^vIq4!@oL za@`sQo`#Ew?MmmTOo4yvH_Dzt?ou24yjA4t(`c3w0xIu4BK_SA-2CY;V?V< zn#9|V&zn`=Wead>tgYPtKT~NUuPH~vQr>QP=0B6-4pccX zyyx??6QA_CbgUpNG$9d$guC@hs?+%xBG zP)Kb3ge2bO+kA7@ufLoSxbKywdc(1@S=@8YY)?Mz6^Pb;%W!e?qWhZj&QB@59^uWn z%Zh8I^`pGzS!a`u*1UCOobddEs#-bub!w>*56woPw0)1_nD@7606R1OLy!$fy;hp;dXJYRE`L6A^g1K$A z@vk4V+L`0-2-nLu9J{!eA%XqWD)Z^NS5=d)sJm@1H3;>;%yzF{f5II*9rgS9%k&fU b{xfW7fAhMw`mHK3eK2^s`njxgN@xNAHAX&u literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/LeftTrigger.png b/Content/Sprites/Controls/PlayStation/LeftTrigger.png new file mode 100644 index 0000000000000000000000000000000000000000..428f8b053c8cde18d7c660c8580fecaadfce8693 GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=?v=l$Q;+poVb&mX^kKEuP8)`x*ozdT(WLp+WrSGY46 z^k_+Nu%32$KZmht^TNmoQJ-}`_}Sl1o5A(%pF89Bi=t z<%4$FNlkzMZ)~{F!Mgr`GVAXLT+kJhUlLL?H~Qj3$%WGe`h=6 z-@Fe-(em?~EEXJ)w&6OUSN*g<`k?=k35QobxWD`P0f)H$EtPvII(k{DS@G+ux7R?_V!p&wu{C{(gp&T8jJ(42=IhT^vIq4!@oL zdedSBo`$tb+f}Z7ufG+V*Tk}B_vYfXb0+&mPKFmPzx-Q1^%ql}se`}UPK{GOza$;j zZ-`|H`)imGCas4S;S9&bbA=|s0bI}4Dhrn}W#|cc{rGSwbpOZ3!-p@jW`wBW-%jL%}CH5fU#c_o+^M0^&sXIQuVAj2wCamF9p z8G0B3>q?Uww6D7qEz&S~BB9W2TG(c|^P{K4#8WO^E#bJkyFytlN@@2SIzSwhSW zf2MsopY-Wu#L`smj+5akMUlPLmNTzJ+>AP6S}vQO&vv?JtzC^tgvLxYJ=>FKugmg2 zxUn&*?A+{>Q<^2uBb2{P%h;zJ`Yu&f^-MQohR@;U>*pU6D^j4ze%F;)X z?p+(3LqY>(4v5WT4>VlS!*wH0VkMWo`P^vp_%`jF?M#awN*zD!F=y}2g)=tp`}sax zCZ3&p{l1R=^_4ac4%&Wv&bUVYE;ECn?8@Nhb5EO@Hb%U-nR|DZ*6M>dp8pqrcE|3? hpTFn7u=YIVFJARlPlU7O7BHDGc)I$ztaD0e0swj6Lqq@o literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/LeftY.png b/Content/Sprites/Controls/PlayStation/LeftY.png new file mode 100644 index 0000000000000000000000000000000000000000..b7277227c3b12c8dd1d5ce607353453ba78503bd GIT binary patch literal 741 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB-PAT^vIq4!@m# zbKPSFp0-S<8w>aRzdWx+HaX+c;)@we9xe*?{(E%BeeaXMr+5EJY`EC;hb>{w_j5J; z8_vw{zM0P$_H)COzkCzkUTFs<5!;%@l^g@*$zF`bovLLxZ`5mVdy)=WfSt^qh<^) zMFDFWwPb^M8nUl5aI+NDreFHaQE{Jn&vb^3Y#sd#xx6=~HE6TVUtcKLEW6`Fp80C# z-y#bf?IjpirRj2YSO!@Ou^e#{5Ec>*Iwh!mG3E?wXjO=ZVSBLd60VhOndiT3-OAvU zlBIoLa!38Gtu_1k8!9#}yC+$>HsnGVs8 z&u=fCVVm=QrS0ZR%{4o}Em62I=QyMDv}!%}F8-@O)|m8JxH&j&6@PYZg6O9OLS44E z^ZP4rw%b1U4R_9CQfdtSeY|0o;VpaCj=l}1x)0S9j{o=4uKw}zh57ucyv?GyVd`mz xw@uwUWohld`o<@br*ogY|NHhg{||Ep`*{IxN~_NBM*$NWgQu&X%Q~loCIEa}U@QOt literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation 4/createfile.png b/Content/Sprites/Controls/PlayStation/North.png similarity index 100% rename from Content/Sprites/Controls/PlayStation 4/createfile.png rename to Content/Sprites/Controls/PlayStation/North.png diff --git a/Content/Sprites/Controls/PlayStation/PS3_Select.png b/Content/Sprites/Controls/PlayStation/PS3_Select.png new file mode 100644 index 0000000000000000000000000000000000000000..36df2ecf32ed2acfa21d7856157a4589f8c1dfcf GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSANKkv`quP+~;zyJMx`+9~YQzv5f!!v)!jkPUp~xoR$;$`@vT++l6LV8t?ZUWMDHmz|O$e+#=E3!R2;V z^tf=6pUoZ9gnds#BPWY^&eG}AjOVN=yxyR~F?)*n`A4Zei|>iWGxEeRuW*@ji$Q_& z#W&yf3cZH~xeU8wUgYlk!?vFBlUhK~Ru+#7tRI3H*KB$bCB4CP=7SZ#bUuf9<}hzL z`DDkJUy(N^Pq;4^_15GcgG0NMZj;<{z65!$s|qg|Cv8!dJix&ALzEtPvII(k{DS@S*V~`3m)GZy@1K8v|9ghs2z7o221W)?7srr@!*8#4 z@--{)Fa*renBMyD|MfoYd9xRsO`3K=qhq3Ycf%RMX43_XygvjNFkZCimC#COsCgN^ z;BL)lk${Jaua|`!)jO5A>eJcc14+~M1d=aS8pdqCqqnTVBCnz1m-96ywWYh+i#~}q zw9I(N)6yY2z0^U*y_!L!D4ciArPyN$PGRgXe0Omh90^~+aA$5B=*;?7SQH zIG*7#1H-J7yANbs{^PptcXY$S&;u9Z*$U)Ym++{#Txi%JzR${$N$ApL2KgqgJu4XO z_yU4A9C6$-<@}FSwX2MiU%I>vd3O9<)}Bo>+PLR>OM7kn{9M93JfO(Pgg&ebxsLQ00mpen*aa+ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/PS4_Select.png b/Content/Sprites/Controls/PlayStation/PS4_Select.png new file mode 100644 index 0000000000000000000000000000000000000000..e3e44f42cbd5a2e50f5445d4250212a39b3433ec GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlA?a%w`%k%fIkKcd){d@+Q*NZeksytmBLn02popzV6 zS%IhZZis-!mp%V4_sK8c(9NlHy38@T*yMq_E$7ir`<_e&wg=h`XBqnDKAvz%Qutj% z?4cXg4SbVzm}QE%{H2wJs~H(eCe3I`{rE_K?vq_C4k-=6DY^-tpXSX8o6UGmXq`=m z-%H_w6K6{0ROGw;*)J-r(>~a)({;b~(Izd1caiV7A3U2L@RV_>WlHiqrOrnYz3j>6 z|HKo%zCB>xvQ>D4)SJX>at$gnj+>YlOlZwwzY}<5ujB)-hHSPQLJ6}OD>@k^8W?|w zK6w0gjaNe!n~rKiX8x+;fB)`Woa*|lNz|6T+af1m(dUfIA9IYV{>bwj_|GioFVdQ&MBb@01H~h4gdfE literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/PS4_Start.png b/Content/Sprites/Controls/PlayStation/PS4_Start.png new file mode 100644 index 0000000000000000000000000000000000000000..24fefabd5b0ec47244c402c12c84aa57c975f019 GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=&M^k=YKzcKLby*^Ku3TMt)Bh#}JR>Z?78q z9X1eQdvLEox`1`sIh{8-bE_MtNjvZ#m>_Lpo%N9Ix13^!9|LN9$ik|mW>~GLowm+;rj|>j?C{2kxVOcxtVpW{g1D2gkZE{>o zE%z76EhuQX-gt@GS7E88`s{VbdT%owd2oZ=6%;#>rB@)cg0M2xcFXE9YfSX z#>u<$6O7&miT_yf?Lf*>iU7=&*^{pf3S4NNS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!>0q{`&9j&)=6{KYu@eJj33ZWi<>8jOLy$jv*e$-(KDA z$K)u&mN3uZknoMDgVH(4*)8k}*F@Zewbz;%8kPk~T2(UW-_CY?th#Z-mJJNd2M;}P zTqGEtTzB5>`;R&1iU({cve4lSAZf^*!VqHoL;Zblj%WEQgY zZLVFiX)eolgCZgJ*y}8hlXyxNJW*%T54bE=u(DZ{aUS13mK|0S+zqOp2XglZJv+B> zb9p|ai}?YKjA*k9+K+W+O=rpwWWRW73F9BrRmHdOENbN2;COh!>*I2>SXS33%&Zc- z@GP9+J)dp52gui;McPEZDrZ_$JTsxDO4QpjXmdKI;Vst0LwMl9smFU literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/RIghtX.png b/Content/Sprites/Controls/PlayStation/RIghtX.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf054738ea256fc370e195a8834a07e22072a7f GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G$J^iU&zE0c&wu{?etm|{eOo#i7?>11T^vIq4!@oL za@`sQo(9>J_*L)!Zwa61Bv^3r}k7EEn~gZ0=31?Lb+;R`4%jR z_J6dbif6{xTcWo1Ob!w4LJ!0eT94n2nXNMG@htIgYz^D8!`^P;Ia@THp*rXBrESNe zD(5)g=5Da*tJFAS*_UQDh41r|shrXWSH`KBbU!Rj|9g!6;QKzd>uv|$M;~n8$lr2% z-=eZwLykvj968Tt&wasYcia6_aJ=2|_jdMz4ZSagMyD)4f|OtJbhPe`@xd%<@$x`I{xRxEyovNz{yYVk Pju<>${an^LB{Ts5(vnVO literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/Right.png b/Content/Sprites/Controls/PlayStation/Right.png new file mode 100644 index 0000000000000000000000000000000000000000..ade49bb249cec9999fd70eabdec1945a1520b31c GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijA1AIbU z-x<3+Gje+lM20}*3S_@9aQ*-P|1%)l(Dj9Z3y_T!JU4QEZr}!&0-6Uj1jxO}#O)8{ zNR|Zo1@rgU-?v|%FaQ3$fB$=X{q_0&=jX@YkDt%LQYzF0RP@Hv#W5t}@Z0OBg_;$3 zSOb24`Rl+f^6$U%ZYE(y-W>(YoUiRo4=jEhQRDA7v2j1!ufS%>-x&$lGM;5P28vgEH&X7?*y&_@re{Y=! zU(!37edZOO`_sf+5FdA-*5S}$#$|dF;#+UeT7Pd!vl7$Z1#v2ZIbys5)_0dM@Ysuq y@fPrW_)~QDfa!skzAfJ!U+0~=?<09*w*2XpEzZ_zC)NV}&EVEtPvII(k{DS-a_2c>L^Y_1Be_sB+{d@+-Kkt_U<=%U`IEF+VetYdU zU$X)aLx9@%)qnr5pPM!_Bf;zT_SStL5~`R)7AB>(%{ajFkH6zsG&g_ZTJw$k84`SV znOPK^wm7hbJYmzYSYYCCh;bz&gQRc;)4p_N?($VqayOioMwJR}(0gZLYLf8(c$m-z z-a7k_6B!*W_6aZ^XMK{+Y4V^d@FL^WiUzI&%yA4ozA@Vr3mD>;JLn|OWfEKwtiV*t z<lBYWI(RE4?P+@cmb_Q^bL-&J!2^{1o0l<*-N933K0RHEYr)@yAB( zx!Wbge#<7c#{Ran=^gd7;5V73C&ebGueWLBymM4~aq;J*#zH44pw}5ZUHx3vIVCg! E0Cje??*IS* literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/RightStick.png b/Content/Sprites/Controls/PlayStation/RightStick.png new file mode 100644 index 0000000000000000000000000000000000000000..bdeaf51fa6bb30feb966d0cd3f96b68f1526a4f6 GIT binary patch literal 694 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSBE+vmsM?_V#kUw{5R|9*zjO)S<73`|0vE{-7)hu=;Q z?|W>(*kUoym65SHi9clrD+i0iuUR`-Wb6(cvWQrqS9>5$^wg?Tp4UVZybqX} zF6CMvn^k>vQA3RKy(SwCvnOs7xP^R|1S!kuKUbc&)+j;gsgz!Bb@_*Vp^M$k84`BR zz2=m@e4fawfR8s9@-S>lb>4q@(X%PswQEG#zxHi9EBkS6^S)U}XC1%U#JJ$rhsgW+ z$=->+SLfViP1`2Bo9WWE-S<_J+NT8vA7IGhn3pQ-+#gt&WqRw2NL`NA_KTY(*4;W9 zJ@ftiYwhRz^DS2LS=7zl+&{n4;=w`dkKY+r$RB2Am=@q?Uzw9F z&=ER6V(+!RGplBq{`>jAb?-KQ^>6R%m+3!<`p394`1Rj_!-Z17l*8cZ>gTe~DWM4f D`y5Os literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/RightY.png b/Content/Sprites/Controls/PlayStation/RightY.png new file mode 100644 index 0000000000000000000000000000000000000000..95d07d35fd3a4b0fb3c7d30195d3c9c15f45fc67 GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB%irH$e||o{{(FX{lc(h~FfgTgx;TbJ9DY0f z=DNoUJPw|Rq^5oPA76dA@8FWm^=^wNwzYe;{y1WG&na$y%oBd*HPfD$GrZnY{;j$} z@L$xS8g7H-{jW{#Gj{#4eaIH@RR54U!`t0U?b$W>r~P6{xcT*QduguWZ;k}LyOzrs z_v;wGXKatwl$r3Zg56`?;YIo`s*n6Q42-O0nKzWEot2v4?Ed*jyN2%4;-D;7-}Z(? zSG7v_U@5ByE^e!v6&icKxqt57_17x1wB;D1$tm_`2EJI0i-4>F8`++N-WL4FMdS&355>zUr{+hnKlpq25?wb>7Trw2A1nR7!g zXdmkvj)rY}|B4CJG{h#SGw%O-kTLYcZX4Ff;0F;*CU4j)%d;Sn%O zzGBLR427pMhFoWl1_exYXV!dLu&(us%c{n=wyV?~zW8K6ZEtuqscG8#e$ELxuV2j# z)e%=aXl8fiZdl-n8$L(hIwT#vkt5yk-8FgRHoJMt7Dd(87sbq(@3CI(g-hW~$3}71 zx6OZIzOcUAB_X4=`?b;CkD=L{*GaRrX=E_msN}rX=zP*dVcMa$K|Xak?|0gE-)gSe z`%T8txp*EsPw4xdQd8nqeT>YMD_kSP=^J;;-8t+`v)hVKk1A}QiOTj(GM5s&>E7TX z;QKGx;k3kCdsYvJ8@s1{5D54qf9aILewn}5Hg6J5c8$K;d38gs2v2IN-Tyd+)N4i7 jKda~0{%8Ep_JCc==ymhmyIMTJ)X3oJ>gTe~DWM4fJIrx( literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/Select.png b/Content/Sprites/Controls/PlayStation/Select.png new file mode 100644 index 0000000000000000000000000000000000000000..396e2c9dc56b8ff3b24c4083c82114d029bbda10 GIT binary patch literal 433 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS?@*URhM_vf$QKmUF_|9b{@a~Ev}21Z^_7srr@!*8#h z7HU@DVGX#?)M)bm|JJR+r6yWci5K-woNGC@9R{;TF;0(GZ-_Yrwpb;raZ+PKO%l2QnNkx7`;7 z+_DtpxOZdaEHl9mI` zS@{{wCgokJFZKgS@}NLGQ9ZEtPvII(k{DS-a^UurI>)YSozn*{o`*?=$`{yhI%3bnwaSVw#{PvnB z-ys7Y)(a&kY_5E_*Huu=h+Xh-c3T-_NMRe9~dt$NYxS z-_@-`){KwmIZyBwPxxHj7sM{`xlV|iZ%M7ar9?-`nkFV;W+pBTwiJ;F2?vD($_j}w#LhxJZuqJvkz-6SeYxls$u!I*fmVcIj%V# z$Zd9TYP=xj$opWoMBsx8<@h-ZtUBBMPh=lIJ!O{Aj$Oj>O`GTTujcGmnCAH}faOPw Zc~STW&sy=?A3)zRc)I$ztaD0e0s#1Rs9pd7 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/Up.png b/Content/Sprites/Controls/PlayStation/Up.png new file mode 100644 index 0000000000000000000000000000000000000000..3e01c93d481982a24e4de3f424f810fba4038c38 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCikF1AIbU z|D%FuMsCjyp@Pp0U0)iy14U4k{C{o)RRA>OIav1Dr5=z4q9s9o!TS95{qpPW*V~`h z??3-O-~ayn`SA=pST$0B3O;zcIEF+VetZ2UU$cS$Ye4ktb!$rh{SUq^K20#7O)dA5 z!TKWqMMZ{Y=lPefJP^-ZyS@7I*OY`?7kyF^?0s0ZK1e4V{MmZX?d9`S&$+37|GwBv zkgR0yVV)5wDdsb8ec4F^wuaq5>G-!omOm literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/West.png b/Content/Sprites/Controls/PlayStation/West.png new file mode 100644 index 0000000000000000000000000000000000000000..006f920a4e8c9365ee2feca4e4da92d417979ff4 GIT binary patch literal 453 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS@7tf(ub1b4Kfizd{&wX6=IS_tx{P2%e}?@IFw?octh_+s~@eFo5Mie&gSRx%QuBI#L)lj1Jsn zINp%Oti?QwH-kq(+Cg1`A%Xe9=lJApj58TG^UkpUpIl{o)R5u+j({dsj!R2#eQ^-Z zf4YFZ$tGe|*@i3kGMMjHz34T&TX3&8J$9J@38# z_aEJhD(lsct}|wJzPWEh?3M1V?~>!b8>ZU)H=cVSF;C_1rNS%G|&0G|-o z|6uUU$nCkI+jAo~2p2*El|V#tvbwv09Ilcezu^1*{rBtR-`DSFaFjhW2`F0Y>EamT zaXfj3Cxbzc1FPWO-Hi$E+Ip;)%bgun`B*O}a2XY9%-{{)P#kiwL375fjndpNI$E?> z-0Kz1Y1ck+Y+ZtM%)vaFgb>ERq6Nv*?>p3#_#av4AY^;;Y!oZ2cHxqffvhFL29nDT t2(>q98nDjWv5Hx@NS%G}r0G|-o zXGU(%4cwj?x;{5_dk$n9y8g!iK(#$rjEG20ad}p|9^T9$fu&hsc~dcGl_w4GXs53C+$2EoU^DFXm$N zIe75GZiRyPvRo0N%;68J#b-B_uYbr@vQfK&ExbT{cT@Rdt{3YMi0y6?KjQwK@eS9r yo@Z+gu71GcEtPvII(k{DSTC{pZKu?_V#kf4=@b|9%D^&)C@v42(ZKT^vIq4!@oL za@`sQo`#Ew?MmmTOo4yvH_Dzt?ou24yjA4t(`c3w0xIu4BK_SA-2CY;V?V< zn#9|V&zn`=Wead>tgYPtKT~NUuPH~vQr>QP=0B6-4pccX zyyx??6QA_CbgUpNG$9d$guC@hs?+%xBG zP)Kb3ge2bO+kA7@ufLoSxbKywdc(1@S=@8YY)?Mz6^Pb;%W!e?qWhZj&QB@59^uWn z%Zh8I^`pGzS!a`u*1UCOobddEs#-bub!w>*56woPw0)1_nD@7606R1OLy!$fy;hp;dXJYRE`L6A^g1K$A z@vk4V+L`0-2-nLu9J{!eA%XqWD)Z^NS5=d)sJm@1H3;>;%yzF{f5II*9rgS9%k&fU b{xfW7fAhMw`mHK3eK2^s`njxgN@xNAHAX&u literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/LeftTrigger.png b/Content/Sprites/Controls/Xbox Series/LeftTrigger.png new file mode 100644 index 0000000000000000000000000000000000000000..f649d8777e84db81a658eafc1f7c0ddcb6f26300 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|m0G|-o z|3m|z4xrk7T$erqS^OnIe!=nQ`R~`~`^&$dzrKIJJ%eL?-W;IRK2I0N5Rc=@748fM zJz5H`2S2Yc{(ten%%!CsTz~#2GsX*W#r;3d_3fbOo#X2s=*JwadBatANc2W>_y@^# z5A69Ia#;&r$xga(K;y^%|Mz!){~=?!ib1UDi1rU>kAwP7T>AvP0_!<7Unnn0kW*y+ z&Y|(+b6-Q#{uYrn$_pO2%QCXwzb6>5p}(PN{(BCM4(G4}x!`}yUWPm5FLQqn5V?}9 z5z!JgAxWfp(+gGIS+b`Mx*lyep0LDUz4uz=mH-BZmZ=NMc5i+b3-k$tr>mdKI;Vst E0A}%{EtPvII(k{DS@G+ux7R?_V!p&wu{C{(gp&T8jJ(42=IhT^vIq4!@oL zdedSBo`$tb+f}Z7ufG+V*Tk}B_vYfXb0+&mPKFmPzx-Q1^%ql}se`}UPK{GOza$;j zZ-`|H`)imGCas4S;S9&bbA=|s0bI}4Dhrn}W#|cc{rGSwbpOZ3!-p@jW`wBW-%jL%}CH5fU#c_o+^M0^&sXIQuVAj2wCamF9p z8G0B3>q?Uww6D7qEz&S~BB9W2TG(c|^P{K4#8WO^E#bJkyFytlN@@2SIzSwhSW zf2MsopY-Wu#L`smj+5akMUlPLmNTzJ+>AP6S}vQO&vv?JtzC^tgvLxYJ=>FKugmg2 zxUn&*?A+{>Q<^2uBb2{P%h;zJ`Yu&f^-MQohR@;U>*pU6D^j4ze%F;)X z?p+(3LqY>(4v5WT4>VlS!*wH0VkMWo`P^vp_%`jF?M#awN*zD!F=y}2g)=tp`}sax zCZ3&p{l1R=^_4ac4%&Wv&bUVYE;ECn?8@Nhb5EO@Hb%U-nR|DZ*6M>dp8pqrcE|3? hpTFn7u=YIVFJARlPlU7O7BHDGc)I$ztaD0e0swj6Lqq@o literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/LeftY.png b/Content/Sprites/Controls/Xbox Series/LeftY.png new file mode 100644 index 0000000000000000000000000000000000000000..b7277227c3b12c8dd1d5ce607353453ba78503bd GIT binary patch literal 741 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB-PAT^vIq4!@m# zbKPSFp0-S<8w>aRzdWx+HaX+c;)@we9xe*?{(E%BeeaXMr+5EJY`EC;hb>{w_j5J; z8_vw{zM0P$_H)COzkCzkUTFs<5!;%@l^g@*$zF`bovLLxZ`5mVdy)=WfSt^qh<^) zMFDFWwPb^M8nUl5aI+NDreFHaQE{Jn&vb^3Y#sd#xx6=~HE6TVUtcKLEW6`Fp80C# z-y#bf?IjpirRj2YSO!@Ou^e#{5Ec>*Iwh!mG3E?wXjO=ZVSBLd60VhOndiT3-OAvU zlBIoLa!38Gtu_1k8!9#}yC+$>HsnGVs8 z&u=fCVVm=QrS0ZR%{4o}Em62I=QyMDv}!%}F8-@O)|m8JxH&j&6@PYZg6O9OLS44E z^ZP4rw%b1U4R_9CQfdtSeY|0o;VpaCj=l}1x)0S9j{o=4uKw}zh57ucyv?GyVd`mz xw@uwUWohld`o<@br*ogY|NHhg{||Ep`*{IxN~_NBM*$NWgQu&X%Q~loCIEa}U@QOt literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/createfile.png b/Content/Sprites/Controls/Xbox Series/North.png similarity index 100% rename from Content/Sprites/Controls/Xbox Series/createfile.png rename to Content/Sprites/Controls/Xbox Series/North.png diff --git a/Content/Sprites/Controls/Xbox Series/Right.png b/Content/Sprites/Controls/Xbox Series/Right.png new file mode 100644 index 0000000000000000000000000000000000000000..dc3f1fd07194614c17f55ab63ef08ba0c10d0b68 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o zXGU(%4cwj?x;{5_dk$n9y8g!iK(#$rjEG20ad}p|9^T9$fu&hsc~dcGl_w4GXs53C+$2EoU^DFXm$N zIruU3eZYa+yA=eqn8P=`mo;N8Uw=UKNn&^b=eh^7Wvu1yq8H*F<;z&7clN)Vd_(j@ x&$BfLS3h9!apd3G`g3Nbz|ZN*d!vr9G4vf=r)8EM+YWRAgQu&X%Q~loCIGA1atQzc literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/deletefile.png b/Content/Sprites/Controls/Xbox Series/RightShoulder.png similarity index 100% rename from Content/Sprites/Controls/Xbox Series/deletefile.png rename to Content/Sprites/Controls/Xbox Series/RightShoulder.png diff --git a/Content/Sprites/Controls/Xbox Series/RightStick.png b/Content/Sprites/Controls/Xbox Series/RightStick.png new file mode 100644 index 0000000000000000000000000000000000000000..bdeaf51fa6bb30feb966d0cd3f96b68f1526a4f6 GIT binary patch literal 694 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSBE+vmsM?_V#kUw{5R|9*zjO)S<73`|0vE{-7)hu=;Q z?|W>(*kUoym65SHi9clrD+i0iuUR`-Wb6(cvWQrqS9>5$^wg?Tp4UVZybqX} zF6CMvn^k>vQA3RKy(SwCvnOs7xP^R|1S!kuKUbc&)+j;gsgz!Bb@_*Vp^M$k84`BR zz2=m@e4fawfR8s9@-S>lb>4q@(X%PswQEG#zxHi9EBkS6^S)U}XC1%U#JJ$rhsgW+ z$=->+SLfViP1`2Bo9WWE-S<_J+NT8vA7IGhn3pQ-+#gt&WqRw2NL`NA_KTY(*4;W9 zJ@ftiYwhRz^DS2LS=7zl+&{n4;=w`dkKY+r$RB2Am=@q?Uzw9F z&=ER6V(+!RGplBq{`>jAb?-KQ^>6R%m+3!<`p394`1Rj_!-Z17l*8cZ>gTe~DWM4f D`y5Os literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/RightTrigger.png b/Content/Sprites/Controls/Xbox Series/RightTrigger.png new file mode 100644 index 0000000000000000000000000000000000000000..0c49d7d14af9a031c88e8a834aaae4057c4c6f27 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DR~2@9Xo|&p+=kzrX+edV7YuJD)ZJ<$ij)IEF+VetZ2i zUyA|{Yd{D~rRcx^+3w<#7jy*g*j(UfuEOG{wLV1fpa8SPf&Gletl5|QH<34(G=+r=5jeWJO6d5 z(#CIxY(-{GDwaEwywq#g;xpFA#b$hdy>-)_n5Sixu8->z8P+q~B~AKbH~sm&6ks4Q Nc)I$ztaD0e0s#57x&8nE literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/RightX.png b/Content/Sprites/Controls/Xbox Series/RightX.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf054738ea256fc370e195a8834a07e22072a7f GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G$J^iU&zE0c&wu{?etm|{eOo#i7?>11T^vIq4!@oL za@`sQo(9>J_*L)!Zwa61Bv^3r}k7EEn~gZ0=31?Lb+;R`4%jR z_J6dbif6{xTcWo1Ob!w4LJ!0eT94n2nXNMG@htIgYz^D8!`^P;Ia@THp*rXBrESNe zD(5)g=5Da*tJFAS*_UQDh41r|shrXWSH`KBbU!Rj|9g!6;QKzd>uv|$M;~n8$lr2% z-=eZwLykvj968Tt&wasYcia6_aJ=2|_jdMz4ZSagMyD)4f|OtJbhPe`@xd%<@$x`I{xRxEyovNz{yYVk Pju<>${an^LB{Ts5(vnVO literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/RightY.png b/Content/Sprites/Controls/Xbox Series/RightY.png new file mode 100644 index 0000000000000000000000000000000000000000..95d07d35fd3a4b0fb3c7d30195d3c9c15f45fc67 GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB%irH$e||o{{(FX{lc(h~FfgTgx;TbJ9DY0f z=DNoUJPw|Rq^5oPA76dA@8FWm^=^wNwzYe;{y1WG&na$y%oBd*HPfD$GrZnY{;j$} z@L$xS8g7H-{jW{#Gj{#4eaIH@RR54U!`t0U?b$W>r~P6{xcT*QduguWZ;k}LyOzrs z_v;wGXKatwl$r3Zg56`?;YIo`s*n6Q42-O0nKzWEot2v4?Ed*jyN2%4;-D;7-}Z(? zSG7v_U@5ByE^e!v6&icKxqt57_17x1wB;D1$tm_`2EJI0i-4>F8`++N-WL4FMdS&355>zUr{+hnKlpq25?wb>7Trw2A1nR7!g zXdmkvj)rY}|B4CJG{h#SGw%O-kTLYcZX4Ff;0F;*CU4j)%d;Sn%O zzGBLR427pMhFoWl1_exYXV!dLu&(us%c{n=wyV?~zW8K6ZEtuqscG8#e$ELxuV2j# z)e%=aXl8fiZdl-n8$L(hIwT#vkt5yk-8FgRHoJMt7Dd(87sbq(@3CI(g-hW~$3}71 zx6OZIzOcUAB_X4=`?b;CkD=L{*GaRrX=E_msN}rX=zP*dVcMa$K|Xak?|0gE-)gSe z`%T8txp*EsPw4xdQd8nqeT>YMD_kSP=^J;;-8t+`v)hVKk1A}QiOTj(GM5s&>E7TX z;QKGx;k3kCdsYvJ8@s1{5D54qf9aILewn}5Hg6J5c8$K;d38gs2v2IN-Tyd+)N4i7 jKda~0{%8Ep_JCc==ymhmyIMTJ)X3oJ>gTe~DWM4fJIrx( literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/Select.png b/Content/Sprites/Controls/Xbox Series/Select.png new file mode 100644 index 0000000000000000000000000000000000000000..4c11c269ea0347d6b549c088d480ecc02490d586 GIT binary patch literal 485 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS@7tf(ub1b4-@ktT{&bm zop)G)hb@6i@rX>!{{NT#X0P(??A;i;Qat$I?yyI~yhq9oe?HqH{o}sFL94ix5qlg~ zPW0>CYSCchapHvAgA5Z-YaIqAU*;WbWkH+QH~4jz$T~!^nI72iPisyCj~K%z9t$(0 zRBJT{)#Oz?B1X$Q9Olb~hMzO?kWRSnd(&ycyaQ4zm<0S8&f4w0m&cd#iD8PQK#fC! zL$vPBDQs*!@&*zPObhO^3onp;ew^WLPRN7j(&7wu3|Eqmm>%d4)H=>}L2|?IhS=Jf zJPh?S=RII_(AUUz(9-Z^Q8PF6bS=Hns2KKiOICCJT>X>1OCxVP&E9IZVQqV4_GZ)P zr}eq#eRPouYASX}EY=1Z9Df4{`ybss nOa6cN__dG!&X+J}?PI9g`|0TOiIdfU0nOm)>gTe~DWM4f#Ae)m literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/confirm.png b/Content/Sprites/Controls/Xbox Series/South.png similarity index 100% rename from Content/Sprites/Controls/Xbox Series/confirm.png rename to Content/Sprites/Controls/Xbox Series/South.png diff --git a/Content/Sprites/Controls/Xbox Series/Start.png b/Content/Sprites/Controls/Xbox Series/Start.png new file mode 100644 index 0000000000000000000000000000000000000000..f6f1ce274a93af6b6e32265644e77ee1cccb8d0f GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlS@7tf(ub1b4Kfizd{&n$s{t*P&1O!HpYJ z-bye`?Oka#;l`XLOh@@dcz^6;_KXI@OL4P_Fusx4VE^A>ZdoDcll?man3!1J2EDbf=u}s@(YSzr z8ryxf>lf4h%=w(LNS%G}@0G|-o z|Ns9#H*y1#&kS9k8-N%<@Z1n24g^3|5Lx@DW-UMtcS(?6aD4sy_wo1l@9(c?NWAy_ z8c?{_)5S5w<9Kp}D}zCg1M9o1yBia#IrUh%%bgoV_*lCWxz-eDMDPZ0$PPK!pcyft zjE&plag+9pVm56H&hQ1zu?H1*G#OhQSi$s5yW^l<{gfXs;u>Qe#j7SoGf%c`Rrc-E zS}?n5sR3)Cg~*x~%^9t$tzI;qm@o12s*)K4!>0ptXUw0e&WK=cYk&Up`I&xJ6+;xpfYR06^L*Pm9}fwT*h1o;K~=iArcUoYQ( zUVs1l`TX$=kL6}%F)%Rpc)B=-L>zuQ{ccf<0#9q8;1m7RzwL9Q*RGz_+)}noT()@k zWPcC8Ly=#9rLJKAu%EGQ&3``cW#S2I&P~5?t%PCDd4)Z~Oqb?p8>(|QIIVMAV3u%d zyWv&_Lvy8j%o^s+?--i?Oe$d9p}@!z&b&mmJIPbD;q0Le5(%3ucvxI46_gq@^{ccr zr#>}gNVsYKqUL$T%0rAh&b^PkcDr%?<+F@@D^vfzX)<{xkeL5Eg%ZJ!uha%acv3CFYAL*Cj}@H@A>F3aMbY7ql8pE4P^S{iZ;-R*X)le*7xAyr+SD5+4s6d4GO>>#|tN&xPN% zoRoY1s4~p<8_P_QtC;~aTmx&xI%lh-ZCY{qfy3bcg>KlXGU2~Jd n_Lj|m^jpSz$#eV5%sYDd|EGQAW)EAp2^4#tu6{1-oD!MPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0%}P_K~#8N?V62E z12GJRTNVH&049J95EH-#zyyo{8^8v@1h4@xL16;Q1i%F4nR}HG;u<@-AK&3mitMOL zVmnSQz1$=Sf*=TjpiLHw#W~75ik54XT{a&ka6p`Hf>)F+cIzJ)d-rX2JNOL*j61As zY@JsQ*$7k0B4E@EVy~)o#`bhNeWRYu8f7*zB@kUZFU&FYIrVIcGJwwa%?&c)l)9Ph z061}e$q9mROWj0P0O0#O#70$f!ybb0LS2n{4}kLz5Z;^@o+(Y3G62rY=`3rYu0R%; ze6nVMYv%<_lIh8yjutw;hB&EezOiJ1B?AWGyuit74oNE%HEh;6>|O<%Gz0ro!)A@c z?zJ4U*-BJvMS7#E!nzY{G1~C~Gd8K$lH3C@X7PEuCsb#Z8O+@= z)mla!0B}TE%h&^ud{5EJ9^m9D@J-5=v1dS%2ms~3Wz^>Y@Q5wofcl?|Jp&#oYZ-e0 z?kQ{01RxnjuOR)CFG)3fz&?a22&rdpF4p}>V@EOr(8m+ip>adG64gv0@TPkJ4;i4f zLAwd|arf5=>Y1{xzn)Rw5?KNuA1BPKnr|#iP<;+SpK=#JgaDYX?Mw$D1Yw7&SFT{= zCv_F(-5N{5>;0hWE%0wl86aQ~*<3EFnjdnU7t9&31exIGt`N>=`;pyHKoI1utLntn z7A4LL<|XhGj4hv~^pyqkQs;%@4wfJrx;!WqeHhgmh{2@jLGB+`eD6XL68l`00000NkvXX Hu0mjfWaTn- diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 64517e0b..2a616bf8 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -136,44 +136,44 @@ public static void Consume() private static string GetControllerName(Gamepads pad) => pad switch { - Gamepads.DualShock4 => "PlayStation 4", - Gamepads.DualSense => "PlayStation 5", + Gamepads.DualShock4 => "PlayStation", + Gamepads.DualSense => "PlayStation", Gamepads.Nintendo => "Nintendo Switch", Gamepads.Xbox => "Xbox Series", _ => "Xbox Series", }; - private static string GetPromptLocation(string name) + public static string GetPromptLocation(VirtualButton button) { var gamepad = Input.Controllers[0]; - var deviceTypeName = - gamepad.Connected ? GetControllerName(gamepad.Gamepad) : "PC"; + var deviceTypeName = + gamepad.Connected ? GetControllerName(gamepad.Gamepad) : "PC"; if (!prompts.TryGetValue(deviceTypeName, out var list)) prompts[deviceTypeName] = list = []; - if (!list.TryGetValue(name, out var lookup)) - list[name] = lookup = $"Controls/{deviceTypeName}/{name}"; + var action = Instance.Actions.ContainsKey(button.Name) ? Instance.Actions[button.Name] : ControlsConfig_V01.Defaults.Actions[button.Name]; - return lookup; - } + var binding = action.FirstOrDefault(b => b.IsForController() == gamepad.Connected); - public static string GetPromptLocation(VirtualButton button) - { - // TODO: instead, query the button's actual bindings and look up a - // texture based on that! no time tho - if (button == Confirm) - return GetPromptLocation("confirm"); - else if (button == Cancel) - return GetPromptLocation("cancel"); - else if (button == CreateFile) - return GetPromptLocation("createfile"); - else if (button == DeleteFile) - return GetPromptLocation("deletefile"); - else if (button == CopyFile) - return GetPromptLocation("copyfile"); - else - return GetPromptLocation("pause"); + string buttonName = binding.GetBindingName(); + + if (gamepad.Gamepad == Gamepads.DualShock4) + { + if (buttonName == "Start") + { + buttonName = "PS4_Start"; + } + else if (buttonName == "Select") + { + buttonName = "PS4_Select"; + } + } + + if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) + list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{binding.GetBindingName()}"; + + return lookup; } public static Subtexture GetPrompt(VirtualButton button) diff --git a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs b/Source/Data/PersistedData/ControlsConfigBinding_V01.cs index afd1bc47..2d43c42b 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding_V01.cs @@ -65,6 +65,32 @@ public void BindTo(VirtualButton button) button.Add(Condition, 0, Axis.Value, AxisInverted ? -1 : 1, AxisDeadzone); } + public string GetBindingName() + { + if (Key != null) + return Key.ToString(); + if (Button != null) + return Button.ToString(); + if (Axis != null) + return Axis.ToString(); + if (MouseButton != null) + return MouseButton.ToString(); + return null; + } + + public bool IsForController() + { + if (Key != null) + return false; + if (Button != null) + return true; + if (Axis != null) + return true; + if (MouseButton != null) + return false; + return false; + } + public override JsonTypeInfo GetTypeInfo() { return ControlsConfigBinding_V01Context.Default.ControlsConfigBinding_V01; From e3c6d38778b8b27830139f1a8f48b2aa117f2c0d Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 15 Apr 2024 01:16:36 -0700 Subject: [PATCH 02/16] Setting up a very basic control rebinding menu. Creating control binding menu and setting up backend for updating bindings. Still very much a wip proof of concept. Sticks are still not supported, and there are probably several bugs. --- .../PC/{Mouse/mouse.png => Mouse.png} | Bin .../Controls/PC/Mouse/mouse_scroll_down.png | Bin 562 -> 0 bytes .../Controls/PC/Mouse/mouse_scroll_up.png | Bin 533 -> 0 bytes .../Sprites/Controls/PC/Mouse/mouse_small.png | Bin 365 -> 0 bytes .../{Mouse/mouse_left.png => MouseLeft.png} | Bin .../mouse_scroll.png => MouseMiddle.png} | Bin .../{Mouse/mouse_move.png => MouseMove.png} | Bin .../{Mouse/mouse_right.png => MouseRight.png} | Bin ...se_scroll_vertical.png => MouseScroll.png} | Bin .../mouse_horizontal.png => MouseX.png} | Bin .../{Mouse/mouse_vertical.png => MouseY.png} | Bin Source/Data/Controls.cs | 161 ++++++++++++++++-- .../ControlsConfigBinding_V01.cs | 45 ++++- Source/Game.cs | 3 +- Source/Helpers/Menu.cs | 44 ++++- Source/Mod/Menu/BindControlMenu.cs | 64 +++++++ Source/Mod/Menu/ControlsMenu.cs | 95 +++++++++++ Source/Mod/Menu/GameOptionsMenu.cs | 7 +- 18 files changed, 399 insertions(+), 20 deletions(-) rename Content/Sprites/Controls/PC/{Mouse/mouse.png => Mouse.png} (100%) delete mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll_down.png delete mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_scroll_up.png delete mode 100644 Content/Sprites/Controls/PC/Mouse/mouse_small.png rename Content/Sprites/Controls/PC/{Mouse/mouse_left.png => MouseLeft.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_scroll.png => MouseMiddle.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_move.png => MouseMove.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_right.png => MouseRight.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_scroll_vertical.png => MouseScroll.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_horizontal.png => MouseX.png} (100%) rename Content/Sprites/Controls/PC/{Mouse/mouse_vertical.png => MouseY.png} (100%) create mode 100644 Source/Mod/Menu/BindControlMenu.cs create mode 100644 Source/Mod/Menu/ControlsMenu.cs diff --git a/Content/Sprites/Controls/PC/Mouse/mouse.png b/Content/Sprites/Controls/PC/Mouse.png similarity index 100% rename from Content/Sprites/Controls/PC/Mouse/mouse.png rename to Content/Sprites/Controls/PC/Mouse.png diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_scroll_down.png b/Content/Sprites/Controls/PC/Mouse/mouse_scroll_down.png deleted file mode 100644 index f69dd0a75c7dc3c8c21f40cc3a2b1b25326f119e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 562 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCij=0(?ST zpBuS8Gje-r=>E(Q$aZ^f;0ENrGj;)S4PF0}0)R#WO#te+`nBs4kRw$R7hdm z@owr2*K(QX_%f)>y4&N^JZ%EQf}M}}IID(l5G||G;kM0^f$cZJ&%DSiM;9%1|?9Kl_2>_ZHVM?+B^=|CO^qn?0a! zkN4+YJO>`@pY~?>da3LxE5rVpzB_@RGSxRTOx$fHxoFWu?YV*5b0b$E_nol|Q2e=}>wlsF&^(|CK;;*@+=PJ~$&w(y;PvPA z>*MFY=kMRY-roOyyng-u`T6qi`Oh;jo+*`QU|{s}ba4!cIQ;hd%e-a-9)<^bcW)J` zo|XOckAGJHU*WNX89~b*#_JxE-zaVQyAjMPey-E$~X z>caEmtsDkV*c+KVBwBsgbM#nRj@c&)`M)>iP&8rN(%Q~%(EV=GMUD%4G3(bStes&Q z@O8WXVpU$IE$5?e*PdPXChH(0gX#J3#c4|zVrBbve(&>_p2XMUS9euWuJ->oriamg zyN*5;t|(8CVs@B&s=YCKa{X=Ao-W?WUv4ox6!Xqf`uuO+)vw2wfA3+LkvJpTndw03 zXMgJjj0qtTEum~H4rI+a@Sd6PbUDX_WQRTmE@ly?44wmhhxM zTq0_?z++~o)?f7-603@|}hy22WQ%mvv4FO#sOi^!We) diff --git a/Content/Sprites/Controls/PC/Mouse/mouse_small.png b/Content/Sprites/Controls/PC/Mouse/mouse_small.png deleted file mode 100644 index 730389335947f6ed6c289ee011ba6c17f61a39cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 365 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_UvR#C{CfU={rdCs_shR$Ff)7Y0hGDu>EamTaXfj4H-kZs zmPDw-x~3Jy@9*v1`~BVB*+*}P#?*i3TlC=W?ua#9?-WGl99_kr@-^t&Bby0EbGWh; z%^rq)c-8gk)b7_GG%Cs%UmUQp;ktLP!9sX@Q}qv#10oN3v-WUtL^<{}UEkht?@qh> z!Oz-d`tPqjVcG#qu#e25$u!e zTa`C`J0LRW*un?5EIa(File.ReadAllText(tempPath)) != null) + { + File.Copy(tempPath, savePath, true); + } + } + public static void LoadConfig(ControlsConfig_V01? config = null) { static ControlsConfigStick_V01 FindStick(ControlsConfig_V01? config, string name) @@ -143,6 +234,11 @@ public static void Consume() _ => "Xbox Series", }; + public static Subtexture GetPrompt(VirtualButton button) + { + return Assets.Subtextures.GetValueOrDefault(GetPromptLocation(button)); + } + public static string GetPromptLocation(VirtualButton button) { var gamepad = Input.Controllers[0]; @@ -158,7 +254,60 @@ public static string GetPromptLocation(VirtualButton button) string buttonName = binding.GetBindingName(); - if (gamepad.Gamepad == Gamepads.DualShock4) + buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); + + if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) + list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{binding.GetBindingName()}"; + + return lookup; + } + + public static List GetPrompts(VirtualButton button) + { + List subtextures = []; + foreach (var location in GetPromptLocations(button)) + subtextures.Add(Assets.Subtextures.GetValueOrDefault(location)); + return subtextures; + } + + private static List GetPromptLocations(VirtualButton button) + { + List locations = []; + var gamepad = Input.Controllers[0]; + var deviceTypeName = + gamepad.Connected ? GetControllerName(gamepad.Gamepad) : "PC"; + foreach (var binding in Instance.Actions[button.Name]) + { + string promptDeviceTypeName = "PC"; + var buttonName = binding.GetBindingName(); + if (binding.IsForController()) + promptDeviceTypeName = GetControllerName(gamepad.Gamepad); + + if (!prompts.TryGetValue(deviceTypeName, out var list)) + prompts[deviceTypeName] = list = []; + + buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); + + if (!list.TryGetValue(buttonName, out var lookup)) + list[buttonName] = lookup = $"Controls/{promptDeviceTypeName}/{buttonName}"; + + if (Gamepads.Nintendo.Equals(binding.NotFor) || !Gamepads.Nintendo.Equals(binding.OnlyFor) || (binding.NotFor == null && binding.OnlyFor == null)) //only non switch prompts atm + locations.Add(lookup); + + } + + return locations; + } + + ///

+ /// Used for special cases where there may be multiple options for a button, like with different control types. + /// + /// + /// + /// + private static string GetButtonOverrides(string buttonName, Gamepads gamepadType) + { + if (gamepadType == Gamepads.DualShock4) { if (buttonName == "Start") { @@ -170,14 +319,6 @@ public static string GetPromptLocation(VirtualButton button) } } - if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) - list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{binding.GetBindingName()}"; - - return lookup; - } - - public static Subtexture GetPrompt(VirtualButton button) - { - return Assets.Subtextures.GetValueOrDefault(GetPromptLocation(button)); + return buttonName; } } diff --git a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs b/Source/Data/PersistedData/ControlsConfigBinding_V01.cs index 2d43c42b..69ce3df0 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding_V01.cs @@ -65,17 +65,51 @@ public void BindTo(VirtualButton button) button.Add(Condition, 0, Axis.Value, AxisInverted ? -1 : 1, AxisDeadzone); } + + /// + /// This is kind of a workaround for how Foster works. + /// We need a custom version of Foster's Button Enum so we can properly get the names from the button. + /// Since Foster's had old obsolete buttons with duplicate values, it was causing it to not properly use the correct name. + /// + public enum FujiButtons + { + None = -1, + South = 0, + East = 1, + West = 2, + North = 3, + Back = 4, + Select = 5, + Start = 6, + LeftStick = 7, + RightStick = 8, + LeftShoulder = 9, + RightShoulder = 10, + Up = 11, + Down = 12, + Left = 13, + Right = 14 + } + + public enum FujiMouseButtons + { + MouseNone, + MouseLeft, + MouseMiddle, + MouseRight + } + public string GetBindingName() { if (Key != null) - return Key.ToString(); + return Key.ToString() ?? ""; if (Button != null) - return Button.ToString(); + return ((FujiButtons)Button).ToString() ?? ""; if (Axis != null) - return Axis.ToString(); + return Axis.ToString() ?? ""; if (MouseButton != null) - return MouseButton.ToString(); - return null; + return ((FujiMouseButtons)MouseButton).ToString() ?? ""; + return ""; } public bool IsForController() @@ -119,7 +153,6 @@ public override void Write(Utf8JsonWriter writer, ControlsConfigBinding_V01 valu } [JsonSourceGenerationOptions( - WriteIndented = true, UseStringEnumConverter = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, AllowTrailingCommas = true diff --git a/Source/Game.cs b/Source/Game.cs index 456d1a9f..2b1f62d5 100644 --- a/Source/Game.cs +++ b/Source/Game.cs @@ -284,6 +284,7 @@ public override void Update() { Save.SaveToFile(); Settings.SaveToFile(); + Controls.SaveToFile(); ModSettings.SaveToFile(); } @@ -316,7 +317,7 @@ public override void Update() if (scenes.TryPeek(out var nextScene)) { if (Settings.EnableAdditionalLogging) Log.Info("Switching scene: " + nextScene.GetType()); - + try { nextScene.Entered(); diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index 6aee868b..7729465e 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -41,6 +41,27 @@ public Item Describe(Loc.Localized description) } } + public class InputBind(string label, VirtualButton button, Menu? rootMenu) : Item + { + public override string Label { get; } = label; + public override bool Pressed() + { + Audio.Play(Sfx.ui_select); + rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button)); + return true; + } + + public List GetTextures() + { + return Controls.GetPrompts(button); + } + + public VirtualButton GetButton() + { + return button; + } + } + public class Submenu(Loc.Localized locString, Menu? rootMenu, Menu? submenu = null) : Item { public override Loc.Localized? LocString => locString; @@ -365,7 +386,7 @@ protected virtual void HandleInput() step = -1; Index += step; - while (!items[(items.Count + Index) % items.Count].Selectable) + while (step != 0 && !items[(items.Count + Index) % items.Count].Selectable) Index += step; Index = (items.Count + Index) % items.Count; @@ -456,6 +477,25 @@ protected virtual void RenderItems(Batcher batch) batch.PopMatrix(); position.Y += font.LineHeight; } + else if (items[i] is InputBind) + { + UI.Text(batch, text, position, new Vec2(1.0f, 0), color); + + InputBind item = (InputBind)items[i]; + var textures = item.GetTextures(); + foreach (var texture in textures) + { + batch.PushMatrix( + Matrix3x2.CreateScale(TitleScale) * + Matrix3x2.CreateTranslation(position)); + position.X += (24 * Game.RelativeScale); + UI.Icon(batch, texture, "", Vec2.Zero); + batch.PopMatrix(); + } + position.Y += font.LineHeight; + position.Y += Spacing; + position.X = 0; + } else { UI.Text(batch, text, position, justify, color); @@ -465,7 +505,7 @@ protected virtual void RenderItems(Batcher batch) } batch.PopMatrix(); - // Render a scrolbar if there are too many items to show on screen at once + // Render a scrollbar if there are too many items to show on screen at once if (showScrollbar && items.Count > maxItemsCount) { // TODO: This will need to be redone if we implement mouse support and want it to interact with menus. diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs new file mode 100644 index 00000000..da5f13cb --- /dev/null +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -0,0 +1,64 @@ +namespace Celeste64; + +public class BindControlMenu : Menu +{ + private float inMenuTime = 0; + + private const float waitBeforeClosingTime = 5; + private VirtualButton button; + + public BindControlMenu(Menu? rootMenu, VirtualButton button) + { + RootMenu = rootMenu; + + this.button = button; + Title = Loc.Str($"Press Button to bind {button.Name}"); + inMenuTime = 0; + } + + protected override void HandleInput() + { + Keys? pressed = Input.Keyboard.FirstPressed(); + if (pressed != null) + { + Controls.AddBinding(button, (Keys)pressed); + RootMenu?.PopSubMenu(); + return; + } + + // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for buttons. + Controller? controller = Input.Controllers.FirstOrDefault(); + if (controller != null) + { + foreach (var button in Enum.GetValues(typeof(Buttons))) + { + if (controller.Pressed((Buttons)button)) + { + Controls.AddBinding(this.button, (Buttons)button); + RootMenu?.PopSubMenu(); + return; + } + } + } + + // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for mouse buttons. + if (controller != null) + { + foreach (var button in Enum.GetValues(typeof(MouseButtons))) + { + if (Input.Mouse.Pressed((MouseButtons)button)) + { + Controls.AddBinding(this.button, (MouseButtons)button); + RootMenu?.PopSubMenu(); + return; + } + } + } + + inMenuTime += Time.Delta; + if (inMenuTime > waitBeforeClosingTime) + { + RootMenu?.PopSubMenu(); + } + } +} diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs new file mode 100644 index 00000000..639ee3d9 --- /dev/null +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -0,0 +1,95 @@ +namespace Celeste64; + +public class ControlsMenu : Menu +{ + private Target GameTarget; + + + public override void Closed() + { + base.Closed(); + Controls.SaveToFile(); + } + + public override void Initialized() + { + Index = 1; + } + + public ControlsMenu(Menu? rootMenu) + { + RootMenu = rootMenu; + + GameTarget = new Target(Game.Width, Game.Height); + Game.OnResolutionChanged += () => GameTarget = new Target(Game.Width, Game.Height); + + Title = Loc.Str("ControlsTitle"); + + Add(new SubHeader("Game")); + Add(new InputBind(Controls.Jump.Name, Controls.Jump, rootMenu)); + Add(new InputBind(Controls.Dash.Name, Controls.Dash, rootMenu)); + Add(new InputBind(Controls.Climb.Name, Controls.Climb, rootMenu)); + Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu)); + + //Add(new SubHeader("Menu")); + //Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu)); + //Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu)); + //Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu)); + //Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu)); + //Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu)); + + Add(new Spacer()); + + Add(new Option("ResetToDefault", () => + { + Controls.ResetBindings(); + })); + + Add(new Option("Exit", () => + { + PopRootSubMenu(); + })); + } + + protected override void HandleInput() + { + base.HandleInput(); + + if (Controls.CopyFile.ConsumePress()) + { + if (items[Index] is InputBind bind) + { + Controls.ResetBinding(bind.GetButton()); + } + } + + if (Controls.CreateFile.ConsumePress()) + { + if (items[Index] is InputBind bind) + { + Controls.ClearBinding(bind.GetButton()); + } + } + } + + protected override void RenderItems(Batcher batch) + { + batch.PushMatrix(new Vec2(GameTarget.Bounds.Center.X, GameTarget.Bounds.Center.Y - 16f), false); + base.RenderItems(batch); + batch.PopMatrix(); + + batch.PushMatrix(Vec2.Zero, false); + var at = GameTarget.Bounds.BottomRight + new Vec2(-32, -4) * Game.RelativeScale + new Vec2(0, -UI.PromptSize); + UI.Prompt(batch, Controls.Cancel, Loc.Str("Back"), at, out var width, 1.0f); + at.X -= width + 8 * Game.RelativeScale; + + UI.Prompt(batch, Controls.Confirm, Loc.Str("Bind"), at, out width, 1.0f); + at.X -= width + 8 * Game.RelativeScale; + + UI.Prompt(batch, Controls.CreateFile, Loc.Str("Clear"), at, out width, 1.0f); + at.X -= width + 8 * Game.RelativeScale; + + UI.Prompt(batch, Controls.CopyFile, Loc.Str("Reset"), at, out width, 1.0f); + batch.PopMatrix(); + } +} diff --git a/Source/Mod/Menu/GameOptionsMenu.cs b/Source/Mod/Menu/GameOptionsMenu.cs index 0997da00..9195f088 100644 --- a/Source/Mod/Menu/GameOptionsMenu.cs +++ b/Source/Mod/Menu/GameOptionsMenu.cs @@ -3,12 +3,13 @@ namespace Celeste64; public class GameOptionsMenu : Menu { public Menu FujiOptionsMenu; - + public ControlsMenu ControlsMenu; public override void Closed() { base.Closed(); Settings.SaveToFile(); + Controls.SaveToFile(); } public GameOptionsMenu(Menu? rootMenu) @@ -16,6 +17,7 @@ public GameOptionsMenu(Menu? rootMenu) RootMenu = rootMenu; // Setup fuji options menu FujiOptionsMenu = new Menu { Title = Loc.Str("FujiOptions") }; + ControlsMenu = new ControlsMenu(rootMenu); FujiOptionsMenu.Add(new Toggle("FujiEnableDebugMenu", Settings.ToggleEnableDebugMenu, () => Settings.EnableDebugMenu)); FujiOptionsMenu.Add(new Toggle("FujiWriteLog", Settings.ToggleWriteLog, () => Settings.WriteLog)); @@ -49,6 +51,9 @@ public GameOptionsMenu(Menu? rootMenu) Add(new Slider("OptionsBGM", 0, 10, () => Settings.MusicVolume, Settings.SetMusicVolume)); Add(new Slider("OptionsSFX", 0, 10, () => Settings.SfxVolume, Settings.SetSfxVolume)); Add(new Spacer()); + + + Add(new Submenu("Controls", this, ControlsMenu)); Add(new Submenu("FujiOptions", this, FujiOptionsMenu)); } } From c03b30aec0aed57379156f0ecd44b9958e02eb4a Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 15 Apr 2024 09:14:39 -0700 Subject: [PATCH 03/16] Cleanup around controls format. Adding Axis binding --- Source/Data/Controls.cs | 11 +++- ...inding_V01.cs => ControlsConfigBinding.cs} | 34 ++++------- .../Data/PersistedData/ControlsConfigStick.cs | 37 +++++++++++ .../PersistedData/ControlsConfigStick_V01.cs | 61 ------------------- .../Data/PersistedData/ControlsConfig_V01.cs | 6 +- Source/Mod/Menu/BindControlMenu.cs | 10 +++ 6 files changed, 72 insertions(+), 87 deletions(-) rename Source/Data/PersistedData/{ControlsConfigBinding_V01.cs => ControlsConfigBinding.cs} (71%) create mode 100644 Source/Data/PersistedData/ControlsConfigStick.cs delete mode 100644 Source/Data/PersistedData/ControlsConfigStick_V01.cs diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 0bdc7b6b..c9a774eb 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -108,6 +108,13 @@ internal static void AddBinding(VirtualButton button, MouseButtons key) Instance.Actions[button.Name].Last().BindTo(button); } + [DisallowHooks] + internal static void AddBinding(VirtualButton button, Axes key, bool inverted) + { + Instance.Actions[button.Name].Add(new(key, 0.5f, inverted)); + Instance.Actions[button.Name].Last().BindTo(button); + } + [DisallowHooks] internal static void ClearBinding(VirtualButton button) { @@ -146,7 +153,7 @@ public static void SaveToFile() public static void LoadConfig(ControlsConfig_V01? config = null) { - static ControlsConfigStick_V01 FindStick(ControlsConfig_V01? config, string name) + static ControlsConfigStick FindStick(ControlsConfig_V01? config, string name) { if (config != null && config.Sticks.TryGetValue(name, out var stick)) return stick; @@ -155,7 +162,7 @@ static ControlsConfigStick_V01 FindStick(ControlsConfig_V01? config, string name throw new Exception($"Missing Stick Binding for '{name}'"); } - static List FindAction(ControlsConfig_V01? config, string name) + static List FindAction(ControlsConfig_V01? config, string name) { if (config != null && config.Actions.TryGetValue(name, out var action)) return action; diff --git a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs b/Source/Data/PersistedData/ControlsConfigBinding.cs similarity index 71% rename from Source/Data/PersistedData/ControlsConfigBinding_V01.cs rename to Source/Data/PersistedData/ControlsConfigBinding.cs index 69ce3df0..e4c1a9ad 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding_V01.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding.cs @@ -1,13 +1,10 @@ using System.Text.Json; using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; namespace Celeste64; -public sealed class ControlsConfigBinding_V01 : PersistedData +public sealed class ControlsConfigBinding { - public override int Version => 1; - public Keys? Key { get; set; } public MouseButtons? MouseButton { get; set; } public Buttons? Button { get; set; } @@ -17,11 +14,11 @@ public sealed class ControlsConfigBinding_V01 : PersistedData public Gamepads? OnlyFor { get; set; } public Gamepads? NotFor { get; set; } - public ControlsConfigBinding_V01() { } - public ControlsConfigBinding_V01(Keys input) => Key = input; - public ControlsConfigBinding_V01(MouseButtons input) => MouseButton = input; - public ControlsConfigBinding_V01(Buttons input) => Button = input; - public ControlsConfigBinding_V01(Axes input, float deadzone, bool inverted) + public ControlsConfigBinding() { } + public ControlsConfigBinding(Keys input) => Key = input; + public ControlsConfigBinding(MouseButtons input) => MouseButton = input; + public ControlsConfigBinding(Buttons input) => Button = input; + public ControlsConfigBinding(Axes input, float deadzone, bool inverted) { Axis = input; AxisDeadzone = deadzone; @@ -124,30 +121,25 @@ public bool IsForController() return false; return false; } - - public override JsonTypeInfo GetTypeInfo() - { - return ControlsConfigBinding_V01Context.Default.ControlsConfigBinding_V01; - } } -public class ControlsConfigBinding_V01Converter : JsonConverter +public class ControlsConfigBinding_Converter : JsonConverter { - public override ControlsConfigBinding_V01? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ControlsConfigBinding? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using (var jsonDoc = JsonDocument.ParseValue(ref reader)) { - return new ControlsConfigBinding_V01().Deserialize(jsonDoc.RootElement.GetRawText()); + return JsonSerializer.Deserialize(jsonDoc.RootElement.GetRawText(), ControlsConfigBindingContext.Default.ControlsConfigBinding); } } - public override void Write(Utf8JsonWriter writer, ControlsConfigBinding_V01 value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ControlsConfigBinding value, JsonSerializerOptions options) { // All of this is just so the Binding values are on a single line to increase readability var data = "\n" + new string(' ', writer.CurrentDepth * 2) + - JsonSerializer.Serialize(value, ControlsConfigBinding_V01Context.Default.ControlsConfigBinding_V01); + JsonSerializer.Serialize(value, ControlsConfigBindingContext.Default.ControlsConfigBinding); writer.WriteRawValue(data); } } @@ -157,5 +149,5 @@ public override void Write(Utf8JsonWriter writer, ControlsConfigBinding_V01 valu DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, AllowTrailingCommas = true )] -[JsonSerializable(typeof(ControlsConfigBinding_V01))] -internal partial class ControlsConfigBinding_V01Context : JsonSerializerContext { } +[JsonSerializable(typeof(ControlsConfigBinding))] +internal partial class ControlsConfigBindingContext : JsonSerializerContext { } diff --git a/Source/Data/PersistedData/ControlsConfigStick.cs b/Source/Data/PersistedData/ControlsConfigStick.cs new file mode 100644 index 00000000..a5fb1781 --- /dev/null +++ b/Source/Data/PersistedData/ControlsConfigStick.cs @@ -0,0 +1,37 @@ +using System.Text.Json.Serialization; + +namespace Celeste64; + +public sealed class ControlsConfigStick +{ + public float Deadzone { get; set; } = 0; + public List Up { get; set; } = []; + public List Down { get; set; } = []; + public List Left { get; set; } = []; + public List Right { get; set; } = []; + + public void BindTo(VirtualStick stick) + { + stick.CircularDeadzone = Deadzone; + stick.Horizontal.OverlapBehaviour = VirtualAxis.Overlaps.TakeNewer; + stick.Vertical.OverlapBehaviour = VirtualAxis.Overlaps.TakeNewer; + foreach (var it in Up) + it.BindTo(stick.Vertical.Negative); + foreach (var it in Down) + it.BindTo(stick.Vertical.Positive); + foreach (var it in Left) + it.BindTo(stick.Horizontal.Negative); + foreach (var it in Right) + it.BindTo(stick.Horizontal.Positive); + } +} + +[JsonSourceGenerationOptions( + WriteIndented = true, + UseStringEnumConverter = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, + Converters = [typeof(ControlsConfigBinding_Converter)], + AllowTrailingCommas = true +)] +[JsonSerializable(typeof(ControlsConfigStick))] +internal partial class ControlsConfigStickContext : JsonSerializerContext { } diff --git a/Source/Data/PersistedData/ControlsConfigStick_V01.cs b/Source/Data/PersistedData/ControlsConfigStick_V01.cs deleted file mode 100644 index e9b78fa0..00000000 --- a/Source/Data/PersistedData/ControlsConfigStick_V01.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; - -namespace Celeste64; - -public sealed class ControlsConfigStick_V01 : PersistedData -{ - public override int Version => 1; - - public float Deadzone { get; set; } = 0; - public List Up { get; set; } = []; - public List Down { get; set; } = []; - public List Left { get; set; } = []; - public List Right { get; set; } = []; - - public void BindTo(VirtualStick stick) - { - stick.CircularDeadzone = Deadzone; - stick.Horizontal.OverlapBehaviour = VirtualAxis.Overlaps.TakeNewer; - stick.Vertical.OverlapBehaviour = VirtualAxis.Overlaps.TakeNewer; - foreach (var it in Up) - it.BindTo(stick.Vertical.Negative); - foreach (var it in Down) - it.BindTo(stick.Vertical.Positive); - foreach (var it in Left) - it.BindTo(stick.Horizontal.Negative); - foreach (var it in Right) - it.BindTo(stick.Horizontal.Positive); - } - - public override JsonTypeInfo GetTypeInfo() - { - return ControlsConfigStick_V01Context.Default.ControlsConfigStick_V01; - } -} - -public class ControlsConfigStick_V01Converter : JsonConverter -{ - public override ControlsConfigStick_V01? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - using (var jsonDoc = JsonDocument.ParseValue(ref reader)) - { - return new ControlsConfigStick_V01().Deserialize(jsonDoc.RootElement.GetRawText()); - } - } - - public override void Write(Utf8JsonWriter writer, ControlsConfigStick_V01 value, JsonSerializerOptions options) - { - value.Serialize(writer, value); - } -} - -[JsonSourceGenerationOptions( - WriteIndented = true, - UseStringEnumConverter = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, - AllowTrailingCommas = true -)] -[JsonSerializable(typeof(ControlsConfigStick_V01))] -internal partial class ControlsConfigStick_V01Context : JsonSerializerContext { } diff --git a/Source/Data/PersistedData/ControlsConfig_V01.cs b/Source/Data/PersistedData/ControlsConfig_V01.cs index a66250d9..dd54fa93 100644 --- a/Source/Data/PersistedData/ControlsConfig_V01.cs +++ b/Source/Data/PersistedData/ControlsConfig_V01.cs @@ -7,8 +7,8 @@ public class ControlsConfig_V01 : PersistedData { public override int Version => 1; - public Dictionary> Actions { get; set; } = []; - public Dictionary Sticks { get; set; } = []; + public Dictionary> Actions { get; set; } = []; + public Dictionary Sticks { get; set; } = []; public static ControlsConfig_V01 Defaults = new() { @@ -149,7 +149,7 @@ public override JsonTypeInfo GetTypeInfo() UseStringEnumConverter = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, AllowTrailingCommas = true, - Converters = [typeof(ControlsConfigBinding_V01Converter), typeof(ControlsConfigStick_V01Converter)] + Converters = [typeof(ControlsConfigBinding_Converter)] )] [JsonSerializable(typeof(ControlsConfig_V01))] internal partial class ControlsConfig_V01Context : JsonSerializerContext { } diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index da5f13cb..8941afc4 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -39,6 +39,16 @@ protected override void HandleInput() return; } } + + foreach (var axis in Enum.GetValues(typeof(Axes))) + { + if (Math.Abs(controller.Axis((Axes)axis)) > 0.5f) + { + Controls.AddBinding(this.button, (Axes)axis, controller.Axis((Axes)axis) < -0.5f); + RootMenu?.PopSubMenu(); + return; + } + } } // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for mouse buttons. From 518d0d0fcb04238bfe32be726553b30a694ee4f2 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Sun, 21 Apr 2024 15:27:55 -0700 Subject: [PATCH 04/16] Adding ability to rebind sticks. Also splitting controller and keyboard into 2 menus. --- .../{Down.png => ButtonDown.png} | Bin .../{Left.png => ButtonLeft.png} | Bin .../{Right.png => ButtonRight.png} | Bin .../Nintendo Switch/{Up.png => ButtonUp.png} | Bin .../Nintendo Switch/LeftXNegative.png | Bin 0 -> 676 bytes .../Nintendo Switch/LeftXPositive.png | Bin 0 -> 675 bytes .../Nintendo Switch/LeftYNegative.png | Bin 0 -> 695 bytes .../Nintendo Switch/LeftYPositive.png | Bin 0 -> 708 bytes .../Nintendo Switch/RightXNegative.png | Bin 0 -> 702 bytes .../Nintendo Switch/RightXPositive.png | Bin 0 -> 705 bytes .../Nintendo Switch/RightYNegative.png | Bin 0 -> 731 bytes .../Nintendo Switch/RightYPositive.png | Bin 0 -> 738 bytes .../PlayStation/{Down.png => ButtonDown.png} | Bin .../PlayStation/{Left.png => ButtonLeft.png} | Bin .../{Right.png => ButtonRight.png} | Bin .../PlayStation/{Up.png => ButtonUp.png} | Bin .../PlayStation/playstation_stick_l_left.png | Bin 0 -> 676 bytes .../PlayStation/playstation_stick_l_press.png | Bin 0 -> 712 bytes .../PlayStation/playstation_stick_l_right.png | Bin 0 -> 675 bytes .../PlayStation/playstation_stick_l_up.png | Bin 0 -> 695 bytes .../PlayStation/playstation_stick_r_down.png | Bin 0 -> 738 bytes .../PlayStation/playstation_stick_r_left.png | Bin 0 -> 702 bytes .../PlayStation/playstation_stick_r_right.png | Bin 0 -> 705 bytes .../PlayStation/playstation_stick_r_up.png | Bin 0 -> 731 bytes .../Xbox Series/{Down.png => ButtonDown.png} | Bin .../Xbox Series/{Left.png => ButtonLeft.png} | Bin .../{Right.png => ButtonRight.png} | Bin .../Xbox Series/{Up.png => ButtonUp.png} | Bin .../Controls/Xbox Series/LeftXNegative.png | Bin 0 -> 676 bytes .../Controls/Xbox Series/LeftXPositive.png | Bin 0 -> 675 bytes .../Controls/Xbox Series/LeftYNegative.png | Bin 0 -> 695 bytes .../Controls/Xbox Series/LeftYPositive.png | Bin 0 -> 708 bytes .../Controls/Xbox Series/RightXNegative.png | Bin 0 -> 702 bytes .../Controls/Xbox Series/RightXPositive.png | Bin 0 -> 705 bytes .../Controls/Xbox Series/RightYNegative.png | Bin 0 -> 731 bytes .../Controls/Xbox Series/RightYPositive.png | Bin 0 -> 738 bytes Content/Text/English.json | 32 +++ Source/Data/Controls.cs | 206 ++++++++++++++---- .../PersistedData/ControlsConfigBinding.cs | 10 +- .../Data/PersistedData/ControlsConfig_V01.cs | 2 +- Source/Helpers/Menu.cs | 10 +- Source/Mod/Menu/BindControlMenu.cs | 64 +++--- Source/Mod/Menu/ControlsMenu.cs | 51 +++-- Source/Mod/Menu/GameOptionsMenu.cs | 13 +- 44 files changed, 279 insertions(+), 109 deletions(-) rename Content/Sprites/Controls/Nintendo Switch/{Down.png => ButtonDown.png} (100%) rename Content/Sprites/Controls/Nintendo Switch/{Left.png => ButtonLeft.png} (100%) rename Content/Sprites/Controls/Nintendo Switch/{Right.png => ButtonRight.png} (100%) rename Content/Sprites/Controls/Nintendo Switch/{Up.png => ButtonUp.png} (100%) create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftXNegative.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftXPositive.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftYNegative.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/LeftYPositive.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightXNegative.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightXPositive.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightYNegative.png create mode 100644 Content/Sprites/Controls/Nintendo Switch/RightYPositive.png rename Content/Sprites/Controls/PlayStation/{Down.png => ButtonDown.png} (100%) rename Content/Sprites/Controls/PlayStation/{Left.png => ButtonLeft.png} (100%) rename Content/Sprites/Controls/PlayStation/{Right.png => ButtonRight.png} (100%) rename Content/Sprites/Controls/PlayStation/{Up.png => ButtonUp.png} (100%) create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_l_left.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_l_press.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_l_right.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_l_up.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_r_down.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_r_left.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_r_right.png create mode 100644 Content/Sprites/Controls/PlayStation/playstation_stick_r_up.png rename Content/Sprites/Controls/Xbox Series/{Down.png => ButtonDown.png} (100%) rename Content/Sprites/Controls/Xbox Series/{Left.png => ButtonLeft.png} (100%) rename Content/Sprites/Controls/Xbox Series/{Right.png => ButtonRight.png} (100%) rename Content/Sprites/Controls/Xbox Series/{Up.png => ButtonUp.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/LeftXNegative.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftXPositive.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftYNegative.png create mode 100644 Content/Sprites/Controls/Xbox Series/LeftYPositive.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightXNegative.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightXPositive.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightYNegative.png create mode 100644 Content/Sprites/Controls/Xbox Series/RightYPositive.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Down.png b/Content/Sprites/Controls/Nintendo Switch/ButtonDown.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/Down.png rename to Content/Sprites/Controls/Nintendo Switch/ButtonDown.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Left.png b/Content/Sprites/Controls/Nintendo Switch/ButtonLeft.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/Left.png rename to Content/Sprites/Controls/Nintendo Switch/ButtonLeft.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Right.png b/Content/Sprites/Controls/Nintendo Switch/ButtonRight.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/Right.png rename to Content/Sprites/Controls/Nintendo Switch/ButtonRight.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Up.png b/Content/Sprites/Controls/Nintendo Switch/ButtonUp.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/Up.png rename to Content/Sprites/Controls/Nintendo Switch/ButtonUp.png diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftXNegative.png b/Content/Sprites/Controls/Nintendo Switch/LeftXNegative.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa8948d56c20e95b14280a7160fda480e8fa27e GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEhM?_V!pf1Y3e{eA}9zlXLlFfcKAx;TbJ9DY0f zb>A8Vo(5UR#%%_B{$G~cxzgdN;q1x2W|!m7dDy>@UH+Xv^%v7W69<2{ojRv{en~ob zf9P$vBF~)mG&1nBJ44aGAep;N1zS_UF7grEI_3YHF7t+@-9lHrM2_l6Fd67Zt9(1Q z$me;11;dGwGfNEK7n%eIc|Bv~^SQyXV5f(M;9+jrgYJPxUc2e&Y^ESjiP$oRo1 ze}hTG8hMi~@{D`VX)oh)IK43O7{lbvrMAo`=9wh$G~_I?X1+6(jhW;B#dq&{Ht;jP z7gIQwe^=sx#R12RO%oW`=p>Xsc29g$TOe@ntKhesmHY}44r(F3os0(pwPOvBrmVTN ziG7J%!!*{GBBP}nH*L*Gt;(&L?Qte$!(O{52c7o4(&TOMdMxhiUzEBcVU_en=0jYW zZ|$rybS+cw8eZGf+}9UWy5vWf+vXit-gakZ-kSEXc`?z_*YI_5HG@L+YzOn{xv!WuUf6uwYL?dOgAYExZ>_u= jedf>Kv|mieKJhR9^X8vO-9K4iI$`j1^>bP0l+XkK?3PHk literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftXPositive.png b/Content/Sprites/Controls/Nintendo Switch/LeftXPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..53df6eb804d5ac17506fb5ea7184daa93bd3bc1c GIT binary patch literal 675 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEI}?_V!pf1Y3e{eA|q8BZ@VFfji2ba4!cIQ(|{ z>%KJ#JPopedAcut+rOQ-x`EYn_GDkP%kj$F?r+($#Uj^!%1iDaml-TI6Bl!so-AkB z`D(A=-c!dLBHt|O_$kQn_MT|>c7_LPnfgwyg5FWaGI zWu1$>=lSR(AOHWfvziP$7N@!jvN1ayznOH`k8w&8N5RxzS}9h zNm#+2!BEHE$MD3C$)b0M7^mccg7B={pLW}t?Lc`SEq0^obx}qkL|}| ziQ7!99Y@1Oih@1%or_6UJ-^6vZHjGw5FgZf4ciOy6{iaEXfHi}` zRZUxy%2k@l=Qp+;b64tY`=oh3!v8|Z-jz%zY-)ae%gm8H)x24_WZP-;uZs+0Z~xkv z-_*hETDnN1L1)tP$fF00w56&R^RE69e0k@pq@*2-Zsxll&e+quck}jwV&}l*>aX|L zTl|yJ+4A#{T>R&Z1Krh+-ZP)5-J;JB;wV{DeDj#MQdRAu@@V$ZuO@3B{QZ7t&TaPj h`|tb2ABgzJxZ~EFe_EtPvII(k{DSTC{p0)Zua}>{zy3VG{(FWOF>8An7?^}TT^vIq4!@oL zvadyfry)>pr`4YSm)9w2P3c-Z`E1JMxBW9UzHOcox9NKOp*l$cwZnFdEFFS}iW{aE zioKlAw5Qv1PCeU=FTY#(60XnZ^k)dxN!i7}VWUtryTFw{!V}MI52@gOkbc`VwQ*kg zqxFn3=Xl~K99Yk=`t^zz(TgS(r1O4Iv!2VeqV(*KVh6stp3Aw@)RP%{X1;mB?IIht z=3;xHuk(sID~{cDG;MtNclq1=XVV@XyDKQnD>3<>lemCp;OANX-pZ^V-U|u^9yeUu zu$PVbOU2QPoI8dbjuIyIWHiOAHBc!~)>rjF5)Vqx;9(Qv14~RJ`ocsDcY30gA zSsQn6$Z-FX<>n`{>hjDBdjgqC3M=};djjThz1VzBY}MoGr_us9ajhu07sGtS+i|Y+ z*7E#yUjmEs*m-VW-+o=$?}bF-p=f8Z>05R^$?vZ;d2npbk6MP8?#0XwtXEF9v%h{` zTgdY8-iEiip_k`;{k~uPMwp$$hWEAK{xbh#d%)hL@wWJ*z^duMq{HCp>gTe~DWM4f DzG literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftYPositive.png b/Content/Sprites/Controls/Nintendo Switch/LeftYPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..184733d5aa3855450ae71077d8f6ff3ce0aecd50 GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB-4R0hyXP6}`o%ls3Yz_y zm&7w(;=9J^amHvX+lm=$moVR0u^^7Q#N<+0L-th@b+(4r=EC;X2cFA5*vxXn^ne}H z2`PtZ4X4@9C&v6}Fw?3zb#x8GT&BKNn!F5F;co>5vRJ+N2sa&7DQz3Su z<2uhKCHc8?dd(giHGKaoaensC0#_z&VX4KZ-Jak6*!S4-tit?5e1{+2*&h(nRcxdY zQ?=z^ynUgUlimMEos(ZF2w$pnjJN+Bz}{6F{B^?g1_yzkf37#g7`FcxOVDQ0bUWnD z@aw;p_JhMLRTVkX7t6Lp&Y!XOn&Z`#Yaaam&n>;LO7>>m|Cx0STmLZEJHGDcj%aEE PrXvPVS3j3^P6EtPvII(k{DS@G+sEhM@0VX+&wu{C{(go%1yM^G7?`9yT^vIq4!@m# zvu}-pfJ3Omf`~8w_kTOJZ|aS-BIA=wUZ32yl6mXnqCWxC^dI;$|4?e}ReEyhKBGlw zx_Z~Ae#Y4rfr7W)8IsROZ+s@mu-k9-%n5-k-tWKg@i(OGRygaWa8k#V)gj`TM$a)O z-sc+(7%vo@S+L=$#VJ({*3Tk7K07$Nk|zorX%FXZxyK%6?JjNV=CFI|vH6Kd8F%k0 zd+1lcpYzdHZ^Z`|) z{fi2juQ4v#7yR%!hlN+!=N(Cz3~i#KHyM&RXa4a!mUB0|;o{V;SB!R*-l6Wwxx5?p zdj0M;&F`<6C$(TXgKxI*o+N&SulvP{lQ@?gWoW&SmdF`exqWfNn`5&L!o&*Bu(uYN zxOY^?TCK5UaAcTx!DK1R0@hVtYk7`7nY_{Sv=;v&-i3k?9_(O z2RFS8jQ@CR@oU}#OOE;PnwN4ppz%R~5z`&6Ri$#WY5tZ=b0xDcIxbyoB75?GYT9Ot zt8crun5?_}VdwSp$=%7mQ@_2FO53(-H`AjdLGDZ&4|gonOkh}Hv)<#dL1~D|ercU$ zoc3mO-ObAnhtBQ4)Vk7JWrP2(y9IK=k>|cXt>6FXhgHH3D`olk&jkm%s~^2*4zRx^ z&ahZs_{GCbxor*xpWkic+jKHZ_2J*|hqgTz+g!VU=DvoVf0$hv-Y8Fexob8s1u=NK L`njxgN@xNA^DI-9 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Nintendo Switch/RightXPositive.png b/Content/Sprites/Controls/Nintendo Switch/RightXPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..43814dcf993569961eeb7bd666b8b3a68c3fdd8d GIT binary patch literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G$J^h}?_V!p&wu{C{(gq;m3I9M3{0|~E{-7)hu==W z*|*w&$01W;x9pGq>-VbeKG?YE;#H5uzgBv_4YrP(cgo{-816qx2QLS|M~lO!NvK;47;_QB<3F! zxmuQfRiX3!`wwsLzY%3GsBTE;QlGPDlG+u2mW1-DwULX@m)?|Z@3THSn>pbmSJC2z zL-(@Sf^2s%E6h7!&9HecWA^I2V20KJMy>FfsttFXBEILa=5Px+oZ$PVtdJBPUfw<9 zBiD`c4dH7WTHk!@E?`+B!;m7+#K^$TaYr%h)8bM^i-shI;M>8n4r}g67G%Cr%E)Ai z@n>+1J+WI&G_o||?OV+Uu5Ce#C)mD*ZoLugkaN^V%tKZ|bKklN{H-FdbL7|L=sQWO zZrU2e?qNGecJ{-Z_xXBa6JPCKa5Pb^wP>XR9|NDq^nIqGD>XUZMmcv(lt^2!=a-x` zC(}${mV{SNjkoDv7b}q4;%Q*9&f?1MgC%mW-`+71X1~<;h+&!cJn@#s+OR#+vAG_X z&fh(^q-*AB(Zt=N@7Jv>7k~Grd3WW)8`;&r@6Wf`$S-!UMo`}VbH#z?@<;EPZxr+J zGsHMD+EwN}))ZW9X;`(^+BEtPvII(k{DSlC{p0)Zua}>{zy3V`dwqs4Cl6d@U|=%$ba4!cIQ(|{ z%f1!`o`%4k>mUA|UpCQMBSbcR^Ua)1e+^GI{MA`H{mEBfMSGqPLAv)DE5w^V&u7-* z4xI5~LiA zjp_r>&hgxvn75lb<$B`9?e40N{5UqOvXEu|uxI%j%LOfcA}`M`S{igtQ}t_>H4Bfn z(aYVY%NH{HJ$e05!9(Hk&&wZI@7z1%YeCBq#_UV?UtVGLskpN_Gy5n*=IKtuj^hnt z>-MFwyy$us`@uDGTA5rN?^TY5sq7vN3=_nc>}fdLz#^uZpnkwxHv4O5Dbs~X-=rAI zRwspiRnY!^dzr9_TmD6gEHF^t z)*Z5)p^M?#HaC67-TWJ}-}ou$)oySUKDFwE<29ZeevCrjnm2h#UD>k6mC@3@ukXsE z1K(w})K#QBRNZx4i!V;pGk)f9$}%SFVUq}pa#jB+&IvY`qkg6>_+^;>WSaao&I$h4 zu3GzN`&haj2`Gmn?c9J~wlQ zc~!#;z4JK@4}V7&K3cQ2vfyveYo$4j4WFK$y}G+V+xfZNt=*yJznqKbvGdffUH{%) zrarOdQ$BB`^x>;FzkQq0&MbGPb3ebs-xYEU8yc*Beo(kxc|W$X-Yh4YH*40#Z$G~u o3Oe1s`1JeQZ-1Hpu|44KwRzK(dnw~5FnKX}y85}Sb4q9e0MEtPvII(k{DSTC15V3`RLxo&wd7&oo^9Um~YZ`y#9MX5$@2$3R~Omzx`o%Q3uBsov>urh%nS zdch-}imh+jWNVmYR8N<%Yp6bXWgfff>kNi%8X0a5hqkTKbGyY^u-0nNRwkG4Uqinr zGU{_ZD9>>^QtjEWbj}T?OnW9irUSRPKNc(a*}$c|$>Hv=hOb&v)@!Lp1~=$3reB}J zu)%yqW~et)Q7?<}Q^$>p=1nmZQk14jan4%fdOjfaOy`vB9b0n!OhjI8a6iv^pvbz_ zDLpAeEx=Y$e*@qvl457QiS6_Tq!`w4@CF7oG{&0nY zDHlw4&9SoYE0;K5%63%hn*-nTpRJ3s=d5=8d8zoz|G&cQ!nc01`_GAD?+rN5{q4t0 zb}NGwvp45&>Svg#aO>xK#1!1K vF8@^7egF4wIJo+{{O$Mlm-!3y|1-P~d^JD2^7bZRDr4|;^>bP0l+XkKSlwbp literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/Down.png b/Content/Sprites/Controls/PlayStation/ButtonDown.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/Down.png rename to Content/Sprites/Controls/PlayStation/ButtonDown.png diff --git a/Content/Sprites/Controls/PlayStation/Left.png b/Content/Sprites/Controls/PlayStation/ButtonLeft.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/Left.png rename to Content/Sprites/Controls/PlayStation/ButtonLeft.png diff --git a/Content/Sprites/Controls/PlayStation/Right.png b/Content/Sprites/Controls/PlayStation/ButtonRight.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/Right.png rename to Content/Sprites/Controls/PlayStation/ButtonRight.png diff --git a/Content/Sprites/Controls/PlayStation/Up.png b/Content/Sprites/Controls/PlayStation/ButtonUp.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/Up.png rename to Content/Sprites/Controls/PlayStation/ButtonUp.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_left.png b/Content/Sprites/Controls/PlayStation/playstation_stick_l_left.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa8948d56c20e95b14280a7160fda480e8fa27e GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEhM?_V!pf1Y3e{eA}9zlXLlFfcKAx;TbJ9DY0f zb>A8Vo(5UR#%%_B{$G~cxzgdN;q1x2W|!m7dDy>@UH+Xv^%v7W69<2{ojRv{en~ob zf9P$vBF~)mG&1nBJ44aGAep;N1zS_UF7grEI_3YHF7t+@-9lHrM2_l6Fd67Zt9(1Q z$me;11;dGwGfNEK7n%eIc|Bv~^SQyXV5f(M;9+jrgYJPxUc2e&Y^ESjiP$oRo1 ze}hTG8hMi~@{D`VX)oh)IK43O7{lbvrMAo`=9wh$G~_I?X1+6(jhW;B#dq&{Ht;jP z7gIQwe^=sx#R12RO%oW`=p>Xsc29g$TOe@ntKhesmHY}44r(F3os0(pwPOvBrmVTN ziG7J%!!*{GBBP}nH*L*Gt;(&L?Qte$!(O{52c7o4(&TOMdMxhiUzEBcVU_en=0jYW zZ|$rybS+cw8eZGf+}9UWy5vWf+vXit-gakZ-kSEXc`?z_*YI_5HG@L+YzOn{xv!WuUf6uwYL?dOgAYExZ>_u= jedf>Kv|mieKJhR9^X8vO-9K4iI$`j1^>bP0l+XkK?3PHk literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_press.png b/Content/Sprites/Controls/PlayStation/playstation_stick_l_press.png new file mode 100644 index 0000000000000000000000000000000000000000..9f998e6f5e412c4418e8a96ea8508a96764fe1e7 GIT binary patch literal 712 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@S*Z0TU-`_7kzy7>F|9gf%FIUWCU|>@5ba4!cIQ(|{ z$)Xko0f*4Ag^vIJXB+2iS{%Z+((BUn!YOr5@AIykr~W?5;N+_|MTeQ|FMpzB!IXw% z$ptCv^snv`oa*;0N>?f{a`r*r3khpi#WA1AJTp^p&c40wag0A+ZV@{8lDmGgJ@dC6 z`Q8V7VV$18W& zVk6_aZ3R#HFSC6Rc(B>0kI^VKSNuV-%GN1T54aosPvj}I$^@>M-CcEl(>h+2`G*&Z zP4aV`uyBcUWOROm{v8uFt7%jJCkF@a%YDoy5S6&9ydlXabKB=t@0N9Kx+>dvC`XPl zs=S@0LvYE(2>F*f^JXp5$|^Qp>-sEoVeqxdcl*v+J}^kN*~&1_(*IEtyq^ILdT!8=l9hgsQ$^+CH3Y( Uz_i5R>FVdQ&MBb@0K0ot5dZ)H literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_right.png b/Content/Sprites/Controls/PlayStation/playstation_stick_l_right.png new file mode 100644 index 0000000000000000000000000000000000000000..53df6eb804d5ac17506fb5ea7184daa93bd3bc1c GIT binary patch literal 675 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEI}?_V!pf1Y3e{eA|q8BZ@VFfji2ba4!cIQ(|{ z>%KJ#JPopedAcut+rOQ-x`EYn_GDkP%kj$F?r+($#Uj^!%1iDaml-TI6Bl!so-AkB z`D(A=-c!dLBHt|O_$kQn_MT|>c7_LPnfgwyg5FWaGI zWu1$>=lSR(AOHWfvziP$7N@!jvN1ayznOH`k8w&8N5RxzS}9h zNm#+2!BEHE$MD3C$)b0M7^mccg7B={pLW}t?Lc`SEq0^obx}qkL|}| ziQ7!99Y@1Oih@1%or_6UJ-^6vZHjGw5FgZf4ciOy6{iaEXfHi}` zRZUxy%2k@l=Qp+;b64tY`=oh3!v8|Z-jz%zY-)ae%gm8H)x24_WZP-;uZs+0Z~xkv z-_*hETDnN1L1)tP$fF00w56&R^RE69e0k@pq@*2-Zsxll&e+quck}jwV&}l*>aX|L zTl|yJ+4A#{T>R&Z1Krh+-ZP)5-J;JB;wV{DeDj#MQdRAu@@V$ZuO@3B{QZ7t&TaPj h`|tb2ABgzJxZ~EFe_EtPvII(k{DSTC{p0)Zua}>{zy3VG{(FWOF>8An7?^}TT^vIq4!@oL zvadyfry)>pr`4YSm)9w2P3c-Z`E1JMxBW9UzHOcox9NKOp*l$cwZnFdEFFS}iW{aE zioKlAw5Qv1PCeU=FTY#(60XnZ^k)dxN!i7}VWUtryTFw{!V}MI52@gOkbc`VwQ*kg zqxFn3=Xl~K99Yk=`t^zz(TgS(r1O4Iv!2VeqV(*KVh6stp3Aw@)RP%{X1;mB?IIht z=3;xHuk(sID~{cDG;MtNclq1=XVV@XyDKQnD>3<>lemCp;OANX-pZ^V-U|u^9yeUu zu$PVbOU2QPoI8dbjuIyIWHiOAHBc!~)>rjF5)Vqx;9(Qv14~RJ`ocsDcY30gA zSsQn6$Z-FX<>n`{>hjDBdjgqC3M=};djjThz1VzBY}MoGr_us9ajhu07sGtS+i|Y+ z*7E#yUjmEs*m-VW-+o=$?}bF-p=f8Z>05R^$?vZ;d2npbk6MP8?#0XwtXEF9v%h{` zTgdY8-iEiip_k`;{k~uPMwp$$hWEAK{xbh#d%)hL@wWJ*z^duMq{HCp>gTe~DWM4f DzG literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_down.png b/Content/Sprites/Controls/PlayStation/playstation_stick_r_down.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6e24ae04e8de1198f5c4b6b69dd609a66ffb3f GIT binary patch literal 738 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC15V3`RLxo&wd7&oo^9Um~YZ`y#9MX5$@2$3R~Omzx`o%Q3uBsov>urh%nS zdch-}imh+jWNVmYR8N<%Yp6bXWgfff>kNi%8X0a5hqkTKbGyY^u-0nNRwkG4Uqinr zGU{_ZD9>>^QtjEWbj}T?OnW9irUSRPKNc(a*}$c|$>Hv=hOb&v)@!Lp1~=$3reB}J zu)%yqW~et)Q7?<}Q^$>p=1nmZQk14jan4%fdOjfaOy`vB9b0n!OhjI8a6iv^pvbz_ zDLpAeEx=Y$e*@qvl457QiS6_Tq!`w4@CF7oG{&0nY zDHlw4&9SoYE0;K5%63%hn*-nTpRJ3s=d5=8d8zoz|G&cQ!nc01`_GAD?+rN5{q4t0 zb}NGwvp45&>Svg#aO>xK#1!1K vF8@^7egF4wIJo+{{O$Mlm-!3y|1-P~d^JD2^7bZRDr4|;^>bP0l+XkKSlwbp literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_left.png b/Content/Sprites/Controls/PlayStation/playstation_stick_r_left.png new file mode 100644 index 0000000000000000000000000000000000000000..86418acd3a0397503d8cccd28cee7b1313253741 GIT binary patch literal 702 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEhM@0VX+&wu{C{(go%1yM^G7?`9yT^vIq4!@m# zvu}-pfJ3Omf`~8w_kTOJZ|aS-BIA=wUZ32yl6mXnqCWxC^dI;$|4?e}ReEyhKBGlw zx_Z~Ae#Y4rfr7W)8IsROZ+s@mu-k9-%n5-k-tWKg@i(OGRygaWa8k#V)gj`TM$a)O z-sc+(7%vo@S+L=$#VJ({*3Tk7K07$Nk|zorX%FXZxyK%6?JjNV=CFI|vH6Kd8F%k0 zd+1lcpYzdHZ^Z`|) z{fi2juQ4v#7yR%!hlN+!=N(Cz3~i#KHyM&RXa4a!mUB0|;o{V;SB!R*-l6Wwxx5?p zdj0M;&F`<6C$(TXgKxI*o+N&SulvP{lQ@?gWoW&SmdF`exqWfNn`5&L!o&*Bu(uYN zxOY^?TCK5UaAcTx!DK1R0@hVtYk7`7nY_{Sv=;v&-i3k?9_(O z2RFS8jQ@CR@oU}#OOE;PnwN4ppz%R~5z`&6Ri$#WY5tZ=b0xDcIxbyoB75?GYT9Ot zt8crun5?_}VdwSp$=%7mQ@_2FO53(-H`AjdLGDZ&4|gonOkh}Hv)<#dL1~D|ercU$ zoc3mO-ObAnhtBQ4)Vk7JWrP2(y9IK=k>|cXt>6FXhgHH3D`olk&jkm%s~^2*4zRx^ z&ahZs_{GCbxor*xpWkic+jKHZ_2J*|hqgTz+g!VU=DvoVf0$hv-Y8Fexob8s1u=NK L`njxgN@xNA^DI-9 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_right.png b/Content/Sprites/Controls/PlayStation/playstation_stick_r_right.png new file mode 100644 index 0000000000000000000000000000000000000000..43814dcf993569961eeb7bd666b8b3a68c3fdd8d GIT binary patch literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G$J^h}?_V!p&wu{C{(gq;m3I9M3{0|~E{-7)hu==W z*|*w&$01W;x9pGq>-VbeKG?YE;#H5uzgBv_4YrP(cgo{-816qx2QLS|M~lO!NvK;47;_QB<3F! zxmuQfRiX3!`wwsLzY%3GsBTE;QlGPDlG+u2mW1-DwULX@m)?|Z@3THSn>pbmSJC2z zL-(@Sf^2s%E6h7!&9HecWA^I2V20KJMy>FfsttFXBEILa=5Px+oZ$PVtdJBPUfw<9 zBiD`c4dH7WTHk!@E?`+B!;m7+#K^$TaYr%h)8bM^i-shI;M>8n4r}g67G%Cr%E)Ai z@n>+1J+WI&G_o||?OV+Uu5Ce#C)mD*ZoLugkaN^V%tKZ|bKklN{H-FdbL7|L=sQWO zZrU2e?qNGecJ{-Z_xXBa6JPCKa5Pb^wP>XR9|NDq^nIqGD>XUZMmcv(lt^2!=a-x` zC(}${mV{SNjkoDv7b}q4;%Q*9&f?1MgC%mW-`+71X1~<;h+&!cJn@#s+OR#+vAG_X z&fh(^q-*AB(Zt=N@7Jv>7k~Grd3WW)8`;&r@6Wf`$S-!UMo`}VbH#z?@<;EPZxr+J zGsHMD+EwN}))ZW9X;`(^+BEtPvII(k{DSlC{p0)Zua}>{zy3V`dwqs4Cl6d@U|=%$ba4!cIQ(|{ z%f1!`o`%4k>mUA|UpCQMBSbcR^Ua)1e+^GI{MA`H{mEBfMSGqPLAv)DE5w^V&u7-* z4xI5~LiA zjp_r>&hgxvn75lb<$B`9?e40N{5UqOvXEu|uxI%j%LOfcA}`M`S{igtQ}t_>H4Bfn z(aYVY%NH{HJ$e05!9(Hk&&wZI@7z1%YeCBq#_UV?UtVGLskpN_Gy5n*=IKtuj^hnt z>-MFwyy$us`@uDGTA5rN?^TY5sq7vN3=_nc>}fdLz#^uZpnkwxHv4O5Dbs~X-=rAI zRwspiRnY!^dzr9_TmD6gEHF^t z)*Z5)p^M?#HaC67-TWJ}-}ou$)oySUKDFwE<29ZeevCrjnm2h#UD>k6mC@3@ukXsE z1K(w})K#QBRNZx4i!V;pGk)f9$}%SFVUq}pa#jB+&IvY`qkg6>_+^;>WSaao&I$h4 zu3GzN`&haj2`Gmn?c9J~wlQ zc~!#;z4JK@4}V7&K3cQ2vfyveYo$4j4WFK$y}G+V+xfZNt=*yJznqKbvGdffUH{%) zrarOdQ$BB`^x>;FzkQq0&MbGPb3ebs-xYEU8yc*Beo(kxc|W$X-Yh4YH*40#Z$G~u o3Oe1s`1JeQZ-1Hpu|44KwRzK(dnw~5FnKX}y85}Sb4q9e0MEtPvII(k{DS@G+sEhM?_V!pf1Y3e{eA}9zlXLlFfcKAx;TbJ9DY0f zb>A8Vo(5UR#%%_B{$G~cxzgdN;q1x2W|!m7dDy>@UH+Xv^%v7W69<2{ojRv{en~ob zf9P$vBF~)mG&1nBJ44aGAep;N1zS_UF7grEI_3YHF7t+@-9lHrM2_l6Fd67Zt9(1Q z$me;11;dGwGfNEK7n%eIc|Bv~^SQyXV5f(M;9+jrgYJPxUc2e&Y^ESjiP$oRo1 ze}hTG8hMi~@{D`VX)oh)IK43O7{lbvrMAo`=9wh$G~_I?X1+6(jhW;B#dq&{Ht;jP z7gIQwe^=sx#R12RO%oW`=p>Xsc29g$TOe@ntKhesmHY}44r(F3os0(pwPOvBrmVTN ziG7J%!!*{GBBP}nH*L*Gt;(&L?Qte$!(O{52c7o4(&TOMdMxhiUzEBcVU_en=0jYW zZ|$rybS+cw8eZGf+}9UWy5vWf+vXit-gakZ-kSEXc`?z_*YI_5HG@L+YzOn{xv!WuUf6uwYL?dOgAYExZ>_u= jedf>Kv|mieKJhR9^X8vO-9K4iI$`j1^>bP0l+XkK?3PHk literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/LeftXPositive.png b/Content/Sprites/Controls/Xbox Series/LeftXPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..53df6eb804d5ac17506fb5ea7184daa93bd3bc1c GIT binary patch literal 675 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G+sEI}?_V!pf1Y3e{eA|q8BZ@VFfji2ba4!cIQ(|{ z>%KJ#JPopedAcut+rOQ-x`EYn_GDkP%kj$F?r+($#Uj^!%1iDaml-TI6Bl!so-AkB z`D(A=-c!dLBHt|O_$kQn_MT|>c7_LPnfgwyg5FWaGI zWu1$>=lSR(AOHWfvziP$7N@!jvN1ayznOH`k8w&8N5RxzS}9h zNm#+2!BEHE$MD3C$)b0M7^mccg7B={pLW}t?Lc`SEq0^obx}qkL|}| ziQ7!99Y@1Oih@1%or_6UJ-^6vZHjGw5FgZf4ciOy6{iaEXfHi}` zRZUxy%2k@l=Qp+;b64tY`=oh3!v8|Z-jz%zY-)ae%gm8H)x24_WZP-;uZs+0Z~xkv z-_*hETDnN1L1)tP$fF00w56&R^RE69e0k@pq@*2-Zsxll&e+quck}jwV&}l*>aX|L zTl|yJ+4A#{T>R&Z1Krh+-ZP)5-J;JB;wV{DeDj#MQdRAu@@V$ZuO@3B{QZ7t&TaPj h`|tb2ABgzJxZ~EFe_EtPvII(k{DSTC{p0)Zua}>{zy3VG{(FWOF>8An7?^}TT^vIq4!@oL zvadyfry)>pr`4YSm)9w2P3c-Z`E1JMxBW9UzHOcox9NKOp*l$cwZnFdEFFS}iW{aE zioKlAw5Qv1PCeU=FTY#(60XnZ^k)dxN!i7}VWUtryTFw{!V}MI52@gOkbc`VwQ*kg zqxFn3=Xl~K99Yk=`t^zz(TgS(r1O4Iv!2VeqV(*KVh6stp3Aw@)RP%{X1;mB?IIht z=3;xHuk(sID~{cDG;MtNclq1=XVV@XyDKQnD>3<>lemCp;OANX-pZ^V-U|u^9yeUu zu$PVbOU2QPoI8dbjuIyIWHiOAHBc!~)>rjF5)Vqx;9(Qv14~RJ`ocsDcY30gA zSsQn6$Z-FX<>n`{>hjDBdjgqC3M=};djjThz1VzBY}MoGr_us9ajhu07sGtS+i|Y+ z*7E#yUjmEs*m-VW-+o=$?}bF-p=f8Z>05R^$?vZ;d2npbk6MP8?#0XwtXEF9v%h{` zTgdY8-iEiip_k`;{k~uPMwp$$hWEAK{xbh#d%)hL@wWJ*z^duMq{HCp>gTe~DWM4f DzG literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/LeftYPositive.png b/Content/Sprites/Controls/Xbox Series/LeftYPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..184733d5aa3855450ae71077d8f6ff3ce0aecd50 GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSTC`{VuB-4R0hyXP6}`o%ls3Yz_y zm&7w(;=9J^amHvX+lm=$moVR0u^^7Q#N<+0L-th@b+(4r=EC;X2cFA5*vxXn^ne}H z2`PtZ4X4@9C&v6}Fw?3zb#x8GT&BKNn!F5F;co>5vRJ+N2sa&7DQz3Su z<2uhKCHc8?dd(giHGKaoaensC0#_z&VX4KZ-Jak6*!S4-tit?5e1{+2*&h(nRcxdY zQ?=z^ynUgUlimMEos(ZF2w$pnjJN+Bz}{6F{B^?g1_yzkf37#g7`FcxOVDQ0bUWnD z@aw;p_JhMLRTVkX7t6Lp&Y!XOn&Z`#Yaaam&n>;LO7>>m|Cx0STmLZEJHGDcj%aEE PrXvPVS3j3^P6EtPvII(k{DS@G+sEhM@0VX+&wu{C{(go%1yM^G7?`9yT^vIq4!@m# zvu}-pfJ3Omf`~8w_kTOJZ|aS-BIA=wUZ32yl6mXnqCWxC^dI;$|4?e}ReEyhKBGlw zx_Z~Ae#Y4rfr7W)8IsROZ+s@mu-k9-%n5-k-tWKg@i(OGRygaWa8k#V)gj`TM$a)O z-sc+(7%vo@S+L=$#VJ({*3Tk7K07$Nk|zorX%FXZxyK%6?JjNV=CFI|vH6Kd8F%k0 zd+1lcpYzdHZ^Z`|) z{fi2juQ4v#7yR%!hlN+!=N(Cz3~i#KHyM&RXa4a!mUB0|;o{V;SB!R*-l6Wwxx5?p zdj0M;&F`<6C$(TXgKxI*o+N&SulvP{lQ@?gWoW&SmdF`exqWfNn`5&L!o&*Bu(uYN zxOY^?TCK5UaAcTx!DK1R0@hVtYk7`7nY_{Sv=;v&-i3k?9_(O z2RFS8jQ@CR@oU}#OOE;PnwN4ppz%R~5z`&6Ri$#WY5tZ=b0xDcIxbyoB75?GYT9Ot zt8crun5?_}VdwSp$=%7mQ@_2FO53(-H`AjdLGDZ&4|gonOkh}Hv)<#dL1~D|ercU$ zoc3mO-ObAnhtBQ4)Vk7JWrP2(y9IK=k>|cXt>6FXhgHH3D`olk&jkm%s~^2*4zRx^ z&ahZs_{GCbxor*xpWkic+jKHZ_2J*|hqgTz+g!VU=DvoVf0$hv-Y8Fexob8s1u=NK L`njxgN@xNA^DI-9 literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/Xbox Series/RightXPositive.png b/Content/Sprites/Controls/Xbox Series/RightXPositive.png new file mode 100644 index 0000000000000000000000000000000000000000..43814dcf993569961eeb7bd666b8b3a68c3fdd8d GIT binary patch literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DS@G$J^h}?_V!p&wu{C{(gq;m3I9M3{0|~E{-7)hu==W z*|*w&$01W;x9pGq>-VbeKG?YE;#H5uzgBv_4YrP(cgo{-816qx2QLS|M~lO!NvK;47;_QB<3F! zxmuQfRiX3!`wwsLzY%3GsBTE;QlGPDlG+u2mW1-DwULX@m)?|Z@3THSn>pbmSJC2z zL-(@Sf^2s%E6h7!&9HecWA^I2V20KJMy>FfsttFXBEILa=5Px+oZ$PVtdJBPUfw<9 zBiD`c4dH7WTHk!@E?`+B!;m7+#K^$TaYr%h)8bM^i-shI;M>8n4r}g67G%Cr%E)Ai z@n>+1J+WI&G_o||?OV+Uu5Ce#C)mD*ZoLugkaN^V%tKZ|bKklN{H-FdbL7|L=sQWO zZrU2e?qNGecJ{-Z_xXBa6JPCKa5Pb^wP>XR9|NDq^nIqGD>XUZMmcv(lt^2!=a-x` zC(}${mV{SNjkoDv7b}q4;%Q*9&f?1MgC%mW-`+71X1~<;h+&!cJn@#s+OR#+vAG_X z&fh(^q-*AB(Zt=N@7Jv>7k~Grd3WW)8`;&r@6Wf`$S-!UMo`}VbH#z?@<;EPZxr+J zGsHMD+EwN}))ZW9X;`(^+BEtPvII(k{DSlC{p0)Zua}>{zy3V`dwqs4Cl6d@U|=%$ba4!cIQ(|{ z%f1!`o`%4k>mUA|UpCQMBSbcR^Ua)1e+^GI{MA`H{mEBfMSGqPLAv)DE5w^V&u7-* z4xI5~LiA zjp_r>&hgxvn75lb<$B`9?e40N{5UqOvXEu|uxI%j%LOfcA}`M`S{igtQ}t_>H4Bfn z(aYVY%NH{HJ$e05!9(Hk&&wZI@7z1%YeCBq#_UV?UtVGLskpN_Gy5n*=IKtuj^hnt z>-MFwyy$us`@uDGTA5rN?^TY5sq7vN3=_nc>}fdLz#^uZpnkwxHv4O5Dbs~X-=rAI zRwspiRnY!^dzr9_TmD6gEHF^t z)*Z5)p^M?#HaC67-TWJ}-}ou$)oySUKDFwE<29ZeevCrjnm2h#UD>k6mC@3@ukXsE z1K(w})K#QBRNZx4i!V;pGk)f9$}%SFVUq}pa#jB+&IvY`qkg6>_+^;>WSaao&I$h4 zu3GzN`&haj2`Gmn?c9J~wlQ zc~!#;z4JK@4}V7&K3cQ2vfyveYo$4j4WFK$y}G+V+xfZNt=*yJznqKbvGdffUH{%) zrarOdQ$BB`^x>;FzkQq0&MbGPb3ebs-xYEU8yc*Beo(kxc|W$X-Yh4YH*40#Z$G~u o3Oe1s`1JeQZ-1Hpu|44KwRzK(dnw~5FnKX}y85}Sb4q9e0MEtPvII(k{DSTC15V3`RLxo&wd7&oo^9Um~YZ`y#9MX5$@2$3R~Omzx`o%Q3uBsov>urh%nS zdch-}imh+jWNVmYR8N<%Yp6bXWgfff>kNi%8X0a5hqkTKbGyY^u-0nNRwkG4Uqinr zGU{_ZD9>>^QtjEWbj}T?OnW9irUSRPKNc(a*}$c|$>Hv=hOb&v)@!Lp1~=$3reB}J zu)%yqW~et)Q7?<}Q^$>p=1nmZQk14jan4%fdOjfaOy`vB9b0n!OhjI8a6iv^pvbz_ zDLpAeEx=Y$e*@qvl457QiS6_Tq!`w4@CF7oG{&0nY zDHlw4&9SoYE0;K5%63%hn*-nTpRJ3s=d5=8d8zoz|G&cQ!nc01`_GAD?+rN5{q4t0 zb}NGwvp45&>Svg#aO>xK#1!1K vF8@^7egF4wIJo+{{O$Mlm-!3y|1-P~d^JD2^7bZRDr4|;^>bP0l+XkKSlwbp literal 0 HcmV?d00001 diff --git a/Content/Text/English.json b/Content/Text/English.json index 1013d496..32bdaf8d 100644 --- a/Content/Text/English.json +++ b/Content/Text/English.json @@ -14,6 +14,9 @@ "Create": "Create", "Delete": "Delete", "Copy": "Copy", + "Bind": "Bind", + "Reset": "Reset", + "Clear": "Clear", "RestartLevel": "Clear Save & Restart Level", "PauseTitle": "Paused", "PauseResume": "Resume", @@ -51,6 +54,35 @@ "OptionsToggleOff": "OFF", "OptionsYes": "Yes", "OptionsNo": "No", + + "KeyboardConfig": "Keyboard Config", + "KeyboardConfig.desc": "Rebind Keyboard/Mouse Controls", + "ControllerConfig": "Controller Config", + "ControllerConfig.desc": "Rebind Controller Controls", + "ControlsHeaderGame": "Game", + "ControlsHeaderMenu": "Menu", + "ControlsHeaderFuji": "Fuji", + "ControlsResetToDefault": "Reset To Default", + "Jump": "Jump", + "Dash": "Dash", + "Climb": "Climb", + "Pause": "Pause", + "MoveDown": "Move Down", + "MoveUp": "Move Up", + "MoveRight": "Move Right", + "MoveLeft": "Move Left", + "CameraDown": "Camera Down", + "CameraUp": "Camera Up", + "CameraRight": "Camera Right", + "CameraLeft": "Camera Left", + "CreateFile": "Create File", + "CopyFile": "Create File", + "DeleteFile": "Delete File", + "MenuDown": "Menu Down", + "MenuUp": "Menu Up", + "MenuRight": "Menu Right", + "MenuLeft": "Menu Left", + "Skin": "Skin", "Skin.desc": "Choose a Skin to Wear", diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index c9a774eb..15622599 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -72,62 +72,170 @@ internal static void LoadControlsByFileName(string file_name) } [DisallowHooks] - internal static void ResetBindings() + internal static void AddBinding(VirtualButton virtualButton, Keys key) { - Instance.Actions.Clear(); - Instance.Sticks.Clear(); - - foreach (var action in ControlsConfig_V01.Defaults.Actions) + var config = GetButtonBindings(Instance, virtualButton); + if (config != null && !config.Any(a => a.Key == key)) { - Instance.Actions[action.Key] = action.Value; + config.Add(new(key)); + config.Last().BindTo(virtualButton); } - foreach (var stick in ControlsConfig_V01.Defaults.Sticks) + } + + [DisallowHooks] + internal static void AddBinding(VirtualButton virtualButton, Buttons button) + { + var config = GetButtonBindings(Instance, virtualButton); + if (config != null && !config.Any(a => a.Button == button)) { - Instance.Sticks[stick.Key] = stick.Value; + config.Add(new(button)); + config.Last().BindTo(virtualButton); } } [DisallowHooks] - internal static void AddBinding(VirtualButton button, Keys key) + internal static void AddBinding(VirtualButton virtualButton, MouseButtons mouseButton) { - Instance.Actions[button.Name].Add(new(key)); - Instance.Actions[button.Name].Last().BindTo(button); + var config = GetButtonBindings(Instance, virtualButton); + if (config != null && !config.Any(a => a.MouseButton == mouseButton)) + { + config.Add(new(mouseButton)); + config.Last().BindTo(virtualButton); + } } [DisallowHooks] - internal static void AddBinding(VirtualButton button, Buttons key) + internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inverted) { - Instance.Actions[button.Name].Add(new(key)); - Instance.Actions[button.Name].Last().BindTo(button); + var config = GetButtonBindings(Instance, virtualButton); + if (config != null && !config.Any(a => a.Axis == axis)) + { + config.Add(new(axis, 0.5f, inverted)); + config.Last().BindTo(virtualButton); + } } [DisallowHooks] - internal static void AddBinding(VirtualButton button, MouseButtons key) + internal static void ClearBinding(VirtualButton virtualButton, bool forController) { - Instance.Actions[button.Name].Add(new(key)); - Instance.Actions[button.Name].Last().BindTo(button); + var config = GetButtonBindings(Instance, virtualButton); + if (config != null) + { + virtualButton.Clear(); + // Remove all bindings for this control type + config.RemoveAll(x => x.IsForController() == forController); + + // Rebind remaining bindings. + // Needed to rebind other control type, i.e. to not lose controller binds when clearing for keyboard. + foreach (var binding in config) + { + binding.BindTo(virtualButton); + } + } } [DisallowHooks] - internal static void AddBinding(VirtualButton button, Axes key, bool inverted) + internal static void ResetBinding(VirtualButton virtualButton, bool forController) { - Instance.Actions[button.Name].Add(new(key, 0.5f, inverted)); - Instance.Actions[button.Name].Last().BindTo(button); + var bindings = GetButtonBindings(Instance, virtualButton); + var defaultBindings = GetButtonBindings(ControlsConfig_V01.Defaults, virtualButton); + if (bindings != null && defaultBindings != null) + { + virtualButton.Clear(); + + // Remove all bindings for this control type + bindings.RemoveAll(x => x.IsForController() == forController); + + // Readd all default bindings for this control type + foreach (var binding in defaultBindings) + { + if (binding.IsForController() == forController) + { + bindings.Add(binding); + } + } + + // Rebind bindings to the virtual button. + foreach (var binding in bindings) + { + binding.BindTo(virtualButton); + } + } } [DisallowHooks] - internal static void ClearBinding(VirtualButton button) + internal static void ResetAllBindings(bool forController) { - button.Clear(); - Instance.Actions[button.Name].Clear(); + // Remove all bindings for this control type + foreach (var action in Instance.Actions) + { + Instance.Actions[action.Key].RemoveAll(x => x.IsForController() == forController); + } + foreach (var action in Instance.Sticks) + { + Instance.Sticks[action.Key].Up.RemoveAll(x => x.IsForController() == forController); + Instance.Sticks[action.Key].Down.RemoveAll(x => x.IsForController() == forController); + Instance.Sticks[action.Key].Left.RemoveAll(x => x.IsForController() == forController); + Instance.Sticks[action.Key].Right.RemoveAll(x => x.IsForController() == forController); + } + + // Readd default bindings for this control type. + foreach (var action in ControlsConfig_V01.Defaults.Actions) + { + foreach (var binding in action.Value) + { + if (binding.IsForController() == forController) + { + Instance.Actions[action.Key].Add(binding); + } + } + } + foreach (var stick in ControlsConfig_V01.Defaults.Sticks) + { + Instance.Sticks[stick.Key].Up.AddRange(stick.Value.Up.Where(b => b.IsForController() == forController)); + Instance.Sticks[stick.Key].Down.AddRange(stick.Value.Down.Where(b => b.IsForController() == forController)); + Instance.Sticks[stick.Key].Left.AddRange(stick.Value.Left.Where(b => b.IsForController() == forController)); + Instance.Sticks[stick.Key].Right.AddRange(stick.Value.Right.Where(b => b.IsForController() == forController)); + } + + // Reload bindings + LoadConfig(Instance); } - [DisallowHooks] - internal static void ResetBinding(VirtualButton button) + private static List? GetButtonBindings(ControlsConfig_V01 config, VirtualButton virtualButton) { - button.Clear(); - Instance.Actions[button.Name].Clear(); - Instance.Actions[button.Name].AddRange(ControlsConfig_V01.Defaults.Actions[button.Name]); + string[] nameParts = virtualButton.Name.Split("/"); + + if (nameParts.Length == 3) + { + var stickConfig = config.Sticks[nameParts[0]]; + + if (stickConfig != null) + { + if (nameParts[1] == "Horizontal" && nameParts[2] == "Positive") + { + return stickConfig.Right; + } + else if (nameParts[1] == "Horizontal" && nameParts[2] == "Negative") + { + return stickConfig.Left; + } + else if (nameParts[1] == "Vertical" && nameParts[2] == "Negative") + { + return stickConfig.Up; + } + else if (nameParts[1] == "Vertical" && nameParts[2] == "Positive") + { + return stickConfig.Down; + } + } + } + else if (config.Actions.ContainsKey(virtualButton.Name)) + { + return config.Actions[virtualButton.Name]; + } + + return null; } [DisallowHooks] @@ -195,7 +303,6 @@ static List FindAction(ControlsConfig_V01? config, string it.BindTo(DeleteFile); foreach (var it in FindAction(config, "CreateFile")) it.BindTo(CreateFile); - } public static void Clear() @@ -269,38 +376,49 @@ public static string GetPromptLocation(VirtualButton button) return lookup; } - public static List GetPrompts(VirtualButton button) + public static List GetPrompts(VirtualButton button, bool isForController) { List subtextures = []; - foreach (var location in GetPromptLocations(button)) + foreach (var location in GetPromptLocations(button, isForController)) subtextures.Add(Assets.Subtextures.GetValueOrDefault(location)); return subtextures; } - private static List GetPromptLocations(VirtualButton button) + private static List GetPromptLocations(VirtualButton button, bool isForController) { List locations = []; var gamepad = Input.Controllers[0]; var deviceTypeName = gamepad.Connected ? GetControllerName(gamepad.Gamepad) : "PC"; - foreach (var binding in Instance.Actions[button.Name]) + + var config = GetButtonBindings(Instance, button); + + if (config != null) { - string promptDeviceTypeName = "PC"; - var buttonName = binding.GetBindingName(); - if (binding.IsForController()) - promptDeviceTypeName = GetControllerName(gamepad.Gamepad); + foreach (var binding in config) + { + if (binding.IsForController() != isForController) + { + continue; + } - if (!prompts.TryGetValue(deviceTypeName, out var list)) - prompts[deviceTypeName] = list = []; + string promptDeviceTypeName = "PC"; + var buttonName = binding.GetBindingName(); + if (binding.IsForController()) + promptDeviceTypeName = GetControllerName(gamepad.Gamepad); - buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); + if (!prompts.TryGetValue(deviceTypeName, out var list)) + prompts[deviceTypeName] = list = []; - if (!list.TryGetValue(buttonName, out var lookup)) - list[buttonName] = lookup = $"Controls/{promptDeviceTypeName}/{buttonName}"; + buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); - if (Gamepads.Nintendo.Equals(binding.NotFor) || !Gamepads.Nintendo.Equals(binding.OnlyFor) || (binding.NotFor == null && binding.OnlyFor == null)) //only non switch prompts atm - locations.Add(lookup); + if (!list.TryGetValue(buttonName, out var lookup)) + list[buttonName] = lookup = $"Controls/{promptDeviceTypeName}/{buttonName}"; + if (Gamepads.Nintendo.Equals(binding.NotFor) || !Gamepads.Nintendo.Equals(binding.OnlyFor) || (binding.NotFor == null && binding.OnlyFor == null)) //only non switch prompts atm + locations.Add(lookup); + + } } return locations; diff --git a/Source/Data/PersistedData/ControlsConfigBinding.cs b/Source/Data/PersistedData/ControlsConfigBinding.cs index e4c1a9ad..fa935c25 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding.cs @@ -82,10 +82,10 @@ public enum FujiButtons RightStick = 8, LeftShoulder = 9, RightShoulder = 10, - Up = 11, - Down = 12, - Left = 13, - Right = 14 + ButtonUp = 11, + ButtonDown = 12, + ButtonLeft = 13, + ButtonRight = 14 } public enum FujiMouseButtons @@ -103,7 +103,7 @@ public string GetBindingName() if (Button != null) return ((FujiButtons)Button).ToString() ?? ""; if (Axis != null) - return Axis.ToString() ?? ""; + return Axis.ToString() + (AxisInverted ? "Negative" : "Positive"); if (MouseButton != null) return ((FujiMouseButtons)MouseButton).ToString() ?? ""; return ""; diff --git a/Source/Data/PersistedData/ControlsConfig_V01.cs b/Source/Data/PersistedData/ControlsConfig_V01.cs index dd54fa93..d6afcd89 100644 --- a/Source/Data/PersistedData/ControlsConfig_V01.cs +++ b/Source/Data/PersistedData/ControlsConfig_V01.cs @@ -45,8 +45,8 @@ public class ControlsConfig_V01 : PersistedData new(Buttons.South) { OnlyFor = Gamepads.Nintendo }, ], ["Pause"] = [ - new(Keys.Enter), new(Keys.Escape), + new(Keys.Enter), new(Buttons.Start), new(Buttons.Select), new(Buttons.Back) diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index 7729465e..1e0d4eb8 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -41,19 +41,19 @@ public Item Describe(Loc.Localized description) } } - public class InputBind(string label, VirtualButton button, Menu? rootMenu) : Item + public class InputBind(Loc.Localized locString, VirtualButton button, Menu? rootMenu, bool isForController) : Item { - public override string Label { get; } = label; + public override Loc.Localized? LocString => locString; public override bool Pressed() { Audio.Play(Sfx.ui_select); - rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button)); + rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button, isForController)); return true; } - public List GetTextures() + public virtual List GetTextures() { - return Controls.GetPrompts(button); + return Controls.GetPrompts(button, isForController); } public VirtualButton GetButton() diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index 8941afc4..1cbb6cf2 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -6,61 +6,65 @@ public class BindControlMenu : Menu private const float waitBeforeClosingTime = 5; private VirtualButton button; + private bool isForController; - public BindControlMenu(Menu? rootMenu, VirtualButton button) + public BindControlMenu(Menu? rootMenu, VirtualButton button, bool isForController) { RootMenu = rootMenu; this.button = button; + this.isForController = isForController; Title = Loc.Str($"Press Button to bind {button.Name}"); inMenuTime = 0; } protected override void HandleInput() { - Keys? pressed = Input.Keyboard.FirstPressed(); - if (pressed != null) + if (!isForController) { - Controls.AddBinding(button, (Keys)pressed); - RootMenu?.PopSubMenu(); - return; - } - - // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for buttons. - Controller? controller = Input.Controllers.FirstOrDefault(); - if (controller != null) - { - foreach (var button in Enum.GetValues(typeof(Buttons))) + Keys? pressed = Input.Keyboard.FirstPressed(); + if (pressed != null) { - if (controller.Pressed((Buttons)button)) - { - Controls.AddBinding(this.button, (Buttons)button); - RootMenu?.PopSubMenu(); - return; - } + Controls.AddBinding(button, (Keys)pressed); + RootMenu?.PopSubMenu(); + return; } - foreach (var axis in Enum.GetValues(typeof(Axes))) + // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for mouse buttons. + foreach (var button in Enum.GetValues(typeof(MouseButtons))) { - if (Math.Abs(controller.Axis((Axes)axis)) > 0.5f) + if (Input.Mouse.Pressed((MouseButtons)button)) { - Controls.AddBinding(this.button, (Axes)axis, controller.Axis((Axes)axis) < -0.5f); + Controls.AddBinding(this.button, (MouseButtons)button); RootMenu?.PopSubMenu(); return; } } } - - // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for mouse buttons. - if (controller != null) + else { - foreach (var button in Enum.GetValues(typeof(MouseButtons))) + // TODO: Maybe find a better way to do this? Foster doesn't expose a FirstPressed for buttons. + Controller? controller = Input.Controllers.FirstOrDefault(); + if (controller != null) { - if (Input.Mouse.Pressed((MouseButtons)button)) + foreach (var button in Enum.GetValues(typeof(Buttons))) { - Controls.AddBinding(this.button, (MouseButtons)button); - RootMenu?.PopSubMenu(); - return; + if (controller.Pressed((Buttons)button)) + { + Controls.AddBinding(this.button, (Buttons)button); + RootMenu?.PopSubMenu(); + return; + } + } + + foreach (var axis in Enum.GetValues(typeof(Axes))) + { + if (Math.Abs(controller.Axis((Axes)axis)) > 0.5f) + { + Controls.AddBinding(this.button, (Axes)axis, controller.Axis((Axes)axis) < -0.5f); + RootMenu?.PopSubMenu(); + return; + } } } } diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index 639ee3d9..bdf142dc 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -4,6 +4,8 @@ public class ControlsMenu : Menu { private Target GameTarget; + private bool isForController; + public override void Closed() { @@ -16,33 +18,44 @@ public override void Initialized() Index = 1; } - public ControlsMenu(Menu? rootMenu) + public ControlsMenu(Menu? rootMenu, bool isForController) { RootMenu = rootMenu; + this.isForController = isForController; GameTarget = new Target(Game.Width, Game.Height); Game.OnResolutionChanged += () => GameTarget = new Target(Game.Width, Game.Height); - Title = Loc.Str("ControlsTitle"); - - Add(new SubHeader("Game")); - Add(new InputBind(Controls.Jump.Name, Controls.Jump, rootMenu)); - Add(new InputBind(Controls.Dash.Name, Controls.Dash, rootMenu)); - Add(new InputBind(Controls.Climb.Name, Controls.Climb, rootMenu)); - Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu)); - - //Add(new SubHeader("Menu")); - //Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu)); - //Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu)); - //Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu)); - //Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu)); - //Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu)); + Add(new SubHeader("ControlsHeaderGame")); + Add(new InputBind(Controls.Jump.Name, Controls.Jump, rootMenu, isForController)); + Add(new InputBind(Controls.Dash.Name, Controls.Dash, rootMenu, isForController)); + Add(new InputBind(Controls.Climb.Name, Controls.Climb, rootMenu, isForController)); + Add(new InputBind(Controls.Move.Name + "Up", Controls.Move.Vertical.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Move.Name + "Down", Controls.Move.Vertical.Positive, rootMenu, isForController)); + Add(new InputBind(Controls.Move.Name + "Left", Controls.Move.Horizontal.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Move.Name + "Right", Controls.Move.Horizontal.Positive, rootMenu, isForController)); + Add(new InputBind(Controls.Camera.Name + "Up", Controls.Camera.Vertical.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Camera.Name + "Down", Controls.Camera.Vertical.Positive, rootMenu, isForController)); + Add(new InputBind(Controls.Camera.Name + "Left", Controls.Camera.Horizontal.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Camera.Name + "Right", Controls.Camera.Horizontal.Positive, rootMenu, isForController)); + + Add(new SubHeader("ControlsHeaderGame")); + Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu, isForController)); + Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu, isForController)); + Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu, isForController)); + Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu, isForController)); + Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu, isForController)); + Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu, isForController)); + Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController)); + Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController)); + Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController)); Add(new Spacer()); - Add(new Option("ResetToDefault", () => + Add(new Option("ControlsResetToDefault", () => { - Controls.ResetBindings(); + Controls.ResetAllBindings(isForController); })); Add(new Option("Exit", () => @@ -59,7 +72,7 @@ protected override void HandleInput() { if (items[Index] is InputBind bind) { - Controls.ResetBinding(bind.GetButton()); + Controls.ResetBinding(bind.GetButton(), isForController); } } @@ -67,7 +80,7 @@ protected override void HandleInput() { if (items[Index] is InputBind bind) { - Controls.ClearBinding(bind.GetButton()); + Controls.ClearBinding(bind.GetButton(), isForController); } } } diff --git a/Source/Mod/Menu/GameOptionsMenu.cs b/Source/Mod/Menu/GameOptionsMenu.cs index 9195f088..72e93c1a 100644 --- a/Source/Mod/Menu/GameOptionsMenu.cs +++ b/Source/Mod/Menu/GameOptionsMenu.cs @@ -3,7 +3,8 @@ namespace Celeste64; public class GameOptionsMenu : Menu { public Menu FujiOptionsMenu; - public ControlsMenu ControlsMenu; + public ControlsMenu KeyboardControlsMenu; + public ControlsMenu ControllerControlsMenu; public override void Closed() { @@ -17,7 +18,8 @@ public GameOptionsMenu(Menu? rootMenu) RootMenu = rootMenu; // Setup fuji options menu FujiOptionsMenu = new Menu { Title = Loc.Str("FujiOptions") }; - ControlsMenu = new ControlsMenu(rootMenu); + KeyboardControlsMenu = new ControlsMenu(rootMenu, false) { Title = Loc.Str("KeyboardConfig") }; + ControllerControlsMenu = new ControlsMenu(rootMenu, true) { Title = Loc.Str("ControllerConfig") }; FujiOptionsMenu.Add(new Toggle("FujiEnableDebugMenu", Settings.ToggleEnableDebugMenu, () => Settings.EnableDebugMenu)); FujiOptionsMenu.Add(new Toggle("FujiWriteLog", Settings.ToggleWriteLog, () => Settings.WriteLog)); @@ -26,7 +28,7 @@ public GameOptionsMenu(Menu? rootMenu) FujiOptionsMenu.Add(new Toggle("FujiAdditionalLog", Settings.ToggleEnableAdditionalLogs, () => Settings.EnableAdditionalLogging)); FujiOptionsMenu.Add(new Option("Exit", () => { - PopSubMenu(); + PopRootSubMenu(); })); // Setup this menu @@ -52,8 +54,9 @@ public GameOptionsMenu(Menu? rootMenu) Add(new Slider("OptionsSFX", 0, 10, () => Settings.SfxVolume, Settings.SetSfxVolume)); Add(new Spacer()); + Add(new Submenu("KeyboardConfig", rootMenu, KeyboardControlsMenu)); + Add(new Submenu("ControllerConfig", rootMenu, ControllerControlsMenu)); - Add(new Submenu("Controls", this, ControlsMenu)); - Add(new Submenu("FujiOptions", this, FujiOptionsMenu)); + Add(new Submenu("FujiOptions", rootMenu, FujiOptionsMenu)); } } From d2fe35789c800cb7b7d30e9a5e6fbd8e86ecbcfa Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Sun, 21 Apr 2024 21:44:57 -0700 Subject: [PATCH 05/16] Fixing deadzone issue. --- Source/Data/Controls.cs | 4 ++-- Source/Data/PersistedData/ControlsConfigBinding.cs | 6 +++++- Source/Helpers/Menu.cs | 4 +++- Source/Mod/Menu/BindControlMenu.cs | 6 ++++-- Source/Mod/Menu/ControlsMenu.cs | 8 ++++---- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 15622599..9b6da9e0 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -105,12 +105,12 @@ internal static void AddBinding(VirtualButton virtualButton, MouseButtons mouseB } [DisallowHooks] - internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inverted) + internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inverted, float deadzone = 0.0f) { var config = GetButtonBindings(Instance, virtualButton); if (config != null && !config.Any(a => a.Axis == axis)) { - config.Add(new(axis, 0.5f, inverted)); + config.Add(new(axis, deadzone, inverted)); config.Last().BindTo(virtualButton); } } diff --git a/Source/Data/PersistedData/ControlsConfigBinding.cs b/Source/Data/PersistedData/ControlsConfigBinding.cs index fa935c25..eaf631a4 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding.cs @@ -62,11 +62,11 @@ public void BindTo(VirtualButton button) button.Add(Condition, 0, Axis.Value, AxisInverted ? -1 : 1, AxisDeadzone); } - /// /// This is kind of a workaround for how Foster works. /// We need a custom version of Foster's Button Enum so we can properly get the names from the button. /// Since Foster's had old obsolete buttons with duplicate values, it was causing it to not properly use the correct name. + /// This also renames some of the buttons for more clarity for up/down/left/right. /// public enum FujiButtons { @@ -88,6 +88,10 @@ public enum FujiButtons ButtonRight = 14 } + /// + /// This renames these enum values to be more unique, which is needed for determining texture names. + /// i.e. MouseLeft instead of just Left, which is already used for keyboards. + /// public enum FujiMouseButtons { MouseNone, diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index 1e0d4eb8..342efa67 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -44,10 +44,12 @@ public Item Describe(Loc.Localized description) public class InputBind(Loc.Localized locString, VirtualButton button, Menu? rootMenu, bool isForController) : Item { public override Loc.Localized? LocString => locString; + + public float DeadZone; public override bool Pressed() { Audio.Play(Sfx.ui_select); - rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button, isForController)); + rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button, isForController, DeadZone)); return true; } diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index 1cbb6cf2..8c83dcfc 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -7,12 +7,14 @@ public class BindControlMenu : Menu private const float waitBeforeClosingTime = 5; private VirtualButton button; private bool isForController; + private float deadZone; - public BindControlMenu(Menu? rootMenu, VirtualButton button, bool isForController) + public BindControlMenu(Menu? rootMenu, VirtualButton button, bool isForController, float deadZone = 0) { RootMenu = rootMenu; this.button = button; + this.deadZone = deadZone; this.isForController = isForController; Title = Loc.Str($"Press Button to bind {button.Name}"); inMenuTime = 0; @@ -61,7 +63,7 @@ protected override void HandleInput() { if (Math.Abs(controller.Axis((Axes)axis)) > 0.5f) { - Controls.AddBinding(this.button, (Axes)axis, controller.Axis((Axes)axis) < -0.5f); + Controls.AddBinding(this.button, (Axes)axis, controller.Axis((Axes)axis) < -0.5f, deadZone); RootMenu?.PopSubMenu(); return; } diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index bdf142dc..bcd3d1f8 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -46,10 +46,10 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu, isForController)); Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu, isForController)); Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu, isForController)); - Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController)); - Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController)); - Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController)); - Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController)); + Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController) { DeadZone = 0.5f }); + Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f }); + Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f }); + Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f }); Add(new Spacer()); From c7c3bd67890df3cacfb7894f84fe9333c50260f2 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Sun, 21 Apr 2024 22:31:02 -0700 Subject: [PATCH 06/16] Fixing Home Buttons and Playstation stick icons --- .../Sprites/Controls/Nintendo Switch/Back.png | Bin 0 -> 503 bytes Content/Sprites/Controls/PlayStation/Back.png | Bin 0 -> 1047 bytes ...tation_stick_l_left.png => LeftXNegative.png} | Bin ...ation_stick_l_right.png => LeftXPositive.png} | Bin ...ystation_stick_l_up.png => LeftYNegative.png} | Bin ...ation_stick_l_press.png => LeftYPositive.png} | Bin ...ation_stick_r_left.png => RightXNegative.png} | Bin ...tion_stick_r_right.png => RightXPositive.png} | Bin ...station_stick_r_up.png => RightYNegative.png} | Bin ...ation_stick_r_down.png => RightYPositive.png} | Bin Content/Sprites/Controls/Xbox Series/Back.png | Bin 0 -> 632 bytes 11 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Content/Sprites/Controls/Nintendo Switch/Back.png create mode 100644 Content/Sprites/Controls/PlayStation/Back.png rename Content/Sprites/Controls/PlayStation/{playstation_stick_l_left.png => LeftXNegative.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_l_right.png => LeftXPositive.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_l_up.png => LeftYNegative.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_l_press.png => LeftYPositive.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_r_left.png => RightXNegative.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_r_right.png => RightXPositive.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_r_up.png => RightYNegative.png} (100%) rename Content/Sprites/Controls/PlayStation/{playstation_stick_r_down.png => RightYPositive.png} (100%) create mode 100644 Content/Sprites/Controls/Xbox Series/Back.png diff --git a/Content/Sprites/Controls/Nintendo Switch/Back.png b/Content/Sprites/Controls/Nintendo Switch/Back.png new file mode 100644 index 0000000000000000000000000000000000000000..3087f312d268b7286a1076bfa4b6f17319c16f85 GIT binary patch literal 503 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlE``e%I=hv^7f4@I|{d@+uRm!mp42;2^E{-7)hu>bm zop)G)hao`dkm-X@|KqJQS8WrB-w^sXwQK$@_W5ob4cArIO1xwIXC4q`cYk8^MkdWG zhOWFP8J5^}yzt}{G5R}OLu$d*gKoLm3~dq{m~KV5Om0lI6PjcCU(d&3mDB43NlpHHAy{i+aas4|DR~VTvf{;hcnk#Zqj&c z&0Q;U>P9X@-jW>VPoE4tRaN*eua0W)I>WpH7|!>YDza9bYdv%Qq5by*OFM)gv|HKK zZY;^IOV3*tRQhvk!SvVbn9KfE@n4%Qs4KDI9DC)_ldJ#iiP|(P*LBggJ-z<-XQf^2 z`LjrJ>gsjs<#P{9Ps`mi{mb25@63Nx_A%f3JpU!*ksnM)wtwQ6n6!`=81xLDu6{1- HoD!M<*>LU& literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/Back.png b/Content/Sprites/Controls/PlayStation/Back.png new file mode 100644 index 0000000000000000000000000000000000000000..a96daa06a194011f389a48542d3c99edb5acbb64 GIT binary patch literal 1047 zcmV+y1nB#TP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1FT6zK~!i%?U`Aq zO;H%f?=@!17|KwF2nh*E6fz_)N*P|fNRm>DOpj(Ea~?);658v48bz4R`N#zVGb4);@dPqL`SNnE#Wqva({U7KGpS;T07X z^C|jb37*3%#l^+1DgQ1=WD6$q1P|jp9Dw!h&}c)Tn=y#HxE;q~OFJ!k5L~WAl6i$Y zaIl>o9SAB+BFU8CKpW<#sb*!qxQ8G7Y9)j4B*`rFn+1kIa$S)#SO>e~BXwk8vke!T zd|r_fmg7%YN`0r_RfQ=eGsWtm$Y&yDR*E}TW@0|cG_<-i`Aj7F;hUUPI&E=;Uv($n zliih}Ryq^aL^@gNOjHwT$~>uVbtj^lNFA){SKWweB8n^2FY~A-@>(@6uewvHL_S)X&P|-e{P^lO-T9?NSnIpuTx>@3yWi`?ZXAxQ z@F40|nuUEy;u__jhoD>IR6K!SQFOp{el;sgZHTOJOl_=>burWf(P^z_(8d(Qa02S} zH2K%*H|&fvak@IPu#9hejw%Y4q6_xI9@r7}9^U|!fPPf!1?(l>#fx|rOT#Y9`Y^o& z4MXjYJjNi}W3DT**v8$6_r0F*+{Crm&kHgL4$^J1&`xsU4mQX2UMo9`upWN!TG`RY z#A!T&$1qzQdr)&T6*?Q?YW#?~(4LjHc1ELjn^ER^)m0+8_n&*MRNmoUoQNq~Mdjt? zHR(H#nK)pF`Owh-^(_RU0JMcO2AkNamC)y!h=LZM@Hp!AwzUmY34NOQLr|ZYSX9!v zjkW9)@1#CncV=`yPe4uh6zJ2p)zivN7(^nGgE$+jymQc34He6Byn#V{!|`^i4;{7e zsQ#J(?K`zXO@3Xuwm1qk>8|2u{H5iWzjZ-9k1k+2=0bBv`^;704_d!h;#*8d!9GA; zo%iZU;ybp(P>IlPgNf(S7tF;iT!npXh+sHS-~MFWhtJRjm*sbfjXxGOc4Dps@f5e= z2(0S`_%m>_UO5M&F8eM#h5BY5qMj|+@enq~4H!gXj-+4Fbd;bH9gj^dl;017Ypygz z1z)*hP~VC{BocYywNlZlq`5c^+t`qWfdG2r8oZ2JQPN2y^2TfVT*3v|&4!5%JiuxY znD%#Ppl-XDC{~~n(H^i?y#5>;>W5)LA>bCMf9{O5wsuHjVq#)q{soGPegJ0Lmz`>f R<@x{s002ovPDHLkV1m6L@m~M{ literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_left.png b/Content/Sprites/Controls/PlayStation/LeftXNegative.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_l_left.png rename to Content/Sprites/Controls/PlayStation/LeftXNegative.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_right.png b/Content/Sprites/Controls/PlayStation/LeftXPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_l_right.png rename to Content/Sprites/Controls/PlayStation/LeftXPositive.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_up.png b/Content/Sprites/Controls/PlayStation/LeftYNegative.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_l_up.png rename to Content/Sprites/Controls/PlayStation/LeftYNegative.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_l_press.png b/Content/Sprites/Controls/PlayStation/LeftYPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_l_press.png rename to Content/Sprites/Controls/PlayStation/LeftYPositive.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_left.png b/Content/Sprites/Controls/PlayStation/RightXNegative.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_r_left.png rename to Content/Sprites/Controls/PlayStation/RightXNegative.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_right.png b/Content/Sprites/Controls/PlayStation/RightXPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_r_right.png rename to Content/Sprites/Controls/PlayStation/RightXPositive.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_up.png b/Content/Sprites/Controls/PlayStation/RightYNegative.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_r_up.png rename to Content/Sprites/Controls/PlayStation/RightYNegative.png diff --git a/Content/Sprites/Controls/PlayStation/playstation_stick_r_down.png b/Content/Sprites/Controls/PlayStation/RightYPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/playstation_stick_r_down.png rename to Content/Sprites/Controls/PlayStation/RightYPositive.png diff --git a/Content/Sprites/Controls/Xbox Series/Back.png b/Content/Sprites/Controls/Xbox Series/Back.png new file mode 100644 index 0000000000000000000000000000000000000000..f5d561477c9ca51a08f98ed401553e5b8c26170a GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DSlK@2~gomp>nGKfiuI|9gfqx3^Om7#Od3x;TbJ9DY0f zWZ7W_9@mXC1sDDKe|=jgyBg@9?ohYoVV(!u zrp$CUw3%+pAHjE1_vjBdf$3*%E^HBnE7EF;a2ZzV&*> z)kE349?UD8+oUVY*^oW&!d^CCzDNOvn|J13Z1q?#&ahl)?jlJB-$^Nonn6mAPa{Md zBQs`yVc-a5a!sD9W%*j=5kp4^lYhFBkmnLchXefS*IPZ3m<*g#=U9e%eqd1O+iVdc z%^gt~vQ=q~&Ve$v_H}EM!}aEHPrDbtE!nly<4{ZMB5xm8Vm^ zTpLvb8)^%i^_3Ood~G$mym5~D+9Rc5&!fH4{^z-7R7G7CzWi^J)@DJztu~iK3g7hR zu6Vn|qbzmvOlh^>+wUab-T0cH`-pm)6#s7rqj9=B7gh8rJBBm`V&`pPL}(uu-E+6zbA}$x6C;-H?i6{ n Date: Sun, 21 Apr 2024 22:52:35 -0700 Subject: [PATCH 07/16] Fixing Trigger Icons, adding advanced bindings for Restart and Debug Menu --- ...eftTrigger.png => LeftTriggerPositive.png} | Bin ...htTrigger.png => RightTriggerPositive.png} | Bin ...eftTrigger.png => LeftTriggerPositive.png} | Bin ...htTrigger.png => RIghtTriggerPositive.png} | Bin ...eftTrigger.png => LeftTriggerPositive.png} | Bin ...htTrigger.png => RightTriggerPositive.png} | Bin Content/Text/English.json | 5 +++-- Source/Data/Controls.cs | 21 +++++++++++++----- .../Data/PersistedData/ControlsConfig_V01.cs | 6 +++++ Source/Mod/ImGui/DebugActorMenu.cs | 2 +- Source/Mod/ImGui/FujiDebugMenu.cs | 2 +- Source/Mod/Menu/ControlsMenu.cs | 5 ++++- Source/Scenes/World.cs | 8 +++++++ 13 files changed, 39 insertions(+), 10 deletions(-) rename Content/Sprites/Controls/Nintendo Switch/{LeftTrigger.png => LeftTriggerPositive.png} (100%) rename Content/Sprites/Controls/Nintendo Switch/{RightTrigger.png => RightTriggerPositive.png} (100%) rename Content/Sprites/Controls/PlayStation/{LeftTrigger.png => LeftTriggerPositive.png} (100%) rename Content/Sprites/Controls/PlayStation/{RIghtTrigger.png => RIghtTriggerPositive.png} (100%) rename Content/Sprites/Controls/Xbox Series/{LeftTrigger.png => LeftTriggerPositive.png} (100%) rename Content/Sprites/Controls/Xbox Series/{RightTrigger.png => RightTriggerPositive.png} (100%) diff --git a/Content/Sprites/Controls/Nintendo Switch/LeftTrigger.png b/Content/Sprites/Controls/Nintendo Switch/LeftTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/LeftTrigger.png rename to Content/Sprites/Controls/Nintendo Switch/LeftTriggerPositive.png diff --git a/Content/Sprites/Controls/Nintendo Switch/RightTrigger.png b/Content/Sprites/Controls/Nintendo Switch/RightTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/Nintendo Switch/RightTrigger.png rename to Content/Sprites/Controls/Nintendo Switch/RightTriggerPositive.png diff --git a/Content/Sprites/Controls/PlayStation/LeftTrigger.png b/Content/Sprites/Controls/PlayStation/LeftTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/LeftTrigger.png rename to Content/Sprites/Controls/PlayStation/LeftTriggerPositive.png diff --git a/Content/Sprites/Controls/PlayStation/RIghtTrigger.png b/Content/Sprites/Controls/PlayStation/RIghtTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/PlayStation/RIghtTrigger.png rename to Content/Sprites/Controls/PlayStation/RIghtTriggerPositive.png diff --git a/Content/Sprites/Controls/Xbox Series/LeftTrigger.png b/Content/Sprites/Controls/Xbox Series/LeftTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/Xbox Series/LeftTrigger.png rename to Content/Sprites/Controls/Xbox Series/LeftTriggerPositive.png diff --git a/Content/Sprites/Controls/Xbox Series/RightTrigger.png b/Content/Sprites/Controls/Xbox Series/RightTriggerPositive.png similarity index 100% rename from Content/Sprites/Controls/Xbox Series/RightTrigger.png rename to Content/Sprites/Controls/Xbox Series/RightTriggerPositive.png diff --git a/Content/Text/English.json b/Content/Text/English.json index 32bdaf8d..921ac940 100644 --- a/Content/Text/English.json +++ b/Content/Text/English.json @@ -61,7 +61,7 @@ "ControllerConfig.desc": "Rebind Controller Controls", "ControlsHeaderGame": "Game", "ControlsHeaderMenu": "Menu", - "ControlsHeaderFuji": "Fuji", + "ControlsHeaderAdvanced": "Advanced", "ControlsResetToDefault": "Reset To Default", "Jump": "Jump", "Dash": "Dash", @@ -81,7 +81,8 @@ "MenuDown": "Menu Down", "MenuUp": "Menu Up", "MenuRight": "Menu Right", - "MenuLeft": "Menu Left", + "MenuLeft": "Menu Left", + "DebugMenu": "Debug Menu", "Skin": "Skin", "Skin.desc": "Choose a Skin to Wear", diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 9b6da9e0..7d62ece0 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -17,6 +17,8 @@ public static class Controls public static readonly VirtualButton CopyFile = new("CopyFile"); public static readonly VirtualButton DeleteFile = new("DeleteFile"); public static readonly VirtualButton CreateFile = new("CreateFile"); + public static readonly VirtualButton DebugMenu = new("DebugMenu"); + public static readonly VirtualButton Restart = new("Restart"); public static ControlsConfig_V01 Instance = new(); @@ -303,6 +305,10 @@ static List FindAction(ControlsConfig_V01? config, string it.BindTo(DeleteFile); foreach (var it in FindAction(config, "CreateFile")) it.BindTo(CreateFile); + foreach (var it in FindAction(config, "DebugMenu")) + it.BindTo(DebugMenu); + foreach (var it in FindAction(config, "Restart")) + it.BindTo(Restart); } public static void Clear() @@ -366,14 +372,19 @@ public static string GetPromptLocation(VirtualButton button) var binding = action.FirstOrDefault(b => b.IsForController() == gamepad.Connected); - string buttonName = binding.GetBindingName(); + if (binding != null) + { + string buttonName = binding.GetBindingName(); + + buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); - buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); + if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) + list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{buttonName}"; - if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) - list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{binding.GetBindingName()}"; + return lookup; + } - return lookup; + return ""; } public static List GetPrompts(VirtualButton button, bool isForController) diff --git a/Source/Data/PersistedData/ControlsConfig_V01.cs b/Source/Data/PersistedData/ControlsConfig_V01.cs index d6afcd89..fe50ddd5 100644 --- a/Source/Data/PersistedData/ControlsConfig_V01.cs +++ b/Source/Data/PersistedData/ControlsConfig_V01.cs @@ -63,6 +63,12 @@ public class ControlsConfig_V01 : PersistedData new(Keys.B), new(Buttons.North) ], + ["DebugMenu"] = [ + new(Keys.F6), + ], + ["Restart"] = [ + new(Keys.R), + ], }, Sticks = new() diff --git a/Source/Mod/ImGui/DebugActorMenu.cs b/Source/Mod/ImGui/DebugActorMenu.cs index 0ec43d82..79aee6c3 100644 --- a/Source/Mod/ImGui/DebugActorMenu.cs +++ b/Source/Mod/ImGui/DebugActorMenu.cs @@ -16,7 +16,7 @@ internal class DebugActorMenu : ImGuiHandler public override void Update() { - if (Input.Keyboard.Pressed(Keys.F6)) + if (Controls.DebugMenu.Pressed) { if (Visible) Visible = false; if (actorListWindowVisible) actorListWindowVisible = false; diff --git a/Source/Mod/ImGui/FujiDebugMenu.cs b/Source/Mod/ImGui/FujiDebugMenu.cs index b59b8581..dbac65c2 100644 --- a/Source/Mod/ImGui/FujiDebugMenu.cs +++ b/Source/Mod/ImGui/FujiDebugMenu.cs @@ -11,7 +11,7 @@ internal class FujiDebugMenu : ImGuiHandler public override void Update() { - if (Input.Keyboard.Pressed(Keys.F6)) + if (Controls.DebugMenu.Pressed) { visible = !visible; } diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index bcd3d1f8..f874e3c5 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -39,7 +39,7 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Camera.Name + "Left", Controls.Camera.Horizontal.Negative, rootMenu, isForController)); Add(new InputBind(Controls.Camera.Name + "Right", Controls.Camera.Horizontal.Positive, rootMenu, isForController)); - Add(new SubHeader("ControlsHeaderGame")); + Add(new SubHeader("ControlsHeaderMenu")); Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu, isForController)); Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu, isForController)); Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu, isForController)); @@ -50,6 +50,9 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f }); Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f }); Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f }); + Add(new SubHeader("ControlsHeaderAdvanced")); + Add(new InputBind(Controls.DebugMenu.Name, Controls.DebugMenu, rootMenu, isForController)); + Add(new InputBind(Controls.Restart.Name, Controls.Restart, rootMenu, isForController)); Add(new Spacer()); diff --git a/Source/Scenes/World.cs b/Source/Scenes/World.cs index 9a238731..919fb6e9 100644 --- a/Source/Scenes/World.cs +++ b/Source/Scenes/World.cs @@ -458,6 +458,14 @@ public override void Update() return; } + if (Controls.Restart.ConsumePress()) + { + SetPaused(false); + Audio.StopBus(Sfx.bus_dialog, false); + Get()?.Kill(); + return; + } + // ONLY update the player when dead if (Get() is { Dead: true } player) { From c1bd83fdccf6589d5769a5e7bc1304d0273e5d2f Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Sun, 21 Apr 2024 23:42:09 -0700 Subject: [PATCH 08/16] Updating Menu bindings to always require 1 binding --- Content/Sprites/Controls/PC/LeftOS.png | Bin 0 -> 307 bytes Content/Text/English.json | 2 +- Source/Data/Controls.cs | 53 +++++++++++++++---------- Source/Helpers/Menu.cs | 1 + Source/Mod/Menu/ControlsMenu.cs | 22 +++++----- Source/Scenes/World.cs | 4 +- 6 files changed, 47 insertions(+), 35 deletions(-) create mode 100644 Content/Sprites/Controls/PC/LeftOS.png diff --git a/Content/Sprites/Controls/PC/LeftOS.png b/Content/Sprites/Controls/PC/LeftOS.png new file mode 100644 index 0000000000000000000000000000000000000000..dec89bb1671cc2c22639e56394ef6973cb741ab2 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu^1z`S$DQ>+}1|_wQ#gRLtoEO3e0jaSZV|o^0XFV9=w& zsvcT)-<5gy+-C}!6ZUqq#<*x$l!|LdFo!2}#~w`G(G>B9YuzEy4@uz#jO!lg@fqld z-g#$P{Om{^M`!3kQvqXfr=-vV_9HgjitX!~W-C040g11jWt`r(zIDRlLc=$YlO|~2 z=#Kqo7IQG_4OiYl(KAQaJy84TYWQu@H?5$|`WxcG|GLheSS|LEf#JmTiJQV|etiQv Olfl!~&t;ucLK6W00*FZf literal 0 HcmV?d00001 diff --git a/Content/Text/English.json b/Content/Text/English.json index 921ac940..901da4e7 100644 --- a/Content/Text/English.json +++ b/Content/Text/English.json @@ -60,7 +60,7 @@ "ControllerConfig": "Controller Config", "ControllerConfig.desc": "Rebind Controller Controls", "ControlsHeaderGame": "Game", - "ControlsHeaderMenu": "Menu", + "ControlsHeaderMenu": "Menu (Requires at least 1 binding)", "ControlsHeaderAdvanced": "Advanced", "ControlsResetToDefault": "Reset To Default", "Jump": "Jump", diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 7d62ece0..0fdb73d3 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -76,60 +76,71 @@ internal static void LoadControlsByFileName(string file_name) [DisallowHooks] internal static void AddBinding(VirtualButton virtualButton, Keys key) { - var config = GetButtonBindings(Instance, virtualButton); - if (config != null && !config.Any(a => a.Key == key)) + var bindings = GetButtonBindings(Instance, virtualButton); + if (bindings != null && !bindings.Any(a => a.Key == key)) { - config.Add(new(key)); - config.Last().BindTo(virtualButton); + bindings.Add(new(key)); + bindings.Last().BindTo(virtualButton); } } [DisallowHooks] internal static void AddBinding(VirtualButton virtualButton, Buttons button) { - var config = GetButtonBindings(Instance, virtualButton); - if (config != null && !config.Any(a => a.Button == button)) + var bindings = GetButtonBindings(Instance, virtualButton); + if (bindings != null && !bindings.Any(a => a.Button == button)) { - config.Add(new(button)); - config.Last().BindTo(virtualButton); + bindings.Add(new(button)); + bindings.Last().BindTo(virtualButton); } } [DisallowHooks] internal static void AddBinding(VirtualButton virtualButton, MouseButtons mouseButton) { - var config = GetButtonBindings(Instance, virtualButton); - if (config != null && !config.Any(a => a.MouseButton == mouseButton)) + var bindings = GetButtonBindings(Instance, virtualButton); + if (bindings != null && !bindings.Any(a => a.MouseButton == mouseButton)) { - config.Add(new(mouseButton)); - config.Last().BindTo(virtualButton); + bindings.Add(new(mouseButton)); + bindings.Last().BindTo(virtualButton); } } [DisallowHooks] internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inverted, float deadzone = 0.0f) { - var config = GetButtonBindings(Instance, virtualButton); - if (config != null && !config.Any(a => a.Axis == axis)) + var bindings = GetButtonBindings(Instance, virtualButton); + if (bindings != null && !bindings.Any(a => a.Axis == axis)) { - config.Add(new(axis, deadzone, inverted)); - config.Last().BindTo(virtualButton); + bindings.Add(new(axis, deadzone, inverted)); + bindings.Last().BindTo(virtualButton); } } [DisallowHooks] - internal static void ClearBinding(VirtualButton virtualButton, bool forController) + internal static void ClearBinding(VirtualButton virtualButton, bool forController, bool requiresBinding = false) { - var config = GetButtonBindings(Instance, virtualButton); - if (config != null) + var bindings = GetButtonBindings(Instance, virtualButton); + if (bindings != null) { virtualButton.Clear(); // Remove all bindings for this control type - config.RemoveAll(x => x.IsForController() == forController); + if (requiresBinding) + { + var toRemove = bindings.Where(x => x.IsForController() == forController).SkipLast(1).ToList(); + foreach (var removeItem in toRemove) + { + bindings.Remove(removeItem); + } + } + else + { + bindings.RemoveAll(x => x.IsForController() == forController); + } // Rebind remaining bindings. // Needed to rebind other control type, i.e. to not lose controller binds when clearing for keyboard. - foreach (var binding in config) + foreach (var binding in bindings) { binding.BindTo(virtualButton); } diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index 342efa67..c93f0797 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -46,6 +46,7 @@ public class InputBind(Loc.Localized locString, VirtualButton button, Menu? root public override Loc.Localized? LocString => locString; public float DeadZone; + public bool RequiresBinding; public override bool Pressed() { Audio.Play(Sfx.ui_select); diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index f874e3c5..33bda0c7 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -40,16 +40,16 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Camera.Name + "Right", Controls.Camera.Horizontal.Positive, rootMenu, isForController)); Add(new SubHeader("ControlsHeaderMenu")); - Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu, isForController)); - Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu, isForController)); - Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu, isForController)); - Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu, isForController)); - Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu, isForController)); - Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu, isForController)); - Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController) { DeadZone = 0.5f }); - Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f }); - Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f }); - Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f }); + Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.Cancel.Name, Controls.Cancel, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); + Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); + Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); + Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new SubHeader("ControlsHeaderAdvanced")); Add(new InputBind(Controls.DebugMenu.Name, Controls.DebugMenu, rootMenu, isForController)); Add(new InputBind(Controls.Restart.Name, Controls.Restart, rootMenu, isForController)); @@ -83,7 +83,7 @@ protected override void HandleInput() { if (items[Index] is InputBind bind) { - Controls.ClearBinding(bind.GetButton(), isForController); + Controls.ClearBinding(bind.GetButton(), isForController, bind.RequiresBinding); } } } diff --git a/Source/Scenes/World.cs b/Source/Scenes/World.cs index 919fb6e9..25997f07 100644 --- a/Source/Scenes/World.cs +++ b/Source/Scenes/World.cs @@ -458,11 +458,11 @@ public override void Update() return; } - if (Controls.Restart.ConsumePress()) + if (Controls.Restart.ConsumePress() && Get() is { Dead: false } livingPlayer) { SetPaused(false); Audio.StopBus(Sfx.bus_dialog, false); - Get()?.Kill(); + livingPlayer?.Kill(); return; } From 8f480f8616c01485cc148e7335fe26283c4732d0 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 22 Apr 2024 00:00:38 -0700 Subject: [PATCH 09/16] Fixing bug where binding to pause button exits menu. --- Source/Data/Controls.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 0fdb73d3..6fedbc09 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -82,6 +82,7 @@ internal static void AddBinding(VirtualButton virtualButton, Keys key) bindings.Add(new(key)); bindings.Last().BindTo(virtualButton); } + Consume(); } [DisallowHooks] @@ -93,6 +94,7 @@ internal static void AddBinding(VirtualButton virtualButton, Buttons button) bindings.Add(new(button)); bindings.Last().BindTo(virtualButton); } + Consume(); } [DisallowHooks] @@ -104,6 +106,7 @@ internal static void AddBinding(VirtualButton virtualButton, MouseButtons mouseB bindings.Add(new(mouseButton)); bindings.Last().BindTo(virtualButton); } + Consume(); } [DisallowHooks] @@ -115,6 +118,7 @@ internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inv bindings.Add(new(axis, deadzone, inverted)); bindings.Last().BindTo(virtualButton); } + Consume(); } [DisallowHooks] @@ -336,6 +340,8 @@ public static void Clear() CopyFile.Clear(); DeleteFile.Clear(); CreateFile.Clear(); + DebugMenu.Clear(); + Restart.Clear(); } public static void Consume() @@ -352,6 +358,8 @@ public static void Consume() CopyFile.Consume(); DeleteFile.Consume(); CreateFile.Consume(); + DebugMenu.Consume(); + Restart.Consume(); } private static readonly Dictionary> prompts = []; From 66ad8256d38a836d5ea10a47d2fb45e68aa4cd75 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Fri, 26 Apr 2024 09:13:00 -0700 Subject: [PATCH 10/16] Reworking bind options menu and some misc cleanup --- Content/Text/English.json | 1 + Source/Helpers/Menu.cs | 18 +++++++++--------- Source/Mod/Menu/BindControlMenu.cs | 15 +++++++++++++-- Source/Mod/Menu/ControlsMenu.cs | 2 +- Source/Mod/Menu/GameOptionsMenu.cs | 7 +++++-- Source/Scenes/World.cs | 2 ++ 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Content/Text/English.json b/Content/Text/English.json index 901da4e7..299cb973 100644 --- a/Content/Text/English.json +++ b/Content/Text/English.json @@ -63,6 +63,7 @@ "ControlsHeaderMenu": "Menu (Requires at least 1 binding)", "ControlsHeaderAdvanced": "Advanced", "ControlsResetToDefault": "Reset To Default", + "PressToBind": "Press any button to bind it to \"{0}\"", "Jump": "Jump", "Dash": "Dash", "Climb": "Climb", diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index c93f0797..0ea9b91d 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -4,7 +4,7 @@ public class Menu { public static float Spacing => 4 * Game.RelativeScale; public static float SpacerHeight => 12 * Game.RelativeScale; - public const float TitleScale = 0.75f; + protected float TitleScale = 0.75f; public abstract class Item { @@ -50,7 +50,7 @@ public class InputBind(Loc.Localized locString, VirtualButton button, Menu? root public override bool Pressed() { Audio.Play(Sfx.ui_select); - rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button, isForController, DeadZone)); + rootMenu?.PushSubMenu(new BindControlMenu(rootMenu, button, locString, isForController, DeadZone)); return true; } @@ -512,16 +512,16 @@ protected virtual void RenderItems(Batcher batch) if (showScrollbar && items.Count > maxItemsCount) { // TODO: This will need to be redone if we implement mouse support and want it to interact with menus. - int padding = 4; - int scrollSize = 16; - int xPos = Game.Width - scrollSize - padding; - int scrollBarHeight = Game.Height - (scrollSize * 2) - padding * 4; - int scrollStartPos = padding * 2 + scrollSize; + float padding = 4 * Game.RelativeScale; + float scrollSize = 16 * Game.RelativeScale; + float xPos = Game.Width - scrollSize - padding; + float scrollBarHeight = Game.Height - (scrollSize * 2) - padding * 4; + float scrollStartPos = padding * 2 + scrollSize; batch.PushMatrix(Vec2.Zero, false); batch.Rect(new Rect(xPos, padding, scrollSize, scrollSize), Color.White); batch.Rect(new Rect(xPos, scrollStartPos, scrollSize, scrollBarHeight), Color.Gray); - int scrollYPos = (int)MathF.Ceiling(scrollStartPos + ((float)scrolledAmount * scrollBarHeight / items.Count)); - int scrollYHeight = scrollBarHeight * maxItemsCount / items.Count; + float scrollYPos = (int)MathF.Ceiling(scrollStartPos + (scrolledAmount * scrollBarHeight / items.Count)); + float scrollYHeight = scrollBarHeight * maxItemsCount / items.Count; batch.Rect(new Rect(xPos, scrollYPos, scrollSize, scrollYHeight), Color.White); batch.Rect(new Rect(xPos, Game.Height - scrollSize - padding, scrollSize, scrollSize), Color.White); batch.PopMatrix(); diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index 8c83dcfc..5da1965c 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -9,14 +9,16 @@ public class BindControlMenu : Menu private bool isForController; private float deadZone; - public BindControlMenu(Menu? rootMenu, VirtualButton button, bool isForController, float deadZone = 0) + public BindControlMenu(Menu? rootMenu, VirtualButton button, string buttonName, bool isForController, float deadZone = 0) { RootMenu = rootMenu; this.button = button; this.deadZone = deadZone; this.isForController = isForController; - Title = Loc.Str($"Press Button to bind {button.Name}"); + Title = string.Format(Loc.Str("PressToBind"), buttonName); + TitleScale = 1; + inMenuTime = 0; } @@ -77,4 +79,13 @@ protected override void HandleInput() RootMenu?.PopSubMenu(); } } + + protected override void RenderItems(Batcher batch) + { + base.RenderItems(batch); + + batch.PushMatrix(Matrix3x2.CreateScale(0.75f)); + UI.Text(batch, $"Menu will close automatically in {(int)Math.Ceiling(waitBeforeClosingTime - inMenuTime)}", new(0, 1), new Vec2(0.5f, 0), new(8421504)); + batch.PopMatrix(); + } } diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index 33bda0c7..5fb779fe 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -6,7 +6,6 @@ public class ControlsMenu : Menu private bool isForController; - public override void Closed() { base.Closed(); @@ -50,6 +49,7 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); + Add(new SubHeader("ControlsHeaderAdvanced")); Add(new InputBind(Controls.DebugMenu.Name, Controls.DebugMenu, rootMenu, isForController)); Add(new InputBind(Controls.Restart.Name, Controls.Restart, rootMenu, isForController)); diff --git a/Source/Mod/Menu/GameOptionsMenu.cs b/Source/Mod/Menu/GameOptionsMenu.cs index 72e93c1a..28bc3015 100644 --- a/Source/Mod/Menu/GameOptionsMenu.cs +++ b/Source/Mod/Menu/GameOptionsMenu.cs @@ -52,11 +52,14 @@ public GameOptionsMenu(Menu? rootMenu) Add(new Spacer()); Add(new Slider("OptionsBGM", 0, 10, () => Settings.MusicVolume, Settings.SetMusicVolume)); Add(new Slider("OptionsSFX", 0, 10, () => Settings.SfxVolume, Settings.SetSfxVolume)); - Add(new Spacer()); + Add(new Spacer()); Add(new Submenu("KeyboardConfig", rootMenu, KeyboardControlsMenu)); Add(new Submenu("ControllerConfig", rootMenu, ControllerControlsMenu)); - Add(new Submenu("FujiOptions", rootMenu, FujiOptionsMenu)); + Add(new Option("Exit", () => + { + PopRootSubMenu(); + })); } } diff --git a/Source/Scenes/World.cs b/Source/Scenes/World.cs index 25997f07..f03681be 100644 --- a/Source/Scenes/World.cs +++ b/Source/Scenes/World.cs @@ -458,6 +458,8 @@ public override void Update() return; } + // Fuji Custom + // Quick Restart if the player presses the restart button. if (Controls.Restart.ConsumePress() && Get() is { Dead: false } livingPlayer) { SetPaused(false); From dd45631d62c5ca43b671f1e2a7b30353be07ffe8 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Fri, 26 Apr 2024 14:51:10 -0700 Subject: [PATCH 11/16] Improving Bind Menu layout --- Source/Mod/Menu/BindControlMenu.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index 5da1965c..c35cb23b 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -82,10 +82,14 @@ protected override void HandleInput() protected override void RenderItems(Batcher batch) { - base.RenderItems(batch); + + batch.PushMatrix(Matrix3x2.CreateScale(TitleScale)); + UI.Text(batch, Title, Vec2.Zero, new Vec2(0.5f, 0), Color.White); + batch.PopMatrix(); + batch.PushMatrix(Matrix3x2.CreateScale(0.75f)); - UI.Text(batch, $"Menu will close automatically in {(int)Math.Ceiling(waitBeforeClosingTime - inMenuTime)}", new(0, 1), new Vec2(0.5f, 0), new(8421504)); + UI.Text(batch, $"Menu will close automatically in {(int)Math.Ceiling(waitBeforeClosingTime - inMenuTime)}", new(0, Game.Height * 0.15f), new Vec2(0.5f, 0), Color.White); batch.PopMatrix(); } } From 1894c1fcd9f92a0bdbbf46738c8cc7e46fbf15a3 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Fri, 26 Apr 2024 16:18:27 -0700 Subject: [PATCH 12/16] Making a few more options rebindable. Adding special handling for a few more keys --- Content/Sprites/Controls/PC/Enter.png | Bin 378 -> 398 bytes Content/Sprites/Controls/PC/KeypadDivide.png | Bin 0 -> 366 bytes Content/Sprites/Controls/PC/KeypadEnter.png | Bin 0 -> 378 bytes Content/Sprites/Controls/PC/KeypadMinus.png | Bin 0 -> 257 bytes .../Sprites/Controls/PC/KeypadMultiply.png | Bin 0 -> 362 bytes Source/Data/Controls.cs | 23 ++++++++++++++++- .../Data/PersistedData/ControlsConfig_V01.cs | 6 +++++ Source/Game.cs | 24 ++++++++---------- Source/Mod/Menu/BindControlMenu.cs | 4 +-- Source/Mod/Menu/ControlsMenu.cs | 2 ++ 10 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 Content/Sprites/Controls/PC/KeypadDivide.png create mode 100644 Content/Sprites/Controls/PC/KeypadEnter.png create mode 100644 Content/Sprites/Controls/PC/KeypadMinus.png create mode 100644 Content/Sprites/Controls/PC/KeypadMultiply.png diff --git a/Content/Sprites/Controls/PC/Enter.png b/Content/Sprites/Controls/PC/Enter.png index c8a7ca1f54c0a4ff89bd3e621972f5633f7c485a..d789807f1f13791cbdbe8ff581e8a3d466431784 100644 GIT binary patch delta 292 zcmV+<0o(ri0*(WabARvOe{ZipkDtE}UmpNYKLN1-008nyL_t(Y$L-ZI4uUWg24L=? zUV$6P=IW%Yql=Ln;0(Hr0mN|sUppfzeM-BX!m!`kuHBIws zKuwG$foNo+7IVT1V2DJnIXEF1OMx{F9tzkrh!yD2;GzJ2NPi1{6C?m`cj3yigD`=m z4qgC`1qYE9fFNCsb-)qX6l4Xt+HwK_=Ah5ZE!+%1NVSm7GmxHPkJT;CQ4QeCu08`F z_!^KG;Gu`YK?Z?vdVc$&{uIpV{ksAi8ax&7X&}BI#q_9+3)B8MEAQV{&HENB@&+K8 W99{|z{j~r900{s|MNUMnLSTZz;CAu= diff --git a/Content/Sprites/Controls/PC/KeypadDivide.png b/Content/Sprites/Controls/PC/KeypadDivide.png new file mode 100644 index 0000000000000000000000000000000000000000..535aa23b68f7c22ab052172d1391b37ba9544faa GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|C0iMnt;khw>EtPvII(k{DRNt>-)#w=YKE1zP^9H{eA}bBNZ=!a;H39977@wzrB7? zs9AxBC19@FJSp48o>0IOQW%lRUkpT zxFLq|fvk%3Yqkc4NS%G}r0G|-o z|HJ{Ha-hP1@~AC97GFt_U$FlD_x1Vf_uKc+=Z}|Xcw=T;50ts*>EamTas2I7TfQa( z5%vPVN32(rUp#xYWVQ0*)y)^BAMifmxZ}X*5cDWv5!3ok!#aUi*3BggCVXOX=lwH% z`m+5`OnpCRIr#RdHD;tN5-UE$mC)g`&eB3r(!0@=SB~q3Nr&i*3lA1C)Om2%39B&V zl|MYSso9`$DPJ5zA1nJru?B_M-qHhtH$_rdcit*uVtBUT{At}gJPsaPC!95&FfXzH zs_wZ!-Unya*)hxikeVR=U}5_qN4Ca-s=D8c{)wD<`FA&yw3LnLhfIZi@<+d{=;glr k&qDkC{jjsY#k4=MDa@3KNS%G}T0G|-o z|F{8A2~e_Mb?rSMi>oBaFZh0azWsXn`ThGD4zHCC0g9G-x;Tb-98aF%$zaf`%%U4mo`qj(uB_XDo5hYX9k+_o`A z1j&1_E-o}&#o$tsI6a;*JfJo9V9|~yjW=A=gyKb#^|PicPW?7{uffyl5q*2I1o;^l YA|-jWw0N>F0v*8M>FVdQ&MBb@0AQD5$N&HU literal 0 HcmV?d00001 diff --git a/Content/Sprites/Controls/PC/KeypadMultiply.png b/Content/Sprites/Controls/PC/KeypadMultiply.png new file mode 100644 index 0000000000000000000000000000000000000000..ba7ab9d45fd3bf08db34c9606a75f28864169d94 GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G}50G|-o z|3m~aq4q`EZ&kJzu^4$>-q23_s7qd-*3+__s@1;pu{Cl7sn8f<8QC-o!8U_`fV%<3dHh0DU^gs4I01TBRbJPVjJMD90TnW$hM zS>Ro>fMc4@jfWgM1!;}}u}@l9FLS;58Jd&2H7|0Rp7w0^nTo4V{HmR#eWamVnETWT zCL`q($HdcXul=>3_w0k-E~fc%`XVzfKUj63jqUsSXv4c%pQE<>tF3=LeL?;GByYKA Xk<+`PA9sHQ`i{ZV)z4*}Q$iB}Talzu literal 0 HcmV?d00001 diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 6fedbc09..183f525d 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -19,6 +19,8 @@ public static class Controls public static readonly VirtualButton CreateFile = new("CreateFile"); public static readonly VirtualButton DebugMenu = new("DebugMenu"); public static readonly VirtualButton Restart = new("Restart"); + public static readonly VirtualButton FullScreen = new("FullScreen"); + public static readonly VirtualButton ReloadAssets = new("ReloadAssets"); public static ControlsConfig_V01 Instance = new(); @@ -324,6 +326,10 @@ static List FindAction(ControlsConfig_V01? config, string it.BindTo(DebugMenu); foreach (var it in FindAction(config, "Restart")) it.BindTo(Restart); + foreach (var it in FindAction(config, "FullScreen")) + it.BindTo(FullScreen); + foreach (var it in FindAction(config, "ReloadAssets")) + it.BindTo(ReloadAssets); } public static void Clear() @@ -342,6 +348,8 @@ public static void Clear() CreateFile.Clear(); DebugMenu.Clear(); Restart.Clear(); + FullScreen.Clear(); + ReloadAssets.Clear(); } public static void Consume() @@ -360,6 +368,8 @@ public static void Consume() CreateFile.Consume(); DebugMenu.Consume(); Restart.Consume(); + FullScreen.Consume(); + ReloadAssets.Consume(); } private static readonly Dictionary> prompts = []; @@ -447,7 +457,6 @@ private static List GetPromptLocations(VirtualButton button, bool isForC if (Gamepads.Nintendo.Equals(binding.NotFor) || !Gamepads.Nintendo.Equals(binding.OnlyFor) || (binding.NotFor == null && binding.OnlyFor == null)) //only non switch prompts atm locations.Add(lookup); - } } @@ -474,6 +483,18 @@ private static string GetButtonOverrides(string buttonName, Gamepads gamepadType } } + if (OperatingSystem.IsMacOS()) + { + if (buttonName == "LeftAlt" || buttonName == "RightAlt") + { + buttonName = "Option"; + } + else if (buttonName == "LeftOS" || buttonName == "RightOS") + { + buttonName = "Command"; + } + } + return buttonName; } } diff --git a/Source/Data/PersistedData/ControlsConfig_V01.cs b/Source/Data/PersistedData/ControlsConfig_V01.cs index fe50ddd5..15999be2 100644 --- a/Source/Data/PersistedData/ControlsConfig_V01.cs +++ b/Source/Data/PersistedData/ControlsConfig_V01.cs @@ -63,6 +63,12 @@ public class ControlsConfig_V01 : PersistedData new(Keys.B), new(Buttons.North) ], + ["FullScreen"] = [ + new(Keys.F4), + ], + ["ReloadAssets"] = [ + new(Keys.F5), + ], ["DebugMenu"] = [ new(Keys.F6), ], diff --git a/Source/Game.cs b/Source/Game.cs index c0ef13dc..d23a2d56 100644 --- a/Source/Game.cs +++ b/Source/Game.cs @@ -202,14 +202,6 @@ private void HandleError(Exception e) public override void Update() { - if (Input.Keyboard.Pressed(Keys.F5) && !IsMidTransition) - { - if (Scene is Startup || Scene is GameErrorMessage) return; - - Log.Info($"--- User has initiated a{(Input.Keyboard.CtrlOrCommand ? " full" : String.Empty)} manual reload. ---"); - ReloadAssets(Input.Keyboard.CtrlOrCommand); // F5 - Reload changed; Ctrl + F5 - Reload all - } - if (IsDynamicRes) { if (Height_old != Height || Width_old != Width) @@ -221,8 +213,6 @@ public override void Update() Width_old = Width; } - imGuiManager.UpdateHandlers(); - scenes.TryPeek(out var scene); // gets the top scene // update top scene @@ -248,6 +238,8 @@ public override void Update() HandleError(e); } + imGuiManager.UpdateHandlers(); + // handle transitions if (transitionStep == TransitionStep.FadeOut) { @@ -482,11 +474,17 @@ public override void Update() } - if (scene is not Celeste64.Startup) + if (scene is not Celeste64.Startup && Scene is not GameErrorMessage) { - // toggle fullsrceen - if ((Input.Keyboard.Alt && Input.Keyboard.Pressed(Keys.Enter)) || Input.Keyboard.Pressed(Keys.F4)) + // toggle fullscreen + if (Controls.FullScreen.ConsumePress()) Settings.ToggleFullscreen(); + + if (Controls.ReloadAssets.ConsumePress() && !IsMidTransition) + { + Log.Info($"--- User has initiated a{(Input.Keyboard.CtrlOrCommand ? " full" : string.Empty)} manual reload. ---"); + ReloadAssets(Input.Keyboard.CtrlOrCommand); // F5 - Reload changed; Ctrl + F5 - Reload all + } } } diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index c35cb23b..98d7e8de 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -27,7 +27,7 @@ protected override void HandleInput() if (!isForController) { Keys? pressed = Input.Keyboard.FirstPressed(); - if (pressed != null) + if (pressed != null && pressed != Keys.Unknown && pressed != Keys.Application && pressed != Keys.ScrollLock) // We don't have icons for these currently, so don't allow them { Controls.AddBinding(button, (Keys)pressed); RootMenu?.PopSubMenu(); @@ -82,12 +82,10 @@ protected override void HandleInput() protected override void RenderItems(Batcher batch) { - batch.PushMatrix(Matrix3x2.CreateScale(TitleScale)); UI.Text(batch, Title, Vec2.Zero, new Vec2(0.5f, 0), Color.White); batch.PopMatrix(); - batch.PushMatrix(Matrix3x2.CreateScale(0.75f)); UI.Text(batch, $"Menu will close automatically in {(int)Math.Ceiling(waitBeforeClosingTime - inMenuTime)}", new(0, Game.Height * 0.15f), new Vec2(0.5f, 0), Color.White); batch.PopMatrix(); diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index 5fb779fe..513ac19f 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -51,6 +51,8 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new SubHeader("ControlsHeaderAdvanced")); + Add(new InputBind(Controls.FullScreen.Name, Controls.FullScreen, rootMenu, isForController)); + Add(new InputBind(Controls.ReloadAssets.Name, Controls.ReloadAssets, rootMenu, isForController)); Add(new InputBind(Controls.DebugMenu.Name, Controls.DebugMenu, rootMenu, isForController)); Add(new InputBind(Controls.Restart.Name, Controls.Restart, rootMenu, isForController)); From 23ba127ef52068e3f842888046d25864250569ba Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 29 Apr 2024 16:56:04 -0700 Subject: [PATCH 13/16] Misc Cleanup and Refactoring. Adding some comments. --- Content/Sprites/Controls/PlayStation/Back.png | Bin 1047 -> 1799 bytes Content/Text/English.json | 2 + Source/Data/Controls.cs | 190 +++++++++++------- .../PersistedData/ControlsConfigBinding.cs | 42 +--- Source/Helpers/Menu.cs | 55 +++++ Source/Mod/Menu/BindControlMenu.cs | 3 + Source/Mod/Menu/ControlsMenu.cs | 12 ++ 7 files changed, 187 insertions(+), 117 deletions(-) diff --git a/Content/Sprites/Controls/PlayStation/Back.png b/Content/Sprites/Controls/PlayStation/Back.png index a96daa06a194011f389a48542d3c99edb5acbb64..2465af22f6dc8b2f140a5d584db432475ce429e2 100644 GIT binary patch delta 1734 zcmV;%208hc2!{@kReuJYNkl@2VId|@ydp_m16c=TU$%MnLBbz z#0PB@N(4UV+YacoA)@zfhKX-CX8n^41vR7!xp zwTO*y1H2Bdf#C|AhiBjk_$^~kA|3Kds4n1CCE`GPIou1sgwrr9X5ewS4=(rSVzw6* zIMU2H36;P(7=NM&3!Z9+w0<$fukZ=DEcCHxFbBxB@N;Oepy%9GHb~c!Gkgti4t?bg z4BKpNf&W6m5@;5(F+1NZjlr#<&)k4PTZwJ(5){mFo-mv8u`Tr7G|UjPAL;=Wk~N-$ z?l)3yg4vd@{xF7yfdRLJAoWZPL!nj@rMbDX*ws-_Vt?jCKDDJsv7{mOJ;Fe?^i~;@ z&M~+d7GTY~Ef$M!A}%uifws1`Zrazl8w=1Izt%QuzP^C{7K@~AW(I?-q_o8fwVsJ^ zrf<{OnVFd`lDe7|+KGG~Uhww?>DO8v^SRf@QeTNNz^xQgFT3+lsI@zVLEYmFB``WV z+ReQ__;lO14vNfHoV|mfuj82+~$oC8{0hOweb^e1A+^NSiFPt5|dxjbaQ@Y3HzPw?H}5 z={9>^R)%&O?LyPOtzaZ{w13|<(jni9L9r+%p)8(iTi^{|<^?&A0w4k3YMJq}EVv3t zjj2*1_EmR_msuP%1B;>B`@v$cm||a^LM#!M+r4nWWnA{m_vVULo(UI}e7TTohw#;>ObQDNpGwsLcZ%4MWBvgj9L^OMDdrX1NjK=GwC;ji?(*$=I*#$#L zPdnC{&d$ys(SM^*D11N?hbfZ+E2L7>4}TRl8M0kzGIYOU3C0q!+5@WF;rZSe%(%wM z;P3G5+1c5h$UersOz9kn3(S8U2zagbB zCX*RfY(BLmuZ)4bLV3P9hhaJz4ttt;V4xL((WiHV60?0?)r z|0Z~q`X(nQyXkv~Ydhn~uf=dkI>>6(G7nQi9?(c2BQ6QbW|W!R?G!!e)(Lkb{Vx*0 zS?PgI{$4VXl|w^A%aA%az5@S-nwUw%o^T9(PwF0!e@o;*s8bavxpG5>M-(Rs_NY_x zplcQU8K>@JiiD2B6ZGBd?^`0;Hh+Jj1V2RY58BcdKZ1{7H@33V)6=)3drEpz^-?jU z9#P7Gl4{d|wjCNRp-CJ+Lw&FE_cgl@!$)!M-ns<3hwEK--%FjfE+|=W1i6nAij^5h z{7!6a<=*S)*zW>LqOn7xfMRNS2_*9m4nJikUtl}!9T*tU&SgQr1l_M7=zr+Ns=glD z=a}UObsd6J@vYc-4V$OXK{Z0S5<>Q}GN9}-My`N=LP1`{*eR6&M3u{FsB)0bL1)N= zYpuu+(0%d}@Qv^(cnnU_Z_wCq(#)4)SmAADTMYvP>{&Soh453?9L82E1OX0`;9E%T zKsP}>?9amY;6)fhc48CcVShf|#2{-w8%Z$8Rz+p=4HVM8+ZBYdQes*$`zgs_!B?CJ zV7}zrO1-|-Fa!pA;RF;EKo%&-D|BgaI4#U!E6tZDS$hQ6Nn}0mB z3&4%;3(S9X|IOQL49Y` z3ysm()!tmpc0FipUj{hT*yzttt}jREH{ZMAT~L39CcpL+r2Y&&4!?rmG5!)#kGn%_d;TEs-RAz-7oQ@Fgta ce?d#jf1H;S3?TP7r~m)}07*qoM6N<$f=!@J#sB~S delta 976 zcmV;>126oC4wnd!ReuAlNkl7{~85X37}KP=*Kz2}u+(Bri%CUc5+> zQi@EEW+8JPND3tnhKwm)FXqV2lp*sxQ^tF*-+%A#+|D`ooPE|doU^fi^=l1x?{&WK z?7h}Ld)=a#n3$OVld`h1VyhN}-}d1Z6&3R-`eF&5!z;zb#ec6U|1L;m3nudf592%> zfc5RrXhWczF^Idk9mioyJ1u$;T&_ftd4)T0u$>+q2r5h>$&}zg8|J5}W@Wy(hadcE zC4=xJ$t?7n1%^O!U6C_b2fO1Vb!1?(4HuexUXc=(<4;&heW%}5g()O6#puVbtj^l zNFA){SKWweB8n^2FY~A-@>(@6uewvHL_S)X z&P|-e{P^lO-T9?NSnIpuTx>@3yWi`?ZXAxQ@F40|ntz3TN#YvipNF7Z<5WC>Ur}_x zb$&G~OKpg(a7=Bik99HB1JP-%X3)kI!*BxX^)&g{={M|*GjX~)vapPAdyXm!mZA&x z!XDTW^&Z~ILj2-o=Y}7E8k}%la_A1Pw#&jy%R7+GDOOve?Gmi1)po@Z7|; z*v|_x2!9UJZL-i#a^Vg($Ms$-JBzR$e(+k^(Z8{umFh`G?7 zm9}<9qj#H8=6cmtBD(jVd#zO7;a;4GDO*M5<>fW$JCB(-V2An8(E#-=1fc-5g);`5 z*r}D!=bDIu7N77q>h-p@4O0nyn)pLdpP5)x(to*)wd@q{q&{AEW^_MKKu!1*=+n2= z)5=X4L?V%cI2)_HbI?}}70YtGfkAx3@ph^Y9kuYN{+a>pJGDYheqFh?I0`lCuHt9> zrRA5ubwNFkE?_z4LUTv^%vIqJTEAD~TTDm6K0sZa_v%REJGR46iO_C?iRaN5%*8ES zg@1i)h+sHS-~MFWhtJRjm*sbfjXxGOc4Dps@f5e=2(0S`_%m>_UO5M&F8eM#h5BY5 zqMj|+@enq~4H!gXj-+4Fbd;bH9gj^dl;017Ypygz1z)*hP~VC{BocYywNlZlq`5c^ z+t`qWfdG2r8oZ2JQPN2y^2TfVT*3v|%}Iud4m`kW5SaFNXP|Domnc@C644&8R=oZk y8|sH)K_TE4sDJK^w6=CgVq#)qV*Uk+ihclQ+LxVbiRJnL0000? GetButtonBindings(ControlsConfig_V01 config, VirtualButton virtualButton) - { - string[] nameParts = virtualButton.Name.Split("/"); - - if (nameParts.Length == 3) - { - var stickConfig = config.Sticks[nameParts[0]]; - - if (stickConfig != null) - { - if (nameParts[1] == "Horizontal" && nameParts[2] == "Positive") - { - return stickConfig.Right; - } - else if (nameParts[1] == "Horizontal" && nameParts[2] == "Negative") - { - return stickConfig.Left; - } - else if (nameParts[1] == "Vertical" && nameParts[2] == "Negative") - { - return stickConfig.Up; - } - else if (nameParts[1] == "Vertical" && nameParts[2] == "Positive") - { - return stickConfig.Down; - } - } - } - else if (config.Actions.ContainsKey(virtualButton.Name)) - { - return config.Actions[virtualButton.Name]; - } - - return null; - } - [DisallowHooks] public static void SaveToFile() { @@ -278,7 +242,8 @@ public static void SaveToFile() } } - public static void LoadConfig(ControlsConfig_V01? config = null) + [DisallowHooks] + internal static void LoadConfig(ControlsConfig_V01? config = null) { static ControlsConfigStick FindStick(ControlsConfig_V01? config, string name) { @@ -374,48 +339,22 @@ public static void Consume() private static readonly Dictionary> prompts = []; - private static string GetControllerName(Gamepads pad) => pad switch - { - Gamepads.DualShock4 => "PlayStation", - Gamepads.DualSense => "PlayStation", - Gamepads.Nintendo => "Nintendo Switch", - Gamepads.Xbox => "Xbox Series", - _ => "Xbox Series", - }; - + /// + /// Get the icon texture for the first binding of a virtual button. + /// + /// Virtual button to get an icon for. + /// public static Subtexture GetPrompt(VirtualButton button) { - return Assets.Subtextures.GetValueOrDefault(GetPromptLocation(button)); - } - - public static string GetPromptLocation(VirtualButton button) - { - var gamepad = Input.Controllers[0]; - - var deviceTypeName = - gamepad.Connected ? GetControllerName(gamepad.Gamepad) : "PC"; - if (!prompts.TryGetValue(deviceTypeName, out var list)) - prompts[deviceTypeName] = list = []; - - var action = Instance.Actions.ContainsKey(button.Name) ? Instance.Actions[button.Name] : ControlsConfig_V01.Defaults.Actions[button.Name]; - - var binding = action.FirstOrDefault(b => b.IsForController() == gamepad.Connected); - - if (binding != null) - { - string buttonName = binding.GetBindingName(); - - buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); - - if (!list.TryGetValue(binding.GetBindingName(), out var lookup)) - list[binding.GetBindingName()] = lookup = $"Controls/{deviceTypeName}/{buttonName}"; - - return lookup; - } - - return ""; + return Assets.Subtextures.GetValueOrDefault(GetPromptLocations(button, Input.Controllers.Any() && Input.Controllers[0].Connected).FirstOrDefault("")); } + /// + /// Get icon textures for all bindings for a virtual button. + /// + /// Virtual button to get icons for. + /// True if we should show controller icons. False to show keyboard icons. + /// public static List GetPrompts(VirtualButton button, bool isForController) { List subtextures = []; @@ -450,7 +389,7 @@ private static List GetPromptLocations(VirtualButton button, bool isForC if (!prompts.TryGetValue(deviceTypeName, out var list)) prompts[deviceTypeName] = list = []; - buttonName = GetButtonOverrides(buttonName, gamepad.Gamepad); + buttonName = GetButtonOverrides(binding, buttonName, gamepad.Gamepad); if (!list.TryGetValue(buttonName, out var lookup)) list[buttonName] = lookup = $"Controls/{promptDeviceTypeName}/{buttonName}"; @@ -463,14 +402,110 @@ private static List GetPromptLocations(VirtualButton button, bool isForC return locations; } + private static List? GetButtonBindings(ControlsConfig_V01 config, VirtualButton virtualButton) + { + string[] nameParts = virtualButton.Name.Split("/"); + + if (nameParts.Length == 3) + { + var stickConfig = config.Sticks[nameParts[0]]; + + if (stickConfig != null) + { + if (nameParts[1] == "Horizontal" && nameParts[2] == "Positive") + { + return stickConfig.Right; + } + else if (nameParts[1] == "Horizontal" && nameParts[2] == "Negative") + { + return stickConfig.Left; + } + else if (nameParts[1] == "Vertical" && nameParts[2] == "Negative") + { + return stickConfig.Up; + } + else if (nameParts[1] == "Vertical" && nameParts[2] == "Positive") + { + return stickConfig.Down; + } + } + } + else if (config.Actions.ContainsKey(virtualButton.Name)) + { + return config.Actions[virtualButton.Name]; + } + + return null; + } + + /// + /// Gets a controller name for a gamepad. This is used to determine which folder we pull icons from. + /// PS4 and PS5 are shared, since most of their icons are the same. This is different from how this was handled in vanilla Celeste 64, which had them split. + /// + /// + /// + private static string GetControllerName(Gamepads pad) => pad switch + { + Gamepads.DualShock4 => "PlayStation", + Gamepads.DualSense => "PlayStation", + Gamepads.Nintendo => "Nintendo Switch", + Gamepads.Xbox => "Xbox Series", + _ => "Xbox Series", + }; + /// /// Used for special cases where there may be multiple options for a button, like with different control types. /// /// /// /// - private static string GetButtonOverrides(string buttonName, Gamepads gamepadType) + private static string GetButtonOverrides(ControlsConfigBinding binding, string buttonName, Gamepads gamepadType) { + // Mouse buttons need special names, since Left and Right could refer to Keyboard Left or Mouse Left. + switch (binding.MouseButton) + { + case MouseButtons.Left: + buttonName = "MouseLeft"; + break; + case MouseButtons.Right: + buttonName = "MouseRight"; + break; + case MouseButtons.Middle: + buttonName = "MouseMiddle"; + break; + default: + break; + } + + // This is needed to workaround 2 problems with how foster's buttons are set up. + // Normally, these can get their name from the enum name directly, but these have some special cases. + // The first issue is that the face buttons have multiple enum entries for the same value, with some being obsolete. We need to force it to get the correct name. + // The second issue is that Select and Back seem to currently be swapped. So we account for this here. If this gets fixed in foster, we should remove the last 2 cases. + switch (binding.Button) + { + case Buttons.South: + buttonName = "South"; + break; + case Buttons.East: + buttonName = "East"; + break; + case Buttons.West: + buttonName = "West"; + break; + case Buttons.North: + buttonName = "North"; + break; + case Buttons.Select: + buttonName = "Back"; + break; + case Buttons.Back: + buttonName = "Select"; + break; + default: + break; + } + + // PS4 has unique icons separate from PS5. We account for that here. if (gamepadType == Gamepads.DualShock4) { if (buttonName == "Start") @@ -483,6 +518,7 @@ private static string GetButtonOverrides(string buttonName, Gamepads gamepadType } } + // Separate MacOS special names from Windows. if (OperatingSystem.IsMacOS()) { if (buttonName == "LeftAlt" || buttonName == "RightAlt") diff --git a/Source/Data/PersistedData/ControlsConfigBinding.cs b/Source/Data/PersistedData/ControlsConfigBinding.cs index eaf631a4..2eec032b 100644 --- a/Source/Data/PersistedData/ControlsConfigBinding.cs +++ b/Source/Data/PersistedData/ControlsConfigBinding.cs @@ -62,54 +62,16 @@ public void BindTo(VirtualButton button) button.Add(Condition, 0, Axis.Value, AxisInverted ? -1 : 1, AxisDeadzone); } - /// - /// This is kind of a workaround for how Foster works. - /// We need a custom version of Foster's Button Enum so we can properly get the names from the button. - /// Since Foster's had old obsolete buttons with duplicate values, it was causing it to not properly use the correct name. - /// This also renames some of the buttons for more clarity for up/down/left/right. - /// - public enum FujiButtons - { - None = -1, - South = 0, - East = 1, - West = 2, - North = 3, - Back = 4, - Select = 5, - Start = 6, - LeftStick = 7, - RightStick = 8, - LeftShoulder = 9, - RightShoulder = 10, - ButtonUp = 11, - ButtonDown = 12, - ButtonLeft = 13, - ButtonRight = 14 - } - - /// - /// This renames these enum values to be more unique, which is needed for determining texture names. - /// i.e. MouseLeft instead of just Left, which is already used for keyboards. - /// - public enum FujiMouseButtons - { - MouseNone, - MouseLeft, - MouseMiddle, - MouseRight - } - public string GetBindingName() { if (Key != null) return Key.ToString() ?? ""; if (Button != null) - return ((FujiButtons)Button).ToString() ?? ""; + return Button.ToString() ?? ""; if (Axis != null) return Axis.ToString() + (AxisInverted ? "Negative" : "Positive"); if (MouseButton != null) - return ((FujiMouseButtons)MouseButton).ToString() ?? ""; + return MouseButton.ToString() ?? ""; return ""; } diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index 0ea9b91d..a2cf2ff8 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -41,6 +41,14 @@ public Item Describe(Loc.Localized description) } } + /// + /// Represents a Input Binding Menu Item. + /// This will show all the current bindings for a virtual buttons, and if you click it, it will open a binding menu to add new bindings. + /// + /// Localization key for label that shows. Shold represent the button name. + /// Virtual button we are trying to bind to + /// Root menu for the menu we are currently in + /// True if this is a controller binding, false for keyboard public class InputBind(Loc.Localized locString, VirtualButton button, Menu? rootMenu, bool isForController) : Item { public override Loc.Localized? LocString => locString; @@ -65,6 +73,13 @@ public VirtualButton GetButton() } } + /// + /// Represents a submenu menu item. + /// When pressed, it will open the given submenu + /// + /// Localization key for the submenu label + /// Root Menu for the menu that we are currently inside of. + /// Submenu to open when clicked. public class Submenu(Loc.Localized locString, Menu? rootMenu, Menu? submenu = null) : Item { public override Loc.Localized? LocString => locString; @@ -83,11 +98,17 @@ public override bool Pressed() } } + /// + /// Spacer menu item to allow a row of separation between menu items. + /// public class Spacer : Item { public override bool Selectable => false; } + /// + /// Basic slider component that allows you to pick an int value between a min and a max. + /// public class Slider : Item { private readonly List labels = []; @@ -111,12 +132,21 @@ public Slider(Loc.Localized locString, int min, int max, Func get, Action set(Calc.Clamp(get() + dir, min, max)); } + /// + /// Represents a subheader menu item. + /// This allows a basic text only entry in a list of menu items to represent a subheader for a group of items. + /// + /// public class SubHeader(Loc.Localized locString) : Item { public override Loc.Localized? LocString => locString; public override bool Selectable { get; } = false; } + /// + /// Menu item that allows you to pick an item from a list of strings. + /// Note: For static lists of options, a Multiselect using an enum is recommended. This item is more for dynamic lists where the options can change dynamically. + /// public class OptionList : Item { private readonly int min; @@ -161,6 +191,11 @@ private int getId() } } + /// + /// Basic menu item that will run an action when clicked + /// + /// Localization key for Option Label + /// Action to run when pressed public class Option(Loc.Localized locString, Action? action = null) : Item { public override Loc.Localized? LocString => locString; @@ -177,6 +212,12 @@ public override bool Pressed() } } + /// + /// Menu item representing a basic boolean value that can be turned off and on. + /// + /// Localization key for Toggle Label + /// action to run when pressed. This should be where you set the boolean value + /// function that gets the current state of the boolean value public class Toggle(Loc.Localized locString, Action action, Func get) : Item { private string labelOff => $"{locString} : {Loc.Str("OptionsToggleOff")}"; @@ -196,6 +237,13 @@ public override bool Pressed() } } + /// + /// Multiselect component that lets you pick a list of strings. + /// + /// + /// + /// + /// public class MultiSelect(Loc.Localized locString, List options, Func get, Action set) : Item { public override Loc.Localized LocString => locString; @@ -214,6 +262,13 @@ public override void Slide(int dir) } } + /// + /// Multiselect component that lets you pick a value from an enum. + /// + /// + /// + /// + /// public class MultiSelect(Loc.Localized locString, Action set, Func get) : MultiSelect(locString, GetEnumOptions(), () => (int)(object)get(), i => set((T)(object)i)) where T : struct, Enum diff --git a/Source/Mod/Menu/BindControlMenu.cs b/Source/Mod/Menu/BindControlMenu.cs index 98d7e8de..12ab2237 100644 --- a/Source/Mod/Menu/BindControlMenu.cs +++ b/Source/Mod/Menu/BindControlMenu.cs @@ -24,6 +24,7 @@ public BindControlMenu(Menu? rootMenu, VirtualButton button, string buttonName, protected override void HandleInput() { + // Only accept keys and mouse buttons if this is not for controller. Otherwise, only accept controller buttons and sticks if (!isForController) { Keys? pressed = Input.Keyboard.FirstPressed(); @@ -73,6 +74,8 @@ protected override void HandleInput() } } + // Closes automatically after seconds + // This is to prevent users from being forced to bind if they click by mistake. inMenuTime += Time.Delta; if (inMenuTime > waitBeforeClosingTime) { diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index 513ac19f..e47890a9 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -20,11 +20,13 @@ public override void Initialized() public ControlsMenu(Menu? rootMenu, bool isForController) { RootMenu = rootMenu; + // This menu can be used for either controller or keyboard bindings, which are separated based on this isForController flag. this.isForController = isForController; GameTarget = new Target(Game.Width, Game.Height); Game.OnResolutionChanged += () => GameTarget = new Target(Game.Width, Game.Height); + // Standard gameplay bindings. Add(new SubHeader("ControlsHeaderGame")); Add(new InputBind(Controls.Jump.Name, Controls.Jump, rootMenu, isForController)); Add(new InputBind(Controls.Dash.Name, Controls.Dash, rootMenu, isForController)); @@ -38,6 +40,8 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Camera.Name + "Left", Controls.Camera.Horizontal.Negative, rootMenu, isForController)); Add(new InputBind(Controls.Camera.Name + "Right", Controls.Camera.Horizontal.Positive, rootMenu, isForController)); + // Menu Item bindings are special, because they must always have at least 1 binding, to prevent the user from getting stuck. + // This is what the RequiresBinding flag is for. Add(new SubHeader("ControlsHeaderMenu")); Add(new InputBind(Controls.Pause.Name, Controls.Pause, rootMenu, isForController) { RequiresBinding = true }); Add(new InputBind(Controls.Confirm.Name, Controls.Confirm, rootMenu, isForController) { RequiresBinding = true }); @@ -50,6 +54,7 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Right", Controls.Menu.Horizontal.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); + // Advanced Bindings for special things that don't really fit into any category. Add(new SubHeader("ControlsHeaderAdvanced")); Add(new InputBind(Controls.FullScreen.Name, Controls.FullScreen, rootMenu, isForController)); Add(new InputBind(Controls.ReloadAssets.Name, Controls.ReloadAssets, rootMenu, isForController)); @@ -58,6 +63,7 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new Spacer()); + // Reset all bindings for this control type to their default value. Add(new Option("ControlsResetToDefault", () => { Controls.ResetAllBindings(isForController); @@ -73,6 +79,7 @@ protected override void HandleInput() { base.HandleInput(); + // Reset current binding to it's default value if (Controls.CopyFile.ConsumePress()) { if (items[Index] is InputBind bind) @@ -81,6 +88,7 @@ protected override void HandleInput() } } + // Clear current binding so there are no bindings (Or 1 binding if RequiredBinding flag is true, where it will keep just the last binding) if (Controls.CreateFile.ConsumePress()) { if (items[Index] is InputBind bind) @@ -90,6 +98,10 @@ protected override void HandleInput() } } + /// + /// Render bindings and input legend + /// + /// protected override void RenderItems(Batcher batch) { batch.PushMatrix(new Vec2(GameTarget.Bounds.Center.X, GameTarget.Bounds.Center.Y - 16f), false); From 5b174422c5aa38caec77ab90407895b6c1d77ee1 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 29 Apr 2024 17:02:33 -0700 Subject: [PATCH 14/16] Moving binding logic to base menu class to make input bind components more portable. --- Source/Helpers/Menu.cs | 15 +++++++++++++++ Source/Mod/Menu/ControlsMenu.cs | 27 --------------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index a2cf2ff8..c889c947 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -55,6 +55,7 @@ public class InputBind(Loc.Localized locString, VirtualButton button, Menu? root public float DeadZone; public bool RequiresBinding; + public bool IsForController => isForController; public override bool Pressed() { Audio.Play(Sfx.ui_select); @@ -471,6 +472,20 @@ protected virtual void HandleInput() if (Controls.Confirm.Pressed && items[Index].Pressed()) Controls.Consume(); + + if (items[Index] is InputBind bind) + { + if (Controls.CopyFile.ConsumePress()) + { + // Reset current binding to it's default value + Controls.ResetBinding(bind.GetButton(), bind.IsForController); + } + else if (Controls.CreateFile.ConsumePress()) + { + // Clear current binding so there are no bindings (Or 1 binding if RequiredBinding flag is true, where it will keep just the last binding) + Controls.ClearBinding(bind.GetButton(), bind.IsForController, bind.RequiresBinding); + } + } } } diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index e47890a9..60cec8c8 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -4,8 +4,6 @@ public class ControlsMenu : Menu { private Target GameTarget; - private bool isForController; - public override void Closed() { base.Closed(); @@ -20,8 +18,6 @@ public override void Initialized() public ControlsMenu(Menu? rootMenu, bool isForController) { RootMenu = rootMenu; - // This menu can be used for either controller or keyboard bindings, which are separated based on this isForController flag. - this.isForController = isForController; GameTarget = new Target(Game.Width, Game.Height); Game.OnResolutionChanged += () => GameTarget = new Target(Game.Width, Game.Height); @@ -75,29 +71,6 @@ public ControlsMenu(Menu? rootMenu, bool isForController) })); } - protected override void HandleInput() - { - base.HandleInput(); - - // Reset current binding to it's default value - if (Controls.CopyFile.ConsumePress()) - { - if (items[Index] is InputBind bind) - { - Controls.ResetBinding(bind.GetButton(), isForController); - } - } - - // Clear current binding so there are no bindings (Or 1 binding if RequiredBinding flag is true, where it will keep just the last binding) - if (Controls.CreateFile.ConsumePress()) - { - if (items[Index] is InputBind bind) - { - Controls.ClearBinding(bind.GetButton(), isForController, bind.RequiresBinding); - } - } - } - /// /// Render bindings and input legend /// From 91549e0a61defa99d443597ee886aa30df5611c1 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 29 Apr 2024 17:50:26 -0700 Subject: [PATCH 15/16] Fixing bug with defaults not being able to reset properly. Also adding actions for resetting and clearing bindings --- Content/Text/English.json | 2 + Source/Data/Controls.cs | 42 ++++++++++++------- .../Data/PersistedData/ControlsConfig_V01.cs | 8 ++++ Source/Helpers/Menu.cs | 4 +- Source/Mod/Menu/ControlsMenu.cs | 3 ++ 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Content/Text/English.json b/Content/Text/English.json index 383bb254..e68fd0cf 100644 --- a/Content/Text/English.json +++ b/Content/Text/English.json @@ -81,6 +81,8 @@ "CreateFile": "Create File", "CopyFile": "Create File", "DeleteFile": "Delete File", + "ResetBindings": "Reset Bindings", + "ClearBindings": "Clear Bindings", "MenuDown": "Menu Down", "MenuUp": "Menu Up", "MenuRight": "Menu Right", diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index 0b9109db..e2e3ea25 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -1,5 +1,4 @@ using Celeste64.Mod; -using System.Text.Json; namespace Celeste64; @@ -17,6 +16,8 @@ public static class Controls public static readonly VirtualButton CopyFile = new("CopyFile"); public static readonly VirtualButton DeleteFile = new("DeleteFile"); public static readonly VirtualButton CreateFile = new("CreateFile"); + public static readonly VirtualButton ResetBindings = new("ResetBindings"); + public static readonly VirtualButton ClearBindings = new("ClearBindings"); public static readonly VirtualButton DebugMenu = new("DebugMenu"); public static readonly VirtualButton Restart = new("Restart"); public static readonly VirtualButton FullScreen = new("FullScreen"); @@ -47,27 +48,28 @@ internal static void LoadControlsByFileName(string file_name) if (controls == null) { - controls = ControlsConfig_V01.Defaults; - using var stream = File.Create(controlsFile); - JsonSerializer.Serialize(stream, ControlsConfig_V01.Defaults, ControlsConfig_V01Context.Default.ControlsConfig_V01); - stream.Flush(); + controls = new ControlsConfig_V01(); } - else + + // Add any default actions and sticks that are missing. + foreach (var defaultAction in ControlsConfig_V01.Defaults.Actions) { - // Add any default actions and sticks that are missing. - foreach (var action in ControlsConfig_V01.Defaults.Actions) + if (!controls.Actions.ContainsKey(defaultAction.Key)) { - if (!controls.Actions.ContainsKey(action.Key)) - { - controls.Actions.Add(action.Key, action.Value); - } + controls.Actions[defaultAction.Key] = [.. defaultAction.Value]; } - foreach (var stick in ControlsConfig_V01.Defaults.Sticks) + } + foreach (var defaultStick in ControlsConfig_V01.Defaults.Sticks) + { + if (!controls.Sticks.ContainsKey(defaultStick.Key)) { - if (!controls.Sticks.ContainsKey(stick.Key)) + controls.Sticks[defaultStick.Key] = new ControlsConfigStick() { - controls.Sticks.Add(stick.Key, stick.Value); - } + Up = [.. defaultStick.Value.Up], + Down = [.. defaultStick.Value.Down], + Left = [.. defaultStick.Value.Left], + Right = [.. defaultStick.Value.Right], + }; } } @@ -287,6 +289,10 @@ static List FindAction(ControlsConfig_V01? config, string it.BindTo(DeleteFile); foreach (var it in FindAction(config, "CreateFile")) it.BindTo(CreateFile); + foreach (var it in FindAction(config, "ResetBindings")) + it.BindTo(ResetBindings); + foreach (var it in FindAction(config, "ClearBindings")) + it.BindTo(ClearBindings); foreach (var it in FindAction(config, "DebugMenu")) it.BindTo(DebugMenu); foreach (var it in FindAction(config, "Restart")) @@ -311,6 +317,8 @@ public static void Clear() CopyFile.Clear(); DeleteFile.Clear(); CreateFile.Clear(); + ResetBindings.Clear(); + ClearBindings.Clear(); DebugMenu.Clear(); Restart.Clear(); FullScreen.Clear(); @@ -331,6 +339,8 @@ public static void Consume() CopyFile.Consume(); DeleteFile.Consume(); CreateFile.Consume(); + ResetBindings.Consume(); + ClearBindings.Consume(); DebugMenu.Consume(); Restart.Consume(); FullScreen.Consume(); diff --git a/Source/Data/PersistedData/ControlsConfig_V01.cs b/Source/Data/PersistedData/ControlsConfig_V01.cs index 15999be2..c8375f75 100644 --- a/Source/Data/PersistedData/ControlsConfig_V01.cs +++ b/Source/Data/PersistedData/ControlsConfig_V01.cs @@ -63,6 +63,14 @@ public class ControlsConfig_V01 : PersistedData new(Keys.B), new(Buttons.North) ], + ["ResetBindings"] = [ + new(Keys.V), + new(Buttons.LeftShoulder) + ], + ["ClearBindings"] = [ + new(Keys.B), + new(Buttons.North) + ], ["FullScreen"] = [ new(Keys.F4), ], diff --git a/Source/Helpers/Menu.cs b/Source/Helpers/Menu.cs index c889c947..1d52901e 100644 --- a/Source/Helpers/Menu.cs +++ b/Source/Helpers/Menu.cs @@ -475,12 +475,12 @@ protected virtual void HandleInput() if (items[Index] is InputBind bind) { - if (Controls.CopyFile.ConsumePress()) + if (Controls.ResetBindings.ConsumePress()) { // Reset current binding to it's default value Controls.ResetBinding(bind.GetButton(), bind.IsForController); } - else if (Controls.CreateFile.ConsumePress()) + else if (Controls.ClearBindings.ConsumePress()) { // Clear current binding so there are no bindings (Or 1 binding if RequiredBinding flag is true, where it will keep just the last binding) Controls.ClearBinding(bind.GetButton(), bind.IsForController, bind.RequiresBinding); diff --git a/Source/Mod/Menu/ControlsMenu.cs b/Source/Mod/Menu/ControlsMenu.cs index 60cec8c8..32c9cd4b 100644 --- a/Source/Mod/Menu/ControlsMenu.cs +++ b/Source/Mod/Menu/ControlsMenu.cs @@ -12,6 +12,7 @@ public override void Closed() public override void Initialized() { + // The first item is a subheader, so we need to start at 1 to account for this. Index = 1; } @@ -45,6 +46,8 @@ public ControlsMenu(Menu? rootMenu, bool isForController) Add(new InputBind(Controls.CopyFile.Name, Controls.CopyFile, rootMenu, isForController) { RequiresBinding = true }); Add(new InputBind(Controls.CreateFile.Name, Controls.CreateFile, rootMenu, isForController) { RequiresBinding = true }); Add(new InputBind(Controls.DeleteFile.Name, Controls.DeleteFile, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.ResetBindings.Name, Controls.ResetBindings, rootMenu, isForController) { RequiresBinding = true }); + Add(new InputBind(Controls.ClearBindings.Name, Controls.ClearBindings, rootMenu, isForController) { RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Up", Controls.Menu.Vertical.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Down", Controls.Menu.Vertical.Positive, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); Add(new InputBind(Controls.Menu.Name + "Left", Controls.Menu.Horizontal.Negative, rootMenu, isForController) { DeadZone = 0.5f, RequiresBinding = true }); From 9b3be7475af29ed1ee8505de946a9ba2c6690b71 Mon Sep 17 00:00:00 2001 From: Jasmine Stephens Date: Mon, 29 Apr 2024 18:22:29 -0700 Subject: [PATCH 16/16] Fixing a few controller binding bugs Fixing missing dpad icons. Fixing issue with default deadzone not getting set or reset correctly. Fixing bug where Positive and Negative directions on an axis couldn't be bound to the same virtual button. --- Source/Data/Controls.cs | 16 +++++++++++++++- Source/Scenes/World.cs | 6 ++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Source/Data/Controls.cs b/Source/Data/Controls.cs index e2e3ea25..6c014e7e 100644 --- a/Source/Data/Controls.cs +++ b/Source/Data/Controls.cs @@ -69,6 +69,7 @@ internal static void LoadControlsByFileName(string file_name) Down = [.. defaultStick.Value.Down], Left = [.. defaultStick.Value.Left], Right = [.. defaultStick.Value.Right], + Deadzone = defaultStick.Value.Deadzone }; } } @@ -117,7 +118,7 @@ internal static void AddBinding(VirtualButton virtualButton, MouseButtons mouseB internal static void AddBinding(VirtualButton virtualButton, Axes axis, bool inverted, float deadzone = 0.0f) { var bindings = GetButtonBindings(Instance, virtualButton); - if (bindings != null && !bindings.Any(a => a.Axis == axis)) + if (bindings != null && !bindings.Any(a => a.Axis == axis && a.AxisInverted == inverted)) { bindings.Add(new(axis, deadzone, inverted)); bindings.Last().BindTo(virtualButton); @@ -217,6 +218,7 @@ internal static void ResetAllBindings(bool forController) Instance.Sticks[stick.Key].Down.AddRange(stick.Value.Down.Where(b => b.IsForController() == forController)); Instance.Sticks[stick.Key].Left.AddRange(stick.Value.Left.Where(b => b.IsForController() == forController)); Instance.Sticks[stick.Key].Right.AddRange(stick.Value.Right.Where(b => b.IsForController() == forController)); + Instance.Sticks[stick.Key].Deadzone = stick.Value.Deadzone; } // Reload bindings @@ -505,6 +507,18 @@ private static string GetButtonOverrides(ControlsConfigBinding binding, string b case Buttons.North: buttonName = "North"; break; + case Buttons.Up: + buttonName = "ButtonUp"; + break; + case Buttons.Down: + buttonName = "ButtonDown"; + break; + case Buttons.Left: + buttonName = "ButtonLeft"; + break; + case Buttons.Right: + buttonName = "ButtonRight"; + break; case Buttons.Select: buttonName = "Back"; break; diff --git a/Source/Scenes/World.cs b/Source/Scenes/World.cs index 22c2bb8d..70b583ea 100644 --- a/Source/Scenes/World.cs +++ b/Source/Scenes/World.cs @@ -384,16 +384,14 @@ public override void Update() { if (Paused) { + pauseMenu.Update(); + if (Controls.Pause.ConsumePress() || (pauseMenu.IsInMainMenu && Controls.Cancel.ConsumePress())) { pauseMenu.CloseSubMenus(); SetPaused(false); Audio.Play(Sfx.ui_unpause); } - else - { - pauseMenu.Update(); - } } if (Panicked)