Menu - Controls Rebind - Gamepad & Keyboard (Cleaner git log) (#1666)
* squased merge rebind_menu * azerty to qwerty * add a check to preven a crash in firefox * reset navigation menu on quit * removed dual lock mekanism * navigation display update icons on new bind * added submit binding * removed attribute no longer used * change protected to abstract * remove last bind protection since action and cancel are protected + renamed default controller to controller * removed default alt qwerty keys in config * fix some errors for doc * fix tests * fix some more errors for docs * fix some more errors for docs final ? * added alt bind for menu navigation + update icons on delete/home
This commit is contained in:
parent
5cf9a98ee0
commit
060b1b2ccc
70
index.css
70
index.css
|
@ -146,7 +146,9 @@ body {
|
||||||
margin-left: 10%;
|
margin-left: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#touchControls:not([data-ui-mode='STARTER_SELECT']) #apad .apadRectBtnContainer > .apadSqBtn, #touchControls:not([data-ui-mode='STARTER_SELECT']) #apad .apadSqBtnContainer > .apadSqBtn {
|
#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode='SETTINGS']):not([data-ui-mode='SETTINGS_GAMEPAD']):not([data-ui-mode='SETTINGS_KEYBOARD']) #apad .apadRectBtnContainer > .apadSqBtn,
|
||||||
|
#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode='SETTINGS']):not([data-ui-mode='SETTINGS_GAMEPAD']):not([data-ui-mode='SETTINGS_KEYBOARD']) #apad .apadSqBtnContainer
|
||||||
|
{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,4 +177,70 @@ body {
|
||||||
input:-internal-autofill-selected {
|
input:-internal-autofill-selected {
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
|
}
|
||||||
|
#banner {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 33.2%;
|
||||||
|
left: 0;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 1000; /* Ensures the banner is on top of other elements */
|
||||||
|
& > img {
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox old*/
|
||||||
|
@-moz-keyframes blink {
|
||||||
|
0% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes blink {
|
||||||
|
0% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* IE */
|
||||||
|
@-ms-keyframes blink {
|
||||||
|
0% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Opera and prob css3 final iteration */
|
||||||
|
@keyframes blink {
|
||||||
|
0% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.blink-image {
|
||||||
|
-moz-animation: blink normal 4s infinite ease-in-out; /* Firefox */
|
||||||
|
-webkit-animation: blink normal 4s infinite ease-in-out; /* Webkit */
|
||||||
|
-ms-animation: blink normal 4s infinite ease-in-out; /* IE */
|
||||||
|
animation: blink normal 4s infinite ease-in-out; /* Opera and prob css3 final iteration */
|
||||||
}
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
{"frames": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"filename": "CIRCLE.png",
|
||||||
|
"frame": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "CROSS.png",
|
||||||
|
"frame": {"x":12,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "DOWN.png",
|
||||||
|
"frame": {"x":24,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "L1.png",
|
||||||
|
"frame": {"x":36,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "L2.png",
|
||||||
|
"frame": {"x":48,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "L3.png",
|
||||||
|
"frame": {"x":60,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "LEFT.png",
|
||||||
|
"frame": {"x":72,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "R1.png",
|
||||||
|
"frame": {"x":84,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "R2.png",
|
||||||
|
"frame": {"x":96,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "R3.png",
|
||||||
|
"frame": {"x":108,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "RIGHT.png",
|
||||||
|
"frame": {"x":120,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SELECT.png",
|
||||||
|
"frame": {"x":132,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SQUARE.png",
|
||||||
|
"frame": {"x":144,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "START.png",
|
||||||
|
"frame": {"x":156,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "TOUCH.png",
|
||||||
|
"frame": {"x":168,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "TRIANGLE.png",
|
||||||
|
"frame": {"x":180,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "UP.png",
|
||||||
|
"frame": {"x":192,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
}],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "1.0",
|
||||||
|
"image": "dualshock.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {"w":204,"h":12},
|
||||||
|
"scale": "1",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:47df68ade4299adf7d334f25cb833ece:039b9ac469e3616fb9635a6a19cca50e:adc25708364be3d9e70074e95305c745$"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,596 @@
|
||||||
|
{"frames": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"filename": "0.png",
|
||||||
|
"frame": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "1.png",
|
||||||
|
"frame": {"x":12,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "2.png",
|
||||||
|
"frame": {"x":24,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "3.png",
|
||||||
|
"frame": {"x":36,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "4.png",
|
||||||
|
"frame": {"x":48,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "5.png",
|
||||||
|
"frame": {"x":60,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "6.png",
|
||||||
|
"frame": {"x":72,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "7.png",
|
||||||
|
"frame": {"x":84,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "8.png",
|
||||||
|
"frame": {"x":96,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "9.png",
|
||||||
|
"frame": {"x":108,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "A.png",
|
||||||
|
"frame": {"x":120,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ALT.png",
|
||||||
|
"frame": {"x":132,"y":0,"w":16,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12},
|
||||||
|
"sourceSize": {"w":16,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "B.png",
|
||||||
|
"frame": {"x":148,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "BACK.png",
|
||||||
|
"frame": {"x":160,"y":0,"w":24,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":24,"h":12},
|
||||||
|
"sourceSize": {"w":24,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C.png",
|
||||||
|
"frame": {"x":184,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "CTRL.png",
|
||||||
|
"frame": {"x":196,"y":0,"w":22,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":22,"h":12},
|
||||||
|
"sourceSize": {"w":22,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "D.png",
|
||||||
|
"frame": {"x":218,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "DEL.png",
|
||||||
|
"frame": {"x":230,"y":0,"w":17,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":17,"h":12},
|
||||||
|
"sourceSize": {"w":17,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "E.png",
|
||||||
|
"frame": {"x":247,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "END.png",
|
||||||
|
"frame": {"x":259,"y":0,"w":18,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":18,"h":12},
|
||||||
|
"sourceSize": {"w":18,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ENTER.png",
|
||||||
|
"frame": {"x":277,"y":0,"w":27,"h":11},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":27,"h":11},
|
||||||
|
"sourceSize": {"w":27,"h":11}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ESC.png",
|
||||||
|
"frame": {"x":304,"y":0,"w":17,"h":11},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":17,"h":11},
|
||||||
|
"sourceSize": {"w":17,"h":11}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F.png",
|
||||||
|
"frame": {"x":321,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F1.png",
|
||||||
|
"frame": {"x":333,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F2.png",
|
||||||
|
"frame": {"x":346,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F3.png",
|
||||||
|
"frame": {"x":359,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F4.png",
|
||||||
|
"frame": {"x":372,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F5.png",
|
||||||
|
"frame": {"x":385,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F6.png",
|
||||||
|
"frame": {"x":398,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F7.png",
|
||||||
|
"frame": {"x":411,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F8.png",
|
||||||
|
"frame": {"x":424,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F9.png",
|
||||||
|
"frame": {"x":437,"y":0,"w":13,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12},
|
||||||
|
"sourceSize": {"w":13,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F10.png",
|
||||||
|
"frame": {"x":450,"y":0,"w":16,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12},
|
||||||
|
"sourceSize": {"w":16,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F11.png",
|
||||||
|
"frame": {"x":466,"y":0,"w":15,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":15,"h":12},
|
||||||
|
"sourceSize": {"w":15,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "F12.png",
|
||||||
|
"frame": {"x":481,"y":0,"w":16,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12},
|
||||||
|
"sourceSize": {"w":16,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "G.png",
|
||||||
|
"frame": {"x":497,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "H.png",
|
||||||
|
"frame": {"x":509,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "HOME.png",
|
||||||
|
"frame": {"x":521,"y":0,"w":23,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":23,"h":12},
|
||||||
|
"sourceSize": {"w":23,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "I.png",
|
||||||
|
"frame": {"x":544,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "INS.png",
|
||||||
|
"frame": {"x":556,"y":0,"w":16,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12},
|
||||||
|
"sourceSize": {"w":16,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "J.png",
|
||||||
|
"frame": {"x":572,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "K.png",
|
||||||
|
"frame": {"x":584,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "KEY_ARROW_DOWN.png",
|
||||||
|
"frame": {"x":596,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "KEY_ARROW_LEFT.png",
|
||||||
|
"frame": {"x":608,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "KEY_ARROW_RIGHT.png",
|
||||||
|
"frame": {"x":620,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "KEY_ARROW_UP.png",
|
||||||
|
"frame": {"x":632,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "L.png",
|
||||||
|
"frame": {"x":644,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "LEFT_BRACKET.png",
|
||||||
|
"frame": {"x":656,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "M.png",
|
||||||
|
"frame": {"x":668,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "MINUS.png",
|
||||||
|
"frame": {"x":680,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "N.png",
|
||||||
|
"frame": {"x":692,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "O.png",
|
||||||
|
"frame": {"x":704,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "P.png",
|
||||||
|
"frame": {"x":716,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "PAGE_DOWN.png",
|
||||||
|
"frame": {"x":728,"y":0,"w":20,"h":11},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":20,"h":11},
|
||||||
|
"sourceSize": {"w":20,"h":11}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "PAGE_UP.png",
|
||||||
|
"frame": {"x":748,"y":0,"w":20,"h":11},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":20,"h":11},
|
||||||
|
"sourceSize": {"w":20,"h":11}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "PLUS.png",
|
||||||
|
"frame": {"x":768,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Q.png",
|
||||||
|
"frame": {"x":780,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "QUOTE.png",
|
||||||
|
"frame": {"x":792,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "R.png",
|
||||||
|
"frame": {"x":804,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "RIGHT_BRACKET.png",
|
||||||
|
"frame": {"x":816,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "S.png",
|
||||||
|
"frame": {"x":828,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SEMICOLON.png",
|
||||||
|
"frame": {"x":840,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SHIFT.png",
|
||||||
|
"frame": {"x":852,"y":0,"w":23,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":23,"h":12},
|
||||||
|
"sourceSize": {"w":23,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SPACE.png",
|
||||||
|
"frame": {"x":875,"y":0,"w":25,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":25,"h":12},
|
||||||
|
"sourceSize": {"w":25,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "T.png",
|
||||||
|
"frame": {"x":900,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "TAB.png",
|
||||||
|
"frame": {"x":912,"y":0,"w":19,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":12},
|
||||||
|
"sourceSize": {"w":19,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "TILDE.png",
|
||||||
|
"frame": {"x":931,"y":0,"w":15,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":15,"h":12},
|
||||||
|
"sourceSize": {"w":15,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "U.png",
|
||||||
|
"frame": {"x":946,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "V.png",
|
||||||
|
"frame": {"x":958,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "W.png",
|
||||||
|
"frame": {"x":970,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "X.png",
|
||||||
|
"frame": {"x":982,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Y.png",
|
||||||
|
"frame": {"x":994,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Z.png",
|
||||||
|
"frame": {"x":1006,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
}],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "1.0",
|
||||||
|
"image": "keyboard.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {"w":1018,"h":12},
|
||||||
|
"scale": "1",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:085d4353a5c4d18c90f82f8926710d72:45908b22b446cf7f4904d4e0b658b16a:bad03abb89ad027d879c383c13fd51bc$"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,140 @@
|
||||||
|
{"frames": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"filename": "Bumper_L.png",
|
||||||
|
"frame": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Bumper_R.png",
|
||||||
|
"frame": {"x":12,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "DOWN.png",
|
||||||
|
"frame": {"x":24,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "LEFT.png",
|
||||||
|
"frame": {"x":36,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "LS.png",
|
||||||
|
"frame": {"x":48,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "RIGHT.png",
|
||||||
|
"frame": {"x":60,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "RS.png",
|
||||||
|
"frame": {"x":72,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "SELECT.png",
|
||||||
|
"frame": {"x":84,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "START.png",
|
||||||
|
"frame": {"x":96,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Trigger_L.png",
|
||||||
|
"frame": {"x":108,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Trigger_R.png",
|
||||||
|
"frame": {"x":120,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "UP.png",
|
||||||
|
"frame": {"x":132,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "XB_Letter_A_OL.png",
|
||||||
|
"frame": {"x":144,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "XB_Letter_B_OL.png",
|
||||||
|
"frame": {"x":156,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "XB_Letter_X_OL.png",
|
||||||
|
"frame": {"x":168,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "XB_Letter_Y_OL.png",
|
||||||
|
"frame": {"x":180,"y":0,"w":12,"h":12},
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
|
||||||
|
"sourceSize": {"w":12,"h":12}
|
||||||
|
}],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "1.0",
|
||||||
|
"image": "xbox.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {"w":192,"h":12},
|
||||||
|
"scale": "1",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:dda9e220b2ea223723253388c465ea25:8ab4a5ecdc22848a8718a1285590a78c:7ad6008cd8fa3f9f4bfb17e0cfcbbb64$"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -1,5 +1,5 @@
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import UI from "./ui/ui";
|
import UI from "./ui/ui";
|
||||||
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
|
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
|
||||||
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
|
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
|
||||||
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
|
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
|
||||||
|
@ -131,8 +131,6 @@ export default class BattleScene extends SceneBase {
|
||||||
public fusionPaletteSwaps: boolean = true;
|
public fusionPaletteSwaps: boolean = true;
|
||||||
public enableTouchControls: boolean = false;
|
public enableTouchControls: boolean = false;
|
||||||
public enableVibration: boolean = false;
|
public enableVibration: boolean = false;
|
||||||
public gamepadSupport: boolean = false;
|
|
||||||
public abSwapped: boolean = false;
|
|
||||||
|
|
||||||
public disableMenu: boolean = false;
|
public disableMenu: boolean = false;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
|
const cfg_keyboard_qwerty = {
|
||||||
|
padID: "default",
|
||||||
|
padType: "keyboard",
|
||||||
|
deviceMapping: {
|
||||||
|
KEY_A: Phaser.Input.Keyboard.KeyCodes.A,
|
||||||
|
KEY_B: Phaser.Input.Keyboard.KeyCodes.B,
|
||||||
|
KEY_C: Phaser.Input.Keyboard.KeyCodes.C,
|
||||||
|
KEY_D: Phaser.Input.Keyboard.KeyCodes.D,
|
||||||
|
KEY_E: Phaser.Input.Keyboard.KeyCodes.E,
|
||||||
|
KEY_F: Phaser.Input.Keyboard.KeyCodes.F,
|
||||||
|
KEY_G: Phaser.Input.Keyboard.KeyCodes.G,
|
||||||
|
KEY_H: Phaser.Input.Keyboard.KeyCodes.H,
|
||||||
|
KEY_I: Phaser.Input.Keyboard.KeyCodes.I,
|
||||||
|
KEY_J: Phaser.Input.Keyboard.KeyCodes.J,
|
||||||
|
KEY_K: Phaser.Input.Keyboard.KeyCodes.K,
|
||||||
|
KEY_L: Phaser.Input.Keyboard.KeyCodes.L,
|
||||||
|
KEY_M: Phaser.Input.Keyboard.KeyCodes.M,
|
||||||
|
KEY_N: Phaser.Input.Keyboard.KeyCodes.N,
|
||||||
|
KEY_O: Phaser.Input.Keyboard.KeyCodes.O,
|
||||||
|
KEY_P: Phaser.Input.Keyboard.KeyCodes.P,
|
||||||
|
KEY_Q: Phaser.Input.Keyboard.KeyCodes.Q,
|
||||||
|
KEY_R: Phaser.Input.Keyboard.KeyCodes.R,
|
||||||
|
KEY_S: Phaser.Input.Keyboard.KeyCodes.S,
|
||||||
|
KEY_T: Phaser.Input.Keyboard.KeyCodes.T,
|
||||||
|
KEY_U: Phaser.Input.Keyboard.KeyCodes.U,
|
||||||
|
KEY_V: Phaser.Input.Keyboard.KeyCodes.V,
|
||||||
|
KEY_W: Phaser.Input.Keyboard.KeyCodes.W,
|
||||||
|
KEY_X: Phaser.Input.Keyboard.KeyCodes.X,
|
||||||
|
KEY_Y: Phaser.Input.Keyboard.KeyCodes.Y,
|
||||||
|
KEY_Z: Phaser.Input.Keyboard.KeyCodes.Z,
|
||||||
|
KEY_0: Phaser.Input.Keyboard.KeyCodes.ZERO,
|
||||||
|
KEY_1: Phaser.Input.Keyboard.KeyCodes.ONE,
|
||||||
|
KEY_2: Phaser.Input.Keyboard.KeyCodes.TWO,
|
||||||
|
KEY_3: Phaser.Input.Keyboard.KeyCodes.THREE,
|
||||||
|
KEY_4: Phaser.Input.Keyboard.KeyCodes.FOUR,
|
||||||
|
KEY_5: Phaser.Input.Keyboard.KeyCodes.FIVE,
|
||||||
|
KEY_6: Phaser.Input.Keyboard.KeyCodes.SIX,
|
||||||
|
KEY_7: Phaser.Input.Keyboard.KeyCodes.SEVEN,
|
||||||
|
KEY_8: Phaser.Input.Keyboard.KeyCodes.EIGHT,
|
||||||
|
KEY_9: Phaser.Input.Keyboard.KeyCodes.NINE,
|
||||||
|
KEY_CTRL: Phaser.Input.Keyboard.KeyCodes.CTRL,
|
||||||
|
KEY_DEL: Phaser.Input.Keyboard.KeyCodes.DELETE,
|
||||||
|
KEY_END: Phaser.Input.Keyboard.KeyCodes.END,
|
||||||
|
KEY_ENTER: Phaser.Input.Keyboard.KeyCodes.ENTER,
|
||||||
|
KEY_ESC: Phaser.Input.Keyboard.KeyCodes.ESC,
|
||||||
|
KEY_F1: Phaser.Input.Keyboard.KeyCodes.F1,
|
||||||
|
KEY_F2: Phaser.Input.Keyboard.KeyCodes.F2,
|
||||||
|
KEY_F3: Phaser.Input.Keyboard.KeyCodes.F3,
|
||||||
|
KEY_F4: Phaser.Input.Keyboard.KeyCodes.F4,
|
||||||
|
KEY_F5: Phaser.Input.Keyboard.KeyCodes.F5,
|
||||||
|
KEY_F6: Phaser.Input.Keyboard.KeyCodes.F6,
|
||||||
|
KEY_F7: Phaser.Input.Keyboard.KeyCodes.F7,
|
||||||
|
KEY_F8: Phaser.Input.Keyboard.KeyCodes.F8,
|
||||||
|
KEY_F9: Phaser.Input.Keyboard.KeyCodes.F9,
|
||||||
|
KEY_F10: Phaser.Input.Keyboard.KeyCodes.F10,
|
||||||
|
KEY_F11: Phaser.Input.Keyboard.KeyCodes.F11,
|
||||||
|
KEY_F12: Phaser.Input.Keyboard.KeyCodes.F12,
|
||||||
|
KEY_HOME: Phaser.Input.Keyboard.KeyCodes.HOME,
|
||||||
|
KEY_INSERT: Phaser.Input.Keyboard.KeyCodes.INSERT,
|
||||||
|
KEY_PAGE_DOWN: Phaser.Input.Keyboard.KeyCodes.PAGE_DOWN,
|
||||||
|
KEY_PAGE_UP: Phaser.Input.Keyboard.KeyCodes.PAGE_UP,
|
||||||
|
KEY_PLUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_ADD, // Assuming numpad plus
|
||||||
|
KEY_MINUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_SUBTRACT, // Assuming numpad minus
|
||||||
|
KEY_QUOTATION: Phaser.Input.Keyboard.KeyCodes.QUOTES,
|
||||||
|
KEY_SHIFT: Phaser.Input.Keyboard.KeyCodes.SHIFT,
|
||||||
|
KEY_SPACE: Phaser.Input.Keyboard.KeyCodes.SPACE,
|
||||||
|
KEY_TAB: Phaser.Input.Keyboard.KeyCodes.TAB,
|
||||||
|
KEY_TILDE: Phaser.Input.Keyboard.KeyCodes.BACKTICK,
|
||||||
|
KEY_ARROW_UP: Phaser.Input.Keyboard.KeyCodes.UP,
|
||||||
|
KEY_ARROW_DOWN: Phaser.Input.Keyboard.KeyCodes.DOWN,
|
||||||
|
KEY_ARROW_LEFT: Phaser.Input.Keyboard.KeyCodes.LEFT,
|
||||||
|
KEY_ARROW_RIGHT: Phaser.Input.Keyboard.KeyCodes.RIGHT,
|
||||||
|
KEY_LEFT_BRACKET: Phaser.Input.Keyboard.KeyCodes.OPEN_BRACKET,
|
||||||
|
KEY_RIGHT_BRACKET: Phaser.Input.Keyboard.KeyCodes.CLOSED_BRACKET,
|
||||||
|
KEY_SEMICOLON: Phaser.Input.Keyboard.KeyCodes.SEMICOLON,
|
||||||
|
KEY_BACKSPACE: Phaser.Input.Keyboard.KeyCodes.BACKSPACE,
|
||||||
|
KEY_ALT: Phaser.Input.Keyboard.KeyCodes.ALT
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
KEY_A: "A.png",
|
||||||
|
KEY_B: "B.png",
|
||||||
|
KEY_C: "C.png",
|
||||||
|
KEY_D: "D.png",
|
||||||
|
KEY_E: "E.png",
|
||||||
|
KEY_F: "F.png",
|
||||||
|
KEY_G: "G.png",
|
||||||
|
KEY_H: "H.png",
|
||||||
|
KEY_I: "I.png",
|
||||||
|
KEY_J: "J.png",
|
||||||
|
KEY_K: "K.png",
|
||||||
|
KEY_L: "L.png",
|
||||||
|
KEY_M: "M.png",
|
||||||
|
KEY_N: "N.png",
|
||||||
|
KEY_O: "O.png",
|
||||||
|
KEY_P: "P.png",
|
||||||
|
KEY_Q: "Q.png",
|
||||||
|
KEY_R: "R.png",
|
||||||
|
KEY_S: "S.png",
|
||||||
|
KEY_T: "T.png",
|
||||||
|
KEY_U: "U.png",
|
||||||
|
KEY_V: "V.png",
|
||||||
|
KEY_W: "W.png",
|
||||||
|
KEY_X: "X.png",
|
||||||
|
KEY_Y: "Y.png",
|
||||||
|
KEY_Z: "Z.png",
|
||||||
|
|
||||||
|
KEY_0: "0.png",
|
||||||
|
KEY_1: "1.png",
|
||||||
|
KEY_2: "2.png",
|
||||||
|
KEY_3: "3.png",
|
||||||
|
KEY_4: "4.png",
|
||||||
|
KEY_5: "5.png",
|
||||||
|
KEY_6: "6.png",
|
||||||
|
KEY_7: "7.png",
|
||||||
|
KEY_8: "8.png",
|
||||||
|
KEY_9: "9.png",
|
||||||
|
|
||||||
|
KEY_F1: "F1.png",
|
||||||
|
KEY_F2: "F2.png",
|
||||||
|
KEY_F3: "F3.png",
|
||||||
|
KEY_F4: "F4.png",
|
||||||
|
KEY_F5: "F5.png",
|
||||||
|
KEY_F6: "F6.png",
|
||||||
|
KEY_F7: "F7.png",
|
||||||
|
KEY_F8: "F8.png",
|
||||||
|
KEY_F9: "F9.png",
|
||||||
|
KEY_F10: "F10.png",
|
||||||
|
KEY_F11: "F11.png",
|
||||||
|
KEY_F12: "F12.png",
|
||||||
|
|
||||||
|
|
||||||
|
KEY_PAGE_DOWN: "PAGE_DOWN.png",
|
||||||
|
KEY_PAGE_UP: "PAGE_UP.png",
|
||||||
|
|
||||||
|
KEY_CTRL: "CTRL.png",
|
||||||
|
KEY_DEL: "DEL.png",
|
||||||
|
KEY_END: "END.png",
|
||||||
|
KEY_ENTER: "ENTER.png",
|
||||||
|
KEY_ESC: "ESC.png",
|
||||||
|
KEY_HOME: "HOME.png",
|
||||||
|
KEY_INSERT: "INS.png",
|
||||||
|
|
||||||
|
KEY_PLUS: "PLUS.png",
|
||||||
|
KEY_MINUS: "MINUS.png",
|
||||||
|
KEY_QUOTATION: "QUOTE.png",
|
||||||
|
KEY_SHIFT: "SHIFT.png",
|
||||||
|
|
||||||
|
KEY_SPACE: "SPACE.png",
|
||||||
|
KEY_TAB: "TAB.png",
|
||||||
|
KEY_TILDE: "TILDE.png",
|
||||||
|
|
||||||
|
KEY_ARROW_UP: "KEY_ARROW_UP.png",
|
||||||
|
KEY_ARROW_DOWN: "KEY_ARROW_DOWN.png",
|
||||||
|
KEY_ARROW_LEFT: "KEY_ARROW_LEFT.png",
|
||||||
|
KEY_ARROW_RIGHT: "KEY_ARROW_RIGHT.png",
|
||||||
|
|
||||||
|
KEY_LEFT_BRACKET: "LEFT_BRACKET.png",
|
||||||
|
KEY_RIGHT_BRACKET: "RIGHT_BRACKET.png",
|
||||||
|
|
||||||
|
KEY_SEMICOLON: "SEMICOLON.png",
|
||||||
|
|
||||||
|
KEY_BACKSPACE: "BACK.png",
|
||||||
|
KEY_ALT: "ALT.png"
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingKeyboard.Button_Up]: Button.UP,
|
||||||
|
[SettingKeyboard.Button_Down]: Button.DOWN,
|
||||||
|
[SettingKeyboard.Button_Left]: Button.LEFT,
|
||||||
|
[SettingKeyboard.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingKeyboard.Button_Submit]: Button.SUBMIT,
|
||||||
|
[SettingKeyboard.Button_Action]: Button.ACTION,
|
||||||
|
[SettingKeyboard.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingKeyboard.Button_Menu]: Button.MENU,
|
||||||
|
[SettingKeyboard.Button_Stats]: Button.STATS,
|
||||||
|
[SettingKeyboard.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingKeyboard.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingKeyboard.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingKeyboard.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingKeyboard.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingKeyboard.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingKeyboard.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingKeyboard.Button_Slow_Down]: Button.SLOW_DOWN,
|
||||||
|
[SettingKeyboard.Alt_Button_Up]: Button.UP,
|
||||||
|
[SettingKeyboard.Alt_Button_Down]: Button.DOWN,
|
||||||
|
[SettingKeyboard.Alt_Button_Left]: Button.LEFT,
|
||||||
|
[SettingKeyboard.Alt_Button_Right]: Button.RIGHT,
|
||||||
|
[SettingKeyboard.Alt_Button_Submit]: Button.SUBMIT,
|
||||||
|
[SettingKeyboard.Alt_Button_Action]: Button.ACTION,
|
||||||
|
[SettingKeyboard.Alt_Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingKeyboard.Alt_Button_Menu]: Button.MENU,
|
||||||
|
[SettingKeyboard.Alt_Button_Stats]: Button.STATS,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingKeyboard.Alt_Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingKeyboard.Alt_Button_Slow_Down]: Button.SLOW_DOWN,
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
KEY_ARROW_UP: SettingKeyboard.Button_Up,
|
||||||
|
KEY_ARROW_DOWN: SettingKeyboard.Button_Down,
|
||||||
|
KEY_ARROW_LEFT: SettingKeyboard.Button_Left,
|
||||||
|
KEY_ARROW_RIGHT: SettingKeyboard.Button_Right,
|
||||||
|
KEY_ENTER: SettingKeyboard.Button_Submit,
|
||||||
|
KEY_SPACE: SettingKeyboard.Button_Action,
|
||||||
|
KEY_BACKSPACE: SettingKeyboard.Button_Cancel,
|
||||||
|
KEY_ESC: SettingKeyboard.Button_Menu,
|
||||||
|
KEY_C: SettingKeyboard.Button_Stats,
|
||||||
|
KEY_R: SettingKeyboard.Button_Cycle_Shiny,
|
||||||
|
KEY_F: SettingKeyboard.Button_Cycle_Form,
|
||||||
|
KEY_G: SettingKeyboard.Button_Cycle_Gender,
|
||||||
|
KEY_E: SettingKeyboard.Button_Cycle_Ability,
|
||||||
|
KEY_N: SettingKeyboard.Button_Cycle_Nature,
|
||||||
|
KEY_V: SettingKeyboard.Button_Cycle_Variant,
|
||||||
|
KEY_PLUS: -1,
|
||||||
|
KEY_MINUS: -1,
|
||||||
|
KEY_A: SettingKeyboard.Alt_Button_Left,
|
||||||
|
KEY_B: -1,
|
||||||
|
KEY_D: SettingKeyboard.Alt_Button_Right,
|
||||||
|
KEY_H: -1,
|
||||||
|
KEY_I: -1,
|
||||||
|
KEY_J: -1,
|
||||||
|
KEY_K: -1,
|
||||||
|
KEY_L: -1,
|
||||||
|
KEY_M: SettingKeyboard.Alt_Button_Menu,
|
||||||
|
KEY_O: -1,
|
||||||
|
KEY_P: -1,
|
||||||
|
KEY_Q: -1,
|
||||||
|
KEY_S: SettingKeyboard.Alt_Button_Down,
|
||||||
|
KEY_T: SettingKeyboard.Alt_Button_Cycle_Form,
|
||||||
|
KEY_U: -1,
|
||||||
|
KEY_W: SettingKeyboard.Alt_Button_Up,
|
||||||
|
KEY_X: SettingKeyboard.Alt_Button_Cancel,
|
||||||
|
KEY_Y: SettingKeyboard.Alt_Button_Cycle_Shiny,
|
||||||
|
KEY_Z: SettingKeyboard.Alt_Button_Action,
|
||||||
|
KEY_0: -1,
|
||||||
|
KEY_1: -1,
|
||||||
|
KEY_2: -1,
|
||||||
|
KEY_3: -1,
|
||||||
|
KEY_4: -1,
|
||||||
|
KEY_5: -1,
|
||||||
|
KEY_6: -1,
|
||||||
|
KEY_7: -1,
|
||||||
|
KEY_8: -1,
|
||||||
|
KEY_9: -1,
|
||||||
|
KEY_CTRL: -1,
|
||||||
|
KEY_DEL: -1,
|
||||||
|
KEY_END: -1,
|
||||||
|
KEY_F1: -1,
|
||||||
|
KEY_F2: -1,
|
||||||
|
KEY_F3: -1,
|
||||||
|
KEY_F4: -1,
|
||||||
|
KEY_F5: -1,
|
||||||
|
KEY_F6: -1,
|
||||||
|
KEY_F7: -1,
|
||||||
|
KEY_F8: -1,
|
||||||
|
KEY_F9: -1,
|
||||||
|
KEY_F10: -1,
|
||||||
|
KEY_F11: -1,
|
||||||
|
KEY_F12: -1,
|
||||||
|
KEY_HOME: -1,
|
||||||
|
KEY_INSERT: -1,
|
||||||
|
KEY_PAGE_DOWN: SettingKeyboard.Button_Slow_Down,
|
||||||
|
KEY_PAGE_UP: SettingKeyboard.Button_Speed_Up,
|
||||||
|
KEY_QUOTATION: -1,
|
||||||
|
KEY_SHIFT: SettingKeyboard.Alt_Button_Stats,
|
||||||
|
KEY_TAB: -1,
|
||||||
|
KEY_TILDE: -1,
|
||||||
|
KEY_LEFT_BRACKET: -1,
|
||||||
|
KEY_RIGHT_BRACKET: -1,
|
||||||
|
KEY_SEMICOLON: -1,
|
||||||
|
KEY_ALT: -1
|
||||||
|
},
|
||||||
|
blacklist: [
|
||||||
|
"KEY_ENTER",
|
||||||
|
"KEY_ESC",
|
||||||
|
"KEY_SPACE",
|
||||||
|
"KEY_BACKSPACE",
|
||||||
|
"KEY_ARROW_UP",
|
||||||
|
"KEY_ARROW_DOWN",
|
||||||
|
"KEY_ARROW_LEFT",
|
||||||
|
"KEY_ARROW_RIGHT",
|
||||||
|
"KEY_DEL",
|
||||||
|
"KEY_HOME",
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default cfg_keyboard_qwerty;
|
|
@ -0,0 +1,208 @@
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the key associated with the specified keycode from the mapping.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing the mapping.
|
||||||
|
* @param keycode - The keycode to search for.
|
||||||
|
* @returns The key associated with the specified keycode.
|
||||||
|
*/
|
||||||
|
export function getKeyWithKeycode(config, keycode) {
|
||||||
|
return Object.keys(config.deviceMapping).find(key => config.deviceMapping[key] === keycode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the setting name associated with the specified keycode.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing custom settings.
|
||||||
|
* @param keycode - The keycode to search for.
|
||||||
|
* @returns The setting name associated with the specified keycode.
|
||||||
|
*/
|
||||||
|
export function getSettingNameWithKeycode(config, keycode) {
|
||||||
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
|
return config.custom[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the icon associated with the specified keycode.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing icons.
|
||||||
|
* @param keycode - The keycode to search for.
|
||||||
|
* @returns The icon associated with the specified keycode.
|
||||||
|
*/
|
||||||
|
export function getIconWithKeycode(config, keycode) {
|
||||||
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
|
return config.icons[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the button associated with the specified keycode.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing settings.
|
||||||
|
* @param keycode - The keycode to search for.
|
||||||
|
* @returns The button associated with the specified keycode.
|
||||||
|
*/
|
||||||
|
export function getButtonWithKeycode(config, keycode) {
|
||||||
|
const settingName = getSettingNameWithKeycode(config, keycode);
|
||||||
|
return config.settings[settingName];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the key associated with the specified setting name.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing custom settings.
|
||||||
|
* @param settingName - The setting name to search for.
|
||||||
|
* @returns The key associated with the specified setting name.
|
||||||
|
*/
|
||||||
|
export function getKeyWithSettingName(config, settingName) {
|
||||||
|
return Object.keys(config.custom).find(key => config.custom[key] === settingName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the setting name associated with the specified key.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing custom settings.
|
||||||
|
* @param key - The key to search for.
|
||||||
|
* @returns The setting name associated with the specified key.
|
||||||
|
*/
|
||||||
|
export function getSettingNameWithKey(config, key) {
|
||||||
|
return config.custom[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the icon associated with the specified key.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing icons.
|
||||||
|
* @param key - The key to search for.
|
||||||
|
* @returns The icon associated with the specified key.
|
||||||
|
*/
|
||||||
|
export function getIconWithKey(config, key) {
|
||||||
|
return config.icons[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the icon associated with the specified setting name.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing icons.
|
||||||
|
* @param settingName - The setting name to search for.
|
||||||
|
* @returns The icon associated with the specified setting name.
|
||||||
|
*/
|
||||||
|
export function getIconWithSettingName(config, settingName) {
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
return getIconWithKey(config, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIconForLatestInput(configs, source, devices, settingName) {
|
||||||
|
let config;
|
||||||
|
if (source === "gamepad") {
|
||||||
|
config = configs[devices[Device.GAMEPAD]];
|
||||||
|
} else {
|
||||||
|
config = configs[devices[Device.KEYBOARD]];
|
||||||
|
}
|
||||||
|
const icon = getIconWithSettingName(config, settingName);
|
||||||
|
if (!icon) {
|
||||||
|
const isAlt = settingName.includes("ALT_");
|
||||||
|
let altSettingName;
|
||||||
|
if (isAlt) {
|
||||||
|
altSettingName = settingName.split("ALT_").splice(1)[0];
|
||||||
|
} else {
|
||||||
|
altSettingName = `ALT_${settingName}`;
|
||||||
|
}
|
||||||
|
return getIconWithSettingName(config, altSettingName);
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assign(config, settingNameTarget, keycode): boolean {
|
||||||
|
// first, we need to check if this keycode is already used on another settingName
|
||||||
|
if (!canIAssignThisKey(config, getKeyWithKeycode(config, keycode)) || !canIOverrideThisSetting(config, settingNameTarget)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const previousSettingName = getSettingNameWithKeycode(config, keycode);
|
||||||
|
// if it was already bound, we delete the bind
|
||||||
|
if (previousSettingName) {
|
||||||
|
const previousKey = getKeyWithSettingName(config, previousSettingName);
|
||||||
|
config.custom[previousKey] = -1;
|
||||||
|
}
|
||||||
|
// then, we need to delete the current key for this settingName
|
||||||
|
const currentKey = getKeyWithSettingName(config, settingNameTarget);
|
||||||
|
config.custom[currentKey] = -1;
|
||||||
|
|
||||||
|
// then, the new key is assigned to the new settingName
|
||||||
|
const newKey = getKeyWithKeycode(config, keycode);
|
||||||
|
config.custom[newKey] = settingNameTarget;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swap(config, settingNameTarget, keycode) {
|
||||||
|
// only for gamepad
|
||||||
|
if (config.padType === "keyboard") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const prev_key = getKeyWithSettingName(config, settingNameTarget);
|
||||||
|
const prev_settingName = getSettingNameWithKey(config, prev_key);
|
||||||
|
|
||||||
|
const new_key = getKeyWithKeycode(config, keycode);
|
||||||
|
const new_settingName = getSettingNameWithKey(config, new_key);
|
||||||
|
|
||||||
|
config.custom[prev_key] = new_settingName;
|
||||||
|
config.custom[new_key] = prev_settingName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the binding of the specified setting name.
|
||||||
|
*
|
||||||
|
* @param config - The configuration object containing custom settings.
|
||||||
|
* @param settingName - The setting name to delete.
|
||||||
|
*/
|
||||||
|
export function deleteBind(config, settingName) {
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
if (config.blacklist.includes(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
config.custom[key] = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canIAssignThisKey(config, key) {
|
||||||
|
const settingName = getSettingNameWithKey(config, key);
|
||||||
|
if (config.blacklist?.includes(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (settingName === -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// if (isTheLatestBind(config, settingName)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canIOverrideThisSetting(config, settingName) {
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
// || isTheLatestBind(config, settingName) no longer needed since action and cancel are protected
|
||||||
|
if (config.blacklist?.includes(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canIDeleteThisKey(config, key) {
|
||||||
|
return canIAssignThisKey(config, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function isTheLatestBind(config, settingName) {
|
||||||
|
// if (config.padType !== "keyboard") {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// const isAlt = settingName.includes("ALT_");
|
||||||
|
// let altSettingName;
|
||||||
|
// if (isAlt) {
|
||||||
|
// altSettingName = settingName.split("ALT_").splice(1)[0];
|
||||||
|
// } else {
|
||||||
|
// altSettingName = `ALT_${settingName}`;
|
||||||
|
// }
|
||||||
|
// const secondButton = getKeyWithSettingName(config, altSettingName);
|
||||||
|
// return secondButton === undefined;
|
||||||
|
// }
|
|
@ -0,0 +1,88 @@
|
||||||
|
import {SettingGamepad} from "../../system/settings-gamepad";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dualshock mapping
|
||||||
|
*/
|
||||||
|
const pad_dualshock = {
|
||||||
|
padID: "Dualshock",
|
||||||
|
padType: "dualshock",
|
||||||
|
deviceMapping: {
|
||||||
|
RC_S: 0,
|
||||||
|
RC_E: 1,
|
||||||
|
RC_W: 2,
|
||||||
|
RC_N: 3,
|
||||||
|
START: 9, // Options
|
||||||
|
SELECT: 8, // Share
|
||||||
|
LB: 4,
|
||||||
|
RB: 5,
|
||||||
|
LT: 6,
|
||||||
|
RT: 7,
|
||||||
|
LS: 10,
|
||||||
|
RS: 11,
|
||||||
|
LC_N: 12,
|
||||||
|
LC_S: 13,
|
||||||
|
LC_W: 14,
|
||||||
|
LC_E: 15,
|
||||||
|
TOUCH: 17
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
RC_S: "CROSS.png",
|
||||||
|
RC_E: "CIRCLE.png",
|
||||||
|
RC_W: "SQUARE.png",
|
||||||
|
RC_N: "TRIANGLE.png",
|
||||||
|
START: "START.png",
|
||||||
|
SELECT: "SELECT.png",
|
||||||
|
LB: "L1.png",
|
||||||
|
RB: "R1.png",
|
||||||
|
LT: "L2.png",
|
||||||
|
RT: "R2.png",
|
||||||
|
LS: "L3.png",
|
||||||
|
RS: "R3.png",
|
||||||
|
LC_N: "UP.png",
|
||||||
|
LC_S: "DOWN.png",
|
||||||
|
LC_W: "LEFT.png",
|
||||||
|
LC_E: "RIGHT.png",
|
||||||
|
TOUCH: "TOUCH.png"
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingGamepad.Button_Up]: Button.UP,
|
||||||
|
[SettingGamepad.Button_Down]: Button.DOWN,
|
||||||
|
[SettingGamepad.Button_Left]: Button.LEFT,
|
||||||
|
[SettingGamepad.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN,
|
||||||
|
[SettingGamepad.Button_Submit]: Button.SUBMIT
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
LC_N: SettingGamepad.Button_Up,
|
||||||
|
LC_S: SettingGamepad.Button_Down,
|
||||||
|
LC_W: SettingGamepad.Button_Left,
|
||||||
|
LC_E: SettingGamepad.Button_Right,
|
||||||
|
RC_S: SettingGamepad.Button_Action,
|
||||||
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
|
RC_N: SettingGamepad.Button_Cycle_Variant,
|
||||||
|
START: SettingGamepad.Button_Menu,
|
||||||
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
RB: SettingGamepad.Button_Cycle_Shiny,
|
||||||
|
LT: SettingGamepad.Button_Cycle_Gender,
|
||||||
|
RT: SettingGamepad.Button_Cycle_Ability,
|
||||||
|
LS: SettingGamepad.Button_Speed_Up,
|
||||||
|
RS: SettingGamepad.Button_Slow_Down,
|
||||||
|
TOUCH: SettingGamepad.Button_Submit,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pad_dualshock;
|
|
@ -0,0 +1,90 @@
|
||||||
|
import {SettingGamepad} from "../../system/settings-gamepad";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic pad mapping
|
||||||
|
*/
|
||||||
|
const pad_generic = {
|
||||||
|
padID: "Generic",
|
||||||
|
padType: "xbox",
|
||||||
|
deviceMapping: {
|
||||||
|
RC_S: 0,
|
||||||
|
RC_E: 1,
|
||||||
|
RC_W: 2,
|
||||||
|
RC_N: 3,
|
||||||
|
START: 9,
|
||||||
|
SELECT: 8,
|
||||||
|
LB: 4,
|
||||||
|
RB: 5,
|
||||||
|
LT: 6,
|
||||||
|
RT: 7,
|
||||||
|
LS: 10,
|
||||||
|
RS: 11,
|
||||||
|
LC_N: 12,
|
||||||
|
LC_S: 13,
|
||||||
|
LC_W: 14,
|
||||||
|
LC_E: 15
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
RC_S: "XB_Letter_A_OL.png",
|
||||||
|
RC_E: "XB_Letter_B_OL.png",
|
||||||
|
RC_W: "XB_Letter_X_OL.png",
|
||||||
|
RC_N: "XB_Letter_Y_OL.png",
|
||||||
|
START: "START.png",
|
||||||
|
SELECT: "SELECT.png",
|
||||||
|
LB: "Bumper_L.png",
|
||||||
|
RB: "Bumper_R.png",
|
||||||
|
LT: "Trigger_L.png",
|
||||||
|
RT: "Trigger_R.png",
|
||||||
|
LS: "LS.png",
|
||||||
|
RS: "RS.png",
|
||||||
|
LC_N: "UP.png",
|
||||||
|
LC_S: "DOWN.png",
|
||||||
|
LC_W: "LEFT.png",
|
||||||
|
LC_E: "RIGHT.png",
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingGamepad.Button_Up]: Button.UP,
|
||||||
|
[SettingGamepad.Button_Down]: Button.DOWN,
|
||||||
|
[SettingGamepad.Button_Left]: Button.LEFT,
|
||||||
|
[SettingGamepad.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
LC_N: SettingGamepad.Button_Up,
|
||||||
|
LC_S: SettingGamepad.Button_Down,
|
||||||
|
LC_W: SettingGamepad.Button_Left,
|
||||||
|
LC_E: SettingGamepad.Button_Right,
|
||||||
|
RC_S: SettingGamepad.Button_Action,
|
||||||
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
|
RC_N: SettingGamepad.Button_Cycle_Variant,
|
||||||
|
START: SettingGamepad.Button_Menu,
|
||||||
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
RB: SettingGamepad.Button_Cycle_Shiny,
|
||||||
|
LT: SettingGamepad.Button_Cycle_Gender,
|
||||||
|
RT: SettingGamepad.Button_Cycle_Ability,
|
||||||
|
LS: SettingGamepad.Button_Speed_Up,
|
||||||
|
RS: SettingGamepad.Button_Slow_Down
|
||||||
|
},
|
||||||
|
blacklist: [
|
||||||
|
"LC_N",
|
||||||
|
"LC_S",
|
||||||
|
"LC_W",
|
||||||
|
"LC_E",
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pad_generic;
|
|
@ -0,0 +1,85 @@
|
||||||
|
import {SettingGamepad} from "#app/system/settings-gamepad";
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nintendo Pro Controller mapping
|
||||||
|
*/
|
||||||
|
const pad_procon = {
|
||||||
|
padID: "Pro Controller",
|
||||||
|
padType: "xbox",
|
||||||
|
deviceMapping: {
|
||||||
|
RC_S: 1,
|
||||||
|
RC_E: 0,
|
||||||
|
RC_W: 3,
|
||||||
|
RC_N: 2,
|
||||||
|
START: 9, // +
|
||||||
|
SELECT: 8, // -
|
||||||
|
LB: 4,
|
||||||
|
RB: 5,
|
||||||
|
LT: 6,
|
||||||
|
RT: 7,
|
||||||
|
LS: 10,
|
||||||
|
RS: 11,
|
||||||
|
LC_N: 12,
|
||||||
|
LC_S: 13,
|
||||||
|
LC_W: 14,
|
||||||
|
LC_E: 15,
|
||||||
|
MENU: 16, // Home
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
RC_S: "XB_Letter_B_OL.png",
|
||||||
|
RC_E: "XB_Letter_A_OL.png",
|
||||||
|
RC_W: "XB_Letter_Y_OL.png",
|
||||||
|
RC_N: "XB_Letter_X_OL.png",
|
||||||
|
START: "START.png",
|
||||||
|
SELECT: "SELECT.png",
|
||||||
|
LB: "Bumper_L.png",
|
||||||
|
RB: "Bumper_R.png",
|
||||||
|
LT: "Trigger_L.png",
|
||||||
|
RT: "Trigger_R.png",
|
||||||
|
LS: "LS.png",
|
||||||
|
RS: "RS.png",
|
||||||
|
LC_N: "UP.png",
|
||||||
|
LC_S: "DOWN.png",
|
||||||
|
LC_W: "LEFT.png",
|
||||||
|
LC_E: "RIGHT.png",
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingGamepad.Button_Up]: Button.UP,
|
||||||
|
[SettingGamepad.Button_Down]: Button.DOWN,
|
||||||
|
[SettingGamepad.Button_Left]: Button.LEFT,
|
||||||
|
[SettingGamepad.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
LC_N: SettingGamepad.Button_Up,
|
||||||
|
LC_S: SettingGamepad.Button_Down,
|
||||||
|
LC_W: SettingGamepad.Button_Left,
|
||||||
|
LC_E: SettingGamepad.Button_Right,
|
||||||
|
RC_S: SettingGamepad.Button_Action,
|
||||||
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
|
RC_N: SettingGamepad.Button_Cycle_Variant,
|
||||||
|
START: SettingGamepad.Button_Menu,
|
||||||
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
RB: SettingGamepad.Button_Cycle_Shiny,
|
||||||
|
LT: SettingGamepad.Button_Cycle_Gender,
|
||||||
|
RT: SettingGamepad.Button_Cycle_Ability,
|
||||||
|
LS: SettingGamepad.Button_Speed_Up,
|
||||||
|
RS: SettingGamepad.Button_Slow_Down
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pad_procon;
|
|
@ -0,0 +1,76 @@
|
||||||
|
import {SettingGamepad} from "../../system/settings-gamepad";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 081f-e401 - UnlicensedSNES
|
||||||
|
*/
|
||||||
|
const pad_unlicensedSNES = {
|
||||||
|
padID: "081f-e401",
|
||||||
|
padType: "xbox",
|
||||||
|
deviceMapping : {
|
||||||
|
RC_S: 2,
|
||||||
|
RC_E: 1,
|
||||||
|
RC_W: 3,
|
||||||
|
RC_N: 0,
|
||||||
|
START: 9,
|
||||||
|
SELECT: 8,
|
||||||
|
LB: 4,
|
||||||
|
RB: 5,
|
||||||
|
LC_N: 12,
|
||||||
|
LC_S: 13,
|
||||||
|
LC_W: 14,
|
||||||
|
LC_E: 15
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
RC_S: "XB_Letter_A_OL.png",
|
||||||
|
RC_E: "XB_Letter_B_OL.png",
|
||||||
|
RC_W: "XB_Letter_X_OL.png",
|
||||||
|
RC_N: "XB_Letter_Y_OL.png",
|
||||||
|
START: "START.png",
|
||||||
|
SELECT: "SELECT.png",
|
||||||
|
LB: "Bumper_L.png",
|
||||||
|
RB: "Bumper_R.png",
|
||||||
|
LC_N: "UP.png",
|
||||||
|
LC_S: "DOWN.png",
|
||||||
|
LC_W: "LEFT.png",
|
||||||
|
LC_E: "RIGHT.png",
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingGamepad.Button_Up]: Button.UP,
|
||||||
|
[SettingGamepad.Button_Down]: Button.DOWN,
|
||||||
|
[SettingGamepad.Button_Left]: Button.LEFT,
|
||||||
|
[SettingGamepad.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
LC_N: SettingGamepad.Button_Up,
|
||||||
|
LC_S: SettingGamepad.Button_Down,
|
||||||
|
LC_W: SettingGamepad.Button_Left,
|
||||||
|
LC_E: SettingGamepad.Button_Right,
|
||||||
|
RC_S: SettingGamepad.Button_Action,
|
||||||
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
|
RC_N: SettingGamepad.Button_Cycle_Variant,
|
||||||
|
START: SettingGamepad.Button_Menu,
|
||||||
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
RB: SettingGamepad.Button_Cycle_Shiny,
|
||||||
|
LT: -1,
|
||||||
|
RT: -1,
|
||||||
|
LS: -1,
|
||||||
|
RS: -1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pad_unlicensedSNES;
|
|
@ -0,0 +1,84 @@
|
||||||
|
import {SettingGamepad} from "../../system/settings-gamepad";
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic pad mapping
|
||||||
|
*/
|
||||||
|
const pad_xbox360 = {
|
||||||
|
padID: "Xbox 360 controller (XInput STANDARD GAMEPAD)",
|
||||||
|
padType: "xbox",
|
||||||
|
deviceMapping: {
|
||||||
|
RC_S: 0,
|
||||||
|
RC_E: 1,
|
||||||
|
RC_W: 2,
|
||||||
|
RC_N: 3,
|
||||||
|
START: 9,
|
||||||
|
SELECT: 8,
|
||||||
|
LB: 4,
|
||||||
|
RB: 5,
|
||||||
|
LT: 6,
|
||||||
|
RT: 7,
|
||||||
|
LS: 10,
|
||||||
|
RS: 11,
|
||||||
|
LC_N: 12,
|
||||||
|
LC_S: 13,
|
||||||
|
LC_W: 14,
|
||||||
|
LC_E: 15
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
RC_S: "XB_Letter_A_OL.png",
|
||||||
|
RC_E: "XB_Letter_B_OL.png",
|
||||||
|
RC_W: "XB_Letter_X_OL.png",
|
||||||
|
RC_N: "XB_Letter_Y_OL.png",
|
||||||
|
START: "START.png",
|
||||||
|
SELECT: "SELECT.png",
|
||||||
|
LB: "Bumper_L.png",
|
||||||
|
RB: "Bumper_R.png",
|
||||||
|
LT: "Trigger_L.png",
|
||||||
|
RT: "Trigger_R.png",
|
||||||
|
LS: "LS.png",
|
||||||
|
RS: "RS.png",
|
||||||
|
LC_N: "UP.png",
|
||||||
|
LC_S: "DOWN.png",
|
||||||
|
LC_W: "LEFT.png",
|
||||||
|
LC_E: "RIGHT.png",
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
[SettingGamepad.Button_Up]: Button.UP,
|
||||||
|
[SettingGamepad.Button_Down]: Button.DOWN,
|
||||||
|
[SettingGamepad.Button_Left]: Button.LEFT,
|
||||||
|
[SettingGamepad.Button_Right]: Button.RIGHT,
|
||||||
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
||||||
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: Button.CYCLE_SHINY,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
LC_N: SettingGamepad.Button_Up,
|
||||||
|
LC_S: SettingGamepad.Button_Down,
|
||||||
|
LC_W: SettingGamepad.Button_Left,
|
||||||
|
LC_E: SettingGamepad.Button_Right,
|
||||||
|
RC_S: SettingGamepad.Button_Action,
|
||||||
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
|
RC_N: SettingGamepad.Button_Cycle_Variant,
|
||||||
|
START: SettingGamepad.Button_Menu,
|
||||||
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
RB: SettingGamepad.Button_Cycle_Shiny,
|
||||||
|
LT: SettingGamepad.Button_Cycle_Gender,
|
||||||
|
RT: SettingGamepad.Button_Cycle_Ability,
|
||||||
|
LS: SettingGamepad.Button_Speed_Up,
|
||||||
|
RS: SettingGamepad.Button_Slow_Down
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default pad_xbox360;
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
* Dualshock mapping
|
|
||||||
*/
|
|
||||||
const pad_dualshock = {
|
|
||||||
padID: "Dualshock",
|
|
||||||
padType: "Sony",
|
|
||||||
gamepadMapping: {
|
|
||||||
RC_S: 0,
|
|
||||||
RC_E: 1,
|
|
||||||
RC_W: 2,
|
|
||||||
RC_N: 3,
|
|
||||||
START: 9, // Options
|
|
||||||
SELECT: 8, // Share
|
|
||||||
LB: 4,
|
|
||||||
RB: 5,
|
|
||||||
LT: 6,
|
|
||||||
RT: 7,
|
|
||||||
LS: 10,
|
|
||||||
RS: 11,
|
|
||||||
LC_N: 12,
|
|
||||||
LC_S: 13,
|
|
||||||
LC_W: 14,
|
|
||||||
LC_E: 15,
|
|
||||||
MENU: 16,
|
|
||||||
TOUCH: 17
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pad_dualshock;
|
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
* Generic pad mapping
|
|
||||||
*/
|
|
||||||
const pad_generic = {
|
|
||||||
padID: "Generic",
|
|
||||||
padType: "generic",
|
|
||||||
gamepadMapping: {
|
|
||||||
RC_S: 0,
|
|
||||||
RC_E: 1,
|
|
||||||
RC_W: 2,
|
|
||||||
RC_N: 3,
|
|
||||||
START: 9,
|
|
||||||
SELECT: 8,
|
|
||||||
LB: 4,
|
|
||||||
RB: 5,
|
|
||||||
LT: 6,
|
|
||||||
RT: 7,
|
|
||||||
LS: 10,
|
|
||||||
RS: 11,
|
|
||||||
LC_N: 12,
|
|
||||||
LC_S: 13,
|
|
||||||
LC_W: 14,
|
|
||||||
LC_E: 15
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pad_generic;
|
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
* Nintendo Pro Controller mapping
|
|
||||||
*/
|
|
||||||
const pad_procon = {
|
|
||||||
padID: "Pro Controller",
|
|
||||||
padType: "Nintendo",
|
|
||||||
gamepadMapping: {
|
|
||||||
RC_S: 1,
|
|
||||||
RC_E: 0,
|
|
||||||
RC_W: 3,
|
|
||||||
RC_N: 2,
|
|
||||||
START: 9, // +
|
|
||||||
SELECT: 8, // -
|
|
||||||
LB: 4,
|
|
||||||
RB: 5,
|
|
||||||
LT: 6,
|
|
||||||
RT: 7,
|
|
||||||
LS: 10,
|
|
||||||
RS: 11,
|
|
||||||
LC_N: 12,
|
|
||||||
LC_S: 13,
|
|
||||||
LC_W: 14,
|
|
||||||
LC_E: 15,
|
|
||||||
MENU: 16, // Home
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pad_procon;
|
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* 081f-e401 - UnlicensedSNES
|
|
||||||
*/
|
|
||||||
const pad_unlicensedSNES = {
|
|
||||||
padID: "081f-e401",
|
|
||||||
padType: "snes",
|
|
||||||
gamepadMapping : {
|
|
||||||
RC_S: 2,
|
|
||||||
RC_E: 1,
|
|
||||||
RC_W: 3,
|
|
||||||
RC_N: 0,
|
|
||||||
START: 9,
|
|
||||||
SELECT: 8,
|
|
||||||
LB: 4,
|
|
||||||
RB: 5,
|
|
||||||
LC_N: 12,
|
|
||||||
LC_S: 13,
|
|
||||||
LC_W: 14,
|
|
||||||
LC_E: 15
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pad_unlicensedSNES;
|
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
* Generic pad mapping
|
|
||||||
*/
|
|
||||||
const pad_xbox360 = {
|
|
||||||
padID: "Xbox 360 controller (XInput STANDARD GAMEPAD)",
|
|
||||||
padType: "xbox",
|
|
||||||
gamepadMapping: {
|
|
||||||
RC_S: 0,
|
|
||||||
RC_E: 1,
|
|
||||||
RC_W: 2,
|
|
||||||
RC_N: 3,
|
|
||||||
START: 9,
|
|
||||||
SELECT: 8,
|
|
||||||
LB: 4,
|
|
||||||
RB: 5,
|
|
||||||
LT: 6,
|
|
||||||
RT: 7,
|
|
||||||
LS: 10,
|
|
||||||
RS: 11,
|
|
||||||
LC_N: 12,
|
|
||||||
LC_S: 13,
|
|
||||||
LC_W: 14,
|
|
||||||
LC_E: 15,
|
|
||||||
MENU: 16
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default pad_xbox360;
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum Device {
|
||||||
|
GAMEPAD,
|
||||||
|
KEYBOARD,
|
||||||
|
}
|
|
@ -1,30 +1,70 @@
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
import {ButtonKey, initTouchControls} from "./touch-controls";
|
import {deepCopy} from "./utils";
|
||||||
import pad_generic from "./configs/pad_generic";
|
import {initTouchControls} from "./touch-controls";
|
||||||
import pad_unlicensedSNES from "./configs/pad_unlicensedSNES";
|
import pad_generic from "./configs/inputs/pad_generic";
|
||||||
import pad_xbox360 from "./configs/pad_xbox360";
|
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
||||||
import pad_dualshock from "./configs/pad_dualshock";
|
import pad_xbox360 from "./configs/inputs/pad_xbox360";
|
||||||
import pad_procon from "./configs/pad_procon";
|
import pad_dualshock from "./configs/inputs/pad_dualshock";
|
||||||
|
import pad_procon from "./configs/inputs/pad_procon";
|
||||||
import {Button} from "./enums/buttons";
|
import {Button} from "./enums/buttons";
|
||||||
|
import {Mode} from "./ui/ui";
|
||||||
|
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
||||||
|
import SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler";
|
||||||
|
import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {
|
||||||
|
assign,
|
||||||
|
getButtonWithKeycode,
|
||||||
|
getIconForLatestInput, swap,
|
||||||
|
} from "#app/configs/inputs/configHandler";
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
|
import {SettingGamepad} from "#app/system/settings-gamepad";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
export interface GamepadMapping {
|
export interface DeviceMapping {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GamepadConfig {
|
export interface IconsMapping {
|
||||||
padID: string;
|
[key: string]: string;
|
||||||
padType: string;
|
|
||||||
gamepadMapping: GamepadMapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionGamepadMapping {
|
export interface SettingMapping {
|
||||||
[key: string]: Button;
|
[key: string]: Button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MappingLayout {
|
||||||
|
[key: string]: SettingGamepad | SettingKeyboard | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InterfaceConfig {
|
||||||
|
padID: string;
|
||||||
|
padType: string;
|
||||||
|
deviceMapping: DeviceMapping;
|
||||||
|
icons: IconsMapping;
|
||||||
|
settings: SettingMapping;
|
||||||
|
default: MappingLayout;
|
||||||
|
custom?: MappingLayout;
|
||||||
|
}
|
||||||
|
|
||||||
const repeatInputDelayMillis = 250;
|
const repeatInputDelayMillis = 250;
|
||||||
|
|
||||||
|
// Phaser.Input.Gamepad.GamepadPlugin#refreshPads
|
||||||
|
declare module "phaser" {
|
||||||
|
namespace Input {
|
||||||
|
namespace Gamepad {
|
||||||
|
interface GamepadPlugin {
|
||||||
|
/**
|
||||||
|
* Refreshes the list of connected Gamepads.
|
||||||
|
* This is called automatically when a gamepad is connected or disconnected, and during the update loop.
|
||||||
|
*/
|
||||||
|
refreshPads(): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages and handles all input controls for the game, including keyboard and gamepad interactions.
|
* Manages and handles all input controls for the game, including keyboard and gamepad interactions.
|
||||||
*
|
*
|
||||||
|
@ -49,17 +89,24 @@ const repeatInputDelayMillis = 250;
|
||||||
*/
|
*/
|
||||||
export class InputsController {
|
export class InputsController {
|
||||||
private buttonKeys: Phaser.Input.Keyboard.Key[][];
|
private buttonKeys: Phaser.Input.Keyboard.Key[][];
|
||||||
private gamepads: Phaser.Input.Gamepad.Gamepad[] = new Array();
|
private gamepads: Array<Phaser.Input.Gamepad.Gamepad> = new Array();
|
||||||
private scene: BattleScene;
|
private scene: BattleScene;
|
||||||
|
public events: Phaser.Events.EventEmitter;
|
||||||
|
|
||||||
private buttonLock: Button;
|
private buttonLock: Button;
|
||||||
private buttonLock2: Button;
|
|
||||||
private interactions: Map<Button, Map<string, boolean>> = new Map();
|
private interactions: Map<Button, Map<string, boolean>> = new Map();
|
||||||
private time: Phaser.Time.Clock;
|
private time: Phaser.Time.Clock;
|
||||||
private player: GamepadMapping;
|
private configs: Map<string, InterfaceConfig> = new Map();
|
||||||
|
|
||||||
private gamepadSupport: boolean = true;
|
public gamepadSupport: boolean = true;
|
||||||
public events: Phaser.Events.EventEmitter;
|
public selectedDevice;
|
||||||
|
|
||||||
|
private disconnectedGamepads: Array<String> = new Array();
|
||||||
|
|
||||||
|
private pauseUpdate: boolean = false;
|
||||||
|
|
||||||
|
public lastSource: string = "keyboard";
|
||||||
|
private keys: Array<number> = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of the game control system, setting up initial state and configurations.
|
* Initializes a new instance of the game control system, setting up initial state and configurations.
|
||||||
|
@ -72,10 +119,15 @@ export class InputsController {
|
||||||
* Specific buttons like MENU and STATS are set not to repeat their actions.
|
* Specific buttons like MENU and STATS are set not to repeat their actions.
|
||||||
* It concludes by calling the `init` method to complete the setup.
|
* It concludes by calling the `init` method to complete the setup.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
constructor(scene: BattleScene) {
|
constructor(scene: BattleScene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.time = this.scene.time;
|
this.time = this.scene.time;
|
||||||
this.buttonKeys = [];
|
this.buttonKeys = [];
|
||||||
|
this.selectedDevice = {
|
||||||
|
[Device.GAMEPAD]: null,
|
||||||
|
[Device.KEYBOARD]: "default"
|
||||||
|
};
|
||||||
|
|
||||||
for (const b of Utils.getEnumValues(Button)) {
|
for (const b of Utils.getEnumValues(Button)) {
|
||||||
this.interactions[b] = {
|
this.interactions[b] = {
|
||||||
|
@ -99,18 +151,28 @@ export class InputsController {
|
||||||
* Additionally, it manages the game's behavior when it loses focus to prevent unwanted game actions during this state.
|
* Additionally, it manages the game's behavior when it loses focus to prevent unwanted game actions during this state.
|
||||||
*/
|
*/
|
||||||
init(): void {
|
init(): void {
|
||||||
this.events = new Phaser.Events.EventEmitter();
|
this.events = this.scene.game.events;
|
||||||
|
|
||||||
this.scene.game.events.on(Phaser.Core.Events.BLUR, () => {
|
this.scene.game.events.on(Phaser.Core.Events.BLUR, () => {
|
||||||
this.loseFocus();
|
this.loseFocus();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof this.scene.input.gamepad !== "undefined") {
|
if (typeof this.scene.input.gamepad !== "undefined") {
|
||||||
this.scene.input.gamepad.on("connected", function (thisGamepad) {
|
this.scene.input.gamepad.on("connected", function (thisGamepad) {
|
||||||
|
if (!thisGamepad) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.refreshGamepads();
|
this.refreshGamepads();
|
||||||
this.setupGamepad(thisGamepad);
|
this.setupGamepad(thisGamepad);
|
||||||
|
this.onReconnect(thisGamepad);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.scene.input.gamepad.on("disconnected", function (thisGamepad) {
|
||||||
|
this.onDisconnect(thisGamepad); // when a gamepad is disconnected
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
// Check to see if the gamepad has already been setup by the browser
|
// Check to see if the gamepad has already been setup by the browser
|
||||||
|
this.scene.input.gamepad.refreshPads();
|
||||||
if (this.scene.input.gamepad.total) {
|
if (this.scene.input.gamepad.total) {
|
||||||
this.refreshGamepads();
|
this.refreshGamepads();
|
||||||
for (const thisGamepad of this.gamepads) {
|
for (const thisGamepad of this.gamepads) {
|
||||||
|
@ -120,10 +182,10 @@ export class InputsController {
|
||||||
|
|
||||||
this.scene.input.gamepad.on("down", this.gamepadButtonDown, this);
|
this.scene.input.gamepad.on("down", this.gamepadButtonDown, this);
|
||||||
this.scene.input.gamepad.on("up", this.gamepadButtonUp, this);
|
this.scene.input.gamepad.on("up", this.gamepadButtonUp, this);
|
||||||
|
this.scene.input.keyboard.on("keydown", this.keyboardKeyDown, this);
|
||||||
|
this.scene.input.keyboard.on("keyup", this.keyboardKeyUp, this);
|
||||||
}
|
}
|
||||||
|
initTouchControls(this.events);
|
||||||
// Keyboard
|
|
||||||
this.setupKeyboardControls();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,35 +211,58 @@ export class InputsController {
|
||||||
this.gamepadSupport = true;
|
this.gamepadSupport = true;
|
||||||
} else {
|
} else {
|
||||||
this.gamepadSupport = false;
|
this.gamepadSupport = false;
|
||||||
// if we disable the gamepad, we want to release every key pressed
|
|
||||||
this.deactivatePressedKey();
|
this.deactivatePressedKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the currently chosen gamepad and initializes related settings.
|
||||||
|
* This method first deactivates any active key presses and then initializes the gamepad settings.
|
||||||
|
*
|
||||||
|
* @param gamepad - The identifier of the gamepad to set as chosen.
|
||||||
|
*/
|
||||||
|
setChosenGamepad(gamepad: String): void {
|
||||||
|
this.deactivatePressedKey();
|
||||||
|
this.initChosenGamepad(gamepad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the currently chosen keyboard layout and initializes related settings.
|
||||||
|
*
|
||||||
|
* @param layoutKeyboard - The identifier of the keyboard layout to set as chosen.
|
||||||
|
*/
|
||||||
|
setChosenKeyboardLayout(layoutKeyboard: String): void {
|
||||||
|
this.deactivatePressedKey();
|
||||||
|
this.initChosenLayoutKeyboard(layoutKeyboard);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the interaction handling by processing input states.
|
* Updates the interaction handling by processing input states.
|
||||||
* This method gives priority to certain buttons by reversing the order in which they are checked.
|
* This method gives priority to certain buttons by reversing the order in which they are checked.
|
||||||
|
* This method loops through all button values, checks for valid and timely interactions, and conditionally processes
|
||||||
|
* or ignores them based on the current state of gamepad support and other criteria.
|
||||||
*
|
*
|
||||||
* @remarks
|
* It handles special conditions such as the absence of gamepad support or mismatches between the source of the input and
|
||||||
* The method iterates over all possible buttons, checking for specific conditions such as:
|
* the currently chosen gamepad. It also respects the paused state of updates to prevent unwanted input processing.
|
||||||
* - If the button is registered in the `interactions` dictionary.
|
|
||||||
* - If the button has been held down long enough.
|
|
||||||
* - If the button is currently pressed.
|
|
||||||
*
|
*
|
||||||
* Special handling is applied if gamepad support is disabled but a gamepad source is still triggering inputs,
|
* If an interaction is valid and should be processed, it emits an 'input_down' event with details of the interaction.
|
||||||
* preventing potential infinite loops by removing the last processed movement time for the button.
|
|
||||||
*/
|
*/
|
||||||
update(): void {
|
update(): void {
|
||||||
for (const b of Utils.getEnumValues(Button).reverse()) {
|
for (const b of Utils.getEnumValues(Button).reverse()) {
|
||||||
if (
|
if (
|
||||||
this.interactions.hasOwnProperty(b) &&
|
this.interactions.hasOwnProperty(b) &&
|
||||||
this.repeatInputDurationJustPassed(b) &&
|
this.repeatInputDurationJustPassed(b as Button) &&
|
||||||
this.interactions[b].isPressed
|
this.interactions[b].isPressed
|
||||||
) {
|
) {
|
||||||
// Prevents repeating button interactions when gamepad support is disabled.
|
// Prevents repeating button interactions when gamepad support is disabled.
|
||||||
if (!this.gamepadSupport && this.interactions[b].source === "gamepad") {
|
if (
|
||||||
|
(!this.gamepadSupport && this.interactions[b].source === "gamepad") ||
|
||||||
|
(this.interactions[b].source === "gamepad" && this.interactions[b].sourceName && this.interactions[b].sourceName !== this.selectedDevice[Device.GAMEPAD]) ||
|
||||||
|
(this.interactions[b].source === "keyboard" && this.interactions[b].sourceName && this.interactions[b].sourceName !== this.selectedDevice[Device.KEYBOARD]) ||
|
||||||
|
this.pauseUpdate
|
||||||
|
) {
|
||||||
// Deletes the last interaction for a button if gamepad is disabled.
|
// Deletes the last interaction for a button if gamepad is disabled.
|
||||||
this.delLastProcessedMovementTime(b);
|
this.delLastProcessedMovementTime(b as Button);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Emits an event for the button press.
|
// Emits an event for the button press.
|
||||||
|
@ -185,25 +270,104 @@ export class InputsController {
|
||||||
controller_type: this.interactions[b].source,
|
controller_type: this.interactions[b].source,
|
||||||
button: b,
|
button: b,
|
||||||
});
|
});
|
||||||
this.setLastProcessedMovementTime(b, this.interactions[b].source);
|
this.setLastProcessedMovementTime(b as Button, this.interactions[b].source, this.interactions[b].sourceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures a gamepad for use based on its device ID.
|
* Retrieves the identifiers of all connected gamepads, excluding any that are currently marked as disconnected.
|
||||||
|
* @returns Array<String> An array of strings representing the IDs of the connected gamepads.
|
||||||
|
*/
|
||||||
|
getGamepadsName(): Array<String> {
|
||||||
|
return this.gamepads.filter(g => !this.disconnectedGamepads.includes(g.id)).map(g => g.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the chosen gamepad by setting its identifier in the local storage and updating the UI to reflect the chosen gamepad.
|
||||||
|
* If a gamepad name is provided, it uses that as the chosen gamepad; otherwise, it defaults to the currently chosen gamepad.
|
||||||
|
* @param gamepadName Optional parameter to specify the name of the gamepad to initialize as chosen.
|
||||||
|
*/
|
||||||
|
initChosenGamepad(gamepadName?: String): void {
|
||||||
|
if (gamepadName) {
|
||||||
|
this.selectedDevice[Device.GAMEPAD] = gamepadName.toLowerCase();
|
||||||
|
}
|
||||||
|
const handler = this.scene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
||||||
|
handler && handler.updateChosenGamepadDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the chosen keyboard layout by setting its identifier in the local storage and updating the UI to reflect the chosen layout.
|
||||||
|
* If a layout name is provided, it uses that as the chosen layout; otherwise, it defaults to the currently chosen layout.
|
||||||
|
* @param layoutKeyboard Optional parameter to specify the name of the keyboard layout to initialize as chosen.
|
||||||
|
*/
|
||||||
|
initChosenLayoutKeyboard(layoutKeyboard?: String): void {
|
||||||
|
if (layoutKeyboard) {
|
||||||
|
this.selectedDevice[Device.KEYBOARD] = layoutKeyboard.toLowerCase();
|
||||||
|
}
|
||||||
|
const handler = this.scene.ui?.handlers[Mode.SETTINGS_KEYBOARD] as SettingsKeyboardUiHandler;
|
||||||
|
handler && handler.updateChosenKeyboardDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the disconnection of a gamepad by adding its identifier to a list of disconnected gamepads.
|
||||||
|
* This is necessary because Phaser retains memory of previously connected gamepads, and without tracking
|
||||||
|
* disconnections, it would be impossible to determine the connection status of gamepads. This method ensures
|
||||||
|
* that disconnected gamepads are recognized and can be appropriately hidden in the gamepad selection menu.
|
||||||
*
|
*
|
||||||
* @param thisGamepad - The gamepad to set up.
|
* @param thisGamepad The gamepad that has been disconnected.
|
||||||
|
*/
|
||||||
|
onDisconnect(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
|
||||||
|
this.disconnectedGamepads.push(thisGamepad.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the tracking of disconnected gamepads when a gamepad is reconnected.
|
||||||
|
* It removes the reconnected gamepad's identifier from the `disconnectedGamepads` array,
|
||||||
|
* effectively updating its status to connected.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @param thisGamepad The gamepad that has been reconnected.
|
||||||
* This method initializes a gamepad by mapping its ID to a predefined configuration.
|
*/
|
||||||
* It updates the player's gamepad mapping based on the identified configuration, ensuring
|
onReconnect(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
|
||||||
* that the gamepad controls are correctly mapped to in-game actions.
|
this.disconnectedGamepads = this.disconnectedGamepads.filter(g => g !== thisGamepad.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes or updates configurations for connected gamepads.
|
||||||
|
* It retrieves the names of all connected gamepads, sets up their configurations according to stored or default settings,
|
||||||
|
* and ensures these configurations are saved. If the connected gamepad is the currently chosen one,
|
||||||
|
* it reinitializes the chosen gamepad settings.
|
||||||
|
*
|
||||||
|
* @param thisGamepad The gamepad that is being set up.
|
||||||
*/
|
*/
|
||||||
setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
|
setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
|
||||||
const gamepadID = thisGamepad.id.toLowerCase();
|
const allGamepads = this.getGamepadsName();
|
||||||
const mappedPad = this.mapGamepad(gamepadID);
|
for (const gamepad of allGamepads) {
|
||||||
this.player = mappedPad.gamepadMapping;
|
const gamepadID = gamepad.toLowerCase();
|
||||||
|
if (!this.selectedDevice[Device.GAMEPAD]) {
|
||||||
|
this.setChosenGamepad(gamepadID);
|
||||||
|
}
|
||||||
|
const config = deepCopy(this.getConfig(gamepadID)) as InterfaceConfig;
|
||||||
|
config.custom = this.configs[gamepadID]?.custom || {...config.default};
|
||||||
|
this.configs[gamepadID] = config;
|
||||||
|
this.scene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]);
|
||||||
|
}
|
||||||
|
this.lastSource = "gamepad";
|
||||||
|
const handler = this.scene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
||||||
|
handler && handler.updateChosenGamepadDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes or updates configurations for connected keyboards.
|
||||||
|
*/
|
||||||
|
setupKeyboard(): void {
|
||||||
|
for (const layout of ["default"]) {
|
||||||
|
const config = deepCopy(this.getConfigKeyboard(layout)) as InterfaceConfig;
|
||||||
|
config.custom = this.configs[layout]?.custom || {...config.default};
|
||||||
|
this.configs[layout] = config;
|
||||||
|
this.scene.gameData?.saveMappingConfigs(this.selectedDevice[Device.KEYBOARD], this.configs[layout]);
|
||||||
|
}
|
||||||
|
this.initChosenLayoutKeyboard(this.selectedDevice[Device.KEYBOARD]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,89 +390,110 @@ export class InputsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current gamepad mapping for in-game actions.
|
* Ensures the keyboard is initialized by checking if there is an active configuration for the keyboard.
|
||||||
*
|
* If not, it sets up the keyboard with default configurations.
|
||||||
* @returns An object mapping gamepad buttons to in-game actions based on the player's current gamepad configuration.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method constructs a mapping of gamepad buttons to in-game action buttons according to the player's
|
|
||||||
* current gamepad configuration. If no configuration is available, it returns an empty mapping.
|
|
||||||
* The mapping includes directional controls, action buttons, and system commands among others,
|
|
||||||
* adjusted for any custom settings such as swapped action buttons.
|
|
||||||
*/
|
*/
|
||||||
getActionGamepadMapping(): ActionGamepadMapping {
|
ensureKeyboardIsInit(): void {
|
||||||
const gamepadMapping = {};
|
if (!this.getActiveConfig(Device.KEYBOARD)?.padID) {
|
||||||
if (!this?.player) {
|
this.setupKeyboard();
|
||||||
return gamepadMapping;
|
|
||||||
}
|
}
|
||||||
gamepadMapping[this.player.LC_N] = Button.UP;
|
|
||||||
gamepadMapping[this.player.LC_S] = Button.DOWN;
|
|
||||||
gamepadMapping[this.player.LC_W] = Button.LEFT;
|
|
||||||
gamepadMapping[this.player.LC_E] = Button.RIGHT;
|
|
||||||
gamepadMapping[this.player.TOUCH] = Button.SUBMIT;
|
|
||||||
gamepadMapping[this.player.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
|
|
||||||
gamepadMapping[this.player.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
|
|
||||||
gamepadMapping[this.player.SELECT] = Button.STATS;
|
|
||||||
gamepadMapping[this.player.START] = Button.MENU;
|
|
||||||
gamepadMapping[this.player.RB] = Button.CYCLE_SHINY;
|
|
||||||
gamepadMapping[this.player.LB] = Button.CYCLE_FORM;
|
|
||||||
gamepadMapping[this.player.LT] = Button.CYCLE_GENDER;
|
|
||||||
gamepadMapping[this.player.RT] = Button.CYCLE_ABILITY;
|
|
||||||
gamepadMapping[this.player.RC_W] = Button.CYCLE_NATURE;
|
|
||||||
gamepadMapping[this.player.RC_N] = Button.V;
|
|
||||||
gamepadMapping[this.player.LS] = Button.SPEED_UP;
|
|
||||||
gamepadMapping[this.player.RS] = Button.SLOW_DOWN;
|
|
||||||
|
|
||||||
return gamepadMapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the 'down' event for gamepad buttons, emitting appropriate events and updating the interaction state.
|
* Handles the keydown event for the keyboard.
|
||||||
*
|
*
|
||||||
* @param pad - The gamepad on which the button press occurred.
|
* @param event The keyboard event.
|
||||||
* @param button - The button that was pressed.
|
|
||||||
* @param value - The value associated with the button press, typically indicating pressure or degree of activation.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method is triggered when a gamepad button is pressed. If gamepad support is enabled, it:
|
|
||||||
* - Retrieves the current gamepad action mapping.
|
|
||||||
* - Checks if the pressed button is mapped to a game action.
|
|
||||||
* - If mapped, emits an 'input_down' event with the controller type and button action, and updates the interaction of this button.
|
|
||||||
*/
|
*/
|
||||||
gamepadButtonDown(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void {
|
keyboardKeyDown(event): void {
|
||||||
if (!this.gamepadSupport) {
|
this.lastSource = "keyboard";
|
||||||
|
const keyDown = event.keyCode;
|
||||||
|
this.ensureKeyboardIsInit();
|
||||||
|
if (this.keys.includes(keyDown)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const actionMapping = this.getActionGamepadMapping();
|
this.keys.push(keyDown);
|
||||||
const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
|
const buttonDown = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), keyDown);
|
||||||
|
if (buttonDown !== undefined) {
|
||||||
|
this.events.emit("input_down", {
|
||||||
|
controller_type: "keyboard",
|
||||||
|
button: buttonDown,
|
||||||
|
});
|
||||||
|
this.setLastProcessedMovementTime(buttonDown, "keyboard", this.selectedDevice[Device.KEYBOARD]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the keyup event for the keyboard.
|
||||||
|
*
|
||||||
|
* @param event The keyboard event.
|
||||||
|
*/
|
||||||
|
keyboardKeyUp(event): void {
|
||||||
|
this.lastSource = "keyboard";
|
||||||
|
const keyDown = event.keyCode;
|
||||||
|
this.keys = this.keys.filter(k => k !== keyDown);
|
||||||
|
this.ensureKeyboardIsInit();
|
||||||
|
const buttonUp = getButtonWithKeycode(this.getActiveConfig(Device.KEYBOARD), keyDown);
|
||||||
|
if (buttonUp !== undefined) {
|
||||||
|
this.events.emit("input_up", {
|
||||||
|
controller_type: "keyboard",
|
||||||
|
button: buttonUp,
|
||||||
|
});
|
||||||
|
this.delLastProcessedMovementTime(buttonUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles button press events on a gamepad. This method sets the gamepad as chosen on the first input if no gamepad is currently chosen.
|
||||||
|
* It checks if gamepad support is enabled and if the event comes from the chosen gamepad. If so, it maps the button press to a specific
|
||||||
|
* action using a custom configuration, emits an event for the button press, and records the time of the action.
|
||||||
|
*
|
||||||
|
* @param pad The gamepad on which the button was pressed.
|
||||||
|
* @param button The specific button that was pressed.
|
||||||
|
* @param value The intensity or value of the button press, if applicable.
|
||||||
|
*/
|
||||||
|
gamepadButtonDown(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void {
|
||||||
|
if (!this.configs[this.selectedDevice[Device.KEYBOARD]]?.padID) {
|
||||||
|
this.setupKeyboard();
|
||||||
|
}
|
||||||
|
if (!pad) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastSource = "gamepad";
|
||||||
|
if (!this.selectedDevice[Device.GAMEPAD] || (this.scene.ui.getMode() !== Mode.GAMEPAD_BINDING && this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase())) {
|
||||||
|
this.setChosenGamepad(pad.id);
|
||||||
|
}
|
||||||
|
if (!this.gamepadSupport || pad.id.toLowerCase() !== this.selectedDevice[Device.GAMEPAD].toLowerCase()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const activeConfig = this.getActiveConfig(Device.GAMEPAD);
|
||||||
|
const buttonDown = activeConfig && getButtonWithKeycode(activeConfig, button.index);
|
||||||
if (buttonDown !== undefined) {
|
if (buttonDown !== undefined) {
|
||||||
this.events.emit("input_down", {
|
this.events.emit("input_down", {
|
||||||
controller_type: "gamepad",
|
controller_type: "gamepad",
|
||||||
button: buttonDown,
|
button: buttonDown,
|
||||||
});
|
});
|
||||||
this.setLastProcessedMovementTime(buttonDown, "gamepad");
|
this.setLastProcessedMovementTime(buttonDown, "gamepad", pad.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the 'up' event for gamepad buttons, emitting appropriate events and clearing the interaction state.
|
* Responds to a button release event on a gamepad by checking if the gamepad is supported and currently chosen.
|
||||||
|
* If conditions are met, it identifies the configured action for the button, emits an event signaling the button release,
|
||||||
|
* and clears the record of the button.
|
||||||
*
|
*
|
||||||
* @param pad - The gamepad on which the button release occurred.
|
* @param pad The gamepad from which the button was released.
|
||||||
* @param button - The button that was released.
|
* @param button The specific button that was released.
|
||||||
* @param value - The value associated with the button release, typically indicating pressure or degree of deactivation.
|
* @param value The intensity or value of the button release, if applicable.
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method is triggered when a gamepad button is released. If gamepad support is enabled, it:
|
|
||||||
* - Retrieves the current gamepad action mapping.
|
|
||||||
* - Checks if the released button is mapped to a game action.
|
|
||||||
* - If mapped, emits an 'input_up' event with the controller type and button action, and clears the interaction for this button.
|
|
||||||
*/
|
*/
|
||||||
gamepadButtonUp(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void {
|
gamepadButtonUp(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void {
|
||||||
if (!this.gamepadSupport) {
|
if (!pad) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const actionMapping = this.getActionGamepadMapping();
|
this.lastSource = "gamepad";
|
||||||
const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
|
if (!this.gamepadSupport || pad.id.toLowerCase() !== this.selectedDevice[Device.GAMEPAD]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const buttonUp = getButtonWithKeycode(this.getActiveConfig(Device.GAMEPAD), button.index);
|
||||||
if (buttonUp !== undefined) {
|
if (buttonUp !== undefined) {
|
||||||
this.events.emit("input_up", {
|
this.events.emit("input_up", {
|
||||||
controller_type: "gamepad",
|
controller_type: "gamepad",
|
||||||
|
@ -319,114 +504,14 @@ export class InputsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures keyboard controls for the game, mapping physical keys to game actions.
|
* Retrieves the configuration object for a gamepad based on its identifier. The method identifies specific gamepad models
|
||||||
|
* based on substrings in the identifier and returns predefined configurations for recognized models.
|
||||||
|
* If no specific configuration matches, it defaults to a generic gamepad configuration.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @param id The identifier string of the gamepad.
|
||||||
* This method sets up keyboard bindings for game controls using Phaser's `KeyCodes`. Each game action, represented
|
* @returns InterfaceConfig The configuration object corresponding to the identified gamepad type.
|
||||||
* by a button in the `Button` enum, is associated with one or more physical keys. For example, movement actions
|
|
||||||
* (up, down, left, right) are mapped to both arrow keys and WASD keys. Actions such as submit, cancel, and other
|
|
||||||
* game-specific functions are mapped to appropriate keys like Enter, Space, etc.
|
|
||||||
*
|
|
||||||
* The method does the following:
|
|
||||||
* - Defines a `keyConfig` object that associates each `Button` enum value with an array of `KeyCodes`.
|
|
||||||
* - Iterates over all values of the `Button` enum to set up these key bindings within the Phaser game scene.
|
|
||||||
* - For each button, it adds the respective keys to the game's input system and stores them in `this.buttonKeys`.
|
|
||||||
* - Additional configurations for mobile or alternative input schemes are stored in `mobileKeyConfig`.
|
|
||||||
*
|
|
||||||
* Post-setup, it initializes touch controls (if applicable) and starts listening for keyboard inputs using
|
|
||||||
* `listenInputKeyboard`, ensuring that all configured keys are actively monitored for player interactions.
|
|
||||||
*/
|
*/
|
||||||
setupKeyboardControls(): void {
|
getConfig(id: string): InterfaceConfig {
|
||||||
const keyCodes = Phaser.Input.Keyboard.KeyCodes;
|
|
||||||
const keyConfig = {
|
|
||||||
[Button.UP]: [keyCodes.UP, keyCodes.W],
|
|
||||||
[Button.DOWN]: [keyCodes.DOWN, keyCodes.S],
|
|
||||||
[Button.LEFT]: [keyCodes.LEFT, keyCodes.A],
|
|
||||||
[Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
|
|
||||||
[Button.SUBMIT]: [keyCodes.ENTER],
|
|
||||||
[Button.ACTION]: [keyCodes.SPACE, keyCodes.Z],
|
|
||||||
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X],
|
|
||||||
[Button.MENU]: [keyCodes.ESC, keyCodes.M],
|
|
||||||
[Button.STATS]: [keyCodes.SHIFT, keyCodes.C],
|
|
||||||
[Button.CYCLE_SHINY]: [keyCodes.R],
|
|
||||||
[Button.CYCLE_FORM]: [keyCodes.F],
|
|
||||||
[Button.CYCLE_GENDER]: [keyCodes.G],
|
|
||||||
[Button.CYCLE_ABILITY]: [keyCodes.E],
|
|
||||||
[Button.CYCLE_NATURE]: [keyCodes.N],
|
|
||||||
[Button.V]: [keyCodes.V],
|
|
||||||
[Button.SPEED_UP]: [keyCodes.PLUS],
|
|
||||||
[Button.SLOW_DOWN]: [keyCodes.MINUS]
|
|
||||||
};
|
|
||||||
const mobileKeyConfig = new Map<string, ButtonKey>();
|
|
||||||
for (const b of Utils.getEnumValues(Button)) {
|
|
||||||
const keys: Phaser.Input.Keyboard.Key[] = [];
|
|
||||||
if (keyConfig.hasOwnProperty(b)) {
|
|
||||||
for (const k of keyConfig[b]) {
|
|
||||||
keys.push(this.scene.input.keyboard.addKey(k, false));
|
|
||||||
}
|
|
||||||
mobileKeyConfig[Button[b]] = keys[0];
|
|
||||||
}
|
|
||||||
this.buttonKeys[b] = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
initTouchControls(mobileKeyConfig);
|
|
||||||
this.listenInputKeyboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up event listeners for keyboard inputs on all registered keys.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method iterates over an array of keyboard button rows (`this.buttonKeys`), adding 'down' and 'up'
|
|
||||||
* event listeners for each key. These listeners handle key press and release actions respectively.
|
|
||||||
*
|
|
||||||
* - **Key Down Event**: When a key is pressed down, the method emits an 'input_down' event with the button
|
|
||||||
* and the source ('keyboard'). It also records the time and state of the key press by calling
|
|
||||||
* `setLastProcessedMovementTime`.
|
|
||||||
*
|
|
||||||
* - **Key Up Event**: When a key is released, the method emits an 'input_up' event similarly, specifying the button
|
|
||||||
* and source. It then clears the recorded press time and state by calling
|
|
||||||
* `delLastProcessedMovementTime`.
|
|
||||||
*
|
|
||||||
* This setup ensures that each key on the keyboard is monitored for press and release events,
|
|
||||||
* and that these events are properly communicated within the system.
|
|
||||||
*/
|
|
||||||
listenInputKeyboard(): void {
|
|
||||||
this.buttonKeys.forEach((row, index) => {
|
|
||||||
for (const key of row) {
|
|
||||||
key.on("down", () => {
|
|
||||||
this.events.emit("input_down", {
|
|
||||||
controller_type: "keyboard",
|
|
||||||
button: index,
|
|
||||||
});
|
|
||||||
this.setLastProcessedMovementTime(index, "keyboard");
|
|
||||||
});
|
|
||||||
key.on("up", () => {
|
|
||||||
this.events.emit("input_up", {
|
|
||||||
controller_type: "keyboard",
|
|
||||||
button: index,
|
|
||||||
});
|
|
||||||
this.delLastProcessedMovementTime(index);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps a gamepad ID to a specific gamepad configuration based on the ID's characteristics.
|
|
||||||
*
|
|
||||||
* @param id - The gamepad ID string, typically representing a unique identifier for a gamepad model or make.
|
|
||||||
* @returns A `GamepadConfig` object corresponding to the identified gamepad model.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This function analyzes the provided gamepad ID and matches it to a predefined configuration based on known identifiers:
|
|
||||||
* - If the ID includes both '081f' and 'e401', it is identified as an unlicensed SNES gamepad.
|
|
||||||
* - If the ID contains 'xbox' and '360', it is identified as an Xbox 360 gamepad.
|
|
||||||
* - If the ID contains '054c', it is identified as a DualShock gamepad.
|
|
||||||
* - If the ID includes both '057e' and '2009', it is identified as a Pro controller gamepad.
|
|
||||||
* If no specific identifiers are recognized, a generic gamepad configuration is returned.
|
|
||||||
*/
|
|
||||||
mapGamepad(id: string): GamepadConfig {
|
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
|
|
||||||
if (id.includes("081f") && id.includes("e401")) {
|
if (id.includes("081f") && id.includes("e401")) {
|
||||||
|
@ -442,6 +527,20 @@ export class InputsController {
|
||||||
return pad_generic;
|
return pad_generic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the configuration object for a keyboard layout based on its identifier.
|
||||||
|
*
|
||||||
|
* @param id The identifier string of the keyboard layout.
|
||||||
|
* @returns InterfaceConfig The configuration object corresponding to the identified keyboard layout.
|
||||||
|
*/
|
||||||
|
getConfigKeyboard(id: string): InterfaceConfig {
|
||||||
|
if (id === "default") {
|
||||||
|
return cfg_keyboard_qwerty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg_keyboard_qwerty;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* repeatInputDurationJustPassed returns true if @param button has been held down long
|
* repeatInputDurationJustPassed returns true if @param button has been held down long
|
||||||
* enough to fire a repeated input. A button must claim the buttonLock before
|
* enough to fire a repeated input. A button must claim the buttonLock before
|
||||||
|
@ -471,7 +570,7 @@ export class InputsController {
|
||||||
*
|
*
|
||||||
* Additionally, this method locks the button (by calling `setButtonLock`) to prevent it from being re-processed until it is released, ensuring that each press is handled distinctly.
|
* Additionally, this method locks the button (by calling `setButtonLock`) to prevent it from being re-processed until it is released, ensuring that each press is handled distinctly.
|
||||||
*/
|
*/
|
||||||
setLastProcessedMovementTime(button: Button, source: String = "keyboard"): void {
|
setLastProcessedMovementTime(button: Button, source: String = "keyboard", sourceName?: String): void {
|
||||||
if (!this.interactions.hasOwnProperty(button)) {
|
if (!this.interactions.hasOwnProperty(button)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -479,6 +578,7 @@ export class InputsController {
|
||||||
this.interactions[button].pressTime = this.time.now;
|
this.interactions[button].pressTime = this.time.now;
|
||||||
this.interactions[button].isPressed = true;
|
this.interactions[button].isPressed = true;
|
||||||
this.interactions[button].source = source;
|
this.interactions[button].source = source;
|
||||||
|
this.interactions[button].sourceName = sourceName.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -503,6 +603,7 @@ export class InputsController {
|
||||||
this.interactions[button].pressTime = null;
|
this.interactions[button].pressTime = null;
|
||||||
this.interactions[button].isPressed = false;
|
this.interactions[button].isPressed = false;
|
||||||
this.interactions[button].source = null;
|
this.interactions[button].source = null;
|
||||||
|
this.interactions[button].sourceName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -512,7 +613,7 @@ export class InputsController {
|
||||||
* This method is used to reset the state of all buttons within the `interactions` dictionary,
|
* This method is used to reset the state of all buttons within the `interactions` dictionary,
|
||||||
* effectively deactivating any currently pressed keys. It performs the following actions:
|
* effectively deactivating any currently pressed keys. It performs the following actions:
|
||||||
*
|
*
|
||||||
* - Releases button locks for predefined buttons (`buttonLock` and `buttonLock2`), allowing them
|
* - Releases button lock for predefined buttons, allowing them
|
||||||
* to be pressed again or properly re-initialized in future interactions.
|
* to be pressed again or properly re-initialized in future interactions.
|
||||||
* - Iterates over all possible button values obtained via `Utils.getEnumValues(Button)`, and for
|
* - Iterates over all possible button values obtained via `Utils.getEnumValues(Button)`, and for
|
||||||
* each button:
|
* each button:
|
||||||
|
@ -524,55 +625,44 @@ export class InputsController {
|
||||||
* This method is typically called when needing to ensure that all inputs are neutralized.
|
* This method is typically called when needing to ensure that all inputs are neutralized.
|
||||||
*/
|
*/
|
||||||
deactivatePressedKey(): void {
|
deactivatePressedKey(): void {
|
||||||
|
this.pauseUpdate = true;
|
||||||
this.releaseButtonLock(this.buttonLock);
|
this.releaseButtonLock(this.buttonLock);
|
||||||
this.releaseButtonLock(this.buttonLock2);
|
|
||||||
for (const b of Utils.getEnumValues(Button)) {
|
for (const b of Utils.getEnumValues(Button)) {
|
||||||
if (this.interactions.hasOwnProperty(b)) {
|
if (this.interactions.hasOwnProperty(b)) {
|
||||||
this.interactions[b].pressTime = null;
|
this.interactions[b].pressTime = null;
|
||||||
this.interactions[b].isPressed = false;
|
this.interactions[b].isPressed = false;
|
||||||
this.interactions[b].source = null;
|
this.interactions[b].source = null;
|
||||||
|
this.interactions[b].sourceName = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setTimeout(() => this.pauseUpdate = false, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a specific button is currently locked.
|
* Checks if a specific button is currently locked.
|
||||||
*
|
*
|
||||||
* @param button - The button to check for a lock status.
|
* @param button - The button to check for a lock status.
|
||||||
* @returns `true` if the button is either of the two potentially locked buttons (`buttonLock` or `buttonLock2`), otherwise `false`.
|
* @returns `true` if the button is locked, otherwise `false`.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* This method is used to determine if a given button is currently prevented from being processed due to a lock.
|
* This method is used to determine if a given button is currently prevented from being processed due to a lock.
|
||||||
* It checks against two separate lock variables, allowing for up to two buttons to be locked simultaneously.
|
* It checks against two separate lock variables, allowing for up to two buttons to be locked simultaneously.
|
||||||
*/
|
*/
|
||||||
isButtonLocked(button: Button): boolean {
|
isButtonLocked(button: Button): boolean {
|
||||||
return (this.buttonLock === button || this.buttonLock2 === button);
|
return this.buttonLock === button;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a lock on a given button if it is not already locked.
|
* Sets a lock on a given button.
|
||||||
*
|
*
|
||||||
* @param button - The button to lock.
|
* @param button - The button to lock.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* This method ensures that a button is not processed multiple times inadvertently.
|
* This method ensures that a button is not processed multiple times inadvertently.
|
||||||
* It checks if the button is already locked by either of the two lock variables (`buttonLock` or `buttonLock2`).
|
* It checks if the button is already locked.
|
||||||
* If not, it locks the button using the first available lock variable.
|
|
||||||
* This mechanism allows for up to two buttons to be locked at the same time.
|
|
||||||
*/
|
*/
|
||||||
setButtonLock(button: Button): void {
|
setButtonLock(button: Button): void {
|
||||||
if (this.buttonLock === button || this.buttonLock2 === button) {
|
this.buttonLock = button;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.buttonLock === button) {
|
|
||||||
this.buttonLock2 = button;
|
|
||||||
} else if (this.buttonLock2 === button) {
|
|
||||||
this.buttonLock = button;
|
|
||||||
} else if (!!this.buttonLock) {
|
|
||||||
this.buttonLock2 = button;
|
|
||||||
} else {
|
|
||||||
this.buttonLock = button;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -581,15 +671,93 @@ export class InputsController {
|
||||||
* @param button - The button whose lock is to be released.
|
* @param button - The button whose lock is to be released.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* This method checks both lock variables (`buttonLock` and `buttonLock2`).
|
* This method checks lock variable.
|
||||||
* If either lock matches the specified button, that lock is cleared.
|
* If either lock matches the specified button, that lock is cleared.
|
||||||
* This action frees the button to be processed again, ensuring it can respond to new inputs.
|
* This action frees the button to be processed again, ensuring it can respond to new inputs.
|
||||||
*/
|
*/
|
||||||
releaseButtonLock(button: Button): void {
|
releaseButtonLock(button: Button): void {
|
||||||
if (this.buttonLock === button) {
|
if (this.buttonLock === button) {
|
||||||
this.buttonLock = null;
|
this.buttonLock = null;
|
||||||
} else if (this.buttonLock2 === button) {
|
}
|
||||||
this.buttonLock2 = null;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the active configuration for the currently chosen device.
|
||||||
|
* It checks if a specific device ID is stored in configurations and returns it.
|
||||||
|
*
|
||||||
|
* @returns InterfaceConfig The configuration object for the active gamepad, or null if not set.
|
||||||
|
*/
|
||||||
|
getActiveConfig(device: Device) {
|
||||||
|
if (this.configs[this.selectedDevice[device]]?.padID) {
|
||||||
|
return this.configs[this.selectedDevice[device]];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconForLatestInputRecorded(settingName) {
|
||||||
|
if (this.lastSource === "keyboard") {
|
||||||
|
this.ensureKeyboardIsInit();
|
||||||
|
}
|
||||||
|
return getIconForLatestInput(this.configs, this.lastSource, this.selectedDevice, settingName);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastSourceDevice(): Device {
|
||||||
|
if (this.lastSource === "gamepad") {
|
||||||
|
return Device.GAMEPAD;
|
||||||
|
} else {
|
||||||
|
return Device.KEYBOARD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastSourceConfig() {
|
||||||
|
const sourceDevice = this.getLastSourceDevice();
|
||||||
|
if (sourceDevice === Device.KEYBOARD) {
|
||||||
|
this.ensureKeyboardIsInit();
|
||||||
|
}
|
||||||
|
return this.getActiveConfig(sourceDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastSourceType() {
|
||||||
|
const config = this.getLastSourceConfig();
|
||||||
|
return config?.padType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects a custom mapping configuration into the configuration for a specific gamepad.
|
||||||
|
* If the device does not have an existing configuration, it initializes one first.
|
||||||
|
*
|
||||||
|
* @param selectedDevice The identifier of the device to configure.
|
||||||
|
* @param mappingConfigs The mapping configuration to apply to the device.
|
||||||
|
*/
|
||||||
|
injectConfig(selectedDevice: string, mappingConfigs): void {
|
||||||
|
if (!this.configs[selectedDevice]) {
|
||||||
|
this.configs[selectedDevice] = {};
|
||||||
|
}
|
||||||
|
this.configs[selectedDevice].custom = mappingConfigs.custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetConfigs(): void {
|
||||||
|
this.configs = new Map();
|
||||||
|
if (this.getGamepadsName()?.length) {
|
||||||
|
this.setupGamepad(this.selectedDevice[Device.GAMEPAD]);
|
||||||
|
}
|
||||||
|
this.setupKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps a binding in the configuration.
|
||||||
|
*
|
||||||
|
* @param config The configuration object.
|
||||||
|
* @param settingName The name of the setting to swap.
|
||||||
|
* @param pressedButton The button that was pressed.
|
||||||
|
*/
|
||||||
|
assignBinding(config, settingName, pressedButton): boolean {
|
||||||
|
this.pauseUpdate = true;
|
||||||
|
setTimeout(() => this.pauseUpdate = false, 500);
|
||||||
|
if (config.padType === "keyboard") {
|
||||||
|
return assign(config, settingName, pressedButton);
|
||||||
|
} else {
|
||||||
|
return swap(config, settingName, pressedButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,6 +251,10 @@ export class LoadingScene extends SceneBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loadAtlas("dualshock", "inputs");
|
||||||
|
this.loadAtlas("xbox", "inputs");
|
||||||
|
this.loadAtlas("keyboard", "inputs");
|
||||||
|
|
||||||
this.loadSe("select");
|
this.loadSe("select");
|
||||||
this.loadSe("menu_open");
|
this.loadSe("menu_open");
|
||||||
this.loadSe("hit");
|
this.loadSe("hit");
|
||||||
|
|
|
@ -30,6 +30,8 @@ import { allMoves } from "../data/move";
|
||||||
import { TrainerVariant } from "../field/trainer";
|
import { TrainerVariant } from "../field/trainer";
|
||||||
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
|
import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
|
||||||
import { Variant, variantData } from "#app/data/variant";
|
import { Variant, variantData } from "#app/data/variant";
|
||||||
|
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings-gamepad";
|
||||||
|
import {setSettingKeyboard, SettingKeyboard, settingKeyboardDefaults} from "#app/system/settings-keyboard";
|
||||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js";
|
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-events.js";
|
||||||
|
|
||||||
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
||||||
|
@ -243,6 +245,8 @@ export class GameData {
|
||||||
constructor(scene: BattleScene) {
|
constructor(scene: BattleScene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.loadSettings();
|
this.loadSettings();
|
||||||
|
this.loadGamepadSettings();
|
||||||
|
this.loadMappingConfigs();
|
||||||
this.trainerId = Utils.randInt(65536);
|
this.trainerId = Utils.randInt(65536);
|
||||||
this.secretId = Utils.randInt(65536);
|
this.secretId = Utils.randInt(65536);
|
||||||
this.starterData = {};
|
this.starterData = {};
|
||||||
|
@ -565,6 +569,125 @@ export class GameData {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the mapping configurations for a specified device.
|
||||||
|
*
|
||||||
|
* @param deviceName - The name of the device for which the configurations are being saved.
|
||||||
|
* @param config - The configuration object containing custom mapping details.
|
||||||
|
* @returns `true` if the configurations are successfully saved.
|
||||||
|
*/
|
||||||
|
public saveMappingConfigs(deviceName: string, config): boolean {
|
||||||
|
const key = deviceName.toLowerCase(); // Convert the gamepad name to lowercase to use as a key
|
||||||
|
let mappingConfigs: object = {}; // Initialize an empty object to hold the mapping configurations
|
||||||
|
if (localStorage.hasOwnProperty("mappingConfigs")) {// Check if 'mappingConfigs' exists in localStorage
|
||||||
|
mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs"));
|
||||||
|
} // Parse the existing 'mappingConfigs' from localStorage
|
||||||
|
if (!mappingConfigs[key]) {
|
||||||
|
mappingConfigs[key] = {};
|
||||||
|
} // If there is no configuration for the given key, create an empty object for it
|
||||||
|
mappingConfigs[key].custom = config.custom; // Assign the custom configuration to the mapping configuration for the given key
|
||||||
|
localStorage.setItem("mappingConfigs", JSON.stringify(mappingConfigs)); // Save the updated mapping configurations back to localStorage
|
||||||
|
return true; // Return true to indicate the operation was successful
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the mapping configurations from localStorage and injects them into the input controller.
|
||||||
|
*
|
||||||
|
* @returns `true` if the configurations are successfully loaded and injected; `false` if no configurations are found in localStorage.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This method checks if the 'mappingConfigs' entry exists in localStorage. If it does not exist, the method returns `false`.
|
||||||
|
* If 'mappingConfigs' exists, it parses the configurations and injects each configuration into the input controller
|
||||||
|
* for the corresponding gamepad or device key. The method then returns `true` to indicate success.
|
||||||
|
*/
|
||||||
|
public loadMappingConfigs(): boolean {
|
||||||
|
if (!localStorage.hasOwnProperty("mappingConfigs")) {// Check if 'mappingConfigs' exists in localStorage
|
||||||
|
return false;
|
||||||
|
} // If 'mappingConfigs' does not exist, return false
|
||||||
|
|
||||||
|
const mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs")); // Parse the existing 'mappingConfigs' from localStorage
|
||||||
|
|
||||||
|
for (const key of Object.keys(mappingConfigs)) {// Iterate over the keys of the mapping configurations
|
||||||
|
this.scene.inputController.injectConfig(key, mappingConfigs[key]);
|
||||||
|
} // Inject each configuration into the input controller for the corresponding key
|
||||||
|
|
||||||
|
return true; // Return true to indicate the operation was successful
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetMappingToFactory(): boolean {
|
||||||
|
if (!localStorage.hasOwnProperty("mappingConfigs")) {// Check if 'mappingConfigs' exists in localStorage
|
||||||
|
return false;
|
||||||
|
} // If 'mappingConfigs' does not exist, return false
|
||||||
|
localStorage.removeItem("mappingConfigs");
|
||||||
|
this.scene.inputController.resetConfigs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a gamepad setting to localStorage.
|
||||||
|
*
|
||||||
|
* @param setting - The gamepad setting to save.
|
||||||
|
* @param valueIndex - The index of the value to set for the gamepad setting.
|
||||||
|
* @returns `true` if the setting is successfully saved.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This method initializes an empty object for gamepad settings if none exist in localStorage.
|
||||||
|
* It then updates the setting in the current scene and iterates over the default gamepad settings
|
||||||
|
* to update the specified setting with the new value. Finally, it saves the updated settings back
|
||||||
|
* to localStorage and returns `true` to indicate success.
|
||||||
|
*/
|
||||||
|
public saveGamepadSetting(setting: SettingGamepad, valueIndex: integer): boolean {
|
||||||
|
let settingsGamepad: object = {}; // Initialize an empty object to hold the gamepad settings
|
||||||
|
|
||||||
|
if (localStorage.hasOwnProperty("settingsGamepad")) { // Check if 'settingsGamepad' exists in localStorage
|
||||||
|
settingsGamepad = JSON.parse(localStorage.getItem("settingsGamepad")); // Parse the existing 'settingsGamepad' from localStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
setSettingGamepad(this.scene, setting as SettingGamepad, valueIndex); // Set the gamepad setting in the current scene
|
||||||
|
|
||||||
|
Object.keys(settingGamepadDefaults).forEach(s => { // Iterate over the default gamepad settings
|
||||||
|
if (s === setting) {// If the current setting matches, update its value
|
||||||
|
settingsGamepad[s] = valueIndex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem("settingsGamepad", JSON.stringify(settingsGamepad)); // Save the updated gamepad settings back to localStorage
|
||||||
|
|
||||||
|
return true; // Return true to indicate the operation was successful
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a keyboard setting to localStorage.
|
||||||
|
*
|
||||||
|
* @param setting - The keyboard setting to save.
|
||||||
|
* @param valueIndex - The index of the value to set for the keyboard setting.
|
||||||
|
* @returns `true` if the setting is successfully saved.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This method initializes an empty object for keyboard settings if none exist in localStorage.
|
||||||
|
* It then updates the setting in the current scene and iterates over the default keyboard settings
|
||||||
|
* to update the specified setting with the new value. Finally, it saves the updated settings back
|
||||||
|
* to localStorage and returns `true` to indicate success.
|
||||||
|
*/
|
||||||
|
public saveKeyboardSetting(setting: SettingKeyboard, valueIndex: integer): boolean {
|
||||||
|
let settingsKeyboard: object = {}; // Initialize an empty object to hold the keyboard settings
|
||||||
|
|
||||||
|
if (localStorage.hasOwnProperty("settingsKeyboard")) { // Check if 'settingsKeyboard' exists in localStorage
|
||||||
|
settingsKeyboard = JSON.parse(localStorage.getItem("settingsKeyboard")); // Parse the existing 'settingsKeyboard' from localStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
setSettingKeyboard(this.scene, setting as SettingKeyboard, valueIndex); // Set the keyboard setting in the current scene
|
||||||
|
|
||||||
|
Object.keys(settingKeyboardDefaults).forEach(s => { // Iterate over the default keyboard settings
|
||||||
|
if (s === setting) {// If the current setting matches, update its value
|
||||||
|
settingsKeyboard[s] = valueIndex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem("settingsKeyboard", JSON.stringify(settingsKeyboard)); // Save the updated keyboard settings back to localStorage
|
||||||
|
|
||||||
|
return true; // Return true to indicate the operation was successful
|
||||||
|
}
|
||||||
|
|
||||||
private loadSettings(): boolean {
|
private loadSettings(): boolean {
|
||||||
Object.values(Setting).map(setting => setting as Setting).forEach(setting => setSetting(this.scene, setting, settingDefaults[setting]));
|
Object.values(Setting).map(setting => setting as Setting).forEach(setting => setSetting(this.scene, setting, settingDefaults[setting]));
|
||||||
|
|
||||||
|
@ -579,6 +702,19 @@ export class GameData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private loadGamepadSettings(): boolean {
|
||||||
|
Object.values(SettingGamepad).map(setting => setting as SettingGamepad).forEach(setting => setSettingGamepad(this.scene, setting, settingGamepadDefaults[setting]));
|
||||||
|
|
||||||
|
if (!localStorage.hasOwnProperty("settingsGamepad")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const settingsGamepad = JSON.parse(localStorage.getItem("settingsGamepad"));
|
||||||
|
|
||||||
|
for (const setting of Object.keys(settingsGamepad)) {
|
||||||
|
setSettingGamepad(this.scene, setting as SettingGamepad, settingsGamepad[setting]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public saveTutorialFlag(tutorial: Tutorial, flag: boolean): boolean {
|
public saveTutorialFlag(tutorial: Tutorial, flag: boolean): boolean {
|
||||||
let tutorials: object = {};
|
let tutorials: object = {};
|
||||||
if (localStorage.hasOwnProperty("tutorials")) {
|
if (localStorage.hasOwnProperty("tutorials")) {
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
import BattleScene from "../battle-scene";
|
||||||
|
import {SettingDefaults, SettingOptions} from "./settings";
|
||||||
|
import SettingsGamepadUiHandler from "../ui/settings/settings-gamepad-ui-handler";
|
||||||
|
import {Mode} from "../ui/ui";
|
||||||
|
import {truncateString} from "../utils";
|
||||||
|
import {Button} from "../enums/buttons";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
|
export enum SettingGamepad {
|
||||||
|
Controller = "CONTROLLER",
|
||||||
|
Gamepad_Support = "GAMEPAD_SUPPORT",
|
||||||
|
Button_Up = "BUTTON_UP",
|
||||||
|
Button_Down = "BUTTON_DOWN",
|
||||||
|
Button_Left = "BUTTON_LEFT",
|
||||||
|
Button_Right = "BUTTON_RIGHT",
|
||||||
|
Button_Action = "BUTTON_ACTION",
|
||||||
|
Button_Cancel = "BUTTON_CANCEL",
|
||||||
|
Button_Menu = "BUTTON_MENU",
|
||||||
|
Button_Stats = "BUTTON_STATS",
|
||||||
|
Button_Cycle_Form = "BUTTON_CYCLE_FORM",
|
||||||
|
Button_Cycle_Shiny = "BUTTON_CYCLE_SHINY",
|
||||||
|
Button_Cycle_Gender = "BUTTON_CYCLE_GENDER",
|
||||||
|
Button_Cycle_Ability = "BUTTON_CYCLE_ABILITY",
|
||||||
|
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
||||||
|
Button_Cycle_Variant = "BUTTON_CYCLE_VARIANT",
|
||||||
|
Button_Speed_Up = "BUTTON_SPEED_UP",
|
||||||
|
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
||||||
|
Button_Submit = "BUTTON_SUBMIT",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const settingGamepadOptions: SettingOptions = {
|
||||||
|
[SettingGamepad.Controller]: ["Default", "Change"],
|
||||||
|
[SettingGamepad.Gamepad_Support]: ["Auto", "Disabled"],
|
||||||
|
[SettingGamepad.Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingGamepad.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingGamepadDefaults: SettingDefaults = {
|
||||||
|
[SettingGamepad.Controller]: 0,
|
||||||
|
[SettingGamepad.Gamepad_Support]: 0,
|
||||||
|
[SettingGamepad.Button_Up]: 0,
|
||||||
|
[SettingGamepad.Button_Down]: 0,
|
||||||
|
[SettingGamepad.Button_Left]: 0,
|
||||||
|
[SettingGamepad.Button_Right]: 0,
|
||||||
|
[SettingGamepad.Button_Action]: 0,
|
||||||
|
[SettingGamepad.Button_Cancel]: 0,
|
||||||
|
[SettingGamepad.Button_Menu]: 0,
|
||||||
|
[SettingGamepad.Button_Stats]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Form]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Shiny]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Gender]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Ability]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Nature]: 0,
|
||||||
|
[SettingGamepad.Button_Cycle_Variant]: 0,
|
||||||
|
[SettingGamepad.Button_Speed_Up]: 0,
|
||||||
|
[SettingGamepad.Button_Slow_Down]: 0,
|
||||||
|
[SettingGamepad.Button_Submit]: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingGamepadBlackList = [
|
||||||
|
SettingKeyboard.Button_Up,
|
||||||
|
SettingKeyboard.Button_Down,
|
||||||
|
SettingKeyboard.Button_Left,
|
||||||
|
SettingKeyboard.Button_Right,
|
||||||
|
];
|
||||||
|
|
||||||
|
export function setSettingGamepad(scene: BattleScene, setting: SettingGamepad, value: integer): boolean {
|
||||||
|
switch (setting) {
|
||||||
|
case SettingGamepad.Gamepad_Support:
|
||||||
|
// if we change the value of the gamepad support, we call a method in the inputController to
|
||||||
|
// activate or deactivate the controller listener
|
||||||
|
scene.inputController.setGamepadSupport(settingGamepadOptions[setting][value] !== "Disabled");
|
||||||
|
break;
|
||||||
|
case SettingGamepad.Button_Action:
|
||||||
|
case SettingGamepad.Button_Cancel:
|
||||||
|
case SettingGamepad.Button_Menu:
|
||||||
|
case SettingGamepad.Button_Stats:
|
||||||
|
case SettingGamepad.Button_Cycle_Shiny:
|
||||||
|
case SettingGamepad.Button_Cycle_Form:
|
||||||
|
case SettingGamepad.Button_Cycle_Gender:
|
||||||
|
case SettingGamepad.Button_Cycle_Ability:
|
||||||
|
case SettingGamepad.Button_Cycle_Nature:
|
||||||
|
case SettingGamepad.Button_Cycle_Variant:
|
||||||
|
case SettingGamepad.Button_Speed_Up:
|
||||||
|
case SettingGamepad.Button_Slow_Down:
|
||||||
|
case SettingGamepad.Button_Submit:
|
||||||
|
if (value) {
|
||||||
|
if (scene.ui) {
|
||||||
|
const cancelHandler = (success: boolean = false) : boolean => {
|
||||||
|
scene.ui.revertMode();
|
||||||
|
(scene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
|
||||||
|
return success;
|
||||||
|
};
|
||||||
|
scene.ui.setOverlayMode(Mode.GAMEPAD_BINDING, {
|
||||||
|
target: setting,
|
||||||
|
cancelHandler: cancelHandler,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SettingGamepad.Controller:
|
||||||
|
if (value) {
|
||||||
|
const gp = scene.inputController.getGamepadsName();
|
||||||
|
if (scene.ui && gp) {
|
||||||
|
const cancelHandler = () => {
|
||||||
|
scene.ui.revertMode();
|
||||||
|
(scene.ui.getHandler() as SettingsGamepadUiHandler).setOptionCursor(Object.values(SettingGamepad).indexOf(SettingGamepad.Controller), 0, true);
|
||||||
|
(scene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const changeGamepadHandler = (gamepad: string) => {
|
||||||
|
scene.inputController.setChosenGamepad(gamepad);
|
||||||
|
cancelHandler();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
|
||||||
|
options: [...gp.map((g: string) => ({
|
||||||
|
label: truncateString(g, 30), // Truncate the gamepad name for display
|
||||||
|
handler: () => changeGamepadHandler(g)
|
||||||
|
})), {
|
||||||
|
label: "Cancel",
|
||||||
|
handler: cancelHandler,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
import {SettingDefaults, SettingOptions} from "#app/system/settings";
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import {Mode} from "#app/ui/ui";
|
||||||
|
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||||
|
|
||||||
|
export enum SettingKeyboard {
|
||||||
|
// Default_Layout = "DEFAULT_LAYOUT",
|
||||||
|
Button_Up = "BUTTON_UP",
|
||||||
|
Alt_Button_Up = "ALT_BUTTON_UP",
|
||||||
|
Button_Down = "BUTTON_DOWN",
|
||||||
|
Alt_Button_Down = "ALT_BUTTON_DOWN",
|
||||||
|
Button_Left = "BUTTON_LEFT",
|
||||||
|
Alt_Button_Left = "ALT_BUTTON_LEFT",
|
||||||
|
Button_Right = "BUTTON_RIGHT",
|
||||||
|
Alt_Button_Right = "ALT_BUTTON_RIGHT",
|
||||||
|
Button_Action = "BUTTON_ACTION",
|
||||||
|
Alt_Button_Action = "ALT_BUTTON_ACTION",
|
||||||
|
Button_Cancel = "BUTTON_CANCEL",
|
||||||
|
Alt_Button_Cancel = "ALT_BUTTON_CANCEL",
|
||||||
|
Button_Menu = "BUTTON_MENU",
|
||||||
|
Alt_Button_Menu = "ALT_BUTTON_MENU",
|
||||||
|
Button_Stats = "BUTTON_STATS",
|
||||||
|
Alt_Button_Stats = "ALT_BUTTON_STATS",
|
||||||
|
Button_Cycle_Form = "BUTTON_CYCLE_FORM",
|
||||||
|
Alt_Button_Cycle_Form = "ALT_BUTTON_CYCLE_FORM",
|
||||||
|
Button_Cycle_Shiny = "BUTTON_CYCLE_SHINY",
|
||||||
|
Alt_Button_Cycle_Shiny = "ALT_BUTTON_CYCLE_SHINY",
|
||||||
|
Button_Cycle_Gender = "BUTTON_CYCLE_GENDER",
|
||||||
|
Alt_Button_Cycle_Gender = "ALT_BUTTON_CYCLE_GENDER",
|
||||||
|
Button_Cycle_Ability = "BUTTON_CYCLE_ABILITY",
|
||||||
|
Alt_Button_Cycle_Ability = "ALT_BUTTON_CYCLE_ABILITY",
|
||||||
|
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
||||||
|
Alt_Button_Cycle_Nature = "ALT_BUTTON_CYCLE_NATURE",
|
||||||
|
Button_Cycle_Variant = "BUTTON_CYCLE_VARIANT",
|
||||||
|
Alt_Button_Cycle_Variant = "ALT_BUTTON_CYCLE_VARIANT",
|
||||||
|
Button_Speed_Up = "BUTTON_SPEED_UP",
|
||||||
|
Alt_Button_Speed_Up = "ALT_BUTTON_SPEED_UP",
|
||||||
|
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
||||||
|
Alt_Button_Slow_Down = "ALT_BUTTON_SLOW_DOWN",
|
||||||
|
Button_Submit = "BUTTON_SUBMIT",
|
||||||
|
Alt_Button_Submit = "ALT_BUTTON_SUBMIT",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const settingKeyboardOptions: SettingOptions = {
|
||||||
|
// [SettingKeyboard.Default_Layout]: ['Default'],
|
||||||
|
[SettingKeyboard.Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Up]: [`KEY ${Button.UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
||||||
|
|
||||||
|
[SettingKeyboard.Alt_Button_Down]: [`KEY ${Button.DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Left]: [`KEY ${Button.LEFT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Right]: [`KEY ${Button.RIGHT.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Action]: [`KEY ${Button.ACTION.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cancel]: [`KEY ${Button.CANCEL.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Menu]: [`KEY ${Button.MENU.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Stats]: [`KEY ${Button.STATS.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Form]: [`KEY ${Button.CYCLE_FORM.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Shiny]: [`KEY ${Button.CYCLE_SHINY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Gender]: [`KEY ${Button.CYCLE_GENDER.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: [`KEY ${Button.CYCLE_ABILITY.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: [`KEY ${Button.CYCLE_NATURE.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Variant]: [`KEY ${Button.V.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Speed_Up]: [`KEY ${Button.SPEED_UP.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Slow_Down]: [`KEY ${Button.SLOW_DOWN.toString()}`, "Press action to assign"],
|
||||||
|
[SettingKeyboard.Alt_Button_Submit]: [`KEY ${Button.SUBMIT.toString()}`, "Press action to assign"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingKeyboardDefaults: SettingDefaults = {
|
||||||
|
// [SettingKeyboard.Default_Layout]: 0,
|
||||||
|
[SettingKeyboard.Button_Up]: 0,
|
||||||
|
[SettingKeyboard.Button_Down]: 0,
|
||||||
|
[SettingKeyboard.Button_Left]: 0,
|
||||||
|
[SettingKeyboard.Button_Right]: 0,
|
||||||
|
[SettingKeyboard.Button_Action]: 0,
|
||||||
|
[SettingKeyboard.Button_Menu]: 0,
|
||||||
|
[SettingKeyboard.Button_Submit]: 0,
|
||||||
|
|
||||||
|
[SettingKeyboard.Alt_Button_Up]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Down]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Left]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Right]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Action]: 0,
|
||||||
|
[SettingKeyboard.Button_Cancel]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cancel]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Menu]: 0,
|
||||||
|
[SettingKeyboard.Button_Stats]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Stats]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Form]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Form]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Shiny]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Shiny]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Gender]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Gender]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Ability]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Nature]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: 0,
|
||||||
|
[SettingKeyboard.Button_Cycle_Variant]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Variant]: 0,
|
||||||
|
[SettingKeyboard.Button_Speed_Up]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Speed_Up]: 0,
|
||||||
|
[SettingKeyboard.Button_Slow_Down]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Slow_Down]: 0,
|
||||||
|
[SettingKeyboard.Alt_Button_Submit]: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingKeyboardBlackList = [
|
||||||
|
SettingKeyboard.Button_Submit,
|
||||||
|
SettingKeyboard.Button_Menu,
|
||||||
|
SettingKeyboard.Button_Action,
|
||||||
|
SettingKeyboard.Button_Cancel,
|
||||||
|
SettingKeyboard.Button_Up,
|
||||||
|
SettingKeyboard.Button_Down,
|
||||||
|
SettingKeyboard.Button_Left,
|
||||||
|
SettingKeyboard.Button_Right,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
export function setSettingKeyboard(scene: BattleScene, setting: SettingKeyboard, value: integer): boolean {
|
||||||
|
switch (setting) {
|
||||||
|
case SettingKeyboard.Button_Up:
|
||||||
|
case SettingKeyboard.Button_Down:
|
||||||
|
case SettingKeyboard.Button_Left:
|
||||||
|
case SettingKeyboard.Button_Right:
|
||||||
|
case SettingKeyboard.Button_Action:
|
||||||
|
case SettingKeyboard.Button_Cancel:
|
||||||
|
case SettingKeyboard.Button_Menu:
|
||||||
|
case SettingKeyboard.Button_Stats:
|
||||||
|
case SettingKeyboard.Button_Cycle_Shiny:
|
||||||
|
case SettingKeyboard.Button_Cycle_Form:
|
||||||
|
case SettingKeyboard.Button_Cycle_Gender:
|
||||||
|
case SettingKeyboard.Button_Cycle_Ability:
|
||||||
|
case SettingKeyboard.Button_Cycle_Nature:
|
||||||
|
case SettingKeyboard.Button_Cycle_Variant:
|
||||||
|
case SettingKeyboard.Button_Speed_Up:
|
||||||
|
case SettingKeyboard.Button_Slow_Down:
|
||||||
|
case SettingKeyboard.Alt_Button_Up:
|
||||||
|
case SettingKeyboard.Alt_Button_Down:
|
||||||
|
case SettingKeyboard.Alt_Button_Left:
|
||||||
|
case SettingKeyboard.Alt_Button_Right:
|
||||||
|
case SettingKeyboard.Alt_Button_Action:
|
||||||
|
case SettingKeyboard.Alt_Button_Cancel:
|
||||||
|
case SettingKeyboard.Alt_Button_Menu:
|
||||||
|
case SettingKeyboard.Alt_Button_Stats:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Shiny:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Form:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Gender:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Ability:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Nature:
|
||||||
|
case SettingKeyboard.Alt_Button_Cycle_Variant:
|
||||||
|
case SettingKeyboard.Alt_Button_Speed_Up:
|
||||||
|
case SettingKeyboard.Alt_Button_Slow_Down:
|
||||||
|
case SettingKeyboard.Alt_Button_Submit:
|
||||||
|
if (value) {
|
||||||
|
if (scene.ui) {
|
||||||
|
const cancelHandler = (success: boolean = false) : boolean => {
|
||||||
|
scene.ui.revertMode();
|
||||||
|
(scene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
|
||||||
|
return success;
|
||||||
|
};
|
||||||
|
scene.ui.setOverlayMode(Mode.KEYBOARD_BINDING, {
|
||||||
|
target: setting,
|
||||||
|
cancelHandler: cancelHandler,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// case SettingKeyboard.Default_Layout:
|
||||||
|
// if (value && scene.ui) {
|
||||||
|
// const cancelHandler = () => {
|
||||||
|
// scene.ui.revertMode();
|
||||||
|
// (scene.ui.getHandler() as SettingsKeyboardUiHandler).setOptionCursor(Object.values(SettingKeyboard).indexOf(SettingKeyboard.Default_Layout), 0, true);
|
||||||
|
// (scene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings();
|
||||||
|
// return false;
|
||||||
|
// };
|
||||||
|
// const changeKeyboardHandler = (keyboardLayout: string) => {
|
||||||
|
// scene.inputController.setChosenKeyboardLayout(keyboardLayout);
|
||||||
|
// cancelHandler();
|
||||||
|
// return true;
|
||||||
|
// };
|
||||||
|
// scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
|
||||||
|
// options: [{
|
||||||
|
// label: 'Default',
|
||||||
|
// handler: changeKeyboardHandler,
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
import SettingsUiHandler from "#app/ui/settings-ui-handler";
|
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
|
@ -7,6 +6,7 @@ import { updateWindowType } from "../ui/ui-theme";
|
||||||
import { PlayerGender } from "./game-data";
|
import { PlayerGender } from "./game-data";
|
||||||
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
||||||
import { MoneyFormat } from "../enums/money-format";
|
import { MoneyFormat } from "../enums/money-format";
|
||||||
|
import SettingsUiHandler from "#app/ui/settings/settings-ui-handler";
|
||||||
|
|
||||||
export enum Setting {
|
export enum Setting {
|
||||||
Game_Speed = "GAME_SPEED",
|
Game_Speed = "GAME_SPEED",
|
||||||
|
@ -31,8 +31,6 @@ export enum Setting {
|
||||||
HP_Bar_Speed = "HP_BAR_SPEED",
|
HP_Bar_Speed = "HP_BAR_SPEED",
|
||||||
Fusion_Palette_Swaps = "FUSION_PALETTE_SWAPS",
|
Fusion_Palette_Swaps = "FUSION_PALETTE_SWAPS",
|
||||||
Player_Gender = "PLAYER_GENDER",
|
Player_Gender = "PLAYER_GENDER",
|
||||||
Gamepad_Support = "GAMEPAD_SUPPORT",
|
|
||||||
Swap_A_and_B = "SWAP_A_B", // Swaps which gamepad button handles ACTION and CANCEL
|
|
||||||
Touch_Controls = "TOUCH_CONTROLS",
|
Touch_Controls = "TOUCH_CONTROLS",
|
||||||
Vibration = "VIBRATION"
|
Vibration = "VIBRATION"
|
||||||
}
|
}
|
||||||
|
@ -68,8 +66,6 @@ export const settingOptions: SettingOptions = {
|
||||||
[Setting.HP_Bar_Speed]: ["Normal", "Fast", "Faster", "Instant"],
|
[Setting.HP_Bar_Speed]: ["Normal", "Fast", "Faster", "Instant"],
|
||||||
[Setting.Fusion_Palette_Swaps]: ["Off", "On"],
|
[Setting.Fusion_Palette_Swaps]: ["Off", "On"],
|
||||||
[Setting.Player_Gender]: ["Boy", "Girl"],
|
[Setting.Player_Gender]: ["Boy", "Girl"],
|
||||||
[Setting.Gamepad_Support]: ["Auto", "Disabled"],
|
|
||||||
[Setting.Swap_A_and_B]: ["Enabled", "Disabled"],
|
|
||||||
[Setting.Touch_Controls]: ["Auto", "Disabled"],
|
[Setting.Touch_Controls]: ["Auto", "Disabled"],
|
||||||
[Setting.Vibration]: ["Auto", "Disabled"]
|
[Setting.Vibration]: ["Auto", "Disabled"]
|
||||||
};
|
};
|
||||||
|
@ -97,8 +93,6 @@ export const settingDefaults: SettingDefaults = {
|
||||||
[Setting.HP_Bar_Speed]: 0,
|
[Setting.HP_Bar_Speed]: 0,
|
||||||
[Setting.Fusion_Palette_Swaps]: 1,
|
[Setting.Fusion_Palette_Swaps]: 1,
|
||||||
[Setting.Player_Gender]: 0,
|
[Setting.Player_Gender]: 0,
|
||||||
[Setting.Gamepad_Support]: 0,
|
|
||||||
[Setting.Swap_A_and_B]: 1, // Set to 'Disabled' by default
|
|
||||||
[Setting.Touch_Controls]: 0,
|
[Setting.Touch_Controls]: 0,
|
||||||
[Setting.Vibration]: 0
|
[Setting.Vibration]: 0
|
||||||
};
|
};
|
||||||
|
@ -194,14 +188,6 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Setting.Gamepad_Support:
|
|
||||||
// if we change the value of the gamepad support, we call a method in the inputController to
|
|
||||||
// activate or deactivate the controller listener
|
|
||||||
scene.inputController.setGamepadSupport(settingOptions[setting][value] !== "Disabled");
|
|
||||||
break;
|
|
||||||
case Setting.Swap_A_and_B:
|
|
||||||
scene.abSwapped = settingOptions[setting][value] !== "Disabled";
|
|
||||||
break;
|
|
||||||
case Setting.Touch_Controls:
|
case Setting.Touch_Controls:
|
||||||
scene.enableTouchControls = settingOptions[setting][value] !== "Disabled" && hasTouchscreen();
|
scene.enableTouchControls = settingOptions[setting][value] !== "Disabled" && hasTouchscreen();
|
||||||
const touchControls = document.getElementById("touchControls");
|
const touchControls = document.getElementById("touchControls");
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import {
|
||||||
|
getIconForLatestInput,
|
||||||
|
getSettingNameWithKeycode
|
||||||
|
} from "#app/configs/inputs/configHandler";
|
||||||
|
import {expect} from "vitest";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
|
export class InGameManip {
|
||||||
|
private config;
|
||||||
|
private keycode;
|
||||||
|
private settingName;
|
||||||
|
private icon;
|
||||||
|
private configs;
|
||||||
|
private latestSource;
|
||||||
|
private selectedDevice;
|
||||||
|
|
||||||
|
constructor(configs, config, selectedDevice) {
|
||||||
|
this.config = config;
|
||||||
|
this.configs = configs;
|
||||||
|
this.selectedDevice = selectedDevice;
|
||||||
|
this.keycode = null;
|
||||||
|
this.settingName = null;
|
||||||
|
this.icon = null;
|
||||||
|
this.latestSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
whenWePressOnKeyboard(keycode) {
|
||||||
|
this.keycode = Phaser.Input.Keyboard.KeyCodes[keycode.toUpperCase()];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
nothingShouldHappen() {
|
||||||
|
const settingName = getSettingNameWithKeycode(this.config, this.keycode);
|
||||||
|
expect(settingName).toEqual(-1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
forTheWantedBind(settingName) {
|
||||||
|
if (!settingName.includes("Button_")) {
|
||||||
|
settingName = "Button_" + settingName;
|
||||||
|
}
|
||||||
|
this.settingName = SettingKeyboard[settingName];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
weShouldSeeTheIcon(icon) {
|
||||||
|
if (!icon.includes("KEY_")) {
|
||||||
|
icon = "KEY_" + icon;
|
||||||
|
}
|
||||||
|
this.icon = this.config.icons[icon];
|
||||||
|
expect(getIconForLatestInput(this.configs, this.latestSource, this.selectedDevice, this.settingName)).toEqual(this.icon);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
forTheSource(source) {
|
||||||
|
this.latestSource = source;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizeSettingNameString(input) {
|
||||||
|
// Convert the input string to lower case
|
||||||
|
const lowerCasedInput = input.toLowerCase();
|
||||||
|
|
||||||
|
// Replace underscores with spaces, capitalize the first letter of each word, and join them back with underscores
|
||||||
|
const words = lowerCasedInput.split("_").map(word => word.charAt(0).toUpperCase() + word.slice(1));
|
||||||
|
const result = words.join("_");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
weShouldTriggerTheButton(settingName) {
|
||||||
|
if (!settingName.includes("Button_")) {
|
||||||
|
settingName = "Button_" + settingName;
|
||||||
|
}
|
||||||
|
this.settingName = SettingKeyboard[this.normalizeSettingNameString(settingName)];
|
||||||
|
expect(getSettingNameWithKeycode(this.config, this.keycode)).toEqual(this.settingName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
import {expect} from "vitest";
|
||||||
|
import {
|
||||||
|
deleteBind,
|
||||||
|
getIconWithKeycode,
|
||||||
|
getIconWithSettingName,
|
||||||
|
getKeyWithKeycode,
|
||||||
|
getKeyWithSettingName,
|
||||||
|
assign,
|
||||||
|
getSettingNameWithKeycode, canIAssignThisKey, canIDeleteThisKey, canIOverrideThisSetting
|
||||||
|
} from "#app/configs/inputs/configHandler";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
|
export class MenuManip {
|
||||||
|
private config;
|
||||||
|
private settingName;
|
||||||
|
private keycode;
|
||||||
|
private icon;
|
||||||
|
private iconDisplayed;
|
||||||
|
private specialCaseIcon;
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
this.config = config;
|
||||||
|
this.settingName = null;
|
||||||
|
this.icon = null;
|
||||||
|
this.iconDisplayed = null;
|
||||||
|
this.specialCaseIcon = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
convertNameToButtonString(input) {
|
||||||
|
// Check if the input starts with "Alt_Button"
|
||||||
|
if (input.startsWith("Alt_Button")) {
|
||||||
|
// Return the last part in uppercase
|
||||||
|
return input.split("_").pop().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the input string by underscore
|
||||||
|
const parts = input.split("_");
|
||||||
|
|
||||||
|
// Skip the first part and join the rest with an underscore
|
||||||
|
const result = parts.slice(1).map(part => part.toUpperCase()).join("_");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
whenCursorIsOnSetting(settingName) {
|
||||||
|
if (!settingName.includes("Button_")) {
|
||||||
|
settingName = "Button_" + settingName;
|
||||||
|
}
|
||||||
|
this.settingName = SettingKeyboard[settingName];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconDisplayedIs(icon) {
|
||||||
|
if (!(icon.toUpperCase().includes("KEY_"))) {
|
||||||
|
icon = "KEY_" + icon.toUpperCase();
|
||||||
|
}
|
||||||
|
this.iconDisplayed = this.config.icons[icon];
|
||||||
|
expect(getIconWithSettingName(this.config, this.settingName)).toEqual(this.iconDisplayed);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
thereShouldBeNoIconAnymore() {
|
||||||
|
const icon = getIconWithSettingName(this.config, this.settingName);
|
||||||
|
expect(icon === undefined).toEqual(true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
thereShouldBeNoIcon() {
|
||||||
|
return this.thereShouldBeNoIconAnymore();
|
||||||
|
}
|
||||||
|
|
||||||
|
nothingShouldHappen() {
|
||||||
|
const settingName = getSettingNameWithKeycode(this.config, this.keycode);
|
||||||
|
expect(settingName).toEqual(-1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
weWantThisBindInstead(keycode) {
|
||||||
|
this.keycode = Phaser.Input.Keyboard.KeyCodes[keycode];
|
||||||
|
const icon = getIconWithKeycode(this.config, this.keycode);
|
||||||
|
const key = getKeyWithKeycode(this.config, this.keycode);
|
||||||
|
const _keys = key.toLowerCase().split("_");
|
||||||
|
const iconIdentifier = _keys[_keys.length-1];
|
||||||
|
expect(icon.toLowerCase().includes(iconIdentifier)).toEqual(true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
whenWeDelete(settingName?: string) {
|
||||||
|
this.settingName = SettingKeyboard[settingName] || this.settingName;
|
||||||
|
// const key = getKeyWithSettingName(this.config, this.settingName);
|
||||||
|
deleteBind(this.config, this.settingName);
|
||||||
|
// expect(this.config.custom[key]).toEqual(-1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
whenWeTryToDelete(settingName?: string) {
|
||||||
|
this.settingName = SettingKeyboard[settingName] || this.settingName;
|
||||||
|
deleteBind(this.config, this.settingName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmAssignment() {
|
||||||
|
assign(this.config, this.settingName, this.keycode);
|
||||||
|
}
|
||||||
|
|
||||||
|
butLetsForceIt() {
|
||||||
|
this.confirm();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
assign(this.config, this.settingName, this.keycode);
|
||||||
|
}
|
||||||
|
|
||||||
|
weCantAssignThisKey() {
|
||||||
|
const key = getKeyWithKeycode(this.config, this.keycode);
|
||||||
|
expect(canIAssignThisKey(this.config, key)).toEqual(false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
weCantOverrideThisBind() {
|
||||||
|
expect(canIOverrideThisSetting(this.config, this.settingName)).toEqual(false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
weCantDelete() {
|
||||||
|
const key = getKeyWithSettingName(this.config, this.settingName);
|
||||||
|
expect(canIDeleteThisKey(this.config, key)).toEqual(false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,417 @@
|
||||||
|
import {beforeEach, describe, expect, it} from "vitest";
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
import {deepCopy} from "#app/utils";
|
||||||
|
import {
|
||||||
|
getKeyWithKeycode,
|
||||||
|
getKeyWithSettingName,
|
||||||
|
} from "#app/configs/inputs/configHandler";
|
||||||
|
import {MenuManip} from "#app/test/helpers/menuManip";
|
||||||
|
import {InGameManip} from "#app/test/helpers/inGameManip";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
|
import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty";
|
||||||
|
import {SettingKeyboard} from "#app/system/settings-keyboard";
|
||||||
|
|
||||||
|
|
||||||
|
describe("Test Rebinding", () => {
|
||||||
|
let config;
|
||||||
|
let inGame;
|
||||||
|
let inTheSettingMenu;
|
||||||
|
const configs: Map<string, InterfaceConfig> = new Map();
|
||||||
|
const selectedDevice = {
|
||||||
|
[Device.GAMEPAD]: null,
|
||||||
|
[Device.KEYBOARD]: "default",
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
config = deepCopy(cfg_keyboard_qwerty);
|
||||||
|
config.custom = {...config.default};
|
||||||
|
configs["default"] = config;
|
||||||
|
inGame = new InGameManip(configs, config, selectedDevice);
|
||||||
|
inTheSettingMenu = new MenuManip(config);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if config is loaded", () => {
|
||||||
|
expect(config).not.toBeNull();
|
||||||
|
});
|
||||||
|
it("Check button for setting name", () => {
|
||||||
|
const settingName = SettingKeyboard.Button_Left;
|
||||||
|
const button = config.settings[settingName];
|
||||||
|
expect(button).toEqual(Button.LEFT);
|
||||||
|
});
|
||||||
|
it("Check key for Keyboard KeyCode", () => {
|
||||||
|
const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.LEFT);
|
||||||
|
const settingName = config.custom[key];
|
||||||
|
const button = config.settings[settingName];
|
||||||
|
expect(button).toEqual(Button.LEFT);
|
||||||
|
});
|
||||||
|
it("Check key for currenly Assigned to action not alt", () => {
|
||||||
|
const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.A);
|
||||||
|
const settingName = config.custom[key];
|
||||||
|
const button = config.settings[settingName];
|
||||||
|
expect(button).toEqual(Button.LEFT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check key for currenly Assigned to setting name", () => {
|
||||||
|
const settingName = SettingKeyboard.Button_Left;
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
expect(key).toEqual("KEY_ARROW_LEFT");
|
||||||
|
});
|
||||||
|
it("Check key for currenly Assigned to setting name alt", () => {
|
||||||
|
const settingName = SettingKeyboard.Alt_Button_Left;
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
expect(key).toEqual("KEY_A");
|
||||||
|
});
|
||||||
|
it("Check key from key code", () => {
|
||||||
|
const keycode = Phaser.Input.Keyboard.KeyCodes.LEFT;
|
||||||
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
|
expect(key).toEqual("KEY_ARROW_LEFT");
|
||||||
|
});
|
||||||
|
it("Check icon for currenly Assigned to key code", () => {
|
||||||
|
const keycode = Phaser.Input.Keyboard.KeyCodes.LEFT;
|
||||||
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
|
const icon = config.icons[key];
|
||||||
|
expect(icon).toEqual("KEY_ARROW_LEFT.png");
|
||||||
|
});
|
||||||
|
it("Check icon for currenly Assigned to key code", () => {
|
||||||
|
const keycode = Phaser.Input.Keyboard.KeyCodes.A;
|
||||||
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
|
const icon = config.icons[key];
|
||||||
|
expect(icon).toEqual("A.png");
|
||||||
|
});
|
||||||
|
it("Check icon for currenly Assigned to setting name", () => {
|
||||||
|
const settingName = SettingKeyboard.Button_Left;
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
const icon = config.icons[key];
|
||||||
|
expect(icon).toEqual("KEY_ARROW_LEFT.png");
|
||||||
|
});
|
||||||
|
it("Check icon for currenly Assigned to setting name alt", () => {
|
||||||
|
const settingName = SettingKeyboard.Alt_Button_Left;
|
||||||
|
const key = getKeyWithSettingName(config, settingName);
|
||||||
|
const icon = config.icons[key];
|
||||||
|
expect(icon).toEqual("A.png");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if is working", () => {
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("A");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Right").iconDisplayedIs("D");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("A").weWantThisBindInstead("D").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check prevent rebind indirectly the d-pad buttons", () => {
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("A");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Right").iconDisplayedIs("D");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("A").weWantThisBindInstead("LEFT").weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Left");
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Swap alt with a d-pad main", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Up").iconDisplayedIs("KEY_ARROW_UP").weWantThisBindInstead("W").weCantOverrideThisBind().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if double assign d-pad is blocked", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").weWantThisBindInstead("RIGHT").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").weWantThisBindInstead("UP").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").weWantThisBindInstead("RIGHT").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if double assign is working", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_A").weWantThisBindInstead("D").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_D").weWantThisBindInstead("W").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_W").weWantThisBindInstead("D").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("W").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if triple swap d-pad is prevented", () => {
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").weWantThisBindInstead("RIGHT").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Right").iconDisplayedIs("KEY_ARROW_RIGHT").weWantThisBindInstead("UP").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").weWantThisBindInstead("LEFT").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if triple swap is working", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_A").weWantThisBindInstead("D").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Right").thereShouldBeNoIcon().weWantThisBindInstead("W").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_D").weWantThisBindInstead("A").confirm();
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Swap alt with a main", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("R").weShouldTriggerTheButton("Cycle_Shiny");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Cycle_Shiny").iconDisplayedIs("KEY_R").weWantThisBindInstead("D").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("multiple Swap alt with another main", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("R").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("F").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Shiny").iconDisplayedIs("KEY_R").weWantThisBindInstead("D").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("F").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Form").iconDisplayedIs("KEY_F").weWantThisBindInstead("R").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("R").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("F").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Swap alt with a key not binded yet", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").iconDisplayedIs("KEY_W").weWantThisBindInstead("B").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("W").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Delete blacklisted bind", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inTheSettingMenu.whenWeDelete("Button_Left").weCantDelete().iconDisplayedIs("KEY_ARROW_LEFT");
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Delete bind", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Left").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Delete bind then assign a not yet binded button", () => {
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Left").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").thereShouldBeNoIcon().weWantThisBindInstead("B").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
});
|
||||||
|
it("swap 2 bind, than delete 1 bind than assign another bind", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("R").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("F").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Shiny").iconDisplayedIs("KEY_R").weWantThisBindInstead("D").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("F").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Form").iconDisplayedIs("KEY_F").weWantThisBindInstead("W").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("F").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Left").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("F").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("S").weShouldTriggerTheButton("Alt_Button_Down");
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Down").iconDisplayedIs("KEY_S").weWantThisBindInstead("B").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("R").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("F").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Button_Cycle_Form");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Button_Cycle_Shiny");
|
||||||
|
inGame.whenWePressOnKeyboard("S").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Down");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("Delete bind then assign not already existing button", () => {
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Left").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").thereShouldBeNoIcon().weWantThisBindInstead("B").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("change alt bind to not already existing button, than another one alt bind with another not already existing button", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("B").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("U").nothingShouldHappen();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").iconDisplayedIs("KEY_A").weWantThisBindInstead("B").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("U").nothingShouldHappen();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Right").iconDisplayedIs("KEY_D").weWantThisBindInstead("U").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("B").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("U").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Swap multiple touch alt and main", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Up").iconDisplayedIs("KEY_ARROW_UP").weWantThisBindInstead("RIGHT").weCantOverrideThisBind().weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").iconDisplayedIs("KEY_W").weWantThisBindInstead("D").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").iconDisplayedIs("KEY_D").weWantThisBindInstead("W").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("W").weShouldTriggerTheButton("Alt_Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("Delete 2 bind then reassign one of them", () => {
|
||||||
|
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Left").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").weShouldTriggerTheButton("Alt_Button_Right");
|
||||||
|
|
||||||
|
inTheSettingMenu.whenWeDelete("Alt_Button_Right").thereShouldBeNoIconAnymore();
|
||||||
|
inGame.whenWePressOnKeyboard("A").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Left").thereShouldBeNoIcon().weWantThisBindInstead("A").confirm();
|
||||||
|
inGame.whenWePressOnKeyboard("A").weShouldTriggerTheButton("Alt_Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("D").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test keyboard listener", () => {
|
||||||
|
const keyDown = Phaser.Input.Keyboard.KeyCodes.S;
|
||||||
|
const key = getKeyWithKeycode(config, keyDown);
|
||||||
|
const settingName = config.custom[key];
|
||||||
|
const buttonDown = config.settings[settingName];
|
||||||
|
expect(buttonDown).toEqual(Button.DOWN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("retrieve the correct icon for a given source", () => {
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Cycle_Shiny").iconDisplayedIs("KEY_R");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Cycle_Form").iconDisplayedIs("KEY_F");
|
||||||
|
inGame.forTheSource("keyboard").forTheWantedBind("Cycle_Shiny").weShouldSeeTheIcon("R");
|
||||||
|
inGame.forTheSource("keyboard").forTheWantedBind("Cycle_Form").weShouldSeeTheIcon("F");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("check the key displayed on confirm", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("ENTER").weShouldTriggerTheButton("Button_Submit");
|
||||||
|
inGame.whenWePressOnKeyboard("UP").weShouldTriggerTheButton("Button_Up");
|
||||||
|
inGame.whenWePressOnKeyboard("DOWN").weShouldTriggerTheButton("Button_Down");
|
||||||
|
inGame.whenWePressOnKeyboard("LEFT").weShouldTriggerTheButton("Button_Left");
|
||||||
|
inGame.whenWePressOnKeyboard("RIGHT").weShouldTriggerTheButton("Button_Right");
|
||||||
|
inGame.whenWePressOnKeyboard("ESC").weShouldTriggerTheButton("Button_Menu");
|
||||||
|
inGame.whenWePressOnKeyboard("HOME").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("DELETE").nothingShouldHappen();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Submit").iconDisplayedIs("KEY_ENTER").whenWeDelete().iconDisplayedIs("KEY_ENTER");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Up").iconDisplayedIs("KEY_ARROW_UP").whenWeDelete().iconDisplayedIs("KEY_ARROW_UP");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Down").iconDisplayedIs("KEY_ARROW_DOWN").whenWeDelete().iconDisplayedIs("KEY_ARROW_DOWN");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Left").iconDisplayedIs("KEY_ARROW_LEFT").whenWeDelete().iconDisplayedIs("KEY_ARROW_LEFT");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Right").iconDisplayedIs("KEY_ARROW_RIGHT").whenWeDelete().iconDisplayedIs("KEY_ARROW_RIGHT");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Menu").iconDisplayedIs("KEY_ESC").whenWeDelete().iconDisplayedIs("KEY_ESC");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").iconDisplayedIs("KEY_W").whenWeDelete().thereShouldBeNoIconAnymore();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").thereShouldBeNoIcon().weWantThisBindInstead("DELETE").weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Up").thereShouldBeNoIcon().weWantThisBindInstead("HOME").weCantAssignThisKey().butLetsForceIt();
|
||||||
|
inGame.whenWePressOnKeyboard("DELETE").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("HOME").nothingShouldHappen();
|
||||||
|
inGame.whenWePressOnKeyboard("W").nothingShouldHappen();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("check to delete all the binds of an action", () => {
|
||||||
|
inGame.whenWePressOnKeyboard("V").weShouldTriggerTheButton("Button_Cycle_Variant");
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Variant").thereShouldBeNoIcon().weWantThisBindInstead("K").confirm();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Variant").iconDisplayedIs("KEY_K").whenWeDelete().thereShouldBeNoIconAnymore();
|
||||||
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Variant").iconDisplayedIs("KEY_V").whenWeDelete().thereShouldBeNoIconAnymore();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,153 +1,137 @@
|
||||||
export interface ButtonKey {
|
import {Button} from "./enums/buttons";
|
||||||
onDown: (opt: object) => void;
|
import EventEmitter = Phaser.Events.EventEmitter;
|
||||||
onUp: (opt: object) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ButtonMap = Map<string, ButtonKey>;
|
// Create a map to store key bindings
|
||||||
|
export const keys = new Map<string, string>();
|
||||||
export const keys = new Map();
|
// Create a map to store keys that are currently pressed
|
||||||
export const keysDown = new Map();
|
export const keysDown = new Map<string, string>();
|
||||||
|
// Variable to store the ID of the last touched element
|
||||||
let lastTouchedId: string;
|
let lastTouchedId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes all touch controls
|
* Initialize touch controls by binding keys to buttons.
|
||||||
*
|
*
|
||||||
* @param buttonMap Map of buttons to key objects
|
* @param events - The event emitter for handling input events.
|
||||||
*/
|
*/
|
||||||
export function initTouchControls(buttonMap: ButtonMap) {
|
export function initTouchControls(events: EventEmitter): void {
|
||||||
preventElementZoom(document.querySelector("#dpad"));
|
preventElementZoom(document.querySelector("#dpad"));
|
||||||
preventElementZoom(document.querySelector("#apad"));
|
preventElementZoom(document.querySelector("#apad"));
|
||||||
|
// Select all elements with the 'data-key' attribute and bind keys to them
|
||||||
for (const button of document.querySelectorAll<HTMLElement>("[data-key]")) {
|
for (const button of document.querySelectorAll("[data-key]")) {
|
||||||
bindKey(button, button.dataset.key, buttonMap);
|
// @ts-ignore - Bind the key to the button using the dataset key
|
||||||
|
bindKey(button, button.dataset.key, events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the device has a touchscreen
|
* Check if the device has a touchscreen.
|
||||||
|
*
|
||||||
|
* @returns `true` if the device has a touchscreen, otherwise `false`.
|
||||||
*/
|
*/
|
||||||
export function hasTouchscreen() {
|
export function hasTouchscreen(): boolean {
|
||||||
return window.matchMedia("(hover: none), (pointer: coarse)").matches;
|
return window.matchMedia("(hover: none), (pointer: coarse)").matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if it's a mobile device through the user-agent
|
* Check if the device is a mobile device.
|
||||||
|
*
|
||||||
|
* @returns `true` if the device is a mobile device, otherwise `false`.
|
||||||
*/
|
*/
|
||||||
export function isMobile() {
|
export function isMobile(): boolean {
|
||||||
const userAgent = navigator.userAgent || navigator.vendor || window["opera"];
|
let ret = false;
|
||||||
return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(userAgent)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)));
|
(function (a) {
|
||||||
|
// Check the user agent string against a regex for mobile devices
|
||||||
|
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
})(navigator.userAgent || navigator.vendor || window["opera"]);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate a keyboard event on the canvas
|
* Simulates a keyboard event on the canvas.
|
||||||
*
|
*
|
||||||
* @param eventType Type of the keyboard event
|
* @param eventType - The type of the keyboard event ('keydown' or 'keyup').
|
||||||
* @param button Button to simulate
|
* @param key - The key to simulate.
|
||||||
* @param buttonMap Map of buttons to key objects
|
* @param events - The event emitter for handling input events.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This function checks if the key exists in the Button enum. If it does, it retrieves the corresponding button
|
||||||
|
* and emits the appropriate event ('input_down' or 'input_up') based on the event type.
|
||||||
*/
|
*/
|
||||||
function simulateKeyboardEvent(eventType: string, button: string, buttonMap: ButtonMap) {
|
function simulateKeyboardEvent(eventType: string, key: string, events: EventEmitter) {
|
||||||
const key = buttonMap[button];
|
if (!Button.hasOwnProperty(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const button = Button[key];
|
||||||
|
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case "keydown":
|
case "keydown":
|
||||||
key.onDown({});
|
events.emit("input_down", {
|
||||||
|
controller_type: "keyboard",
|
||||||
|
button: button,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "keyup":
|
case "keyup":
|
||||||
key.onUp({});
|
events.emit("input_up", {
|
||||||
|
controller_type: "keyboard",
|
||||||
|
button: button,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate a keyboard input from 'keydown' to 'keyup'
|
* Binds a node to a specific key to simulate keyboard events on touch.
|
||||||
*
|
*
|
||||||
* @param {string} key Key to simulate
|
* @param node - The DOM element to bind the key to.
|
||||||
* @param {object} buttonMap Map of buttons to key objects
|
* @param key - The key to simulate.
|
||||||
*/
|
* @param events - The event emitter for handling input events.
|
||||||
// function simulateKeyboardInput(key, buttonMap) {
|
|
||||||
// simulateKeyboardEvent('keydown', key, buttonMap);
|
|
||||||
// window.setTimeout(() => {
|
|
||||||
// simulateKeyboardEvent('keyup', key, buttonMap);
|
|
||||||
// }, 100);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind a node by a specific key to simulate on touch
|
|
||||||
*
|
*
|
||||||
* @param node The node to bind a key to
|
* @remarks
|
||||||
* @param key Key to simulate
|
* This function binds touch events to a node to simulate 'keydown' and 'keyup' keyboard events.
|
||||||
* @param buttonMap Map of buttons to key objects
|
* It adds the key to the keys map and tracks the keydown state. When a touch starts, it simulates
|
||||||
|
* a 'keydown' event and adds an 'active' class to the node. When the touch ends, it simulates a 'keyup'
|
||||||
|
* event, removes the keydown state, and removes the 'active' class from the node and the last touched element.
|
||||||
*/
|
*/
|
||||||
function bindKey(node: Element, key: string, buttonMap: ButtonMap) {
|
function bindKey(node: HTMLElement, key: string, events) {
|
||||||
keys.set(node.id, key);
|
keys.set(node.id, key);
|
||||||
|
|
||||||
node.addEventListener("touchstart", (event: TouchEvent) => {
|
node.addEventListener("touchstart", event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
simulateKeyboardEvent("keydown", key, buttonMap);
|
simulateKeyboardEvent("keydown", key, events);
|
||||||
if (!(event.target instanceof Element)) {
|
keysDown.set(event.target["id"], node.id);
|
||||||
return;
|
|
||||||
}
|
|
||||||
keysDown.set(event.target.id, node.id);
|
|
||||||
node.classList.add("active");
|
node.classList.add("active");
|
||||||
});
|
});
|
||||||
|
|
||||||
node.addEventListener("touchend", (event: TouchEvent) => {
|
node.addEventListener("touchend", event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (!(event.target instanceof Element)) {
|
const pressedKey = keysDown.get(event.target["id"]);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pressedKey = keysDown.get(event.target.id);
|
|
||||||
if (pressedKey && keys.has(pressedKey)) {
|
if (pressedKey && keys.has(pressedKey)) {
|
||||||
const key = keys.get(pressedKey);
|
const key = keys.get(pressedKey);
|
||||||
simulateKeyboardEvent("keyup", key, buttonMap);
|
simulateKeyboardEvent("keyup", key, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
keysDown.delete(event.target.id);
|
keysDown.delete(event.target["id"]);
|
||||||
node.classList.remove("active");
|
node.classList.remove("active");
|
||||||
|
|
||||||
if (lastTouchedId) {
|
if (lastTouchedId) {
|
||||||
document.getElementById(lastTouchedId).classList.remove("active");
|
document.getElementById(lastTouchedId).classList.remove("active");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Inspired by https://github.com/pulsejet/mkxp-web/blob/262a2254b684567311c9f0e135ee29f6e8c3613e/extra/js/dpad.js
|
|
||||||
node.addEventListener("touchmove", (event : TouchEvent) => {
|
|
||||||
if (!(event.changedTouches[0].target instanceof Element)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { target, clientX, clientY } = event.changedTouches[0];
|
|
||||||
const origTargetId = keysDown.get(target.id);
|
|
||||||
const nextTargetId = document.elementFromPoint(clientX, clientY).id;
|
|
||||||
if (origTargetId === nextTargetId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (origTargetId) {
|
|
||||||
const key = keys.get(origTargetId);
|
|
||||||
simulateKeyboardEvent("keyup", key, buttonMap);
|
|
||||||
keysDown.delete(target.id);
|
|
||||||
document.getElementById(origTargetId).classList.remove("active");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keys.has(nextTargetId)) {
|
|
||||||
const key = keys.get(nextTargetId);
|
|
||||||
simulateKeyboardEvent("keydown", key, buttonMap);
|
|
||||||
keysDown.set(target.id, nextTargetId);
|
|
||||||
lastTouchedId = nextTargetId;
|
|
||||||
document.getElementById(nextTargetId).classList.add("active");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent zoom on specified element
|
|
||||||
*
|
|
||||||
* {@link https://stackoverflow.com/a/39778831/4622620|Source}
|
* {@link https://stackoverflow.com/a/39778831/4622620|Source}
|
||||||
*
|
*
|
||||||
* @param element The element to prevent zoom on
|
* Prevent zoom on specified element
|
||||||
|
* @param {HTMLElement} element
|
||||||
*/
|
*/
|
||||||
function preventElementZoom(element: HTMLElement) {
|
function preventElementZoom(element: HTMLElement): void {
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
element.addEventListener("touchstart", (event: TouchEvent) => {
|
element.addEventListener("touchstart", (event: TouchEvent) => {
|
||||||
|
|
||||||
if (!(event.currentTarget instanceof HTMLElement)) {
|
if (!(event.currentTarget instanceof HTMLElement)) {
|
||||||
|
|
|
@ -4,8 +4,10 @@ import {InputsController} from "./inputs-controller";
|
||||||
import MessageUiHandler from "./ui/message-ui-handler";
|
import MessageUiHandler from "./ui/message-ui-handler";
|
||||||
import StarterSelectUiHandler from "./ui/starter-select-ui-handler";
|
import StarterSelectUiHandler from "./ui/starter-select-ui-handler";
|
||||||
import {Setting, settingOptions} from "./system/settings";
|
import {Setting, settingOptions} from "./system/settings";
|
||||||
import SettingsUiHandler from "./ui/settings-ui-handler";
|
import SettingsUiHandler from "./ui/settings/settings-ui-handler";
|
||||||
import {Button} from "./enums/buttons";
|
import {Button} from "./enums/buttons";
|
||||||
|
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
||||||
|
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
|
|
||||||
type ActionKeys = Record<Button, () => void>;
|
type ActionKeys = Record<Button, () => void>;
|
||||||
|
@ -159,7 +161,9 @@ export class UiInputs {
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonCycleOption(button: Button): void {
|
buttonCycleOption(button: Button): void {
|
||||||
if (this.scene.ui?.getHandler() instanceof StarterSelectUiHandler) {
|
const whitelist = [StarterSelectUiHandler, SettingsUiHandler, SettingsGamepadUiHandler, SettingsKeyboardUiHandler];
|
||||||
|
const uiHandler = this.scene.ui?.getHandler();
|
||||||
|
if (whitelist.some(handler => uiHandler instanceof handler)) {
|
||||||
this.scene.ui.processInput(button);
|
this.scene.ui.processInput(button);
|
||||||
} else if (button === Button.V) {
|
} else if (button === Button.V) {
|
||||||
this.buttonInfo(true);
|
this.buttonInfo(true);
|
||||||
|
|
|
@ -0,0 +1,259 @@
|
||||||
|
import UiHandler from "../ui-handler";
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import {addWindow} from "../ui-theme";
|
||||||
|
import {addTextObject, TextStyle} from "../text";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
import {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for handling UI elements related to button bindings.
|
||||||
|
*/
|
||||||
|
export default abstract class AbstractBindingUiHandler extends UiHandler {
|
||||||
|
// Containers for different segments of the UI.
|
||||||
|
protected optionSelectContainer: Phaser.GameObjects.Container;
|
||||||
|
protected actionsContainer: Phaser.GameObjects.Container;
|
||||||
|
|
||||||
|
// Background elements for titles and action areas.
|
||||||
|
protected titleBg: Phaser.GameObjects.NineSlice;
|
||||||
|
protected actionBg: Phaser.GameObjects.NineSlice;
|
||||||
|
protected optionSelectBg: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
|
// Text elements for displaying instructions and actions.
|
||||||
|
protected unlockText: Phaser.GameObjects.Text;
|
||||||
|
protected timerText: Phaser.GameObjects.Text;
|
||||||
|
protected swapText: Phaser.GameObjects.Text;
|
||||||
|
protected actionLabel: Phaser.GameObjects.Text;
|
||||||
|
protected cancelLabel: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
|
protected listening: boolean = false;
|
||||||
|
protected buttonPressed: number | null = null;
|
||||||
|
|
||||||
|
// Icons for displaying current and new button assignments.
|
||||||
|
protected newButtonIcon: Phaser.GameObjects.Sprite;
|
||||||
|
protected targetButtonIcon: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
|
// Function to call on cancel or completion of binding.
|
||||||
|
protected cancelFn: (boolean?) => boolean;
|
||||||
|
abstract swapAction(): boolean;
|
||||||
|
|
||||||
|
protected timeLeftAutoClose: number = 5;
|
||||||
|
protected countdownTimer;
|
||||||
|
|
||||||
|
// The specific setting being modified.
|
||||||
|
protected target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the AbstractBindingUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup UI elements.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
const ui = this.getUi();
|
||||||
|
this.optionSelectContainer = this.scene.add.container(0, 0);
|
||||||
|
this.actionsContainer = this.scene.add.container(0, 0);
|
||||||
|
// Initially, containers are not visible.
|
||||||
|
this.optionSelectContainer.setVisible(false);
|
||||||
|
this.actionsContainer.setVisible(false);
|
||||||
|
|
||||||
|
// Add containers to the UI.
|
||||||
|
ui.add(this.optionSelectContainer);
|
||||||
|
ui.add(this.actionsContainer);
|
||||||
|
|
||||||
|
// Setup backgrounds and text objects for UI.
|
||||||
|
this.titleBg = addWindow(this.scene, (this.scene.game.canvas.width / 6) - this.getWindowWidth(), -(this.scene.game.canvas.height / 6) + 28 + 21, this.getWindowWidth(), 24);
|
||||||
|
this.titleBg.setOrigin(0.5);
|
||||||
|
this.optionSelectContainer.add(this.titleBg);
|
||||||
|
|
||||||
|
this.actionBg = addWindow(this.scene, (this.scene.game.canvas.width / 6) - this.getWindowWidth(), -(this.scene.game.canvas.height / 6) + this.getWindowHeight() + 28 + 21 + 21, this.getWindowWidth(), 24);
|
||||||
|
this.actionBg.setOrigin(0.5);
|
||||||
|
this.actionsContainer.add(this.actionBg);
|
||||||
|
|
||||||
|
// Text prompts and instructions for the user.
|
||||||
|
this.unlockText = addTextObject(this.scene, 0, 0, "Press a button...", TextStyle.WINDOW);
|
||||||
|
this.unlockText.setOrigin(0, 0);
|
||||||
|
this.unlockText.setPositionRelative(this.titleBg, 36, 4);
|
||||||
|
this.optionSelectContainer.add(this.unlockText);
|
||||||
|
|
||||||
|
this.timerText = addTextObject(this.scene, 0, 0, "(5)", TextStyle.WINDOW);
|
||||||
|
this.timerText.setOrigin(0, 0);
|
||||||
|
this.timerText.setPositionRelative(this.unlockText, (this.unlockText.width/6) + 5, 0);
|
||||||
|
this.optionSelectContainer.add(this.timerText);
|
||||||
|
|
||||||
|
this.optionSelectBg = addWindow(this.scene, (this.scene.game.canvas.width / 6) - this.getWindowWidth(), -(this.scene.game.canvas.height / 6) + this.getWindowHeight() + 28, this.getWindowWidth(), this.getWindowHeight());
|
||||||
|
this.optionSelectBg.setOrigin(0.5);
|
||||||
|
this.optionSelectContainer.add(this.optionSelectBg);
|
||||||
|
|
||||||
|
this.cancelLabel = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
||||||
|
this.cancelLabel.setOrigin(0, 0.5);
|
||||||
|
this.cancelLabel.setPositionRelative(this.actionBg, 10, this.actionBg.height / 2);
|
||||||
|
this.actionsContainer.add(this.cancelLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
manageAutoCloseTimer() {
|
||||||
|
clearTimeout(this.countdownTimer);
|
||||||
|
this.countdownTimer = setTimeout(() => {
|
||||||
|
this.timeLeftAutoClose -= 1;
|
||||||
|
this.timerText.setText(`(${this.timeLeftAutoClose})`);
|
||||||
|
if (this.timeLeftAutoClose >= 0) {
|
||||||
|
this.manageAutoCloseTimer();
|
||||||
|
} else {
|
||||||
|
this.cancelFn();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UI with the provided arguments.
|
||||||
|
*
|
||||||
|
* @param args - Arguments to be passed to the show method.
|
||||||
|
* @returns `true` if successful.
|
||||||
|
*/
|
||||||
|
show(args: any[]): boolean {
|
||||||
|
super.show(args);
|
||||||
|
this.buttonPressed = null;
|
||||||
|
this.timeLeftAutoClose = 5;
|
||||||
|
this.cancelFn = args[0].cancelHandler;
|
||||||
|
this.target = args[0].target;
|
||||||
|
|
||||||
|
// Bring the option and action containers to the front of the UI.
|
||||||
|
this.getUi().bringToTop(this.optionSelectContainer);
|
||||||
|
this.getUi().bringToTop(this.actionsContainer);
|
||||||
|
|
||||||
|
this.optionSelectContainer.setVisible(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.listening = true;
|
||||||
|
this.manageAutoCloseTimer();
|
||||||
|
}, 100);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the width of the window.
|
||||||
|
*
|
||||||
|
* @returns The window width.
|
||||||
|
*/
|
||||||
|
getWindowWidth(): number {
|
||||||
|
return 160;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the height of the window.
|
||||||
|
*
|
||||||
|
* @returns The window height.
|
||||||
|
*/
|
||||||
|
getWindowHeight(): number {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the input for the given button.
|
||||||
|
*
|
||||||
|
* @param button - The button to process.
|
||||||
|
* @returns `true` if the input was processed successfully.
|
||||||
|
*/
|
||||||
|
processInput(button: Button): boolean {
|
||||||
|
if (this.buttonPressed === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ui = this.getUi();
|
||||||
|
let success = false;
|
||||||
|
switch (button) {
|
||||||
|
case Button.LEFT:
|
||||||
|
case Button.RIGHT:
|
||||||
|
// Toggle between action and cancel options.
|
||||||
|
const cursor = this.cursor ? 0 : 1;
|
||||||
|
success = this.setCursor(cursor);
|
||||||
|
break;
|
||||||
|
case Button.ACTION:
|
||||||
|
// Process actions based on current cursor position.
|
||||||
|
if (this.cursor === 0) {
|
||||||
|
this.cancelFn();
|
||||||
|
} else {
|
||||||
|
success = this.swapAction();
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
this.cancelFn(success);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plays a select sound effect if an action was successfully processed.
|
||||||
|
if (success) {
|
||||||
|
ui.playSelect();
|
||||||
|
} else {
|
||||||
|
ui.playError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param cursor - The cursor position to set.
|
||||||
|
* @returns `true` if the cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setCursor(cursor: integer): boolean {
|
||||||
|
this.cursor = cursor;
|
||||||
|
if (cursor === 1) {
|
||||||
|
this.actionLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||||
|
this.actionLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||||
|
this.cancelLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
||||||
|
this.cancelLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.actionLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
||||||
|
this.actionLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
||||||
|
this.cancelLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||||
|
this.cancelLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the UI elements and state.
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
super.clear();
|
||||||
|
clearTimeout(this.countdownTimer);
|
||||||
|
this.timerText.setText("(5)");
|
||||||
|
this.timeLeftAutoClose = 5;
|
||||||
|
this.listening = false;
|
||||||
|
this.target = null;
|
||||||
|
this.cancelFn = null;
|
||||||
|
this.optionSelectContainer.setVisible(false);
|
||||||
|
this.actionsContainer.setVisible(false);
|
||||||
|
this.newButtonIcon.setVisible(false);
|
||||||
|
this.buttonPressed = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle input down events.
|
||||||
|
*
|
||||||
|
* @param buttonIcon - The icon of the button that was pressed.
|
||||||
|
* @param assignedButtonIcon - The icon of the button that is assigned.
|
||||||
|
* @param type - The type of button press.
|
||||||
|
*/
|
||||||
|
onInputDown(buttonIcon: string, assignedButtonIcon: string, type: string): void {
|
||||||
|
clearTimeout(this.countdownTimer);
|
||||||
|
this.timerText.setText("");
|
||||||
|
this.newButtonIcon.setTexture(type);
|
||||||
|
this.newButtonIcon.setFrame(buttonIcon);
|
||||||
|
if (assignedButtonIcon) {
|
||||||
|
this.targetButtonIcon.setTexture(type);
|
||||||
|
this.targetButtonIcon.setFrame(assignedButtonIcon);
|
||||||
|
this.targetButtonIcon.setVisible(true);
|
||||||
|
this.swapText.setVisible(true);
|
||||||
|
}
|
||||||
|
this.newButtonIcon.setVisible(true);
|
||||||
|
this.setCursor(0);
|
||||||
|
this.actionsContainer.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,647 @@
|
||||||
|
import UiHandler from "../ui-handler";
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import {InterfaceConfig} from "../../inputs-controller";
|
||||||
|
import {addWindow} from "../ui-theme";
|
||||||
|
import {addTextObject, TextStyle} from "../text";
|
||||||
|
import {Button} from "../../enums/buttons";
|
||||||
|
import {getIconWithSettingName} from "#app/configs/inputs/configHandler";
|
||||||
|
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
|
||||||
|
export interface InputsIcons {
|
||||||
|
[key: string]: Phaser.GameObjects.Sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayoutConfig {
|
||||||
|
optionsContainer: Phaser.GameObjects.Container;
|
||||||
|
inputsIcons: InputsIcons;
|
||||||
|
settingLabels: Phaser.GameObjects.Text[];
|
||||||
|
optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
optionCursors: integer[];
|
||||||
|
keys: string[];
|
||||||
|
bindingSettings: Array<String>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Abstract class for handling UI elements related to settings.
|
||||||
|
*/
|
||||||
|
export default abstract class AbstractSettingsUiUiHandler extends UiHandler {
|
||||||
|
protected settingsContainer: Phaser.GameObjects.Container;
|
||||||
|
protected optionsContainer: Phaser.GameObjects.Container;
|
||||||
|
protected navigationContainer: NavigationMenu;
|
||||||
|
|
||||||
|
protected scrollCursor: integer;
|
||||||
|
protected optionCursors: integer[];
|
||||||
|
protected cursorObj: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
|
protected optionsBg: Phaser.GameObjects.NineSlice;
|
||||||
|
protected actionsBg: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
|
protected settingLabels: Phaser.GameObjects.Text[];
|
||||||
|
protected optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
|
||||||
|
// layout will contain the 3 Gamepad tab for each config - dualshock, xbox, snes
|
||||||
|
protected layout: Map<string, LayoutConfig> = new Map<string, LayoutConfig>();
|
||||||
|
// Will contain the input icons from the selected layout
|
||||||
|
protected inputsIcons: InputsIcons;
|
||||||
|
protected navigationIcons: InputsIcons;
|
||||||
|
// list all the setting keys used in the selected layout (because dualshock has more buttons than xbox)
|
||||||
|
protected keys: Array<String>;
|
||||||
|
|
||||||
|
// Store the specific settings related to key bindings for the current gamepad configuration.
|
||||||
|
protected bindingSettings: Array<String>;
|
||||||
|
|
||||||
|
protected settingDevice;
|
||||||
|
protected settingBlacklisted;
|
||||||
|
protected settingDeviceDefaults;
|
||||||
|
protected settingDeviceOptions;
|
||||||
|
protected configs;
|
||||||
|
protected commonSettingsCount;
|
||||||
|
protected textureOverride;
|
||||||
|
protected titleSelected;
|
||||||
|
protected localStoragePropertyName;
|
||||||
|
protected rowsToDisplay: number;
|
||||||
|
|
||||||
|
abstract getLocalStorageSetting(): object;
|
||||||
|
abstract navigateMenuLeft(): boolean;
|
||||||
|
abstract navigateMenuRight(): boolean;
|
||||||
|
abstract saveSettingToLocalStorage(setting, cursor): void;
|
||||||
|
abstract getActiveConfig(): InterfaceConfig;
|
||||||
|
abstract setSetting(scene: BattleScene, setting, value: integer): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the AbstractSettingsUiUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.rowsToDisplay = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup UI elements.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
const ui = this.getUi();
|
||||||
|
this.navigationIcons = {};
|
||||||
|
|
||||||
|
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||||
|
|
||||||
|
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
||||||
|
|
||||||
|
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
||||||
|
|
||||||
|
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
||||||
|
this.optionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
this.actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
||||||
|
this.actionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconAction.setOrigin(0, -0.1);
|
||||||
|
iconAction.setPositionRelative(this.actionsBg, this.navigationContainer.width - 32, 4);
|
||||||
|
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
||||||
|
|
||||||
|
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
||||||
|
actionText.setOrigin(0, 0.15);
|
||||||
|
actionText.setPositionRelative(iconAction, -actionText.width/6-2, 0);
|
||||||
|
|
||||||
|
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconCancel.setOrigin(0, -0.1);
|
||||||
|
iconCancel.setPositionRelative(this.actionsBg, this.navigationContainer.width - 100, 4);
|
||||||
|
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
||||||
|
|
||||||
|
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
||||||
|
cancelText.setOrigin(0, 0.15);
|
||||||
|
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
||||||
|
|
||||||
|
const iconReset = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconReset.setOrigin(0, -0.1);
|
||||||
|
iconReset.setPositionRelative(this.actionsBg, this.navigationContainer.width - 180, 4);
|
||||||
|
this.navigationIcons["BUTTON_HOME"] = iconReset;
|
||||||
|
|
||||||
|
const resetText = addTextObject(this.scene, 0, 0, "Reset all", TextStyle.SETTINGS_LABEL);
|
||||||
|
resetText.setOrigin(0, 0.15);
|
||||||
|
resetText.setPositionRelative(iconReset, -resetText.width/6-2, 0);
|
||||||
|
|
||||||
|
this.settingsContainer.add(this.optionsBg);
|
||||||
|
this.settingsContainer.add(this.actionsBg);
|
||||||
|
this.settingsContainer.add(this.navigationContainer);
|
||||||
|
this.settingsContainer.add(iconAction);
|
||||||
|
this.settingsContainer.add(iconCancel);
|
||||||
|
this.settingsContainer.add(iconReset);
|
||||||
|
this.settingsContainer.add(actionText);
|
||||||
|
this.settingsContainer.add(cancelText);
|
||||||
|
this.settingsContainer.add(resetText);
|
||||||
|
|
||||||
|
/// Initialize a new configuration "screen" for each type of gamepad.
|
||||||
|
for (const config of this.configs) {
|
||||||
|
// Create a map to store layout settings based on the pad type.
|
||||||
|
this.layout[config.padType] = new Map();
|
||||||
|
// Create a container for gamepad options in the scene, initially hidden.
|
||||||
|
|
||||||
|
const optionsContainer = this.scene.add.container(0, 0);
|
||||||
|
optionsContainer.setVisible(false);
|
||||||
|
|
||||||
|
// Gather all binding settings from the configuration.
|
||||||
|
const bindingSettings = Object.keys(config.settings);
|
||||||
|
|
||||||
|
// Array to hold labels for different settings such as 'Controller', 'Gamepad Support', etc.
|
||||||
|
const settingLabels: Phaser.GameObjects.Text[] = [];
|
||||||
|
|
||||||
|
// Array to hold options for each setting, e.g., 'Auto', 'Disabled'.
|
||||||
|
const optionValueLabels: Phaser.GameObjects.GameObject[][] = [];
|
||||||
|
|
||||||
|
// Object to store sprites for each button configuration.
|
||||||
|
const inputsIcons: InputsIcons = {};
|
||||||
|
|
||||||
|
// Fetch common setting keys such as 'Controller' and 'Gamepad Support' from gamepad settings.
|
||||||
|
const commonSettingKeys = Object.keys(this.settingDevice).slice(0, this.commonSettingsCount).map(key => this.settingDevice[key]);
|
||||||
|
// Combine common and specific bindings into a single array.
|
||||||
|
const specificBindingKeys = [...commonSettingKeys, ...Object.keys(config.settings)];
|
||||||
|
// Fetch default values for these settings and prepare to highlight selected options.
|
||||||
|
const optionCursors = Object.values(Object.keys(this.settingDeviceDefaults).filter(s => specificBindingKeys.includes(s)).map(k => this.settingDeviceDefaults[k]));
|
||||||
|
// Filter out settings that are not relevant to the current gamepad configuration.
|
||||||
|
const settingFiltered = Object.keys(this.settingDevice).filter(_key => specificBindingKeys.includes(this.settingDevice[_key]));
|
||||||
|
// Loop through the filtered settings to manage display and options.
|
||||||
|
|
||||||
|
settingFiltered.forEach((setting, s) => {
|
||||||
|
// Convert the setting key from format 'Key_Name' to 'Key name' for display.
|
||||||
|
const settingName = setting.replace(/\_/g, " ");
|
||||||
|
|
||||||
|
// Create and add a text object for the setting name to the scene.
|
||||||
|
const isLock = this.settingBlacklisted.includes(this.settingDevice[setting]);
|
||||||
|
const labelStyle = isLock ? TextStyle.SETTINGS_LOCKED : TextStyle.SETTINGS_LABEL;
|
||||||
|
settingLabels[s] = addTextObject(this.scene, 8, 28 + s * 16, settingName, labelStyle);
|
||||||
|
settingLabels[s].setOrigin(0, 0);
|
||||||
|
optionsContainer.add(settingLabels[s]);
|
||||||
|
|
||||||
|
// Initialize an array to store the option labels for this setting.
|
||||||
|
const valueLabels: Phaser.GameObjects.GameObject[] = [];
|
||||||
|
|
||||||
|
// Process each option for the current setting.
|
||||||
|
for (const [o, option] of this.settingDeviceOptions[this.settingDevice[setting]].entries()) {
|
||||||
|
// Check if the current setting is for binding keys.
|
||||||
|
if (bindingSettings.includes(this.settingDevice[setting])) {
|
||||||
|
// Create a label for non-null options, typically indicating actionable options like 'change'.
|
||||||
|
if (o) {
|
||||||
|
const valueLabel = addTextObject(this.scene, 0, 0, isLock ? "" : option, TextStyle.WINDOW);
|
||||||
|
valueLabel.setOrigin(0, 0);
|
||||||
|
optionsContainer.add(valueLabel);
|
||||||
|
valueLabels.push(valueLabel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// For null options, add an icon for the key.
|
||||||
|
const icon = this.scene.add.sprite(0, 0, this.textureOverride ? this.textureOverride : config.padType);
|
||||||
|
icon.setOrigin(0, -0.15);
|
||||||
|
inputsIcons[this.settingDevice[setting]] = icon;
|
||||||
|
optionsContainer.add(icon);
|
||||||
|
valueLabels.push(icon);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// For regular settings like 'Gamepad support', create a label and determine if it is selected.
|
||||||
|
const valueLabel = addTextObject(this.scene, 0, 0, option, this.settingDeviceDefaults[this.settingDevice[setting]] === o ? TextStyle.SETTINGS_SELECTED : TextStyle.WINDOW);
|
||||||
|
valueLabel.setOrigin(0, 0);
|
||||||
|
|
||||||
|
optionsContainer.add(valueLabel);
|
||||||
|
|
||||||
|
//if a setting has 2 options, valueLabels will be an array of 2 elements
|
||||||
|
valueLabels.push(valueLabel);
|
||||||
|
}
|
||||||
|
// Collect all option labels for this setting into the main array.
|
||||||
|
optionValueLabels.push(valueLabels);
|
||||||
|
|
||||||
|
// Calculate the total width of all option labels within a specific setting
|
||||||
|
// This is achieved by summing the width of each option label
|
||||||
|
const totalWidth = optionValueLabels[s].map((o) => (o as Phaser.GameObjects.Text).width).reduce((total, width) => total += width, 0);
|
||||||
|
|
||||||
|
// Define the minimum width for a label, ensuring it's at least 78 pixels wide or the width of the setting label plus some padding
|
||||||
|
const labelWidth = Math.max(130, settingLabels[s].displayWidth + 8);
|
||||||
|
|
||||||
|
// Calculate the total available space for placing option labels next to their setting label
|
||||||
|
// We reserve space for the setting label and then distribute the remaining space evenly
|
||||||
|
const totalSpace = (300 - labelWidth) - totalWidth / 6;
|
||||||
|
// Calculate the spacing between options based on the available space divided by the number of gaps between labels
|
||||||
|
const optionSpacing = Math.floor(totalSpace / (optionValueLabels[s].length - 1));
|
||||||
|
|
||||||
|
// Initialize xOffset to zero, which will be used to position each option label horizontally
|
||||||
|
let xOffset = 0;
|
||||||
|
|
||||||
|
// Start positioning each option label one by one
|
||||||
|
for (const value of optionValueLabels[s]) {
|
||||||
|
// Set the option label's position right next to the setting label, adjusted by xOffset
|
||||||
|
(value as Phaser.GameObjects.Text).setPositionRelative(settingLabels[s], labelWidth + xOffset, 0);
|
||||||
|
// Move the xOffset to the right for the next label, ensuring each label is spaced evenly
|
||||||
|
xOffset += (value as Phaser.GameObjects.Text).width / 6 + optionSpacing;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assigning the newly created components to the layout map under the specific gamepad type.
|
||||||
|
this.layout[config.padType].optionsContainer = optionsContainer; // Container for this pad's options.
|
||||||
|
this.layout[config.padType].inputsIcons = inputsIcons; // Icons for each input specific to this pad.
|
||||||
|
this.layout[config.padType].settingLabels = settingLabels; // Text labels for each setting available on this pad.
|
||||||
|
this.layout[config.padType].optionValueLabels = optionValueLabels; // Labels for values corresponding to each setting.
|
||||||
|
this.layout[config.padType].optionCursors = optionCursors; // Cursors to navigate through the options.
|
||||||
|
this.layout[config.padType].keys = specificBindingKeys; // Keys that identify each setting specifically bound to this pad.
|
||||||
|
this.layout[config.padType].bindingSettings = bindingSettings; // Settings that define how the keys are bound.
|
||||||
|
|
||||||
|
// Add the options container to the overall settings container to be displayed in the UI.
|
||||||
|
this.settingsContainer.add(optionsContainer);
|
||||||
|
}
|
||||||
|
// Add the settings container to the UI.
|
||||||
|
ui.add(this.settingsContainer);
|
||||||
|
|
||||||
|
// Initially hide the settings container until needed (e.g., when a gamepad is connected or a button is pressed).
|
||||||
|
this.settingsContainer.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the bindings for the current active device configuration.
|
||||||
|
*/
|
||||||
|
updateBindings(): void {
|
||||||
|
// Hide the options container for all layouts to reset the UI visibility.
|
||||||
|
Object.keys(this.layout).forEach((key) => this.layout[key].optionsContainer.setVisible(false));
|
||||||
|
// Fetch the active gamepad configuration from the input controller.
|
||||||
|
const activeConfig = this.getActiveConfig();
|
||||||
|
|
||||||
|
// Set the UI layout for the active configuration. If unsuccessful, exit the function early.
|
||||||
|
if (!this.setLayout(activeConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
||||||
|
const settings: object = this.getLocalStorageSetting();
|
||||||
|
|
||||||
|
// Update the cursor for each key based on the stored settings or default cursors.
|
||||||
|
this.keys.forEach((key, index) => {
|
||||||
|
this.setOptionCursor(index, settings.hasOwnProperty(key as string) ? settings[key as string] : this.optionCursors[index]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the active configuration has no custom bindings set, exit the function early.
|
||||||
|
// by default, if custom does not exists, a default is assigned to it
|
||||||
|
// it only means the gamepad is not yet initalized
|
||||||
|
if (!activeConfig.custom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each element in the binding settings, update the icon according to the current assignment.
|
||||||
|
for (const elm of this.bindingSettings) {
|
||||||
|
const icon = getIconWithSettingName(activeConfig, elm);
|
||||||
|
if (icon) {
|
||||||
|
this.inputsIcons[elm as string].setFrame(icon);
|
||||||
|
this.inputsIcons[elm as string].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.inputsIcons[elm as string].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the cursor and scroll cursor to their initial positions.
|
||||||
|
this.setCursor(this.cursor);
|
||||||
|
this.setScrollCursor(this.scrollCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNavigationDisplay() {
|
||||||
|
const specialIcons = {
|
||||||
|
"BUTTON_HOME": "HOME.png",
|
||||||
|
"BUTTON_DELETE": "DEL.png",
|
||||||
|
};
|
||||||
|
for (const settingName of Object.keys(this.navigationIcons)) {
|
||||||
|
if (Object.keys(specialIcons).includes(settingName)) {
|
||||||
|
this.navigationIcons[settingName].setTexture("keyboard");
|
||||||
|
this.navigationIcons[settingName].setFrame(specialIcons[settingName]);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const icon = this.scene.inputController?.getIconForLatestInputRecorded(settingName);
|
||||||
|
if (icon) {
|
||||||
|
const type = this.scene.inputController?.getLastSourceType();
|
||||||
|
this.navigationIcons[settingName].setTexture(type);
|
||||||
|
this.navigationIcons[settingName].setFrame(icon);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.navigationIcons[settingName].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UI with the provided arguments.
|
||||||
|
*
|
||||||
|
* @param args - Arguments to be passed to the show method.
|
||||||
|
* @returns `true` if successful.
|
||||||
|
*/
|
||||||
|
show(args: any[]): boolean {
|
||||||
|
super.show(args);
|
||||||
|
|
||||||
|
this.updateNavigationDisplay();
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
// Update the bindings for the current active gamepad configuration.
|
||||||
|
this.updateBindings();
|
||||||
|
|
||||||
|
// Make the settings container visible to the user.
|
||||||
|
this.settingsContainer.setVisible(true);
|
||||||
|
// Reset the scroll cursor to the top of the settings container.
|
||||||
|
this.resetScroll();
|
||||||
|
|
||||||
|
// Move the settings container to the end of the UI stack to ensure it is displayed on top.
|
||||||
|
this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1);
|
||||||
|
|
||||||
|
// Hide any tooltips that might be visible before showing the settings container.
|
||||||
|
this.getUi().hideTooltip();
|
||||||
|
|
||||||
|
// Return true to indicate the UI was successfully shown.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the UI layout for the active device configuration.
|
||||||
|
*
|
||||||
|
* @param activeConfig - The active device configuration.
|
||||||
|
* @returns `true` if the layout was successfully applied, otherwise `false`.
|
||||||
|
*/
|
||||||
|
setLayout(activeConfig: InterfaceConfig): boolean {
|
||||||
|
// Check if there is no active configuration (e.g., no gamepad connected).
|
||||||
|
if (!activeConfig) {
|
||||||
|
// Retrieve the layout for when no gamepads are connected.
|
||||||
|
const layout = this.layout["noGamepads"];
|
||||||
|
// Make the options container visible to show message.
|
||||||
|
layout.optionsContainer.setVisible(true);
|
||||||
|
// Return false indicating the layout application was not successful due to lack of gamepad.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Extract the type of the gamepad from the active configuration.
|
||||||
|
const configType = activeConfig.padType;
|
||||||
|
|
||||||
|
// Retrieve the layout settings based on the type of the gamepad.
|
||||||
|
const layout = this.layout[configType];
|
||||||
|
// Update the main controller with configuration details from the selected layout.
|
||||||
|
this.keys = layout.keys;
|
||||||
|
this.optionsContainer = layout.optionsContainer;
|
||||||
|
this.optionsContainer.setVisible(true);
|
||||||
|
this.settingLabels = layout.settingLabels;
|
||||||
|
this.optionValueLabels = layout.optionValueLabels;
|
||||||
|
this.optionCursors = layout.optionCursors;
|
||||||
|
this.inputsIcons = layout.inputsIcons;
|
||||||
|
this.bindingSettings = layout.bindingSettings;
|
||||||
|
|
||||||
|
// Return true indicating the layout was successfully applied.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the input for the given button.
|
||||||
|
*
|
||||||
|
* @param button - The button to process.
|
||||||
|
* @returns `true` if the input was processed successfully.
|
||||||
|
*/
|
||||||
|
processInput(button: Button): boolean {
|
||||||
|
const ui = this.getUi();
|
||||||
|
// Defines the maximum number of rows that can be displayed on the screen.
|
||||||
|
let success = false;
|
||||||
|
this.updateNavigationDisplay();
|
||||||
|
|
||||||
|
// Handle the input based on the button pressed.
|
||||||
|
if (button === Button.CANCEL) {
|
||||||
|
// Handle cancel button press, reverting UI mode to previous state.
|
||||||
|
success = true;
|
||||||
|
NavigationManager.getInstance().reset();
|
||||||
|
this.scene.ui.revertMode();
|
||||||
|
} else {
|
||||||
|
const cursor = this.cursor + this.scrollCursor; // Calculate the absolute cursor position.
|
||||||
|
const setting = this.settingDevice[Object.keys(this.settingDevice)[cursor]];
|
||||||
|
switch (button) {
|
||||||
|
case Button.ACTION:
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || !setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
success = this.setSetting(this.scene, setting, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.UP: // Move up in the menu.
|
||||||
|
if (!this.optionValueLabels) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cursor) { // If not at the top, move the cursor up.
|
||||||
|
if (this.cursor) {
|
||||||
|
success = this.setCursor(this.cursor - 1);
|
||||||
|
} else {// If at the top of the visible items, scroll up.
|
||||||
|
success = this.setScrollCursor(this.scrollCursor - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When at the top of the menu and pressing UP, move to the bottommost item.
|
||||||
|
// First, set the cursor to the last visible element, preparing for the scroll to the end.
|
||||||
|
const successA = this.setCursor(this.rowsToDisplay - 1);
|
||||||
|
// Then, adjust the scroll to display the bottommost elements of the menu.
|
||||||
|
const successB = this.setScrollCursor(this.optionValueLabels.length - this.rowsToDisplay);
|
||||||
|
success = successA && successB; // success is just there to play the little validation sound effect
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.DOWN: // Move down in the menu.
|
||||||
|
if (!this.optionValueLabels) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cursor < this.optionValueLabels.length - 1) {
|
||||||
|
if (this.cursor < this.rowsToDisplay - 1) {
|
||||||
|
success = this.setCursor(this.cursor + 1);
|
||||||
|
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
||||||
|
success = this.setScrollCursor(this.scrollCursor + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When at the bottom of the menu and pressing DOWN, move to the topmost item.
|
||||||
|
// First, set the cursor to the first visible element, resetting the scroll to the top.
|
||||||
|
const successA = this.setCursor(0);
|
||||||
|
// Then, reset the scroll to start from the first element of the menu.
|
||||||
|
const successB = this.setScrollCursor(0);
|
||||||
|
success = successA && successB; // Indicates a successful cursor and scroll adjustment.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.LEFT: // Move selection left within the current option set.
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else if (this.optionCursors[cursor]) {
|
||||||
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.RIGHT: // Move selection right within the current option set.
|
||||||
|
if (!this.optionCursors || !this.optionValueLabels) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) {
|
||||||
|
success = false;
|
||||||
|
} else if (this.optionCursors[cursor] < this.optionValueLabels[cursor].length - 1) {
|
||||||
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Button.CYCLE_FORM:
|
||||||
|
case Button.CYCLE_SHINY:
|
||||||
|
success = this.navigationContainer.navigate(button);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a change occurred, play the selection sound.
|
||||||
|
if (success) {
|
||||||
|
ui.playSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success; // Return whether the input resulted in a successful action.
|
||||||
|
}
|
||||||
|
|
||||||
|
resetScroll() {
|
||||||
|
this.cursorObj?.destroy();
|
||||||
|
this.cursorObj = null;
|
||||||
|
this.cursor = null;
|
||||||
|
this.setCursor(0);
|
||||||
|
this.setScrollCursor(0);
|
||||||
|
this.updateSettingsScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param cursor - The cursor position to set.
|
||||||
|
* @returns `true` if the cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setCursor(cursor: integer): boolean {
|
||||||
|
const ret = super.setCursor(cursor);
|
||||||
|
// If the optionsContainer is not initialized, return the result from the parent class directly.
|
||||||
|
if (!this.optionsContainer) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the cursor object exists, if not, create it.
|
||||||
|
if (!this.cursorObj) {
|
||||||
|
this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1);
|
||||||
|
this.cursorObj.setOrigin(0, 0); // Set the origin to the top-left corner.
|
||||||
|
this.optionsContainer.add(this.cursorObj); // Add the cursor to the options container.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the position of the cursor object relative to the options background based on the current cursor and scroll positions.
|
||||||
|
this.cursorObj.setPositionRelative(this.optionsBg, 4, 4 + (this.cursor + this.scrollCursor) * 16);
|
||||||
|
|
||||||
|
return ret; // Return the result from the parent class's setCursor method.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the scroll cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param scrollCursor - The scroll cursor position to set.
|
||||||
|
* @returns `true` if the scroll cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setScrollCursor(scrollCursor: integer): boolean {
|
||||||
|
// Check if the new scroll position is the same as the current one; if so, do not update.
|
||||||
|
if (scrollCursor === this.scrollCursor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the internal scroll cursor state
|
||||||
|
this.scrollCursor = scrollCursor;
|
||||||
|
|
||||||
|
// Apply the new scroll position to the settings UI.
|
||||||
|
this.updateSettingsScroll();
|
||||||
|
|
||||||
|
// Reset the cursor to its current position to adjust its visibility after scrolling.
|
||||||
|
this.setCursor(this.cursor);
|
||||||
|
|
||||||
|
return true; // Return true to indicate the scroll cursor was successfully updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the option cursor to the specified position.
|
||||||
|
*
|
||||||
|
* @param settingIndex - The index of the setting.
|
||||||
|
* @param cursor - The cursor position to set.
|
||||||
|
* @param save - Whether to save the setting to local storage.
|
||||||
|
* @returns `true` if the option cursor was set successfully.
|
||||||
|
*/
|
||||||
|
setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean {
|
||||||
|
// Retrieve the specific setting using the settingIndex from the settingDevice enumeration.
|
||||||
|
const setting = this.settingDevice[Object.keys(this.settingDevice)[settingIndex]];
|
||||||
|
|
||||||
|
// Get the current cursor position for this setting.
|
||||||
|
const lastCursor = this.optionCursors[settingIndex];
|
||||||
|
|
||||||
|
// Check if the setting is not part of the bindings (i.e., it's a regular setting).
|
||||||
|
if (!this.bindingSettings.includes(setting) && !setting.includes("BUTTON_")) {
|
||||||
|
// Get the label of the last selected option and revert its color to the default.
|
||||||
|
const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor];
|
||||||
|
lastValueLabel.setColor(this.getTextColor(TextStyle.WINDOW));
|
||||||
|
lastValueLabel.setShadowColor(this.getTextColor(TextStyle.WINDOW, true));
|
||||||
|
|
||||||
|
// Update the cursor for the setting to the new position.
|
||||||
|
this.optionCursors[settingIndex] = cursor;
|
||||||
|
|
||||||
|
// Change the color of the new selected option to indicate it's selected.
|
||||||
|
const newValueLabel = this.optionValueLabels[settingIndex][cursor];
|
||||||
|
newValueLabel.setColor(this.getTextColor(TextStyle.SETTINGS_SELECTED));
|
||||||
|
newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the save flag is set, save the setting to local storage
|
||||||
|
if (save) {
|
||||||
|
this.saveSettingToLocalStorage(setting, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Return true to indicate the cursor was successfully updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the scroll position of the settings UI.
|
||||||
|
*/
|
||||||
|
updateSettingsScroll(): void {
|
||||||
|
// Return immediately if the options container is not initialized.
|
||||||
|
if (!this.optionsContainer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the vertical position of the options container based on the current scroll cursor, multiplying by the item height.
|
||||||
|
this.optionsContainer.setY(-16 * this.scrollCursor);
|
||||||
|
|
||||||
|
// Iterate over all setting labels to update their visibility.
|
||||||
|
for (let s = 0; s < this.settingLabels.length; s++) {
|
||||||
|
// Determine if the current setting should be visible based on the scroll position.
|
||||||
|
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
||||||
|
|
||||||
|
// Set the visibility of the setting label and its corresponding options.
|
||||||
|
this.settingLabels[s].setVisible(visible);
|
||||||
|
for (const option of this.optionValueLabels[s]) {
|
||||||
|
option.setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the UI elements and state.
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
super.clear();
|
||||||
|
|
||||||
|
// Hide the settings container to remove it from the view.
|
||||||
|
this.settingsContainer.setVisible(false);
|
||||||
|
|
||||||
|
// Remove the cursor from the UI.
|
||||||
|
this.eraseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase the cursor from the UI.
|
||||||
|
*/
|
||||||
|
eraseCursor(): void {
|
||||||
|
// Check if a cursor object exists.
|
||||||
|
if (this.cursorObj) {
|
||||||
|
this.cursorObj.destroy();
|
||||||
|
} // Destroy the cursor object to clean up resources.
|
||||||
|
|
||||||
|
// Set the cursor object reference to null to fully dereference it.
|
||||||
|
this.cursorObj = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import AbstractBindingUiHandler from "./abstract-binding-ui-handler";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {getIconWithSettingName, getKeyWithKeycode} from "#app/configs/inputs/configHandler";
|
||||||
|
import {addTextObject, TextStyle} from "#app/ui/text";
|
||||||
|
|
||||||
|
|
||||||
|
export default class GamepadBindingUiHandler extends AbstractBindingUiHandler {
|
||||||
|
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.scene.input.gamepad.on("down", this.gamepadButtonDown, this);
|
||||||
|
}
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
|
||||||
|
// New button icon setup.
|
||||||
|
this.newButtonIcon = this.scene.add.sprite(0, 0, "xbox");
|
||||||
|
this.newButtonIcon.setPositionRelative(this.optionSelectBg, 78, 16);
|
||||||
|
this.newButtonIcon.setOrigin(0.5);
|
||||||
|
this.newButtonIcon.setVisible(false);
|
||||||
|
|
||||||
|
this.swapText = addTextObject(this.scene, 0, 0, "will swap with", TextStyle.WINDOW);
|
||||||
|
this.swapText.setOrigin(0.5);
|
||||||
|
this.swapText.setPositionRelative(this.optionSelectBg, this.optionSelectBg.width / 2 - 2, this.optionSelectBg.height / 2 - 2);
|
||||||
|
this.swapText.setVisible(false);
|
||||||
|
|
||||||
|
this.targetButtonIcon = this.scene.add.sprite(0, 0, "xbox");
|
||||||
|
this.targetButtonIcon.setPositionRelative(this.optionSelectBg, 78, 48);
|
||||||
|
this.targetButtonIcon.setOrigin(0.5);
|
||||||
|
this.targetButtonIcon.setVisible(false);
|
||||||
|
|
||||||
|
this.actionLabel = addTextObject(this.scene, 0, 0, "Confirm swap", TextStyle.SETTINGS_LABEL);
|
||||||
|
this.actionLabel.setOrigin(0, 0.5);
|
||||||
|
this.actionLabel.setPositionRelative(this.actionBg, this.actionBg.width - 75, this.actionBg.height / 2);
|
||||||
|
this.actionsContainer.add(this.actionLabel);
|
||||||
|
|
||||||
|
this.optionSelectContainer.add(this.newButtonIcon);
|
||||||
|
this.optionSelectContainer.add(this.swapText);
|
||||||
|
this.optionSelectContainer.add(this.targetButtonIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedDevice() {
|
||||||
|
return this.scene.inputController?.selectedDevice[Device.GAMEPAD];
|
||||||
|
}
|
||||||
|
|
||||||
|
gamepadButtonDown(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void {
|
||||||
|
const blacklist = [12, 13, 14, 15]; // d-pad buttons are blacklisted.
|
||||||
|
// Check conditions before processing the button press.
|
||||||
|
if (!this.listening || pad.id.toLowerCase() !== this.getSelectedDevice() || blacklist.includes(button.index) || this.buttonPressed !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const activeConfig = this.scene.inputController.getActiveConfig(Device.GAMEPAD);
|
||||||
|
const type = activeConfig.padType;
|
||||||
|
const key = getKeyWithKeycode(activeConfig, button.index);
|
||||||
|
const buttonIcon = activeConfig.icons[key];
|
||||||
|
if (!buttonIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.buttonPressed = button.index;
|
||||||
|
const assignedButtonIcon = getIconWithSettingName(activeConfig, this.target);
|
||||||
|
this.onInputDown(buttonIcon, assignedButtonIcon, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
swapAction(): boolean {
|
||||||
|
const activeConfig = this.scene.inputController.getActiveConfig(Device.GAMEPAD);
|
||||||
|
if (this.scene.inputController.assignBinding(activeConfig, this.target, this.buttonPressed)) {
|
||||||
|
this.scene.gameData.saveMappingConfigs(this.getSelectedDevice(), activeConfig);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the UI elements and state.
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
super.clear();
|
||||||
|
this.targetButtonIcon.setVisible(false);
|
||||||
|
this.swapText.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import AbstractBindingUiHandler from "./abstract-binding-ui-handler";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import { getKeyWithKeycode} from "#app/configs/inputs/configHandler";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {addTextObject, TextStyle} from "#app/ui/text";
|
||||||
|
|
||||||
|
|
||||||
|
export default class KeyboardBindingUiHandler extends AbstractBindingUiHandler {
|
||||||
|
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
// Listen to gamepad button down events to initiate binding.
|
||||||
|
scene.input.keyboard.on("keydown", this.onKeyDown, this);
|
||||||
|
}
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
|
||||||
|
// New button icon setup.
|
||||||
|
this.newButtonIcon = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
this.newButtonIcon.setPositionRelative(this.optionSelectBg, 78, 32);
|
||||||
|
this.newButtonIcon.setOrigin(0.5);
|
||||||
|
this.newButtonIcon.setVisible(false);
|
||||||
|
|
||||||
|
this.actionLabel = addTextObject(this.scene, 0, 0, "Assign button", TextStyle.SETTINGS_LABEL);
|
||||||
|
this.actionLabel.setOrigin(0, 0.5);
|
||||||
|
this.actionLabel.setPositionRelative(this.actionBg, this.actionBg.width - 80, this.actionBg.height / 2);
|
||||||
|
this.actionsContainer.add(this.actionLabel);
|
||||||
|
|
||||||
|
this.optionSelectContainer.add(this.newButtonIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedDevice() {
|
||||||
|
return this.scene.inputController?.selectedDevice[Device.KEYBOARD];
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown(event): void {
|
||||||
|
const blacklist = [
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.UP,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.DOWN,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.LEFT,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.RIGHT,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.HOME,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.ENTER,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.ESC,
|
||||||
|
Phaser.Input.Keyboard.KeyCodes.DELETE,
|
||||||
|
];
|
||||||
|
const key = event.keyCode;
|
||||||
|
// // Check conditions before processing the button press.
|
||||||
|
if (!this.listening || this.buttonPressed !== null || blacklist.includes(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const activeConfig = this.scene.inputController.getActiveConfig(Device.KEYBOARD);
|
||||||
|
const _key = getKeyWithKeycode(activeConfig, key);
|
||||||
|
const buttonIcon = activeConfig.icons[_key];
|
||||||
|
if (!buttonIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.buttonPressed = key;
|
||||||
|
// const assignedButtonIcon = getIconWithSettingName(activeConfig, this.target);
|
||||||
|
this.onInputDown(buttonIcon, null, "keyboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
swapAction(): boolean {
|
||||||
|
const activeConfig = this.scene.inputController.getActiveConfig(Device.KEYBOARD);
|
||||||
|
if (this.scene.inputController.assignBinding(activeConfig, this.target, this.buttonPressed)) {
|
||||||
|
this.scene.gameData.saveMappingConfigs(this.getSelectedDevice(), activeConfig);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import {Mode} from "#app/ui/ui";
|
||||||
|
import {InputsIcons} from "#app/ui/settings/abstract-settings-ui-handler";
|
||||||
|
import {addTextObject, setTextStyle, TextStyle} from "#app/ui/text";
|
||||||
|
import {addWindow} from "#app/ui/ui-theme";
|
||||||
|
import {Button} from "#app/enums/buttons";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages navigation and menus tabs within the setting menu.
|
||||||
|
*/
|
||||||
|
export class NavigationManager {
|
||||||
|
private static instance: NavigationManager;
|
||||||
|
public modes: Mode[];
|
||||||
|
public selectedMode: Mode = Mode.SETTINGS;
|
||||||
|
public navigationMenus: NavigationMenu[] = new Array<NavigationMenu>();
|
||||||
|
public labels: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of NavigationManager.
|
||||||
|
* To create a new tab in the menu, add the mode to the modes array and the label to the labels array.
|
||||||
|
* and instantiate a new NavigationMenu instance in your handler
|
||||||
|
* like: this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.modes = [
|
||||||
|
Mode.SETTINGS,
|
||||||
|
Mode.SETTINGS_GAMEPAD,
|
||||||
|
Mode.SETTINGS_KEYBOARD,
|
||||||
|
];
|
||||||
|
this.labels = ["General", "Gamepad", "Keyboard"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset() {
|
||||||
|
this.selectedMode = Mode.SETTINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the singleton instance of the NavigationManager.
|
||||||
|
* @returns The singleton instance of NavigationManager.
|
||||||
|
*/
|
||||||
|
public static getInstance(): NavigationManager {
|
||||||
|
if (!NavigationManager.instance) {
|
||||||
|
NavigationManager.instance = new NavigationManager();
|
||||||
|
}
|
||||||
|
return NavigationManager.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to the previous mode in the modes array.
|
||||||
|
* @param scene The current BattleScene instance.
|
||||||
|
*/
|
||||||
|
public navigateLeft(scene) {
|
||||||
|
const pos = this.modes.indexOf(this.selectedMode);
|
||||||
|
const maxPos = this.modes.length - 1;
|
||||||
|
if (pos === 0) {
|
||||||
|
this.selectedMode = this.modes[maxPos];
|
||||||
|
} else {
|
||||||
|
this.selectedMode = this.modes[pos - 1];
|
||||||
|
}
|
||||||
|
scene.ui.setMode(this.selectedMode);
|
||||||
|
this.updateNavigationMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to the next mode in the modes array.
|
||||||
|
* @param scene The current BattleScene instance.
|
||||||
|
*/
|
||||||
|
public navigateRight(scene) {
|
||||||
|
const pos = this.modes.indexOf(this.selectedMode);
|
||||||
|
const maxPos = this.modes.length - 1;
|
||||||
|
if (pos === maxPos) {
|
||||||
|
this.selectedMode = this.modes[0];
|
||||||
|
} else {
|
||||||
|
this.selectedMode = this.modes[pos + 1];
|
||||||
|
}
|
||||||
|
scene.ui.setMode(this.selectedMode);
|
||||||
|
this.updateNavigationMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all navigation menus.
|
||||||
|
*/
|
||||||
|
public updateNavigationMenus() {
|
||||||
|
for (const instance of this.navigationMenus) {
|
||||||
|
instance.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates icons for all navigation menus.
|
||||||
|
*/
|
||||||
|
public updateIcons() {
|
||||||
|
for (const instance of this.navigationMenus) {
|
||||||
|
instance.updateIcons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class NavigationMenu extends Phaser.GameObjects.Container {
|
||||||
|
private navigationIcons: InputsIcons;
|
||||||
|
public scene: BattleScene;
|
||||||
|
protected headerTitles: Phaser.GameObjects.Text[] = new Array<Phaser.GameObjects.Text>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of NavigationMenu.
|
||||||
|
* @param scene The current BattleScene instance.
|
||||||
|
* @param x The x position of the NavigationMenu.
|
||||||
|
* @param y The y position of the NavigationMenu.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, x: number, y: number) {
|
||||||
|
super(scene, x, y);
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
this.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the NavigationMenu by adding windows, icons, and labels.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
const navigationManager = NavigationManager.getInstance();
|
||||||
|
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
|
||||||
|
headerBg.setOrigin(0, 0);
|
||||||
|
this.add(headerBg);
|
||||||
|
this.width = headerBg.width;
|
||||||
|
this.height = headerBg.height;
|
||||||
|
|
||||||
|
this.navigationIcons = {};
|
||||||
|
|
||||||
|
const iconPreviousTab = this.scene.add.sprite(8, 4, "keyboard");
|
||||||
|
iconPreviousTab.setOrigin(0, -0.1);
|
||||||
|
iconPreviousTab.setPositionRelative(headerBg, 8, 4);
|
||||||
|
this.navigationIcons["BUTTON_CYCLE_FORM"] = iconPreviousTab;
|
||||||
|
|
||||||
|
const iconNextTab = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconNextTab.setOrigin(0, -0.1);
|
||||||
|
iconNextTab.setPositionRelative(headerBg, headerBg.width - 20, 4);
|
||||||
|
this.navigationIcons["BUTTON_CYCLE_SHINY"] = iconNextTab;
|
||||||
|
|
||||||
|
let relative: Phaser.GameObjects.Sprite | Phaser.GameObjects.Text = iconPreviousTab;
|
||||||
|
let relativeWidth: number = iconPreviousTab.width*6;
|
||||||
|
for (const label of navigationManager.labels) {
|
||||||
|
const labelText = addTextObject(this.scene, 0, 0, label, TextStyle.SETTINGS_LABEL);
|
||||||
|
labelText.setOrigin(0, 0);
|
||||||
|
labelText.setPositionRelative(relative, 6 + relativeWidth/6, 0);
|
||||||
|
this.add(labelText);
|
||||||
|
this.headerTitles.push(labelText);
|
||||||
|
relative = labelText;
|
||||||
|
relativeWidth = labelText.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.add(iconPreviousTab);
|
||||||
|
this.add(iconNextTab);
|
||||||
|
navigationManager.navigationMenus.push(this);
|
||||||
|
navigationManager.updateNavigationMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the NavigationMenu's header titles based on the selected mode.
|
||||||
|
*/
|
||||||
|
update() {
|
||||||
|
const navigationManager = NavigationManager.getInstance();
|
||||||
|
const posSelected = navigationManager.modes.indexOf(navigationManager.selectedMode);
|
||||||
|
|
||||||
|
for (const [index, title] of this.headerTitles.entries()) {
|
||||||
|
setTextStyle(title, this.scene, index === posSelected ? TextStyle.SETTINGS_SELECTED : TextStyle.SETTINGS_LABEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the icons in the NavigationMenu based on the latest input recorded.
|
||||||
|
*/
|
||||||
|
updateIcons() {
|
||||||
|
const specialIcons = {
|
||||||
|
"BUTTON_HOME": "HOME.png",
|
||||||
|
"BUTTON_DELETE": "DEL.png",
|
||||||
|
};
|
||||||
|
for (const settingName of Object.keys(this.navigationIcons)) {
|
||||||
|
if (Object.keys(specialIcons).includes(settingName)) {
|
||||||
|
this.navigationIcons[settingName].setTexture("keyboard");
|
||||||
|
this.navigationIcons[settingName].setFrame(specialIcons[settingName]);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const icon = this.scene.inputController?.getIconForLatestInputRecorded(settingName);
|
||||||
|
if (icon) {
|
||||||
|
const type = this.scene.inputController?.getLastSourceType();
|
||||||
|
this.navigationIcons[settingName].setTexture(type);
|
||||||
|
this.navigationIcons[settingName].setFrame(icon);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.navigationIcons[settingName].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles navigation based on the button pressed.
|
||||||
|
* @param button The button pressed for navigation.
|
||||||
|
* @returns A boolean indicating if the navigation was handled.
|
||||||
|
*/
|
||||||
|
navigate(button: Button): boolean {
|
||||||
|
const navigationManager = NavigationManager.getInstance();
|
||||||
|
switch (button) {
|
||||||
|
case Button.CYCLE_FORM:
|
||||||
|
navigationManager.navigateLeft(this.scene);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case Button.CYCLE_SHINY:
|
||||||
|
navigationManager.navigateRight(this.scene);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import AbstractOptionSelectUiHandler from "./abstact-option-select-ui-handler";
|
import AbstractOptionSelectUiHandler from "../abstact-option-select-ui-handler";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "../ui";
|
||||||
|
|
||||||
export default class OptionSelectUiHandler extends AbstractOptionSelectUiHandler {
|
export default class OptionSelectUiHandler extends AbstractOptionSelectUiHandler {
|
||||||
constructor(scene: BattleScene, mode: Mode = Mode.OPTION_SELECT) {
|
constructor(scene: BattleScene, mode: Mode = Mode.OPTION_SELECT) {
|
|
@ -0,0 +1,168 @@
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import {addTextObject, TextStyle} from "../text";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import {
|
||||||
|
setSettingGamepad,
|
||||||
|
SettingGamepad,
|
||||||
|
settingGamepadBlackList,
|
||||||
|
settingGamepadDefaults,
|
||||||
|
settingGamepadOptions
|
||||||
|
} from "../../system/settings-gamepad";
|
||||||
|
import pad_xbox360 from "#app/configs/inputs/pad_xbox360";
|
||||||
|
import pad_dualshock from "#app/configs/inputs/pad_dualshock";
|
||||||
|
import pad_unlicensedSNES from "#app/configs/inputs/pad_unlicensedSNES";
|
||||||
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
|
import AbstractSettingsUiUiHandler from "#app/ui/settings/abstract-settings-ui-handler";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {truncateString} from "#app/utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the settings UI handler for gamepads.
|
||||||
|
*
|
||||||
|
* @extends AbstractSettingsUiUiHandler
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class SettingsGamepadUiHandler extends AbstractSettingsUiUiHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of SettingsGamepadUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode, optional.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.titleSelected = "Gamepad";
|
||||||
|
this.settingDevice = SettingGamepad;
|
||||||
|
this.settingDeviceDefaults = settingGamepadDefaults;
|
||||||
|
this.settingDeviceOptions = settingGamepadOptions;
|
||||||
|
this.configs = [pad_xbox360, pad_dualshock, pad_unlicensedSNES];
|
||||||
|
this.commonSettingsCount = 2;
|
||||||
|
this.localStoragePropertyName = "settingsGamepad";
|
||||||
|
this.settingBlacklisted = settingGamepadBlackList;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSetting(scene: BattleScene, setting, value: integer): boolean {
|
||||||
|
return setSettingGamepad(scene, setting, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup UI elements.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
// If no gamepads are detected, set up a default UI prompt in the settings container.
|
||||||
|
this.layout["noGamepads"] = new Map();
|
||||||
|
const optionsContainer = this.scene.add.container(0, 0);
|
||||||
|
optionsContainer.setVisible(false); // Initially hide the container as no gamepads are connected.
|
||||||
|
const label = addTextObject(this.scene, 8, 28, "Please plug a controller or press a button", TextStyle.SETTINGS_LABEL);
|
||||||
|
label.setOrigin(0, 0);
|
||||||
|
optionsContainer.add(label);
|
||||||
|
this.settingsContainer.add(optionsContainer);
|
||||||
|
|
||||||
|
// Map the 'noGamepads' layout options for easy access.
|
||||||
|
this.layout["noGamepads"].optionsContainer = optionsContainer;
|
||||||
|
this.layout["noGamepads"].label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the active configuration.
|
||||||
|
*
|
||||||
|
* @returns The active gamepad configuration.
|
||||||
|
*/
|
||||||
|
getActiveConfig(): InterfaceConfig {
|
||||||
|
return this.scene.inputController.getActiveConfig(Device.GAMEPAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gamepad settings from local storage.
|
||||||
|
*
|
||||||
|
* @returns The gamepad settings from local storage.
|
||||||
|
*/
|
||||||
|
getLocalStorageSetting(): object {
|
||||||
|
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
||||||
|
const settings: object = localStorage.hasOwnProperty("settingsGamepad") ? JSON.parse(localStorage.getItem("settingsGamepad")) : {};
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the layout for the active configuration.
|
||||||
|
*
|
||||||
|
* @param activeConfig - The active gamepad configuration.
|
||||||
|
* @returns `true` if the layout was successfully applied, otherwise `false`.
|
||||||
|
*/
|
||||||
|
setLayout(activeConfig: InterfaceConfig): boolean {
|
||||||
|
// Check if there is no active configuration (e.g., no gamepad connected).
|
||||||
|
if (!activeConfig) {
|
||||||
|
// Retrieve the layout for when no gamepads are connected.
|
||||||
|
const layout = this.layout["noGamepads"];
|
||||||
|
// Make the options container visible to show message.
|
||||||
|
layout.optionsContainer.setVisible(true);
|
||||||
|
// Return false indicating the layout application was not successful due to lack of gamepad.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.setLayout(activeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the left menu tab.
|
||||||
|
*
|
||||||
|
* @returns `true` indicating the navigation was successful.
|
||||||
|
*/
|
||||||
|
navigateMenuLeft(): boolean {
|
||||||
|
this.scene.ui.setMode(Mode.SETTINGS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the right menu tab.
|
||||||
|
*
|
||||||
|
* @returns `true` indicating the navigation was successful.
|
||||||
|
*/
|
||||||
|
navigateMenuRight(): boolean {
|
||||||
|
this.scene.ui.setMode(Mode.SETTINGS_KEYBOARD);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the display of the chosen gamepad.
|
||||||
|
*/
|
||||||
|
updateChosenGamepadDisplay(): void {
|
||||||
|
// Update any bindings that might have changed since the last update.
|
||||||
|
this.updateBindings();
|
||||||
|
this.resetScroll();
|
||||||
|
|
||||||
|
// Iterate over the keys in the settingDevice enumeration.
|
||||||
|
for (const [index, key] of Object.keys(this.settingDevice).entries()) {
|
||||||
|
const setting = this.settingDevice[key]; // Get the actual setting value using the key.
|
||||||
|
|
||||||
|
// Check if the current setting corresponds to the controller setting.
|
||||||
|
if (setting === this.settingDevice.Controller) {
|
||||||
|
// Iterate over all layouts excluding the 'noGamepads' special case.
|
||||||
|
for (const _key of Object.keys(this.layout)) {
|
||||||
|
if (_key === "noGamepads") {
|
||||||
|
continue;
|
||||||
|
} // Skip updating the no gamepad layout.
|
||||||
|
|
||||||
|
// Update the text of the first option label under the current setting to the name of the chosen gamepad,
|
||||||
|
// truncating the name to 30 characters if necessary.
|
||||||
|
this.layout[_key].optionValueLabels[index][0].setText(truncateString(this.scene.inputController.selectedDevice[Device.GAMEPAD], 20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the setting to local storage.
|
||||||
|
*
|
||||||
|
* @param setting - The setting to save.
|
||||||
|
* @param cursor - The cursor position to save.
|
||||||
|
*/
|
||||||
|
saveSettingToLocalStorage(setting, cursor): void {
|
||||||
|
if (this.settingDevice[setting] !== this.settingDevice.Controller) {
|
||||||
|
this.scene.gameData.saveGamepadSetting(setting, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
import BattleScene from "../../battle-scene";
|
||||||
|
import {Mode} from "../ui";
|
||||||
|
import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty";
|
||||||
|
import {
|
||||||
|
setSettingKeyboard,
|
||||||
|
SettingKeyboard,
|
||||||
|
settingKeyboardBlackList,
|
||||||
|
settingKeyboardDefaults,
|
||||||
|
settingKeyboardOptions
|
||||||
|
} from "#app/system/settings-keyboard";
|
||||||
|
import {reverseValueToKeySetting, truncateString} from "#app/utils";
|
||||||
|
import AbstractSettingsUiUiHandler from "#app/ui/settings/abstract-settings-ui-handler";
|
||||||
|
import {InterfaceConfig} from "#app/inputs-controller";
|
||||||
|
import {addTextObject, TextStyle} from "#app/ui/text";
|
||||||
|
import {deleteBind} from "#app/configs/inputs/configHandler";
|
||||||
|
import {Device} from "#app/enums/devices";
|
||||||
|
import {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the settings UI handler for keyboards.
|
||||||
|
*
|
||||||
|
* @extends AbstractSettingsUiUiHandler
|
||||||
|
*/
|
||||||
|
export default class SettingsKeyboardUiHandler extends AbstractSettingsUiUiHandler {
|
||||||
|
/**
|
||||||
|
* Creates an instance of SettingsKeyboardUiHandler.
|
||||||
|
*
|
||||||
|
* @param scene - The BattleScene instance.
|
||||||
|
* @param mode - The UI mode, optional.
|
||||||
|
*/
|
||||||
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
|
super(scene, mode);
|
||||||
|
this.titleSelected = "Keyboard";
|
||||||
|
this.settingDevice = SettingKeyboard;
|
||||||
|
this.settingDeviceDefaults = settingKeyboardDefaults;
|
||||||
|
this.settingDeviceOptions = settingKeyboardOptions;
|
||||||
|
this.configs = [cfg_keyboard_qwerty];
|
||||||
|
this.commonSettingsCount = 0;
|
||||||
|
this.textureOverride = "keyboard";
|
||||||
|
this.localStoragePropertyName = "settingsKeyboard";
|
||||||
|
this.settingBlacklisted = settingKeyboardBlackList;
|
||||||
|
|
||||||
|
const deleteEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DELETE);
|
||||||
|
const restoreDefaultEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.HOME);
|
||||||
|
deleteEvent.on("up", this.onDeleteDown, this);
|
||||||
|
restoreDefaultEvent.on("up", this.onHomeDown, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSetting(scene: BattleScene, setting, value: integer): boolean {
|
||||||
|
return setSettingKeyboard(scene, setting, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup UI elements.
|
||||||
|
*/
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
// If no gamepads are detected, set up a default UI prompt in the settings container.
|
||||||
|
this.layout["noKeyboard"] = new Map();
|
||||||
|
const optionsContainer = this.scene.add.container(0, 0);
|
||||||
|
optionsContainer.setVisible(false); // Initially hide the container as no gamepads are connected.
|
||||||
|
const label = addTextObject(this.scene, 8, 28, "Please press a key on your keyboard", TextStyle.SETTINGS_LABEL);
|
||||||
|
label.setOrigin(0, 0);
|
||||||
|
optionsContainer.add(label);
|
||||||
|
this.settingsContainer.add(optionsContainer);
|
||||||
|
|
||||||
|
const iconDelete = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconDelete.setOrigin(0, -0.1);
|
||||||
|
iconDelete.setPositionRelative(this.actionsBg, this.navigationContainer.width - 260, 4);
|
||||||
|
this.navigationIcons["BUTTON_DELETE"] = iconDelete;
|
||||||
|
|
||||||
|
const deleteText = addTextObject(this.scene, 0, 0, "Delete", TextStyle.SETTINGS_LABEL);
|
||||||
|
deleteText.setOrigin(0, 0.15);
|
||||||
|
deleteText.setPositionRelative(iconDelete, -deleteText.width/6-2, 0);
|
||||||
|
|
||||||
|
this.settingsContainer.add(iconDelete);
|
||||||
|
this.settingsContainer.add(deleteText);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Map the 'noKeyboard' layout options for easy access.
|
||||||
|
this.layout["noKeyboard"].optionsContainer = optionsContainer;
|
||||||
|
this.layout["noKeyboard"].label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the home key press event.
|
||||||
|
*/
|
||||||
|
onHomeDown(): void {
|
||||||
|
if (![Mode.SETTINGS_KEYBOARD, Mode.SETTINGS_GAMEPAD].includes(this.scene.ui.getMode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.scene.gameData.resetMappingToFactory();
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the delete key press event.
|
||||||
|
*/
|
||||||
|
onDeleteDown(): void {
|
||||||
|
if (this.scene.ui.getMode() !== Mode.SETTINGS_KEYBOARD) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cursor = this.cursor + this.scrollCursor; // Calculate the absolute cursor position.
|
||||||
|
const selection = this.settingLabels[cursor].text;
|
||||||
|
const key = reverseValueToKeySetting(selection);
|
||||||
|
const settingName = SettingKeyboard[key];
|
||||||
|
const activeConfig = this.getActiveConfig();
|
||||||
|
const success = deleteBind(this.getActiveConfig(), settingName);
|
||||||
|
if (success) {
|
||||||
|
this.saveCustomKeyboardMappingToLocalStorage(activeConfig);
|
||||||
|
this.updateBindings();
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the active configuration.
|
||||||
|
*
|
||||||
|
* @returns The active keyboard configuration.
|
||||||
|
*/
|
||||||
|
getActiveConfig(): InterfaceConfig {
|
||||||
|
return this.scene.inputController.getActiveConfig(Device.KEYBOARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the keyboard settings from local storage.
|
||||||
|
*
|
||||||
|
* @returns The keyboard settings from local storage.
|
||||||
|
*/
|
||||||
|
getLocalStorageSetting(): object {
|
||||||
|
// Retrieve the gamepad settings from local storage or use an empty object if none exist.
|
||||||
|
const settings: object = localStorage.hasOwnProperty("settingsKeyboard") ? JSON.parse(localStorage.getItem("settingsKeyboard")) : {};
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the layout for the active configuration.
|
||||||
|
*
|
||||||
|
* @param activeConfig - The active keyboard configuration.
|
||||||
|
* @returns `true` if the layout was successfully applied, otherwise `false`.
|
||||||
|
*/
|
||||||
|
setLayout(activeConfig: InterfaceConfig): boolean {
|
||||||
|
// Check if there is no active configuration (e.g., no gamepad connected).
|
||||||
|
if (!activeConfig) {
|
||||||
|
// Retrieve the layout for when no gamepads are connected.
|
||||||
|
const layout = this.layout["noKeyboard"];
|
||||||
|
// Make the options container visible to show message.
|
||||||
|
layout.optionsContainer.setVisible(true);
|
||||||
|
// Return false indicating the layout application was not successful due to lack of gamepad.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.setLayout(activeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the left menu tab.
|
||||||
|
*
|
||||||
|
* @returns `true` indicating the navigation was successful.
|
||||||
|
*/
|
||||||
|
navigateMenuLeft(): boolean {
|
||||||
|
this.scene.ui.setMode(Mode.SETTINGS_GAMEPAD);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the right menu tab.
|
||||||
|
*
|
||||||
|
* @returns `true` indicating the navigation was successful.
|
||||||
|
*/
|
||||||
|
navigateMenuRight(): boolean {
|
||||||
|
this.scene.ui.setMode(Mode.SETTINGS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the display of the chosen keyboard layout.
|
||||||
|
*/
|
||||||
|
updateChosenKeyboardDisplay(): void {
|
||||||
|
// Update any bindings that might have changed since the last update.
|
||||||
|
this.updateBindings();
|
||||||
|
|
||||||
|
// Iterate over the keys in the settingDevice enumeration.
|
||||||
|
for (const [index, key] of Object.keys(this.settingDevice).entries()) {
|
||||||
|
const setting = this.settingDevice[key]; // Get the actual setting value using the key.
|
||||||
|
|
||||||
|
// Check if the current setting corresponds to the layout setting.
|
||||||
|
if (setting === this.settingDevice.Default_Layout) {
|
||||||
|
// Iterate over all layouts excluding the 'noGamepads' special case.
|
||||||
|
for (const _key of Object.keys(this.layout)) {
|
||||||
|
if (_key === "noKeyboard") {
|
||||||
|
continue;
|
||||||
|
} // Skip updating the no gamepad layout.
|
||||||
|
// Update the text of the first option label under the current setting to the name of the chosen gamepad,
|
||||||
|
// truncating the name to 30 characters if necessary.
|
||||||
|
this.layout[_key].optionValueLabels[index][0].setText(truncateString(this.scene.inputController.selectedDevice[Device.KEYBOARD], 22));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the custom keyboard mapping to local storage.
|
||||||
|
*
|
||||||
|
* @param config - The configuration to save.
|
||||||
|
*/
|
||||||
|
saveCustomKeyboardMappingToLocalStorage(config): void {
|
||||||
|
this.scene.gameData.saveMappingConfigs(this.scene.inputController?.selectedDevice[Device.KEYBOARD], config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the setting to local storage.
|
||||||
|
*
|
||||||
|
* @param settingName - The name of the setting to save.
|
||||||
|
* @param cursor - The cursor position to save.
|
||||||
|
*/
|
||||||
|
saveSettingToLocalStorage(settingName, cursor): void {
|
||||||
|
if (this.settingDevice[settingName] !== this.settingDevice.Default_Layout) {
|
||||||
|
this.scene.gameData.saveKeyboardSetting(settingName, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,18 @@
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import { Setting, reloadSettings, settingDefaults, settingOptions } from "../system/settings";
|
import {Setting, reloadSettings, settingDefaults, settingOptions} from "../../system/settings";
|
||||||
import { hasTouchscreen, isMobile } from "../touch-controls";
|
import { hasTouchscreen, isMobile } from "../../touch-controls";
|
||||||
import { TextStyle, addTextObject } from "./text";
|
import { TextStyle, addTextObject } from "../text";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "../ui";
|
||||||
import UiHandler from "./ui-handler";
|
import UiHandler from "../ui-handler";
|
||||||
import { addWindow } from "./ui-theme";
|
import { addWindow } from "../ui-theme";
|
||||||
import {Button} from "../enums/buttons";
|
import {Button} from "../../enums/buttons";
|
||||||
|
import {InputsIcons} from "#app/ui/settings/abstract-settings-ui-handler";
|
||||||
|
import NavigationMenu, {NavigationManager} from "#app/ui/settings/navigationMenu";
|
||||||
|
|
||||||
export default class SettingsUiHandler extends UiHandler {
|
export default class SettingsUiHandler extends UiHandler {
|
||||||
private settingsContainer: Phaser.GameObjects.Container;
|
private settingsContainer: Phaser.GameObjects.Container;
|
||||||
private optionsContainer: Phaser.GameObjects.Container;
|
private optionsContainer: Phaser.GameObjects.Container;
|
||||||
|
private navigationContainer: NavigationMenu;
|
||||||
|
|
||||||
private scrollCursor: integer;
|
private scrollCursor: integer;
|
||||||
|
|
||||||
|
@ -20,16 +23,20 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
private settingLabels: Phaser.GameObjects.Text[];
|
private settingLabels: Phaser.GameObjects.Text[];
|
||||||
private optionValueLabels: Phaser.GameObjects.Text[][];
|
private optionValueLabels: Phaser.GameObjects.Text[][];
|
||||||
|
|
||||||
|
protected navigationIcons: InputsIcons;
|
||||||
|
|
||||||
private cursorObj: Phaser.GameObjects.NineSlice;
|
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
private reloadRequired: boolean;
|
private reloadRequired: boolean;
|
||||||
private reloadI18n: boolean;
|
private reloadI18n: boolean;
|
||||||
|
private rowsToDisplay: number;
|
||||||
|
|
||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
|
||||||
this.reloadRequired = false;
|
this.reloadRequired = false;
|
||||||
this.reloadI18n = false;
|
this.reloadI18n = false;
|
||||||
|
this.rowsToDisplay = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -37,18 +44,36 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
|
|
||||||
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
this.settingsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
|
||||||
|
|
||||||
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
|
this.settingsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6 - 20), Phaser.Geom.Rectangle.Contains);
|
||||||
|
|
||||||
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
|
this.navigationIcons = {};
|
||||||
headerBg.setOrigin(0, 0);
|
|
||||||
|
|
||||||
const headerText = addTextObject(this.scene, 0, 0, "Options", TextStyle.SETTINGS_LABEL);
|
this.navigationContainer = new NavigationMenu(this.scene, 0, 0);
|
||||||
headerText.setOrigin(0, 0);
|
|
||||||
headerText.setPositionRelative(headerBg, 8, 4);
|
|
||||||
|
|
||||||
this.optionsBg = addWindow(this.scene, 0, headerBg.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 2);
|
this.optionsBg = addWindow(this.scene, 0, this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 16 - this.navigationContainer.height - 2);
|
||||||
this.optionsBg.setOrigin(0, 0);
|
this.optionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
const actionsBg = addWindow(this.scene, 0, (this.scene.game.canvas.height / 6) - this.navigationContainer.height, (this.scene.game.canvas.width / 6) - 2, 22);
|
||||||
|
actionsBg.setOrigin(0, 0);
|
||||||
|
|
||||||
|
const iconAction = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconAction.setOrigin(0, -0.1);
|
||||||
|
iconAction.setPositionRelative(actionsBg, this.navigationContainer.width - 32, 4);
|
||||||
|
this.navigationIcons["BUTTON_ACTION"] = iconAction;
|
||||||
|
|
||||||
|
const actionText = addTextObject(this.scene, 0, 0, "Action", TextStyle.SETTINGS_LABEL);
|
||||||
|
actionText.setOrigin(0, 0.15);
|
||||||
|
actionText.setPositionRelative(iconAction, -actionText.width/6-2, 0);
|
||||||
|
|
||||||
|
const iconCancel = this.scene.add.sprite(0, 0, "keyboard");
|
||||||
|
iconCancel.setOrigin(0, -0.1);
|
||||||
|
iconCancel.setPositionRelative(actionsBg, this.navigationContainer.width - 100, 4);
|
||||||
|
this.navigationIcons["BUTTON_CANCEL"] = iconCancel;
|
||||||
|
|
||||||
|
const cancelText = addTextObject(this.scene, 0, 0, "Cancel", TextStyle.SETTINGS_LABEL);
|
||||||
|
cancelText.setOrigin(0, 0.15);
|
||||||
|
cancelText.setPositionRelative(iconCancel, -cancelText.width/6-2, 0);
|
||||||
|
|
||||||
this.optionsContainer = this.scene.add.container(0, 0);
|
this.optionsContainer = this.scene.add.container(0, 0);
|
||||||
|
|
||||||
this.settingLabels = [];
|
this.settingLabels = [];
|
||||||
|
@ -91,10 +116,14 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
|
|
||||||
this.optionCursors = Object.values(settingDefaults);
|
this.optionCursors = Object.values(settingDefaults);
|
||||||
|
|
||||||
this.settingsContainer.add(headerBg);
|
|
||||||
this.settingsContainer.add(headerText);
|
|
||||||
this.settingsContainer.add(this.optionsBg);
|
this.settingsContainer.add(this.optionsBg);
|
||||||
|
this.settingsContainer.add(this.navigationContainer);
|
||||||
|
this.settingsContainer.add(actionsBg);
|
||||||
this.settingsContainer.add(this.optionsContainer);
|
this.settingsContainer.add(this.optionsContainer);
|
||||||
|
this.settingsContainer.add(iconAction);
|
||||||
|
this.settingsContainer.add(iconCancel);
|
||||||
|
this.settingsContainer.add(actionText);
|
||||||
|
this.settingsContainer.add(cancelText);
|
||||||
|
|
||||||
ui.add(this.settingsContainer);
|
ui.add(this.settingsContainer);
|
||||||
|
|
||||||
|
@ -104,8 +133,30 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
this.settingsContainer.setVisible(false);
|
this.settingsContainer.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateBindings(): void {
|
||||||
|
for (const settingName of Object.keys(this.navigationIcons)) {
|
||||||
|
if (settingName === "BUTTON_HOME") {
|
||||||
|
this.navigationIcons[settingName].setTexture("keyboard");
|
||||||
|
this.navigationIcons[settingName].setFrame("HOME.png");
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const icon = this.scene.inputController?.getIconForLatestInputRecorded(settingName);
|
||||||
|
if (icon) {
|
||||||
|
const type = this.scene.inputController?.getLastSourceType();
|
||||||
|
this.navigationIcons[settingName].setTexture(type);
|
||||||
|
this.navigationIcons[settingName].setFrame(icon);
|
||||||
|
this.navigationIcons[settingName].alpha = 1;
|
||||||
|
} else {
|
||||||
|
this.navigationIcons[settingName].alpha = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NavigationManager.getInstance().updateIcons();
|
||||||
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
super.show(args);
|
super.show(args);
|
||||||
|
this.updateBindings();
|
||||||
|
|
||||||
const settings: object = localStorage.hasOwnProperty("settings") ? JSON.parse(localStorage.getItem("settings")) : {};
|
const settings: object = localStorage.hasOwnProperty("settings") ? JSON.parse(localStorage.getItem("settings")) : {};
|
||||||
|
|
||||||
|
@ -133,12 +184,12 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
processInput(button: Button): boolean {
|
processInput(button: Button): boolean {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
// Defines the maximum number of rows that can be displayed on the screen.
|
// Defines the maximum number of rows that can be displayed on the screen.
|
||||||
const rowsToDisplay = 9;
|
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
|
|
||||||
if (button === Button.CANCEL) {
|
if (button === Button.CANCEL) {
|
||||||
success = true;
|
success = true;
|
||||||
|
NavigationManager.getInstance().reset();
|
||||||
// Reverts UI to its previous state on cancel.
|
// Reverts UI to its previous state on cancel.
|
||||||
this.scene.ui.revertMode();
|
this.scene.ui.revertMode();
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,17 +205,17 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
} else {
|
} else {
|
||||||
// When at the top of the menu and pressing UP, move to the bottommost item.
|
// When at the top of the menu and pressing UP, move to the bottommost item.
|
||||||
// First, set the cursor to the last visible element, preparing for the scroll to the end.
|
// First, set the cursor to the last visible element, preparing for the scroll to the end.
|
||||||
const successA = this.setCursor(rowsToDisplay - 1);
|
const successA = this.setCursor(this.rowsToDisplay - 1);
|
||||||
// Then, adjust the scroll to display the bottommost elements of the menu.
|
// Then, adjust the scroll to display the bottommost elements of the menu.
|
||||||
const successB = this.setScrollCursor(this.optionValueLabels.length - rowsToDisplay);
|
const successB = this.setScrollCursor(this.optionValueLabels.length - this.rowsToDisplay);
|
||||||
success = successA && successB; // success is just there to play the little validation sound effect
|
success = successA && successB; // success is just there to play the little validation sound effect
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.DOWN:
|
case Button.DOWN:
|
||||||
if (cursor < this.optionValueLabels.length - 1) {
|
if (cursor < this.optionValueLabels.length - 1) {
|
||||||
if (this.cursor < rowsToDisplay - 1) { // if the visual cursor is in the frame of 0 to 8
|
if (this.cursor < this.rowsToDisplay - 1) {// if the visual cursor is in the frame of 0 to 8
|
||||||
success = this.setCursor(this.cursor + 1);
|
success = this.setCursor(this.cursor + 1);
|
||||||
} else if (this.scrollCursor < this.optionValueLabels.length - rowsToDisplay) {
|
} else if (this.scrollCursor < this.optionValueLabels.length - this.rowsToDisplay) {
|
||||||
success = this.setScrollCursor(this.scrollCursor + 1);
|
success = this.setScrollCursor(this.scrollCursor + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +228,7 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.LEFT:
|
case Button.LEFT:
|
||||||
if (this.optionCursors[cursor]) { // Moves the option cursor left, if possible.
|
if (this.optionCursors[cursor]) {// Moves the option cursor left, if possible.
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] - 1, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -187,6 +238,10 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
success = this.setOptionCursor(cursor, this.optionCursors[cursor] + 1, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Button.CYCLE_FORM:
|
||||||
|
case Button.CYCLE_SHINY:
|
||||||
|
success = this.navigationContainer.navigate(button);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +318,7 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
this.optionsContainer.setY(-16 * this.scrollCursor);
|
this.optionsContainer.setY(-16 * this.scrollCursor);
|
||||||
|
|
||||||
for (let s = 0; s < this.settingLabels.length; s++) {
|
for (let s = 0; s < this.settingLabels.length; s++) {
|
||||||
const visible = s >= this.scrollCursor && s < this.scrollCursor + 9;
|
const visible = s >= this.scrollCursor && s < this.scrollCursor + this.rowsToDisplay;
|
||||||
this.settingLabels[s].setVisible(visible);
|
this.settingLabels[s].setVisible(visible);
|
||||||
for (const option of this.optionValueLabels[s]) {
|
for (const option of this.optionValueLabels[s]) {
|
||||||
option.setVisible(visible);
|
option.setVisible(visible);
|
|
@ -742,7 +742,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||||
allAbilityInfo.push(this.passiveContainer);
|
allAbilityInfo.push(this.passiveContainer);
|
||||||
|
|
||||||
// Sets up the pixel button prompt image
|
// Sets up the pixel button prompt image
|
||||||
this.abilityPrompt = this.scene.add.image(0, 0, !this.scene.gamepadSupport ? "summary_profile_prompt_z" : "summary_profile_prompt_a");
|
this.abilityPrompt = this.scene.add.image(0, 0, !this.scene.inputController?.gamepadSupport ? "summary_profile_prompt_z" : "summary_profile_prompt_a");
|
||||||
this.abilityPrompt.setPosition(8, 43);
|
this.abilityPrompt.setPosition(8, 43);
|
||||||
this.abilityPrompt.setVisible(true);
|
this.abilityPrompt.setVisible(true);
|
||||||
this.abilityPrompt.setOrigin(0, 0);
|
this.abilityPrompt.setOrigin(0, 0);
|
||||||
|
|
|
@ -26,6 +26,7 @@ export enum TextStyle {
|
||||||
STATS_VALUE,
|
STATS_VALUE,
|
||||||
SETTINGS_LABEL,
|
SETTINGS_LABEL,
|
||||||
SETTINGS_SELECTED,
|
SETTINGS_SELECTED,
|
||||||
|
SETTINGS_LOCKED,
|
||||||
TOOLTIP_TITLE,
|
TOOLTIP_TITLE,
|
||||||
TOOLTIP_CONTENT,
|
TOOLTIP_CONTENT,
|
||||||
MOVE_INFO_CONTENT
|
MOVE_INFO_CONTENT
|
||||||
|
@ -63,6 +64,15 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setTextStyle(obj: Phaser.GameObjects.Text, scene: Phaser.Scene, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) {
|
||||||
|
const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
|
||||||
|
obj.setScale(0.1666666667);
|
||||||
|
obj.setShadow(shadowXpos, shadowYpos, shadowColor);
|
||||||
|
if (!(styleOptions as Phaser.Types.GameObjects.Text.TextStyle).lineSpacing) {
|
||||||
|
obj.setLineSpacing(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText {
|
export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText {
|
||||||
const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
|
const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
|
||||||
|
|
||||||
|
@ -143,6 +153,7 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
|
||||||
break;
|
break;
|
||||||
case TextStyle.MESSAGE:
|
case TextStyle.MESSAGE:
|
||||||
case TextStyle.SETTINGS_LABEL:
|
case TextStyle.SETTINGS_LABEL:
|
||||||
|
case TextStyle.SETTINGS_LOCKED:
|
||||||
case TextStyle.SETTINGS_SELECTED:
|
case TextStyle.SETTINGS_SELECTED:
|
||||||
styleOptions.fontSize = languageSettings[lang]?.summaryFontSize || "96px";
|
styleOptions.fontSize = languageSettings[lang]?.summaryFontSize || "96px";
|
||||||
break;
|
break;
|
||||||
|
@ -226,6 +237,7 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
|
||||||
case TextStyle.SUMMARY_GOLD:
|
case TextStyle.SUMMARY_GOLD:
|
||||||
case TextStyle.MONEY:
|
case TextStyle.MONEY:
|
||||||
return !shadow ? "#e8e8a8" : "#a0a060";
|
return !shadow ? "#e8e8a8" : "#a0a060";
|
||||||
|
case TextStyle.SETTINGS_LOCKED:
|
||||||
case TextStyle.SUMMARY_GRAY:
|
case TextStyle.SUMMARY_GRAY:
|
||||||
return !shadow ? "#a0a0a0" : "#636363";
|
return !shadow ? "#a0a0a0" : "#636363";
|
||||||
case TextStyle.STATS_LABEL:
|
case TextStyle.STATS_LABEL:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { DailyRunScoreboard } from "./daily-run-scoreboard";
|
import { DailyRunScoreboard } from "./daily-run-scoreboard";
|
||||||
import OptionSelectUiHandler from "./option-select-ui-handler";
|
import OptionSelectUiHandler from "./settings/option-select-ui-handler";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "./ui";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { TextStyle, addTextObject } from "./text";
|
import { TextStyle, addTextObject } from "./text";
|
||||||
|
|
24
src/ui/ui.ts
24
src/ui/ui.ts
|
@ -12,12 +12,13 @@ import SummaryUiHandler from "./summary-ui-handler";
|
||||||
import StarterSelectUiHandler from "./starter-select-ui-handler";
|
import StarterSelectUiHandler from "./starter-select-ui-handler";
|
||||||
import EvolutionSceneHandler from "./evolution-scene-handler";
|
import EvolutionSceneHandler from "./evolution-scene-handler";
|
||||||
import TargetSelectUiHandler from "./target-select-ui-handler";
|
import TargetSelectUiHandler from "./target-select-ui-handler";
|
||||||
import SettingsUiHandler from "./settings-ui-handler";
|
import SettingsUiHandler from "./settings/settings-ui-handler";
|
||||||
import {addTextObject, TextStyle} from "./text";
|
import SettingsGamepadUiHandler from "./settings/settings-gamepad-ui-handler";
|
||||||
|
import { TextStyle, addTextObject } from "./text";
|
||||||
import AchvBar from "./achv-bar";
|
import AchvBar from "./achv-bar";
|
||||||
import MenuUiHandler from "./menu-ui-handler";
|
import MenuUiHandler from "./menu-ui-handler";
|
||||||
import AchvsUiHandler from "./achvs-ui-handler";
|
import AchvsUiHandler from "./achvs-ui-handler";
|
||||||
import OptionSelectUiHandler from "./option-select-ui-handler";
|
import OptionSelectUiHandler from "./settings/option-select-ui-handler";
|
||||||
import EggHatchSceneHandler from "./egg-hatch-scene-handler";
|
import EggHatchSceneHandler from "./egg-hatch-scene-handler";
|
||||||
import EggListUiHandler from "./egg-list-ui-handler";
|
import EggListUiHandler from "./egg-list-ui-handler";
|
||||||
import EggGachaUiHandler from "./egg-gacha-ui-handler";
|
import EggGachaUiHandler from "./egg-gacha-ui-handler";
|
||||||
|
@ -38,6 +39,9 @@ import SessionReloadModalUiHandler from "./session-reload-modal-ui-handler";
|
||||||
import {Button} from "../enums/buttons";
|
import {Button} from "../enums/buttons";
|
||||||
import i18next, {ParseKeys} from "i18next";
|
import i18next, {ParseKeys} from "i18next";
|
||||||
import {PlayerGender} from "#app/system/game-data";
|
import {PlayerGender} from "#app/system/game-data";
|
||||||
|
import GamepadBindingUiHandler from "./settings/gamepad-binding-ui-handler";
|
||||||
|
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||||
|
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";
|
||||||
|
|
||||||
export enum Mode {
|
export enum Mode {
|
||||||
MESSAGE,
|
MESSAGE,
|
||||||
|
@ -58,6 +62,10 @@ export enum Mode {
|
||||||
MENU,
|
MENU,
|
||||||
MENU_OPTION_SELECT,
|
MENU_OPTION_SELECT,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
SETTINGS_GAMEPAD,
|
||||||
|
GAMEPAD_BINDING,
|
||||||
|
SETTINGS_KEYBOARD,
|
||||||
|
KEYBOARD_BINDING,
|
||||||
ACHIEVEMENTS,
|
ACHIEVEMENTS,
|
||||||
GAME_STATS,
|
GAME_STATS,
|
||||||
VOUCHERS,
|
VOUCHERS,
|
||||||
|
@ -88,7 +96,11 @@ const noTransitionModes = [
|
||||||
Mode.OPTION_SELECT,
|
Mode.OPTION_SELECT,
|
||||||
Mode.MENU,
|
Mode.MENU,
|
||||||
Mode.MENU_OPTION_SELECT,
|
Mode.MENU_OPTION_SELECT,
|
||||||
|
Mode.GAMEPAD_BINDING,
|
||||||
|
Mode.KEYBOARD_BINDING,
|
||||||
Mode.SETTINGS,
|
Mode.SETTINGS,
|
||||||
|
Mode.SETTINGS_GAMEPAD,
|
||||||
|
Mode.SETTINGS_KEYBOARD,
|
||||||
Mode.ACHIEVEMENTS,
|
Mode.ACHIEVEMENTS,
|
||||||
Mode.GAME_STATS,
|
Mode.GAME_STATS,
|
||||||
Mode.VOUCHERS,
|
Mode.VOUCHERS,
|
||||||
|
@ -103,7 +115,7 @@ const noTransitionModes = [
|
||||||
export default class UI extends Phaser.GameObjects.Container {
|
export default class UI extends Phaser.GameObjects.Container {
|
||||||
private mode: Mode;
|
private mode: Mode;
|
||||||
private modeChain: Mode[];
|
private modeChain: Mode[];
|
||||||
private handlers: UiHandler[];
|
public handlers: UiHandler[];
|
||||||
private overlay: Phaser.GameObjects.Rectangle;
|
private overlay: Phaser.GameObjects.Rectangle;
|
||||||
public achvBar: AchvBar;
|
public achvBar: AchvBar;
|
||||||
public savingIcon: SavingIconHandler;
|
public savingIcon: SavingIconHandler;
|
||||||
|
@ -139,6 +151,10 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||||
new MenuUiHandler(scene),
|
new MenuUiHandler(scene),
|
||||||
new OptionSelectUiHandler(scene, Mode.MENU_OPTION_SELECT),
|
new OptionSelectUiHandler(scene, Mode.MENU_OPTION_SELECT),
|
||||||
new SettingsUiHandler(scene),
|
new SettingsUiHandler(scene),
|
||||||
|
new SettingsGamepadUiHandler(scene),
|
||||||
|
new GamepadBindingUiHandler(scene),
|
||||||
|
new SettingsKeyboardUiHandler(scene),
|
||||||
|
new KeyboardBindingUiHandler(scene),
|
||||||
new AchvsUiHandler(scene),
|
new AchvsUiHandler(scene),
|
||||||
new GameStatsUiHandler(scene),
|
new GameStatsUiHandler(scene),
|
||||||
new VouchersUiHandler(scene),
|
new VouchersUiHandler(scene),
|
||||||
|
|
46
src/utils.ts
46
src/utils.ts
|
@ -423,3 +423,49 @@ export function printContainerList(container: Phaser.GameObjects.Container): voi
|
||||||
return {type: go.type, name: go.name};
|
return {type: go.type, name: go.name};
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncate a string to a specified maximum length and add an ellipsis if it exceeds that length.
|
||||||
|
*
|
||||||
|
* @param str - The string to be truncated.
|
||||||
|
* @param maxLength - The maximum length of the truncated string, defaults to 10.
|
||||||
|
* @returns The truncated string with an ellipsis if it was longer than maxLength.
|
||||||
|
*/
|
||||||
|
export function truncateString(str: String, maxLength: number = 10) {
|
||||||
|
// Check if the string length exceeds the maximum length
|
||||||
|
if (str.length > maxLength) {
|
||||||
|
// Truncate the string and add an ellipsis
|
||||||
|
return str.slice(0, maxLength - 3) + "..."; // Subtract 3 to accommodate the ellipsis
|
||||||
|
}
|
||||||
|
// Return the original string if it does not exceed the maximum length
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a deep copy of an object.
|
||||||
|
*
|
||||||
|
* @param values - The object to be deep copied.
|
||||||
|
* @returns A new object that is a deep copy of the input.
|
||||||
|
*/
|
||||||
|
export function deepCopy(values: object): object {
|
||||||
|
// Convert the object to a JSON string and parse it back to an object to perform a deep copy
|
||||||
|
return JSON.parse(JSON.stringify(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a space-separated string into a capitalized and underscored string.
|
||||||
|
*
|
||||||
|
* @param input - The string to be converted.
|
||||||
|
* @returns The converted string with words capitalized and separated by underscores.
|
||||||
|
*/
|
||||||
|
export function reverseValueToKeySetting(input) {
|
||||||
|
// Split the input string into an array of words
|
||||||
|
const words = input.split(" ");
|
||||||
|
// Capitalize the first letter of each word and convert the rest to lowercase
|
||||||
|
const capitalizedWords = words.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
||||||
|
// Join the capitalized words with underscores and return the result
|
||||||
|
return capitalizedWords.join("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue