rename files
5
phaser-client/.gitignore
vendored
@ -1,5 +0,0 @@
|
|||||||
package-lock.json
|
|
||||||
node_modules/
|
|
||||||
dist/
|
|
||||||
.cache/
|
|
||||||
assets/molecules
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 28 KiB |
@ -1,444 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 1024,
|
|
||||||
"h": 1024
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames":[
|
|
||||||
{
|
|
||||||
"filename":"sprite0",
|
|
||||||
"frame":{
|
|
||||||
"x":655,
|
|
||||||
"y":100,
|
|
||||||
"w":110,
|
|
||||||
"h":97
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":110,
|
|
||||||
"h":97
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":110,
|
|
||||||
"h":97
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite1",
|
|
||||||
"frame":{
|
|
||||||
"x":180,
|
|
||||||
"y":105,
|
|
||||||
"w":140,
|
|
||||||
"h":88
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":88
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":88
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite2",
|
|
||||||
"frame":{
|
|
||||||
"x":20,
|
|
||||||
"y":106,
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite3",
|
|
||||||
"frame":{
|
|
||||||
"x":475,
|
|
||||||
"y":106,
|
|
||||||
"w":150,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":150,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":150,
|
|
||||||
"h":86
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite4",
|
|
||||||
"frame":{
|
|
||||||
"x":330,
|
|
||||||
"y":112,
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite5",
|
|
||||||
"frame":{
|
|
||||||
"x":198,
|
|
||||||
"y":274,
|
|
||||||
"w":104,
|
|
||||||
"h":110
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":104,
|
|
||||||
"h":110
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":104,
|
|
||||||
"h":110
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite6",
|
|
||||||
"frame":{
|
|
||||||
"x":342,
|
|
||||||
"y":279,
|
|
||||||
"w":116,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":116,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":116,
|
|
||||||
"h":100
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite7",
|
|
||||||
"frame":{
|
|
||||||
"x":480,
|
|
||||||
"y":283,
|
|
||||||
"w":140,
|
|
||||||
"h":92
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":92
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":92
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite8",
|
|
||||||
"frame":{
|
|
||||||
"x":24,
|
|
||||||
"y":284,
|
|
||||||
"w":132,
|
|
||||||
"h":90
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":132,
|
|
||||||
"h":90
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":132,
|
|
||||||
"h":90
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite9",
|
|
||||||
"frame":{
|
|
||||||
"x":645,
|
|
||||||
"y":287,
|
|
||||||
"w":130,
|
|
||||||
"h":84
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":130,
|
|
||||||
"h":84
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":130,
|
|
||||||
"h":84
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite10",
|
|
||||||
"frame":{
|
|
||||||
"x":514,
|
|
||||||
"y":434,
|
|
||||||
"w":74,
|
|
||||||
"h":110
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":74,
|
|
||||||
"h":110
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":74,
|
|
||||||
"h":110
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite11",
|
|
||||||
"frame":{
|
|
||||||
"x":222,
|
|
||||||
"y":439,
|
|
||||||
"w":56,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":56,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":56,
|
|
||||||
"h":100
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite12",
|
|
||||||
"frame":{
|
|
||||||
"x":667,
|
|
||||||
"y":439,
|
|
||||||
"w":86,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":86,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":86,
|
|
||||||
"h":100
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite13",
|
|
||||||
"frame":{
|
|
||||||
"x":20,
|
|
||||||
"y":451,
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":74
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite14",
|
|
||||||
"frame":{
|
|
||||||
"x":335,
|
|
||||||
"y":453,
|
|
||||||
"w":130,
|
|
||||||
"h":72
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":130,
|
|
||||||
"h":72
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":130,
|
|
||||||
"h":72
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite15",
|
|
||||||
"frame":{
|
|
||||||
"x":493,
|
|
||||||
"y":619,
|
|
||||||
"w":114,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":114,
|
|
||||||
"h":100
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":114,
|
|
||||||
"h":100
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite16",
|
|
||||||
"frame":{
|
|
||||||
"x":180,
|
|
||||||
"y":626,
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":86
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite17",
|
|
||||||
"frame":{
|
|
||||||
"x":640,
|
|
||||||
"y":632,
|
|
||||||
"w":140,
|
|
||||||
"h":94
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":140,
|
|
||||||
"h":94
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":140,
|
|
||||||
"h":94
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite18",
|
|
||||||
"frame":{
|
|
||||||
"x":329,
|
|
||||||
"y":635,
|
|
||||||
"w":141,
|
|
||||||
"h":88
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":141,
|
|
||||||
"h":88
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":141,
|
|
||||||
"h":88
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename":"sprite19",
|
|
||||||
"frame":{
|
|
||||||
"x":25,
|
|
||||||
"y":641,
|
|
||||||
"w":130,
|
|
||||||
"h":76
|
|
||||||
},
|
|
||||||
"rotated":false,
|
|
||||||
"trimmed":false,
|
|
||||||
"spriteSourceSize":{
|
|
||||||
"x":0,
|
|
||||||
"y":0,
|
|
||||||
"w":130,
|
|
||||||
"h":76
|
|
||||||
},
|
|
||||||
"sourceSize":{
|
|
||||||
"w":130,
|
|
||||||
"h":76
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta":{
|
|
||||||
"app":"https://www.leshylabs.com/apps/sstool/",
|
|
||||||
"version":"Leshy SpriteSheet Tool v0.8.4",
|
|
||||||
"image":"spritesheet.png",
|
|
||||||
"size":{
|
|
||||||
"w":800,
|
|
||||||
"h":800
|
|
||||||
},
|
|
||||||
"scale":1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 431 KiB |
|
Before Width: | Height: | Size: 187 KiB |
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="13.8889in" height="13.8889in"
|
|
||||||
viewBox="0 0 1000 1000">
|
|
||||||
<path id="Unnamed"
|
|
||||||
fill="none" stroke="black" stroke-width="1"
|
|
||||||
d="M 250.00,-1.00
|
|
||||||
C 250.00,-1.00 0.00,300.00 0.00,300.00
|
|
||||||
0.00,300.00 1000.00,300.00 1000.00,300.00
|
|
||||||
1000.00,300.00 750.00,2.00 750.00,2.00M 500.00,300.00
|
|
||||||
C 500.00,300.00 500.00,700.00 500.00,700.00M 250.00,1000.00
|
|
||||||
C 250.00,1000.00 0.00,700.00 0.00,700.00
|
|
||||||
0.00,700.00 999.00,700.00 1000.00,700.00
|
|
||||||
1001.00,700.00 750.00,1000.00 750.00,1000.00" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 811 B |
@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="13.8889in" height="13.8889in"
|
|
||||||
viewBox="0 0 1000 1000">
|
|
||||||
<path id="c2"
|
|
||||||
fill="none" stroke="black" stroke-width="1"
|
|
||||||
d="M 250.00,-1.00
|
|
||||||
C 250.00,-1.00 250.00,300.00 250.00,300.00
|
|
||||||
250.00,300.00 750.00,299.00 750.00,299.00
|
|
||||||
750.00,299.00 750.00,2.00 750.00,2.00M 500.00,100.00
|
|
||||||
C 500.00,100.00 500.00,300.00 500.00,300.00
|
|
||||||
500.00,300.00 500.00,700.00 500.00,700.00M 250.00,1000.00
|
|
||||||
C 250.00,1000.00 500.00,700.00 500.00,700.00
|
|
||||||
500.00,700.00 750.00,1000.00 750.00,1000.00M 750.00,700.00
|
|
||||||
C 750.00,700.00 500.00,400.00 500.00,400.00
|
|
||||||
500.00,400.00 249.00,699.00 249.00,699.00" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 938 B |
@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="13.8889in" height="13.8889in"
|
|
||||||
viewBox="0 0 1000 1000">
|
|
||||||
<path id="c3"
|
|
||||||
fill="none" stroke="black" stroke-width="1"
|
|
||||||
d="M 250.00,-1.00
|
|
||||||
C 250.00,-1.00 250.00,300.00 250.00,300.00
|
|
||||||
250.00,300.00 750.00,299.00 750.00,299.00
|
|
||||||
750.00,299.00 750.00,2.00 750.00,2.00M 500.00,300.00
|
|
||||||
C 500.00,300.00 500.00,700.00 500.00,700.00M 250.00,1000.00
|
|
||||||
C 250.00,1000.00 250.00,700.00 250.00,700.00
|
|
||||||
250.00,700.00 500.00,700.00 500.00,700.00
|
|
||||||
500.00,700.00 750.00,700.00 750.00,700.00
|
|
||||||
750.00,700.00 750.00,1000.00 750.00,1000.00M 250.00,500.00
|
|
||||||
C 250.00,500.00 750.00,500.00 750.00,500.00" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 938 B |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
@ -1,24 +0,0 @@
|
|||||||
/*@font-face {
|
|
||||||
font-family: 'nowayregular';
|
|
||||||
src: url('./assets/fonts/noway-regular-webfont.eot');
|
|
||||||
src: url('./assets/fonts/noway-regular-webfont.eot?#iefix') format('embedded-opentype'),
|
|
||||||
url('./assets/fonts/noway-regular-webfont.woff2') format('woff2'),
|
|
||||||
url('./assets/fonts/noway-regular-webfont.woff') format('woff'),
|
|
||||||
url('./assets/fonts/noway-regular-webfont.ttf') format('truetype'),
|
|
||||||
url('./assets/fonts/noway-regular-webfont.svg#nowayregular') format('svg');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
body {
|
|
||||||
background-color: #181818;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas{
|
|
||||||
display:block;
|
|
||||||
margin: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>constructs.gg - mnml pvp atbs</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
||||||
<link rel="stylesheet" href="./node_modules/izitoast/dist/css/iziToast.min.css"></script>
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Jura" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
|
|
||||||
<script defer src="https://use.fontawesome.com/releases/v5.1.0/js/all.js"></script>
|
|
||||||
</head>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
<script src="./index.js"></script>
|
|
||||||
</html>
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
require('./constructs.css');
|
|
||||||
|
|
||||||
// kick it off
|
|
||||||
require('./src/main');
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
// http://mrl.nyu.edu/~perlin/noise/
|
|
||||||
|
|
||||||
const ImprovedNoise = function () {
|
|
||||||
const p = [151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10,
|
|
||||||
23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87,
|
|
||||||
174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211,
|
|
||||||
133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208,
|
|
||||||
89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5,
|
|
||||||
202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119,
|
|
||||||
248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
|
|
||||||
178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,
|
|
||||||
14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205,
|
|
||||||
93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180];
|
|
||||||
|
|
||||||
for (let i = 0; i < 256; i++) {
|
|
||||||
p[256 + i] = p[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
function fade(t) {
|
|
||||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function lerp(t, a, b) {
|
|
||||||
return a + t * (b - a);
|
|
||||||
}
|
|
||||||
|
|
||||||
function grad(hash, x, y, z) {
|
|
||||||
const h = hash & 15;
|
|
||||||
const u = h < 8 ? x : y; const
|
|
||||||
v = h < 4 ? y : h == 12 || h == 14 ? x : z;
|
|
||||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
noise(x, y, z) {
|
|
||||||
const floorX = Math.floor(x); const floorY = Math.floor(y); const
|
|
||||||
floorZ = Math.floor(z);
|
|
||||||
|
|
||||||
const X = floorX & 255; const Y = floorY & 255; const
|
|
||||||
Z = floorZ & 255;
|
|
||||||
|
|
||||||
x -= floorX;
|
|
||||||
y -= floorY;
|
|
||||||
z -= floorZ;
|
|
||||||
|
|
||||||
const xMinus1 = x - 1; const yMinus1 = y - 1; const
|
|
||||||
zMinus1 = z - 1;
|
|
||||||
|
|
||||||
const u = fade(x); const v = fade(y); const
|
|
||||||
w = fade(z);
|
|
||||||
|
|
||||||
const A = p[X] + Y; const AA = p[A] + Z; const AB = p[A + 1] + Z; const B = p[X + 1] + Y; const BA = p[B] + Z; const
|
|
||||||
BB = p[B + 1] + Z;
|
|
||||||
|
|
||||||
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z),
|
|
||||||
grad(p[BA], xMinus1, y, z)),
|
|
||||||
lerp(u, grad(p[AB], x, yMinus1, z),
|
|
||||||
grad(p[BB], xMinus1, yMinus1, z))),
|
|
||||||
lerp(v, lerp(u, grad(p[AA + 1], x, y, zMinus1),
|
|
||||||
grad(p[BA + 1], xMinus1, y, z - 1)),
|
|
||||||
lerp(u, grad(p[AB + 1], x, yMinus1, zMinus1),
|
|
||||||
grad(p[BB + 1], xMinus1, yMinus1, zMinus1))));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const currentRandom = Math.random;
|
|
||||||
|
|
||||||
// Pseudo-random generator
|
|
||||||
function Marsaglia(i1, i2) {
|
|
||||||
// from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c
|
|
||||||
let z = i1 || 362436069; let
|
|
||||||
w = i2 || 521288629;
|
|
||||||
const nextInt = function () {
|
|
||||||
z = (36969 * (z & 65535) + (z >>> 16)) & 0xFFFFFFFF;
|
|
||||||
w = (18000 * (w & 65535) + (w >>> 16)) & 0xFFFFFFFF;
|
|
||||||
return (((z & 0xFFFF) << 16) | (w & 0xFFFF)) & 0xFFFFFFFF;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.nextDouble = function () {
|
|
||||||
const i = nextInt() / 4294967296;
|
|
||||||
return i < 0 ? 1 + i : i;
|
|
||||||
};
|
|
||||||
this.nextInt = nextInt;
|
|
||||||
}
|
|
||||||
Marsaglia.createRandomized = function () {
|
|
||||||
const now = new Date();
|
|
||||||
return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Noise functions and helpers
|
|
||||||
function PerlinNoise(seed) {
|
|
||||||
const rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized();
|
|
||||||
let i; let
|
|
||||||
j;
|
|
||||||
// http://www.noisemachine.com/talk1/17b.html
|
|
||||||
// http://mrl.nyu.edu/~perlin/noise/
|
|
||||||
// generate permutation
|
|
||||||
const p = new Array(512);
|
|
||||||
for (i = 0; i < 256; ++i) { p[i] = i; }
|
|
||||||
for (i = 0; i < 256; ++i) { const t = p[j = rnd.nextInt() & 0xFF]; p[j] = p[i]; p[i] = t; }
|
|
||||||
// copy to avoid taking mod in p[0];
|
|
||||||
for (i = 0; i < 256; ++i) { p[i + 256] = p[i]; }
|
|
||||||
|
|
||||||
function grad3d(i, x, y, z) {
|
|
||||||
const h = i & 15; // convert into 12 gradient directions
|
|
||||||
const u = h < 8 ? x : y;
|
|
||||||
|
|
||||||
|
|
||||||
const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
|
|
||||||
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
|
||||||
}
|
|
||||||
|
|
||||||
function grad2d(i, x, y) {
|
|
||||||
const v = (i & 1) === 0 ? x : y;
|
|
||||||
return (i & 2) === 0 ? -v : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
function grad1d(i, x) {
|
|
||||||
return (i & 1) === 0 ? -x : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
function lerp(t, a, b) { return a + t * (b - a); }
|
|
||||||
|
|
||||||
this.noise3d = function (x, y, z) {
|
|
||||||
const X = Math.floor(x) & 255; const Y = Math.floor(y) & 255; const
|
|
||||||
Z = Math.floor(z) & 255;
|
|
||||||
x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
|
|
||||||
const fx = (3 - 2 * x) * x * x; const fy = (3 - 2 * y) * y * y; const
|
|
||||||
fz = (3 - 2 * z) * z * z;
|
|
||||||
const p0 = p[X] + Y; const p00 = p[p0] + Z; const p01 = p[p0 + 1] + Z; const p1 = p[X + 1] + Y; const p10 = p[p1] + Z; const
|
|
||||||
p11 = p[p1 + 1] + Z;
|
|
||||||
return lerp(fz,
|
|
||||||
lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x - 1, y, z)),
|
|
||||||
lerp(fx, grad3d(p[p01], x, y - 1, z), grad3d(p[p11], x - 1, y - 1, z))),
|
|
||||||
lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z - 1), grad3d(p[p10 + 1], x - 1, y, z - 1)),
|
|
||||||
lerp(fx, grad3d(p[p01 + 1], x, y - 1, z - 1), grad3d(p[p11 + 1], x - 1, y - 1, z - 1))));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.noise2d = function (x, y) {
|
|
||||||
const X = Math.floor(x) & 255; const
|
|
||||||
Y = Math.floor(y) & 255;
|
|
||||||
x -= Math.floor(x); y -= Math.floor(y);
|
|
||||||
const fx = (3 - 2 * x) * x * x; const
|
|
||||||
fy = (3 - 2 * y) * y * y;
|
|
||||||
const p0 = p[X] + Y; const
|
|
||||||
p1 = p[X + 1] + Y;
|
|
||||||
return lerp(fy,
|
|
||||||
lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x - 1, y)),
|
|
||||||
lerp(fx, grad2d(p[p0 + 1], x, y - 1), grad2d(p[p1 + 1], x - 1, y - 1)));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.noise1d = function (x) {
|
|
||||||
const X = Math.floor(x) & 255;
|
|
||||||
x -= Math.floor(x);
|
|
||||||
const fx = (3 - 2 * x) * x * x;
|
|
||||||
return lerp(fx, grad1d(p[X], x), grad1d(p[X + 1], x - 1));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// these are lifted from Processing.js
|
|
||||||
// processing defaults
|
|
||||||
const noiseProfile = {
|
|
||||||
generator: undefined, octaves: 4, fallout: 0.5, seed: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function noise(x, y, z) {
|
|
||||||
if (noiseProfile.generator === undefined) {
|
|
||||||
// caching
|
|
||||||
noiseProfile.generator = new PerlinNoise(noiseProfile.seed);
|
|
||||||
}
|
|
||||||
const generator = noiseProfile.generator;
|
|
||||||
let effect = 1; let k = 1; let
|
|
||||||
sum = 0;
|
|
||||||
for (let i = 0; i < noiseProfile.octaves; ++i) {
|
|
||||||
effect *= noiseProfile.fallout;
|
|
||||||
switch (arguments.length) {
|
|
||||||
case 1:
|
|
||||||
sum += effect * (1 + generator.noise1d(k * x)) / 2; break;
|
|
||||||
case 2:
|
|
||||||
sum += effect * (1 + generator.noise2d(k * x, k * y)) / 2; break;
|
|
||||||
case 3:
|
|
||||||
sum += effect * (1 + generator.noise3d(k * x, k * y, k * z)) / 2; break;
|
|
||||||
}
|
|
||||||
k *= 2;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
};
|
|
||||||
@ -1,220 +0,0 @@
|
|||||||
const noise = require('./fizzy-noise');
|
|
||||||
|
|
||||||
function fizzyText(message) {
|
|
||||||
const that = this;
|
|
||||||
|
|
||||||
// These are the variables that we manipulate with gui-dat.
|
|
||||||
// Notice they're all defined with "this". That makes them public.
|
|
||||||
// Otherwise, gui-dat can't see them.
|
|
||||||
|
|
||||||
this.growthSpeed = 0.8; // how fast do particles change size?
|
|
||||||
this.minSize = 1;
|
|
||||||
this.maxSize = 4; // how big can they get?
|
|
||||||
this.noiseStrength = 10; // how turbulent is the flow?
|
|
||||||
this.speed = 0.4; // how fast do particles move?
|
|
||||||
this.displayOutline = false; // should we draw the message as a stroke?
|
|
||||||
this.framesRendered = 0;
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const _this = this;
|
|
||||||
|
|
||||||
const width = 550;
|
|
||||||
const height = 200;
|
|
||||||
const textAscent = 101;
|
|
||||||
const textOffsetLeft = 80;
|
|
||||||
const noiseScale = 300;
|
|
||||||
const frameTime = 30;
|
|
||||||
|
|
||||||
const colors = ['#000000', '#1A1A1A', '#163C50', '#205A79', '#2A78A2'];
|
|
||||||
|
|
||||||
// This is the context we use to get a bitmap of text using
|
|
||||||
// the getImageData function.
|
|
||||||
const r = document.createElement('canvas');
|
|
||||||
const s = r.getContext('2d');
|
|
||||||
|
|
||||||
// This is the context we actually use to draw.
|
|
||||||
const c = document.createElement('canvas');
|
|
||||||
const g = c.getContext('2d');
|
|
||||||
|
|
||||||
r.setAttribute('width', width);
|
|
||||||
c.setAttribute('width', width);
|
|
||||||
r.setAttribute('height', height);
|
|
||||||
c.setAttribute('height', height);
|
|
||||||
|
|
||||||
// Add our demo to the HTML
|
|
||||||
document.getElementById('fizzytext').appendChild(c);
|
|
||||||
|
|
||||||
// Stores bitmap image
|
|
||||||
let pixels = [];
|
|
||||||
|
|
||||||
// Stores a list of particles
|
|
||||||
const particles = [];
|
|
||||||
|
|
||||||
// Set g.font to the same font as the bitmap canvas, incase we
|
|
||||||
// want to draw some outlines.
|
|
||||||
s.font = g.font = '800 82px monospace, monospace';
|
|
||||||
|
|
||||||
// Instantiate some particles
|
|
||||||
for (let i = 0; i < 1000; i++) {
|
|
||||||
particles.push(new Particle(Math.random() * width, Math.random() * height));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function creates a bitmap of pixels based on your message
|
|
||||||
// It's called every time we change the message property.
|
|
||||||
const createBitmap = function (msg) {
|
|
||||||
s.fillStyle = '#fff';
|
|
||||||
s.fillRect(0, 0, width, height);
|
|
||||||
|
|
||||||
s.fillStyle = '#222';
|
|
||||||
s.fillText(msg, textOffsetLeft, textAscent);
|
|
||||||
|
|
||||||
// Pull reference
|
|
||||||
const imageData = s.getImageData(0, 0, width, height);
|
|
||||||
pixels = imageData.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called once per frame, updates the animation.
|
|
||||||
const render = function () {
|
|
||||||
that.framesRendered++;
|
|
||||||
|
|
||||||
g.clearRect(0, 0, width, height);
|
|
||||||
|
|
||||||
if (_this.displayOutline) {
|
|
||||||
g.globalCompositeOperation = 'source-over';
|
|
||||||
g.strokeStyle = '#000';
|
|
||||||
g.lineWidth = 0.5;
|
|
||||||
g.strokeText(message, textOffsetLeft, textAscent);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.globalCompositeOperation = 'darker';
|
|
||||||
|
|
||||||
for (let i = 0; i < particles.length; i++) {
|
|
||||||
g.fillStyle = colors[i % colors.length];
|
|
||||||
particles[i].render();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns x, y coordinates for a given index in the pixel array.
|
|
||||||
const getPosition = function (i) {
|
|
||||||
return {
|
|
||||||
x: (i - (width * 4) * Math.floor(i / (width * 4))) / 4,
|
|
||||||
y: Math.floor(i / (width * 4)),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns a color for a given pixel in the pixel array.
|
|
||||||
const getColor = function (x, y) {
|
|
||||||
const base = (Math.floor(y) * width + Math.floor(x)) * 4;
|
|
||||||
const c = {
|
|
||||||
r: pixels[base + 0],
|
|
||||||
g: pixels[base + 1],
|
|
||||||
b: pixels[base + 2],
|
|
||||||
a: pixels[base + 3],
|
|
||||||
};
|
|
||||||
|
|
||||||
return `rgb(${c.r},${c.g},${c.b})`;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.message = message;
|
|
||||||
createBitmap(message);
|
|
||||||
|
|
||||||
var loop = function () {
|
|
||||||
requestAnimationFrame(loop);
|
|
||||||
render();
|
|
||||||
};
|
|
||||||
|
|
||||||
// This calls the render function every 30 milliseconds.
|
|
||||||
loop();
|
|
||||||
|
|
||||||
// This class is responsible for drawing and moving those little
|
|
||||||
// colored dots.
|
|
||||||
function Particle(x, y, c) {
|
|
||||||
// Position
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
|
|
||||||
// Size of particle
|
|
||||||
this.r = 1;
|
|
||||||
|
|
||||||
// This velocity is used by the explode function.
|
|
||||||
this.vx = 0;
|
|
||||||
this.vy = 0;
|
|
||||||
|
|
||||||
this.constrain = function constrainFn(v, o1, o2) {
|
|
||||||
if (v < o1) v = o1;
|
|
||||||
else if (v > o2) v = o2;
|
|
||||||
return v;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called every frame
|
|
||||||
this.render = function renderFrame() {
|
|
||||||
// What color is the pixel we're sitting on top of?
|
|
||||||
const c = getColor(this.x, this.y);
|
|
||||||
|
|
||||||
// Where should we move?
|
|
||||||
const angle = noise(this.x / noiseScale, this.y / noiseScale) * _this.noiseStrength;
|
|
||||||
// var angle = -Math.PI/2;
|
|
||||||
|
|
||||||
// Are we within the boundaries of the image?
|
|
||||||
const onScreen = this.x > 0 && this.x < width && this.y > 0 && this.y < height;
|
|
||||||
|
|
||||||
const isBlack = c !== 'rgb(255,255,255)' && onScreen;
|
|
||||||
|
|
||||||
// If we're on top of a black pixel, grow.
|
|
||||||
// If not, shrink.
|
|
||||||
if (isBlack) {
|
|
||||||
this.r += _this.growthSpeed;
|
|
||||||
} else {
|
|
||||||
this.r -= _this.growthSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This velocity is used by the explode function.
|
|
||||||
this.vx *= 0.5;
|
|
||||||
this.vy *= 0.5;
|
|
||||||
|
|
||||||
// Change our position based on the flow field and our
|
|
||||||
// explode velocity.
|
|
||||||
this.x += Math.cos(angle) * _this.speed + this.vx;
|
|
||||||
this.y += -Math.sin(angle) * _this.speed + this.vy;
|
|
||||||
|
|
||||||
if (this.r > _this.maxSize) {
|
|
||||||
this.r = _this.maxSize;
|
|
||||||
} else if (this.r < 0) {
|
|
||||||
this.r = 0;
|
|
||||||
this.x = Math.random() * width;
|
|
||||||
this.y = Math.random() * height;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this.r = 3;
|
|
||||||
// debugger
|
|
||||||
// console.log(DAT.GUI.constrain(this.r, 0, _this.maxSize));
|
|
||||||
// this.r = this.constrain(this.r, _this.minSize, _this.maxSize);
|
|
||||||
|
|
||||||
// If we're tiny, keep moving around until we find a black
|
|
||||||
// pixel.
|
|
||||||
if (this.r <= 0) {
|
|
||||||
this.x = Math.random() * width;
|
|
||||||
this.y = Math.random() * height;
|
|
||||||
return false; // Don't draw!
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're off the screen, go over to other side
|
|
||||||
if (this.x < 0) this.x = width;
|
|
||||||
if (this.x > width) this.x = 0;
|
|
||||||
if (this.y < 0) this.y = height;
|
|
||||||
if (this.y > height) this.y = 0;
|
|
||||||
|
|
||||||
// Draw the circle.
|
|
||||||
g.beginPath();
|
|
||||||
// g.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
|
|
||||||
g.rect(this.x, this.y, this.r, this.r);
|
|
||||||
g.fill();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = fizzyText;
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "constructs-client",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "parcel index.html --port 40080 --no-hmr --no-source-maps",
|
|
||||||
"build": "rm -rf dist && parcel build --no-source-maps index.html",
|
|
||||||
"lint": "eslint --fix src/",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "UNLICENSED",
|
|
||||||
"dependencies": {
|
|
||||||
"async": "^2.6.1",
|
|
||||||
"borc": "^2.0.3",
|
|
||||||
"docco": "^0.7.0",
|
|
||||||
"izitoast": "^1.4.0",
|
|
||||||
"jdenticon": "^2.1.0",
|
|
||||||
"key": "^0.1.11",
|
|
||||||
"keymaster": "^1.6.2",
|
|
||||||
"lodash": "^4.17.11",
|
|
||||||
"parcel": "^1.11.0",
|
|
||||||
"phaser": "^3.16.1",
|
|
||||||
"redux": "^4.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "^5.6.0",
|
|
||||||
"eslint-config-airbnb-base": "^13.1.0",
|
|
||||||
"eslint-plugin-import": "^2.14.0",
|
|
||||||
"jest": "^18.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,219 +0,0 @@
|
|||||||
const toast = require('izitoast');
|
|
||||||
|
|
||||||
function registerEvents(registry, events, tutorial) {
|
|
||||||
function setConstructs(constructs) {
|
|
||||||
registry.set('constructs', constructs);
|
|
||||||
tutorial('homepage');
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConstructList(constructs) {
|
|
||||||
registry.set('constructList', constructs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setWs(ws) {
|
|
||||||
registry.set('ws', ws);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setGame(game) {
|
|
||||||
if (game.phase === 'Skill') tutorial('skillPhase');
|
|
||||||
if (game.phase === 'Target') tutorial('targetPhase');
|
|
||||||
if (game.resolved.length) tutorial('resolutionPhase');
|
|
||||||
if (game.phase === 'Finish') tutorial('finishPhase');
|
|
||||||
return registry.set('game', game);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAccount(account) {
|
|
||||||
registry.set('account', account);
|
|
||||||
registry.set('home', true);
|
|
||||||
events.emit('ACCOUNT', account);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveSkill(skill) {
|
|
||||||
registry.set('activeSkill', skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMenu() {
|
|
||||||
registry.set('menu', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setVbox(items) {
|
|
||||||
registry.set('vbox', items);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setScores(scores) {
|
|
||||||
registry.set('scores', scores);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPlayerList(list) {
|
|
||||||
registry.set('playerList', list);
|
|
||||||
registry.set('homeInstances', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPlayer(player) {
|
|
||||||
registry.set('player', player);
|
|
||||||
if (!registry.get('inMenu')) {
|
|
||||||
setMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setZone(zone) {
|
|
||||||
registry.set('zone', zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setGameList(gameList) {
|
|
||||||
registry.set('gameList', gameList);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConstructStatusUpdate(id, skill, target) {
|
|
||||||
registry.set('constructStatusUpdate', { id, skill, target });
|
|
||||||
}
|
|
||||||
|
|
||||||
events.on('SET_PLAYER', setPlayer);
|
|
||||||
|
|
||||||
events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) {
|
|
||||||
const ws = registry.get('ws');
|
|
||||||
ws.sendGameSkill(gameId, constructId, targetConstructId, skill);
|
|
||||||
setConstructStatusUpdate(constructId, skill, targetConstructId);
|
|
||||||
});
|
|
||||||
|
|
||||||
events.on('CONSTRUCT_ACTIVE', function constructActiveCb(construct) {
|
|
||||||
const constructs = registry.get('constructs');
|
|
||||||
for (let i = 0; i < constructs.length; i += 1) {
|
|
||||||
if (constructs[i].id === construct.id) constructs[i].active = !constructs[i].active;
|
|
||||||
}
|
|
||||||
return setConstructs(constructs);
|
|
||||||
});
|
|
||||||
|
|
||||||
const errMessages = {
|
|
||||||
select_constructs: 'Select your constructs before battle using the numbered buttons next to the construct avatar',
|
|
||||||
complete_nodes: 'You need to complete the previously connected nodes first',
|
|
||||||
max_skills: 'Your construct can only learn a maximum of 4 skills',
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
function errorPrompt(type) {
|
|
||||||
const message = errMessages[type];
|
|
||||||
const OK_BUTTON = '<button type="submit">OK</button>';
|
|
||||||
toast.info({
|
|
||||||
theme: 'dark',
|
|
||||||
color: 'black',
|
|
||||||
timeout: false,
|
|
||||||
drag: false,
|
|
||||||
position: 'center',
|
|
||||||
maxWidth: window.innerWidth / 2,
|
|
||||||
close: false,
|
|
||||||
buttons: [
|
|
||||||
[OK_BUTTON, (instance, thisToast) => instance.hide({ transitionOut: 'fadeOut' }, thisToast)],
|
|
||||||
],
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loginPrompt() {
|
|
||||||
const USER_INPUT = '<input className="input" type="email" placeholder="username" />';
|
|
||||||
const PASSWORD_INPUT = '<input className="input" type="password" placeholder="password" />';
|
|
||||||
const LOGIN_BUTTON = '<button type="submit">Login</button>';
|
|
||||||
const REGISTER_BUTTON = '<button type="submit">Register</button>';
|
|
||||||
const DEMO_BUTTON = '<button type="submit">Demo</button>';
|
|
||||||
|
|
||||||
const ws = registry.get('ws');
|
|
||||||
|
|
||||||
function submitLogin(instance, thisToast, button, e, inputs) {
|
|
||||||
const USERNAME = inputs[0].value;
|
|
||||||
const PASSWORD = inputs[1].value;
|
|
||||||
ws.sendAccountLogin(USERNAME, PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitRegister(instance, thisToast, button, e, inputs) {
|
|
||||||
const USERNAME = inputs[0].value;
|
|
||||||
const PASSWORD = inputs[1].value;
|
|
||||||
ws.sendAccountCreate(USERNAME, PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitDemo() {
|
|
||||||
ws.sendAccountDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
const existing = document.querySelector('#login'); // Selector of your toast
|
|
||||||
if (existing) toast.hide({}, existing, 'reconnect');
|
|
||||||
|
|
||||||
toast.question({
|
|
||||||
id: 'login',
|
|
||||||
theme: 'dark',
|
|
||||||
color: 'black',
|
|
||||||
timeout: false,
|
|
||||||
// overlay: true,
|
|
||||||
drag: false,
|
|
||||||
close: false,
|
|
||||||
title: 'LOGIN',
|
|
||||||
position: 'center',
|
|
||||||
inputs: [
|
|
||||||
[USER_INPUT, 'change', () => true, true], // true to focus
|
|
||||||
[PASSWORD_INPUT, 'change', () => true],
|
|
||||||
],
|
|
||||||
buttons: [
|
|
||||||
[LOGIN_BUTTON, submitLogin], // true to focus
|
|
||||||
[REGISTER_BUTTON, submitRegister], // true to focus
|
|
||||||
[DEMO_BUTTON, submitDemo], // true to focus
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
events.once('ACCOUNT', function closeLoginCb() {
|
|
||||||
const prompt = document.querySelector('#login'); // Selector of your toast
|
|
||||||
if (prompt) toast.hide({ transitionOut: 'fadeOut' }, prompt, 'event');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
events.on('CONSTRUCT_SPAWN', function spawnPrompt() {
|
|
||||||
const NAME_INPUT = '<input className="input" type="email" placeholder="name" />';
|
|
||||||
const SPAWN_BUTTON = '<button type="submit">SPAWN</button>';
|
|
||||||
|
|
||||||
const ws = registry.get('ws');
|
|
||||||
|
|
||||||
function submitSpawn(instance, thisToast, button, e, inputs) {
|
|
||||||
const NAME = inputs[0].value;
|
|
||||||
ws.sendConstructSpawn(NAME);
|
|
||||||
instance.hide({ transitionOut: 'fadeOut' }, thisToast, 'button');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.question({
|
|
||||||
theme: 'dark',
|
|
||||||
color: 'black',
|
|
||||||
timeout: false,
|
|
||||||
// overlay: true,
|
|
||||||
drag: false,
|
|
||||||
close: true,
|
|
||||||
title: 'SPAWN CONSTRUCT',
|
|
||||||
position: 'center',
|
|
||||||
inputs: [
|
|
||||||
[NAME_INPUT, 'change', null, true], // true to focus
|
|
||||||
],
|
|
||||||
buttons: [
|
|
||||||
[SPAWN_BUTTON, submitSpawn], // true to focus
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tutorial('welcome');
|
|
||||||
|
|
||||||
return {
|
|
||||||
errorPrompt,
|
|
||||||
loginPrompt,
|
|
||||||
setAccount,
|
|
||||||
setActiveSkill,
|
|
||||||
setConstructs,
|
|
||||||
setConstructList,
|
|
||||||
setGame,
|
|
||||||
setMenu,
|
|
||||||
setPlayer,
|
|
||||||
setPlayerList,
|
|
||||||
setVbox,
|
|
||||||
setWs,
|
|
||||||
setGameList,
|
|
||||||
setZone,
|
|
||||||
setScores,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = registerEvents;
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
const renderConstructs = require('./scenes/constructs');
|
|
||||||
|
|
||||||
const createSocket = require('./socket');
|
|
||||||
const registerEvents = require('./events');
|
|
||||||
const createTutorial = require('./tutorial');
|
|
||||||
|
|
||||||
document.fonts.load('10pt "Jura"').then(() => {
|
|
||||||
const game = renderConstructs();
|
|
||||||
const tutorial = createTutorial();
|
|
||||||
const events = registerEvents(game.registry, game.events, tutorial);
|
|
||||||
const ws = createSocket(events);
|
|
||||||
|
|
||||||
// events.setWs(ws);
|
|
||||||
// events.setGameList([]);
|
|
||||||
|
|
||||||
ws.connect();
|
|
||||||
});
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
const genAvatar = (name) => {
|
|
||||||
let hash = 0;
|
|
||||||
if (name.length === 0) return hash;
|
|
||||||
// Probs don't need to hash using the whole string
|
|
||||||
for (let i = 0; i < name.length; i += 1) {
|
|
||||||
const chr = name.charCodeAt(i);
|
|
||||||
hash = ((hash << 5) - hash) + chr;
|
|
||||||
hash = hash & 10000; // We have avatars named 0-19
|
|
||||||
}
|
|
||||||
return `sprite${hash}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = genAvatar;
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const CHART = `
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision mediump float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#extension GL_OES_standard_derivatives : enable
|
|
||||||
|
|
||||||
uniform float time;
|
|
||||||
uniform vec2 mouse;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
|
|
||||||
float rand(float n){return fract(sin(n) * 43758.5453123 * time * 0.00001);}
|
|
||||||
|
|
||||||
float noise(float p){
|
|
||||||
float fl = floor(p);
|
|
||||||
float fc = fract(p);
|
|
||||||
// return mix(rand(fl), rand(fl + 1.0), p);
|
|
||||||
return mix(rand(fl), rand(fl + 1.0), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getLine(vec2 p, float y){
|
|
||||||
float margin = 0.;
|
|
||||||
|
|
||||||
vec2 pos = p;
|
|
||||||
float a = time * 100. + y * 31.;
|
|
||||||
vec2 lineCenter = vec2(0.5, y);
|
|
||||||
|
|
||||||
pos -= lineCenter;
|
|
||||||
pos *- mat2(cos(a), -sin(a), sin(a), cos(a));
|
|
||||||
pos += lineCenter;
|
|
||||||
|
|
||||||
|
|
||||||
float marginb = 0.005;
|
|
||||||
float b = 0.004;
|
|
||||||
float t = y + (noise((pos.x + y) * 100.) - 0.5) * 0.02;
|
|
||||||
float f = (smoothstep(t - b, t, pos.y) - smoothstep(t, t + b, pos.y));
|
|
||||||
f *= smoothstep(margin - marginb, margin, pos.x) - smoothstep(1. - margin, 1. - margin + marginb, pos.x);
|
|
||||||
f *= 0.8;
|
|
||||||
|
|
||||||
float light = 0.5 + 0.5 * sin(time * .2);
|
|
||||||
vec2 point = vec2(margin + light * (1. - margin * 2.), t);
|
|
||||||
f += .008 / distance(pos, point);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main( void ) {
|
|
||||||
vec2 p = gl_FragCoord.xy / resolution.xy;
|
|
||||||
float f = 0.;
|
|
||||||
|
|
||||||
for(int i = 0; i < 10; i++){
|
|
||||||
f += getLine(p, 0.1 + (0.8) / 10. * float(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 color = vec3(0., .4, .6) * f;
|
|
||||||
gl_FragColor = vec4(color, 1.);
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const STARS = `
|
|
||||||
//--- hatsuyuki ---
|
|
||||||
// by Catzpaw 2016
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision mediump float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#extension GL_OES_standard_derivatives : enable
|
|
||||||
|
|
||||||
uniform float time;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
float hash(float x){
|
|
||||||
return fract(sin(x*133.3)*12.13);
|
|
||||||
}
|
|
||||||
void main(void){
|
|
||||||
vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);
|
|
||||||
vec3 c=vec3(.2,.2,.2);
|
|
||||||
float a=4.4;
|
|
||||||
float si=sin(a),co=cos(a);
|
|
||||||
uv*=mat2(co,-si,si,co);
|
|
||||||
uv*=length(uv+vec2(0,1.9))*.5+1.;
|
|
||||||
float v=1.-sin(hash(floor(uv.x*200.))*2.);
|
|
||||||
float b=clamp(abs(sin(5.*time*v+uv.y*(5./(2.+v))))-.95,0.,1.)*20.;
|
|
||||||
c*=v*b;
|
|
||||||
gl_FragColor = vec4(c,2);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const PLASMA = `
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
uniform sampler2D uMainSampler;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
uniform float time;
|
|
||||||
|
|
||||||
varying vec2 outTexCoord;
|
|
||||||
varying vec4 outTint;
|
|
||||||
|
|
||||||
#define MAX_ITER 4
|
|
||||||
|
|
||||||
void main( void )
|
|
||||||
{
|
|
||||||
vec2 v_texCoord = gl_FragCoord.xy / resolution;
|
|
||||||
|
|
||||||
vec2 p = v_texCoord * 8.0 - vec2(20.0);
|
|
||||||
vec2 i = p;
|
|
||||||
float c = 1.0;
|
|
||||||
float inten = .05;
|
|
||||||
|
|
||||||
for (int n = 0; n < MAX_ITER; n++)
|
|
||||||
{
|
|
||||||
float t = time * (1.0 - (3.0 / float(n+1)));
|
|
||||||
|
|
||||||
i = p + vec2(cos(t - i.x) + sin(t + i.y),
|
|
||||||
sin(t - i.y) + cos(t + i.x));
|
|
||||||
|
|
||||||
c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),
|
|
||||||
p.y / (cos(i.y+t)/inten)));
|
|
||||||
}
|
|
||||||
|
|
||||||
c /= float(MAX_ITER);
|
|
||||||
c = 1.5 - sqrt(c);
|
|
||||||
|
|
||||||
vec4 texColor = vec4(0.01, 0.01, 0.01, 1.0);
|
|
||||||
|
|
||||||
texColor.rgb *= (1.0 / (1.0 - (c + 0.05)));
|
|
||||||
|
|
||||||
gl_FragColor = texColor;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const CustomPipeline = new Phaser.Class({
|
|
||||||
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
|
|
||||||
initialize: function CustomPipeline (game) {
|
|
||||||
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
|
|
||||||
game,
|
|
||||||
renderer: game.renderer,
|
|
||||||
fragShader: STARS,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
class Background extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Background', active: true });
|
|
||||||
this.bgTime = 10.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
const game = this.game;
|
|
||||||
this.customPipeline = game.renderer.addPipeline('Custom', new CustomPipeline(game));
|
|
||||||
this.customPipeline.setFloat2('resolution', 1600, 1000);
|
|
||||||
|
|
||||||
const sprite = this.add.sprite(800, 500);
|
|
||||||
sprite.setPipeline('Custom');
|
|
||||||
sprite.displayWidth = 1600 * window.devicePixelRatio;
|
|
||||||
sprite.displayHeight = 1000 * window.devicePixelRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.customPipeline.setFloat1('time', this.bgTime);
|
|
||||||
this.bgTime += 0.005;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Background;
|
|
||||||
@ -1,250 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { COMBAT }, DELAYS } = require('./constants');
|
|
||||||
|
|
||||||
const randomColour = () => {
|
|
||||||
const colours = ['green', 'blue', 'red', 'white', 'yellow'];
|
|
||||||
return colours[Math.floor(Math.random() * 5)];
|
|
||||||
};
|
|
||||||
|
|
||||||
const animationParams = (sourceAlly) => {
|
|
||||||
const spawnLocation = sourceAlly ? COMBAT.width() * 0.35 : COMBAT.width() * 0.65;
|
|
||||||
const speed = sourceAlly ? 250 : -250;
|
|
||||||
const img = randomColour();
|
|
||||||
const angleMin = sourceAlly ? 320 : 180;
|
|
||||||
const angleMax = sourceAlly ? 360 : 220;
|
|
||||||
return { spawnLocation, speed, img, angleMin, angleMax };
|
|
||||||
};
|
|
||||||
|
|
||||||
const randomAttack = () => {
|
|
||||||
const animations = ['wall', 'spit', 'gravBlast', 'gravBomb', 'chargeBall'];
|
|
||||||
return animations[Math.floor(Math.random() * 5)];
|
|
||||||
};
|
|
||||||
|
|
||||||
class CombatSkills extends Phaser.GameObjects.Group {
|
|
||||||
constructor(scene) {
|
|
||||||
super(scene);
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSkill(type, sourceAlly, targetAlly, castLocation) {
|
|
||||||
const genericHeal = ['Heal', 'Triage', 'TriageTick', 'DecayTick'];
|
|
||||||
const genericBlock = ['Block', 'Parry', 'Evasion', 'Shield'];
|
|
||||||
|
|
||||||
if (genericHeal.includes(type)) {
|
|
||||||
this.genericHeal(targetAlly, castLocation);
|
|
||||||
} else if (genericBlock.includes(type)) {
|
|
||||||
this.genericBlock(sourceAlly);
|
|
||||||
} else {
|
|
||||||
this[randomAttack()](sourceAlly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genericHeal(sourceAlly, castLocation) {
|
|
||||||
// const { sourceX, sourceY } = getConstructPosition(sourcePos, 0);
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const colour = randomColour();
|
|
||||||
const particles = this.scene.add.particles(colour);
|
|
||||||
const x = sourceAlly ? COMBAT.width() * 0.3 : COMBAT.width() * 0.7;
|
|
||||||
|
|
||||||
const emitter2 = particles.createEmitter({
|
|
||||||
x: castLocation.x,
|
|
||||||
y: castLocation.y,
|
|
||||||
moveToX: x,
|
|
||||||
moveToY: COMBAT.height() * 0.2,
|
|
||||||
speed: 500,
|
|
||||||
lifespan: lifespan / 3,
|
|
||||||
scale: { start: 0.5, end: 1 },
|
|
||||||
quantity: 3,
|
|
||||||
_frequency: 20,
|
|
||||||
blendMode: 'ADD',
|
|
||||||
emitZone: { source: new Phaser.Geom.Rectangle(-200, -100, 400, 200) },
|
|
||||||
});
|
|
||||||
|
|
||||||
const emitter = particles.createEmitter({
|
|
||||||
x,
|
|
||||||
y: COMBAT.height() * 0.2,
|
|
||||||
angle: { min: 250, max: 290 },
|
|
||||||
speed: 250,
|
|
||||||
gravityY: 1000,
|
|
||||||
quantity: 4,
|
|
||||||
scale: { start: 0.1, end: 1 },
|
|
||||||
blendMode: 'ADD',
|
|
||||||
lifespan,
|
|
||||||
active: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(lifespan / 3, () => { emitter2.stop(); }, [], this);
|
|
||||||
this.scene.time.delayedCall(lifespan / 3, () => { emitter.active = true; }, [], this);
|
|
||||||
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { emitter.stop(); }, [], this);
|
|
||||||
}
|
|
||||||
|
|
||||||
genericBlock(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const colour = randomColour();
|
|
||||||
const x = sourceAlly ? COMBAT.width() * 0.3 : COMBAT.width() * 0.7;
|
|
||||||
const emitter1 = this.scene.add.particles(colour).createEmitter({
|
|
||||||
x,
|
|
||||||
y: COMBAT.height() * 0.4,
|
|
||||||
scale: { start: 0.75, end: 0.25 },
|
|
||||||
blendMode: 'ADD',
|
|
||||||
emitZone: {
|
|
||||||
source: new Phaser.Geom.Rectangle(-100, -100, 200, 200),
|
|
||||||
type: 'edge',
|
|
||||||
quantity: 24,
|
|
||||||
yoyo: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emitter2 = this.scene.add.particles(colour).createEmitter({
|
|
||||||
x,
|
|
||||||
y: COMBAT.height() * 0.4,
|
|
||||||
blendMode: 'SCREEN',
|
|
||||||
scale: { start: 0.2, end: 0 },
|
|
||||||
speed: { min: -100, max: 100 },
|
|
||||||
quantity: 50,
|
|
||||||
active: false,
|
|
||||||
emitZone: {
|
|
||||||
source: new Phaser.Geom.Rectangle(-100, -100, 200, 200),
|
|
||||||
type: 'edge',
|
|
||||||
quantity: 50,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.scene.time.delayedCall(lifespan / 2, () => { emitter1.stop(); }, [], this);
|
|
||||||
this.scene.time.delayedCall(lifespan / 2, () => { emitter2.active = true; }, [], this);
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { emitter2.stop(); }, [], this);
|
|
||||||
}
|
|
||||||
|
|
||||||
wall(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const { spawnLocation, speed, img } = animationParams(sourceAlly);
|
|
||||||
const particles = this.scene.add.particles(img);
|
|
||||||
const emitter = particles.createEmitter({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: { min: COMBAT.height() * 0.2, max: COMBAT.height() * 0.5 },
|
|
||||||
speedX: { min: speed, max: speed * 2 },
|
|
||||||
scale: { start: 0.4, end: 0 },
|
|
||||||
quantity: 4,
|
|
||||||
blendMode: 'ADD',
|
|
||||||
lifespan,
|
|
||||||
});
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(1000, () => { emitter.stop(); }, [], this.scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
spit(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const { spawnLocation, speed, img, angleMin, angleMax } = animationParams(sourceAlly);
|
|
||||||
const particles = this.scene.add.particles(img);
|
|
||||||
const emitter = particles.createEmitter({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: COMBAT.height() * 0.35,
|
|
||||||
angle: { min: angleMin, max: angleMax },
|
|
||||||
speed: speed * 2,
|
|
||||||
scale: { start: 0.4, end: 1 },
|
|
||||||
gravityY: 250,
|
|
||||||
quantity: 4,
|
|
||||||
blendMode: 'ADD',
|
|
||||||
lifespan,
|
|
||||||
});
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { emitter.stop(); }, [], this);
|
|
||||||
}
|
|
||||||
|
|
||||||
gravBomb(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
|
|
||||||
const { spawnLocation, img } = animationParams(!sourceAlly);
|
|
||||||
const particles = this.scene.add.particles(img);
|
|
||||||
const well = particles.createGravityWell({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: COMBAT.height() * 0.25,
|
|
||||||
power: 4,
|
|
||||||
gravity: 500,
|
|
||||||
});
|
|
||||||
this.emitter = particles.createEmitter({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: COMBAT.height() * 0.25,
|
|
||||||
speed: 1000,
|
|
||||||
scale: { start: 0.7, end: 1 },
|
|
||||||
blendMode: 'ADD',
|
|
||||||
lifespan,
|
|
||||||
});
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { this.emitter.stop(); well.active = false; }, [], this.scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
gravBlast(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const WELL_END = lifespan / 2;
|
|
||||||
|
|
||||||
const img = randomColour();
|
|
||||||
const spawnLocation = sourceAlly ? COMBAT.width() * 0.35 : COMBAT.width() * 0.65;
|
|
||||||
const isEnemyLocation = sourceAlly ? COMBAT.width() * 0.7 : COMBAT.width() * 0.3;
|
|
||||||
const particles = this.scene.add.particles(img);
|
|
||||||
const bounds = sourceAlly
|
|
||||||
? { x: COMBAT.width() * 0.3, y: COMBAT.height() * 0.2, w: COMBAT.width() * 0.5, h: COMBAT.height() * 0.2 }
|
|
||||||
: { x: 0.2 * COMBAT.width(), y: COMBAT.height() * 0.2, w: COMBAT.width() * 0.5, h: COMBAT.height() * 0.2 };
|
|
||||||
const well = particles.createGravityWell({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: COMBAT.height() * 0.35,
|
|
||||||
power: 4,
|
|
||||||
gravity: 500,
|
|
||||||
});
|
|
||||||
const emitter = particles.createEmitter({
|
|
||||||
x: spawnLocation,
|
|
||||||
y: COMBAT.height() * 0.35,
|
|
||||||
speed: 1000,
|
|
||||||
scale: { start: 0.7, end: 1 },
|
|
||||||
blendMode: 'ADD',
|
|
||||||
bounds,
|
|
||||||
lifespan,
|
|
||||||
});
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(WELL_END, () => { emitter.stop(); well.x = isEnemyLocation; }, [], this.scene);
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { well.active = false; }, [], this.scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
chargeBall(sourceAlly) {
|
|
||||||
const lifespan = DELAYS.ANIMATION_DURATION;
|
|
||||||
const CHARGE_LIFESPAN = lifespan / 3;
|
|
||||||
|
|
||||||
const { img, spawnLocation } = animationParams(sourceAlly);
|
|
||||||
const targetLocation = sourceAlly ? 0.7 * COMBAT.width() : 0.25 * COMBAT.width();
|
|
||||||
const particles = this.scene.add.particles(img);
|
|
||||||
const emitter = particles.createEmitter({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
moveToX: spawnLocation,
|
|
||||||
moveToY: COMBAT.height() * 0.1,
|
|
||||||
scale: 0.75,
|
|
||||||
quantity: 4,
|
|
||||||
_frequency: 20,
|
|
||||||
blendMode: 'ADD',
|
|
||||||
emitZone: { source: new Phaser.Geom.Rectangle(0, 0, COMBAT.width(), COMBAT.height()) },
|
|
||||||
lifespan: CHARGE_LIFESPAN,
|
|
||||||
});
|
|
||||||
const emitter2 = particles.createEmitter({
|
|
||||||
radial: false,
|
|
||||||
x: { min: spawnLocation, max: targetLocation, steps: 90 },
|
|
||||||
y: { min: COMBAT.height() * 0.1, max: COMBAT.height() * 0.4, steps: 90 },
|
|
||||||
quantity: 4,
|
|
||||||
gravityY: 0,
|
|
||||||
scale: { start: 2, end: 0.1, ease: 'Power3' },
|
|
||||||
blendMode: 'ADD',
|
|
||||||
active: false,
|
|
||||||
lifespan: CHARGE_LIFESPAN,
|
|
||||||
});
|
|
||||||
this.add(particles);
|
|
||||||
this.scene.time.delayedCall(CHARGE_LIFESPAN, () => { emitter.stop(); }, [], this.scene);
|
|
||||||
this.scene.time.delayedCall(CHARGE_LIFESPAN * 2, () => { emitter2.active = true; }, [], this.scene);
|
|
||||||
this.scene.time.delayedCall(lifespan, () => { emitter2.stop(); }, [], this.scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
this.children.entries.forEach(obj => obj.destroy());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CombatSkills;
|
|
||||||
@ -1,239 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const genAvatar = require('./avatar');
|
|
||||||
const StatBar = require('./elements/combat.statbar');
|
|
||||||
|
|
||||||
const { DELAYS, TEXT, POSITIONS: { COMBAT } } = require('./constants');
|
|
||||||
|
|
||||||
const CONSTRUCT_MARGIN = COMBAT.constructMargin();
|
|
||||||
const TEXT_MARGIN = COMBAT.textMargin();
|
|
||||||
|
|
||||||
const constructAvatarText = (team, iter) => {
|
|
||||||
const nameX = COMBAT.width() * team;
|
|
||||||
const nameY = COMBAT.y() + CONSTRUCT_MARGIN * iter + COMBAT.height() * 0.07;
|
|
||||||
const statusX = COMBAT.width() * team;
|
|
||||||
const statusY = COMBAT.y() + TEXT_MARGIN * 6 + CONSTRUCT_MARGIN * iter + COMBAT.height() * 0.07;
|
|
||||||
return { statusX, statusY, nameX, nameY };
|
|
||||||
};
|
|
||||||
|
|
||||||
const constructEffects = (team, iter) => {
|
|
||||||
const constructEffectsX = team ? COMBAT.width() - COMBAT.width() / 6.5 : COMBAT.width() / 6.5;
|
|
||||||
const constructEffectsY = TEXT_MARGIN * 2 + CONSTRUCT_MARGIN * iter;
|
|
||||||
return { constructEffectsX, constructEffectsY };
|
|
||||||
};
|
|
||||||
|
|
||||||
const constructPosition = (team, iter) => {
|
|
||||||
const constructAvatarX = team ? COMBAT.width() - COMBAT.width() / 6 : COMBAT.width() / 6;
|
|
||||||
const constructAvatarY = TEXT_MARGIN * 5 + CONSTRUCT_MARGIN * iter;
|
|
||||||
return { constructAvatarX, constructAvatarY };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Effects extends Phaser.GameObjects.Group {
|
|
||||||
constructor(scene, team, iter) {
|
|
||||||
super(scene);
|
|
||||||
this.scene = scene;
|
|
||||||
const { constructEffectsX, constructEffectsY } = constructEffects(team, iter);
|
|
||||||
this.x = constructEffectsX; this.y = constructEffectsY;
|
|
||||||
this.effectCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addEffect(effect) {
|
|
||||||
const y = this.y + this.effectCount * TEXT_MARGIN;
|
|
||||||
const text = `${effect.effect} for ${effect.duration} turn`;
|
|
||||||
const e = this.scene.add.text(this.x, y, text, TEXT.NORMAL);
|
|
||||||
e.effect = effect.effect;
|
|
||||||
this.add(e);
|
|
||||||
this.effectCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeEffect(effect) {
|
|
||||||
this.children.entries.forEach((e) => {
|
|
||||||
if (e.effect === effect) e.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
update(effects) {
|
|
||||||
this.effectCount = 0;
|
|
||||||
this.children.entries.forEach(e => e.destroy());
|
|
||||||
effects.forEach((effect) => {
|
|
||||||
this.addEffect(effect);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConstructImage extends Phaser.GameObjects.Image {
|
|
||||||
constructor(scene, team, iter, construct) {
|
|
||||||
// Get coords
|
|
||||||
const { constructAvatarX, constructAvatarY } = constructPosition(team, iter);
|
|
||||||
const { statusX, statusY, nameX, nameY } = constructAvatarText(team, iter);
|
|
||||||
|
|
||||||
// Construct display
|
|
||||||
// const avatar = team ? 'magmar' : 'alk';
|
|
||||||
super(scene, constructAvatarX, constructAvatarY, 'aztec', genAvatar(construct.name));
|
|
||||||
this.setScale(0.5);
|
|
||||||
|
|
||||||
if (!team) this.flipX = true;
|
|
||||||
|
|
||||||
// Save position and construct details
|
|
||||||
this.scene = scene;
|
|
||||||
this.iter = iter;
|
|
||||||
this.team = team;
|
|
||||||
this.construct = construct;
|
|
||||||
this.state = 'deselect';
|
|
||||||
// Add construct name
|
|
||||||
scene.add.text(nameX, nameY, construct.name, TEXT.NORMAL).setOrigin(team, 0);
|
|
||||||
// Add construct stat bars
|
|
||||||
this.health = scene.add.existing(new StatBar(scene, this, 'HP'));
|
|
||||||
this.red_shield = scene.add.existing(new StatBar(scene, this, 'Red Shield'));
|
|
||||||
this.blue_shield = scene.add.existing(new StatBar(scene, this, 'Blue Shield'));
|
|
||||||
// this.evasion = scene.add.existing(new StatBar(scene, this, 'Evasion'));
|
|
||||||
|
|
||||||
this.effects = scene.add.existing(new Effects(scene, team, iter));
|
|
||||||
this.statusText = scene.add.text(statusX, statusY, '', TEXT.NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
select() {
|
|
||||||
this.setTint('0x00bb00');
|
|
||||||
this.state = 'select';
|
|
||||||
}
|
|
||||||
|
|
||||||
setKo() {
|
|
||||||
this.state = 'ko';
|
|
||||||
this.setTint('0x9d9ea0');
|
|
||||||
}
|
|
||||||
|
|
||||||
deselect() {
|
|
||||||
if (this.state !== 'ko') {
|
|
||||||
this.clearTint();
|
|
||||||
this.state = 'deselect';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearStatus() {
|
|
||||||
this.statusText.text = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
reduceDefense(amount, type) {
|
|
||||||
if (type === 'PhysDmg') {
|
|
||||||
this.red_shield.takeDamage(amount);
|
|
||||||
} else if (type === 'BlueDmg') {
|
|
||||||
this.blue_shield.takeDamage(amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
takeDamage(props) {
|
|
||||||
const { amount, mitigation, category } = props;
|
|
||||||
if (mitigation) this.reduceDefense(mitigation, category);
|
|
||||||
this.setTint(0xff0000);
|
|
||||||
this.health.takeDamage(amount);
|
|
||||||
this.scene.time.delayedCall(DELAYS.DAMAGE_TICK, () => {
|
|
||||||
if (this.state !== 'ko') this.clearTint();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
takeHealing(amount) {
|
|
||||||
this.setTint(0x00bb00);
|
|
||||||
this.health.takeDamage(amount * -1);
|
|
||||||
this.scene.time.delayedCall(DELAYS.DAMAGE_TICK, () => {
|
|
||||||
if (this.state !== 'ko') this.clearTint();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CombatConstructs extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'CombatConstructs' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(game) {
|
|
||||||
this.constructs = this.add.group();
|
|
||||||
this.phase = game.phase;
|
|
||||||
this.account = this.registry.get('account');
|
|
||||||
this.drawConstructs(game);
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.set('constructStatusUpdate', false);
|
|
||||||
this.teams = game.teams.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'game' && data) {
|
|
||||||
if (data.teams.length !== this.teams) this.scene.restart(data);
|
|
||||||
const isAnimating = this.phase === 'animating';
|
|
||||||
this.game = data;
|
|
||||||
if (isAnimating) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === 'gamePhase' && data) {
|
|
||||||
const shouldUpdate = data !== this.phase;
|
|
||||||
this.phase = data;
|
|
||||||
if (shouldUpdate) {
|
|
||||||
this.constructs.children.entries.forEach(c => c.clearStatus());
|
|
||||||
this.drawConstructs(this.game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === 'constructStatusUpdate' && data) {
|
|
||||||
this.updateConstructStatus(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
drawConstructs(game) {
|
|
||||||
const renderConstruct = (construct, iter, team) => {
|
|
||||||
// Add Image Avatar Class
|
|
||||||
const constructObj = new ConstructImage(this, team, iter, construct);
|
|
||||||
this.add.existing(constructObj);
|
|
||||||
this.constructs.add(constructObj);
|
|
||||||
return constructObj;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTeam = (construct, iter, team) => {
|
|
||||||
const constructObj = this.constructs.children.entries
|
|
||||||
.find(c => c.construct.id === construct.id)
|
|
||||||
|| renderConstruct(construct, iter, team);
|
|
||||||
constructObj.health.val = construct.hp.value;
|
|
||||||
constructObj.red_shield.val = construct.red_shield.value;
|
|
||||||
constructObj.blue_shield.val = construct.red_shield.value;
|
|
||||||
|
|
||||||
constructObj.health.drawStatBar();
|
|
||||||
constructObj.red_shield.drawStatBar();
|
|
||||||
constructObj.blue_shield.drawStatBar();
|
|
||||||
constructObj.effects.update(construct.effects);
|
|
||||||
};
|
|
||||||
|
|
||||||
const allyTeam = game.teams.find(t => t.id === this.account.id);
|
|
||||||
// in future there will be more than one
|
|
||||||
const [enemyTeam] = game.teams.filter(t => t.id !== this.account.id);
|
|
||||||
|
|
||||||
allyTeam.constructs.forEach((construct, i) => renderTeam(construct, i, 0));
|
|
||||||
if (!enemyTeam) return false;
|
|
||||||
enemyTeam.constructs.forEach((construct, i) => renderTeam(construct, i, 1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectConstruct(constructId) {
|
|
||||||
this.constructs.children.entries.forEach(c => c.deselect());
|
|
||||||
if (constructId) this.constructs.children.entries.find(c => c.construct.id === constructId).select();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateConstructStatus(status) {
|
|
||||||
const sourceConstruct = this.constructs.children.entries
|
|
||||||
.find(c => c.construct.id === status.id);
|
|
||||||
|
|
||||||
const targetConstruct = this.constructs.children.entries
|
|
||||||
.find(c => c.construct.id === status.target);
|
|
||||||
|
|
||||||
if (this.phase === 'Skill') {
|
|
||||||
sourceConstruct.statusText.text = `${status.skill} on ${targetConstruct.construct.name}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CombatConstructs;
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { COMBAT } } = require('./constants');
|
|
||||||
|
|
||||||
const CONSTRUCT_MARGIN = COMBAT.constructMargin();
|
|
||||||
const BOX_HEIGHT = CONSTRUCT_MARGIN * 0.8;
|
|
||||||
const BOX_WIDTH = COMBAT.width() * 0.2;
|
|
||||||
|
|
||||||
|
|
||||||
class ConstructHitBox extends Phaser.GameObjects.Rectangle {
|
|
||||||
constructor(scene, iter, team, cback) {
|
|
||||||
const y = COMBAT.y() + COMBAT.height() * 0.05 + CONSTRUCT_MARGIN * iter;
|
|
||||||
super(scene, (COMBAT.width() - BOX_WIDTH) * team, y, BOX_WIDTH, BOX_HEIGHT, 0x222222);
|
|
||||||
this.setOrigin(0);
|
|
||||||
this.clickHandler = () => cback();
|
|
||||||
}
|
|
||||||
|
|
||||||
select() {
|
|
||||||
this.setFillStyle(0x003300);
|
|
||||||
}
|
|
||||||
|
|
||||||
deselect() {
|
|
||||||
this.setFillStyle(0x222222);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CombatHitBox extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'CombatHitBox' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(phase) {
|
|
||||||
this.phase = phase;
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
if (phase === 'animating') return true;
|
|
||||||
this.selectHitBox(phase);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'game' && data) {
|
|
||||||
// In the case that we hit skill phase but teams change we restart
|
|
||||||
if (data.teams.length !== this.teams) this.scene.restart(data.phase);
|
|
||||||
}
|
|
||||||
if (key === 'gamePhase' && data) {
|
|
||||||
const shouldUpdate = data !== this.phase;
|
|
||||||
if (shouldUpdate) this.scene.restart(data);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectHitBox(phase) {
|
|
||||||
const game = this.registry.get('game');
|
|
||||||
this.teams = game.teams.length;
|
|
||||||
if (phase === 'Skill') return this.skillHitBox(game);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
skillHitBox(game) {
|
|
||||||
const account = this.registry.get('account');
|
|
||||||
const group = this.scene.get('CombatConstructs').constructs;
|
|
||||||
const skillScene = this.scene.get('CombatSkills');
|
|
||||||
game.teams.forEach((t) => {
|
|
||||||
t.constructs.forEach((c) => {
|
|
||||||
const cback = () => {
|
|
||||||
const { activeSkill } = skillScene;
|
|
||||||
if (activeSkill) {
|
|
||||||
this.scene.get('CombatSkills').clearConstructActive(activeSkill.construct.id);
|
|
||||||
activeSkill.activate();
|
|
||||||
skillScene.activeSkill = null;
|
|
||||||
this.game.events.emit('SEND_SKILL', game.id, activeSkill.construct.id, c.id, activeSkill.skill.skill);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const constructSpawn = group.children.entries.find(s => s.construct.id === c.id);
|
|
||||||
const team = c.account === account.id ? 0 : 1;
|
|
||||||
if (constructSpawn) this.add.existing(new ConstructHitBox(this, constructSpawn.iter, team, cback));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.scene.moveBelow('Combat');
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CombatHitBox;
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { throttle } = require('lodash');
|
|
||||||
|
|
||||||
const { TEXT, POSITIONS: { COMBAT } } = require('./constants');
|
|
||||||
const CombatLog = require('./combat.log');
|
|
||||||
const CombatConstructs = require('./combat.constructs');
|
|
||||||
const CombatSkills = require('./combat.skills');
|
|
||||||
const CombatHitBox = require('./combat.hitbox');
|
|
||||||
|
|
||||||
const renderResolutions = require('./combat.render.resolutions');
|
|
||||||
|
|
||||||
|
|
||||||
class Combat extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Combat' });
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
this.load.image('proj', 'https://labs.phaser.io/assets/sprites/bullet.png');
|
|
||||||
this.load.image('blue', 'https://labs.phaser.io/assets/particles/blue.png');
|
|
||||||
this.load.image('green', 'https://labs.phaser.io/assets/particles/green.png');
|
|
||||||
this.load.image('red', 'https://labs.phaser.io/assets/particles/red.png');
|
|
||||||
this.load.image('white', 'https://labs.phaser.io/assets/particles/white.png');
|
|
||||||
this.load.image('yellow', 'https://labs.phaser.io/assets/particles/yellow.png');
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
console.log('creating game');
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.addLeaveGame();
|
|
||||||
|
|
||||||
this.registry.set('gamePhase', false);
|
|
||||||
this.registry.set('inGame', true);
|
|
||||||
this.registry.set('gameAnimating', false);
|
|
||||||
this.account = this.registry.get('account');
|
|
||||||
this.fetchGame = throttle(() => {
|
|
||||||
const game = this.registry.get('game');
|
|
||||||
if (game) {
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
return ws.sendGameState(game.id);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
startGame(game) {
|
|
||||||
this.scene.manager.add('CombatConstructs', CombatConstructs, true, game);
|
|
||||||
this.scene.manager.add('CombatLog', CombatLog, true, game);
|
|
||||||
this.renderedResolves = game.resolved.length; // In case you rejoin mid way
|
|
||||||
this.scene.manager.add('CombatSkills', CombatSkills, true, game.phase);
|
|
||||||
this.scene.manager.add('CombatHitBox', CombatHitBox, true, game.phase);
|
|
||||||
this.registry.set('gamePhase', game.phase);
|
|
||||||
this.phase = game.phase;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.fetchGame();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'game') {
|
|
||||||
if (!data) return false;
|
|
||||||
const startGame = this.registry.get('gamePhase') === false;
|
|
||||||
if (startGame) { this.startGame(data); return true; }
|
|
||||||
this.checkAnimation(data);
|
|
||||||
// Game over?
|
|
||||||
// if (data.phase === 'Finish') {
|
|
||||||
// this.time.delayedCall(10000, () => {
|
|
||||||
// this.endGame();
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAnimation(game) {
|
|
||||||
// Check constructs are loaded and whether game is animating
|
|
||||||
const cantAnimate = this.registry.get('gamePhase') === 'animating';
|
|
||||||
if (cantAnimate) return false;
|
|
||||||
if (game.resolved.length !== this.renderedResolves) {
|
|
||||||
const newResolutions = game.resolved.slice(this.renderedResolves);
|
|
||||||
renderResolutions(this, game, newResolutions);
|
|
||||||
this.renderedResolves = game.resolved.length;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.phase !== game.phase) {
|
|
||||||
this.phase = game.phase;
|
|
||||||
this.registry.set('gamePhase', game.phase);
|
|
||||||
}
|
|
||||||
if (this.registry.get('gameLog') !== game.log.length) {
|
|
||||||
this.registry.set('gameLog', game.log.length);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
addLeaveGame() {
|
|
||||||
const leaveGame = () => this.cleanUp();
|
|
||||||
this.input.keyboard.on('keydown_BACKSPACE', leaveGame, 0, this);
|
|
||||||
const LEAVE_HEIGHT = COMBAT.height() / 6;
|
|
||||||
const LEAVE_WIDTH = COMBAT.width() / 5;
|
|
||||||
const LEAVE_X = COMBAT.width() * 0.8;
|
|
||||||
const LEAVE_Y = COMBAT.height() * 0.9;
|
|
||||||
|
|
||||||
const menu = this.add
|
|
||||||
.rectangle(LEAVE_X, LEAVE_Y, LEAVE_WIDTH, LEAVE_HEIGHT, 0x440000)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', leaveGame);
|
|
||||||
|
|
||||||
this.add
|
|
||||||
.text(menu.getCenter().x, menu.getCenter().y, 'Menu', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
|
|
||||||
this.registry.set('inGame', null);
|
|
||||||
this.registry.set('menu', true);
|
|
||||||
this.registry.set('game', null);
|
|
||||||
|
|
||||||
const ACTIVE_SCENES = ['CombatLog', 'CombatConstructs', 'CombatSkills', 'CombatHitBox'];
|
|
||||||
ACTIVE_SCENES.forEach((sKey) => {
|
|
||||||
if (this.scene.get(sKey)) this.scene.get(sKey).cleanUp();
|
|
||||||
});
|
|
||||||
this.scene.remove();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Combat;
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { COMBAT }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
class CombatLog extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'CombatLog' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(game) {
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.cameras.main.setViewport(COMBAT.LOG.x(), COMBAT.LOG.y(), COMBAT.LOG.width(), COMBAT.LOG.height());
|
|
||||||
this.log = this.add.text(0, 0, '', TEXT.NORMAL);
|
|
||||||
this.logIndex = game.log.length;
|
|
||||||
this.logData = game.log;
|
|
||||||
this.log.setWordWrapWidth(COMBAT.LOG.width());
|
|
||||||
this.log.setText(Array.from(game.log).reverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
const UPDATE_KEYS = ['game', 'gameLog'];
|
|
||||||
if (UPDATE_KEYS.includes(key) && data) {
|
|
||||||
if (key === 'game') {
|
|
||||||
this.logData = data.log;
|
|
||||||
}
|
|
||||||
if (key === 'gameLog') {
|
|
||||||
this.logIndex = data;
|
|
||||||
}
|
|
||||||
this.updateLog();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateLog() {
|
|
||||||
// shallow copy because reverse mutates
|
|
||||||
if (this.logData.length > this.logIndex + 1
|
|
||||||
&& Array.from(this.logData)[this.logIndex].slice(-2) === 'KO') {
|
|
||||||
this.logIndex += 1;
|
|
||||||
this.registry.set('gameLog', this.logIndex);
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
this.log.setText(Array.from(this.logData).slice(0, this.logIndex).reverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CombatLog;
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
const { eachSeries } = require('async');
|
|
||||||
|
|
||||||
const CombatAnimations = require('./combat.animations');
|
|
||||||
const {
|
|
||||||
DELAYS: { ANIMATION_DURATION, MOVE_CREEP, DAMAGE_TICK },
|
|
||||||
POSITIONS: { COMBAT },
|
|
||||||
} = require('./constants');
|
|
||||||
|
|
||||||
function findResolutionConstructs(scene, group, resolution, game) {
|
|
||||||
const sourceSpawn = group.children.entries.find(c => c.construct.id === resolution.source.id);
|
|
||||||
|
|
||||||
/* const sourceConstruct = game.teams.find(t => t.constructs.find(c => c.id === resolution.source_construct_id))
|
|
||||||
.constructs.find(c => c.id === resolution.source_construct_id);
|
|
||||||
|
|
||||||
const targetConstruct = game.teams.find(t => t.constructs.find(c => c.id === resolution.target_construct_id))
|
|
||||||
.constructs.find(c => c.id === resolution.target_construct_id);
|
|
||||||
*/
|
|
||||||
const targetSpawn = group.children.entries.find(c => c.construct.id === resolution.target.id);
|
|
||||||
|
|
||||||
return { sourceSpawn, targetSpawn };
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateTweenParams(sourceSpawn, targetSpawn, account, skill) {
|
|
||||||
const tweenParams = (targets, centreSpot) => {
|
|
||||||
const enemy = targets.construct.account !== account.id;
|
|
||||||
let x = centreSpot ? COMBAT.width() * 0.3 : targets.x;
|
|
||||||
x = (enemy && centreSpot) ? x + COMBAT.width() * 0.4 : x;
|
|
||||||
const y = centreSpot ? COMBAT.height() * 13.25 / 35 : targets.y;
|
|
||||||
const ease = 'Power1';
|
|
||||||
const duration = MOVE_CREEP;
|
|
||||||
return {
|
|
||||||
targets, x, y, ease, duration,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
let moveSourceBattle = false;
|
|
||||||
let moveSourceOrig = false;
|
|
||||||
const targetOnlySkill = ['DecayTick'];
|
|
||||||
if (!(targetOnlySkill.includes(skill))) {
|
|
||||||
if (sourceSpawn.construct.account !== targetSpawn.construct.account) {
|
|
||||||
moveSourceBattle = tweenParams(sourceSpawn, true);
|
|
||||||
moveSourceOrig = tweenParams(sourceSpawn, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveTargetBattle = tweenParams(targetSpawn, true);
|
|
||||||
const moveTargetOrig = tweenParams(targetSpawn, false);
|
|
||||||
|
|
||||||
return {
|
|
||||||
moveSourceBattle, moveSourceOrig, moveTargetBattle, moveTargetOrig,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function animatePhase(scene, game, resolution, cb) {
|
|
||||||
// return early for disabled skills
|
|
||||||
if (resolution.length === 0) return cb();
|
|
||||||
if (resolution.event[0] === 'Disable'
|
|
||||||
|| resolution.event[0] === 'TargetKo'
|
|
||||||
|| resolution.event === 'Ko') return cb();
|
|
||||||
|
|
||||||
const group = scene.scene.get('CombatConstructs').constructs;
|
|
||||||
const animations = new CombatAnimations(scene);
|
|
||||||
const account = scene.registry.get('account');
|
|
||||||
|
|
||||||
// Find constructs, targets
|
|
||||||
const { sourceSpawn, targetSpawn } = findResolutionConstructs(scene, group, resolution, game);
|
|
||||||
const {
|
|
||||||
moveSourceBattle, moveSourceOrig, moveTargetBattle, moveTargetOrig,
|
|
||||||
} = calculateTweenParams(sourceSpawn, targetSpawn, account, resolution.event[1].skill);
|
|
||||||
|
|
||||||
const castParams = () => {
|
|
||||||
const x = (sourceSpawn === targetSpawn) ? moveTargetBattle.x : sourceSpawn.x;
|
|
||||||
const y = (sourceSpawn === targetSpawn) ? moveTargetBattle.y : sourceSpawn.y;
|
|
||||||
return { x, y };
|
|
||||||
};
|
|
||||||
const castLocation = castParams();
|
|
||||||
|
|
||||||
// Move constructs into position
|
|
||||||
if (moveSourceBattle) scene.tweens.add(moveSourceBattle);
|
|
||||||
scene.tweens.add(moveTargetBattle);
|
|
||||||
|
|
||||||
return scene.time.delayedCall(MOVE_CREEP, () => {
|
|
||||||
const sourceAlly = sourceSpawn.construct.account === account.id;
|
|
||||||
const targetAlly = targetSpawn.construct.account === account.id;
|
|
||||||
// animate animation
|
|
||||||
animations.getSkill(resolution.event[1].skill, sourceAlly, targetAlly, castLocation);
|
|
||||||
// Target construct takes damage
|
|
||||||
scene.time.delayedCall(ANIMATION_DURATION, () => {
|
|
||||||
console.log(resolution);
|
|
||||||
if (resolution.event[0] === 'Damage') {
|
|
||||||
targetSpawn.takeDamage(resolution.event[1]);
|
|
||||||
scene.registry.set('gameLog', scene.registry.get('gameLog') + 1);
|
|
||||||
}
|
|
||||||
if (resolution.event[0] === 'Healing') {
|
|
||||||
targetSpawn.takeHealing(resolution.event[1]);
|
|
||||||
scene.registry.set('gameLog', scene.registry.get('gameLog') + 1);
|
|
||||||
}
|
|
||||||
if (resolution.event[0] === 'Effect') {
|
|
||||||
targetSpawn.effects.addEffect(resolution.event[1]);
|
|
||||||
console.log('target has new effect', resolution.event[1].effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolution.event[0] === 'Removal') {
|
|
||||||
targetSpawn.effects.removeEffect(resolution.event[1].effect);
|
|
||||||
console.log('target effect removed', resolution.event[1].effect);
|
|
||||||
}
|
|
||||||
if (moveSourceOrig) scene.tweens.add(moveSourceOrig);
|
|
||||||
scene.tweens.add(moveTargetOrig);
|
|
||||||
|
|
||||||
// all done
|
|
||||||
scene.time.delayedCall(MOVE_CREEP, () => {
|
|
||||||
animations.destroy(true);
|
|
||||||
return cb();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderResolutions(scene, game, resolutions) {
|
|
||||||
scene.registry.set('gamePhase', 'animating');
|
|
||||||
scene.registry.set('gameLog', scene.registry.get('gameLog') + 1);
|
|
||||||
|
|
||||||
eachSeries(
|
|
||||||
resolutions,
|
|
||||||
(resolution, cb) => animatePhase(scene, game, resolution, cb),
|
|
||||||
(err) => {
|
|
||||||
if (err) return console.error(err);
|
|
||||||
scene.registry.set('gamePhase', 'Skill');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = renderResolutions;
|
|
||||||
@ -1,235 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const { TEXT, POSITIONS: { COMBAT } } = require('./constants');
|
|
||||||
|
|
||||||
const CONSTRUCT_KEY_MAP = ['keydown_ONE', 'keydown_TWO', 'keydown_THREE'];
|
|
||||||
const SKILL_KEY_MAP = ['keydown_Q', 'keydown_W', 'keydown_E', 'keydown_R'];
|
|
||||||
const TARGET_KEY_MAP = ['keydown_SEVEN', 'keydown_EIGHT', 'keydown_NINE', 'keydown_ZERO'];
|
|
||||||
|
|
||||||
const CONSTRUCT_MARGIN = COMBAT.constructMargin();
|
|
||||||
const TEXT_MARGIN = COMBAT.textMargin();
|
|
||||||
const SKILL_WIDTH = COMBAT.width() / 10;
|
|
||||||
const SKILL_HEIGHT = COMBAT.height() / 30;
|
|
||||||
|
|
||||||
const skillPosition = (constructIter, skillIter) => {
|
|
||||||
const skillTextX = COMBAT.width() / 3.8;
|
|
||||||
const skillTextY = (TEXT_MARGIN * skillIter) * 1.5 + CONSTRUCT_MARGIN * constructIter + COMBAT.y() + COMBAT.height() * 0.07;
|
|
||||||
return [skillTextX, skillTextY];
|
|
||||||
};
|
|
||||||
|
|
||||||
const skillCheckHitBox = (scenePlugin, pointer) => {
|
|
||||||
const { list } = scenePlugin.get('CombatHitBox').children;
|
|
||||||
for (let i = 0; i < list.length; i += 1) {
|
|
||||||
if (Phaser.Geom.Rectangle.ContainsPoint(list[i].getBounds(),
|
|
||||||
pointer.position)) return list[i];
|
|
||||||
}
|
|
||||||
// If we didn't find a hitbox deselect them all
|
|
||||||
for (let i = 0; i < list.length; i += 1) list[i].deselect();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConstructSkill extends Phaser.GameObjects.Container {
|
|
||||||
constructor(scene, x, y, skill, construct) {
|
|
||||||
// Avatar will be a property of construct
|
|
||||||
super(scene, x, y);
|
|
||||||
const CD_TEXT = skill.cd ? `(${skill.cd}T)` : '';
|
|
||||||
const SKILL_TEXT = `${skill.skill} ${CD_TEXT}`;
|
|
||||||
this.origX = x; this.origY = y;
|
|
||||||
|
|
||||||
this.skillBox = scene.add.rectangle(0, 0, SKILL_WIDTH, SKILL_HEIGHT, 0x222222);
|
|
||||||
this.skillText = scene.add.text(0, 0, SKILL_TEXT, TEXT.NORMAL).setOrigin(0.5, 0.5);
|
|
||||||
this.add(this.skillBox);
|
|
||||||
this.add(this.skillText);
|
|
||||||
|
|
||||||
this.state = 'deselect';
|
|
||||||
this.construct = construct;
|
|
||||||
this.skill = skill;
|
|
||||||
this.scene = scene;
|
|
||||||
|
|
||||||
this.setSize(SKILL_WIDTH, SKILL_HEIGHT);
|
|
||||||
this.setInteractive();
|
|
||||||
}
|
|
||||||
|
|
||||||
clickHandler() {
|
|
||||||
if (this.scene.phase === 'Skill') this.scene.activeSkill = this;
|
|
||||||
this.select();
|
|
||||||
}
|
|
||||||
|
|
||||||
select() {
|
|
||||||
this.scene.children.list.forEach((skill) => {
|
|
||||||
if (skill.state === 'select') skill.deselect();
|
|
||||||
});
|
|
||||||
this.skillBox.setFillStyle(0x004bfe);
|
|
||||||
this.state = 'select';
|
|
||||||
}
|
|
||||||
|
|
||||||
activate() {
|
|
||||||
this.scene.children.list.forEach((skill) => {
|
|
||||||
if (skill.state === 'select') skill.deselect();
|
|
||||||
});
|
|
||||||
this.skillBox.setFillStyle(0xff0000);
|
|
||||||
this.state = 'activate';
|
|
||||||
}
|
|
||||||
|
|
||||||
deselect() {
|
|
||||||
this.skillBox.setFillStyle(0x222222);
|
|
||||||
this.state = 'deselect';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CombatSkills extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'CombatSkills' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(phase) {
|
|
||||||
this.phase = phase;
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.account = this.registry.get('account');
|
|
||||||
|
|
||||||
this.input.on('dragstart', (pointer, box) => {
|
|
||||||
box.clickHandler();
|
|
||||||
});
|
|
||||||
this.input.on('drag', (pointer, box, dragX, dragY) => {
|
|
||||||
const hitBox = skillCheckHitBox(this.scene, pointer);
|
|
||||||
if (hitBox) hitBox.select();
|
|
||||||
box.setPosition(dragX, dragY);
|
|
||||||
});
|
|
||||||
this.input.on('dragend', (pointer, box) => {
|
|
||||||
box.deselect();
|
|
||||||
const hitBox = skillCheckHitBox(this.scene, pointer);
|
|
||||||
if (hitBox) {
|
|
||||||
hitBox.clickHandler();
|
|
||||||
}
|
|
||||||
box.setPosition(box.origX, box.origY);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (phase === 'animating') return true;
|
|
||||||
// can't set this.game cause of phaser class named the same
|
|
||||||
const game = this.registry.get('game');
|
|
||||||
this.renderSkills(game, phase);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'gamePhase' && data) {
|
|
||||||
const shouldUpdate = data !== this.phase;
|
|
||||||
if (shouldUpdate) {
|
|
||||||
this.scene.get('CombatConstructs').selectConstruct(null);
|
|
||||||
return this.scene.restart(data);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSkills(game, phase) {
|
|
||||||
if (phase === 'Skill') return this.renderSkillPhase(game);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSkillPhase(game) {
|
|
||||||
const { account } = this;
|
|
||||||
const { keyboard } = this.input;
|
|
||||||
const { events } = this.game;
|
|
||||||
|
|
||||||
const addSkill = (i, j, skill, construct) => {
|
|
||||||
const skillTextPos = skillPosition(i, j);
|
|
||||||
const skillObj = new ConstructSkill(this, skillTextPos[0], skillTextPos[1], skill, construct);
|
|
||||||
if (skill.cd) {
|
|
||||||
skillObj.skillBox.setFillStyle(0x9d9ea0);
|
|
||||||
} else {
|
|
||||||
this.input.setDraggable(skillObj);
|
|
||||||
}
|
|
||||||
this.add.existing(skillObj);
|
|
||||||
return skillObj;
|
|
||||||
};
|
|
||||||
|
|
||||||
const team = game.teams.find(t => t.id === account.id);
|
|
||||||
const enemyTeam = game.teams.find(t => t.id !== account.id);
|
|
||||||
|
|
||||||
team.constructs.forEach((construct) => {
|
|
||||||
// return early if KOd
|
|
||||||
if (construct.hp.value === 0) return true;
|
|
||||||
|
|
||||||
// find the construct position
|
|
||||||
const { iter } = this.scene.get('CombatConstructs').constructs.children.entries.find(c => c.construct.id === construct.id);
|
|
||||||
|
|
||||||
// draw the skills
|
|
||||||
const skillButtons = construct.skills.map((skill, j) => addSkill(iter, j, skill, construct));
|
|
||||||
|
|
||||||
const bindConstructKeys = () => this.mapSkillKeys(skillButtons, game.id, construct.id, team.id, enemyTeam.id, iter);
|
|
||||||
|
|
||||||
// reset everything
|
|
||||||
keyboard.on('keydown_ESC', bindConstructKeys, this);
|
|
||||||
events.on('SEND_SKILL', bindConstructKeys, this);
|
|
||||||
bindConstructKeys();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
// needs to send constructId not team
|
|
||||||
mapSkillKeys(skillButtons, gameId, constructId, alliesId, enemyId, i) {
|
|
||||||
const { keyboard } = this.input;
|
|
||||||
|
|
||||||
keyboard.removeListener(CONSTRUCT_KEY_MAP[i]);
|
|
||||||
|
|
||||||
keyboard.on(CONSTRUCT_KEY_MAP[i], () => {
|
|
||||||
SKILL_KEY_MAP.forEach(k => keyboard.removeListener(k));
|
|
||||||
|
|
||||||
this.scene.get('CombatConstructs').selectConstruct(constructId);
|
|
||||||
|
|
||||||
skillButtons.forEach((button, j) => {
|
|
||||||
keyboard.on(SKILL_KEY_MAP[j], () => {
|
|
||||||
this.activeSkill = button;
|
|
||||||
button.select();
|
|
||||||
|
|
||||||
// clear existing keys
|
|
||||||
CONSTRUCT_KEY_MAP.forEach(k => keyboard.removeListener(k));
|
|
||||||
TARGET_KEY_MAP.forEach(k => keyboard.removeListener(k));
|
|
||||||
|
|
||||||
CONSTRUCT_KEY_MAP.forEach(k => keyboard.on(k, () => {
|
|
||||||
this.clearConstructActive(constructId);
|
|
||||||
button.activate();
|
|
||||||
this.activeSkill = null;
|
|
||||||
this.game.events.emit('SEND_SKILL', gameId, constructId, alliesId, button.skill.skill);
|
|
||||||
}));
|
|
||||||
|
|
||||||
TARGET_KEY_MAP.forEach(k => keyboard.on(k, () => {
|
|
||||||
this.clearConstructActive(constructId);
|
|
||||||
button.activate();
|
|
||||||
this.activeSkill = null;
|
|
||||||
this.game.events.emit('SEND_SKILL', gameId, constructId, enemyId, button.skill.skill);
|
|
||||||
}));
|
|
||||||
}, this);
|
|
||||||
});
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearConstructActive(constructId) {
|
|
||||||
this.scene.scene.children.list.forEach((s) => {
|
|
||||||
if (s.construct.id === constructId && s.state === 'activate') s.deselect();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
clearKeys() {
|
|
||||||
TARGET_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey));
|
|
||||||
CONSTRUCT_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey));
|
|
||||||
SKILL_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CombatSkills;
|
|
||||||
@ -1,388 +0,0 @@
|
|||||||
// POSITIONING FNS
|
|
||||||
// floors prevent subpixel rendering which looks trash
|
|
||||||
|
|
||||||
const CANVAS_WIDTH = () => Math.floor(window.innerHeight * 1.6);
|
|
||||||
const CANVAS_HEIGHT = () => Math.floor(window.innerHeight);
|
|
||||||
|
|
||||||
const headerWidth = () => CANVAS_WIDTH();
|
|
||||||
const headerHeight = () => Math.floor(CANVAS_HEIGHT() * 0.05);
|
|
||||||
|
|
||||||
const menuConstructListWidth = () => Math.floor(CANVAS_WIDTH() * 0.3);
|
|
||||||
const menuConstructListHeight = () => Math.floor(CANVAS_HEIGHT() - headerHeight());
|
|
||||||
const menuConstructListX = () => Math.floor(CANVAS_WIDTH() * 0.3);
|
|
||||||
const menuConstructListY = () => headerHeight();
|
|
||||||
|
|
||||||
const itemListWidth = () => Math.floor(CANVAS_WIDTH() * 0.5);
|
|
||||||
const itemListHeight = () => Math.floor(CANVAS_HEIGHT() * 0.95);
|
|
||||||
const itemListX = () => 0;
|
|
||||||
const itemListY = () => headerHeight();
|
|
||||||
const itemBlockWidth = () => Math.floor(itemListWidth() * 0.12);
|
|
||||||
const itemBlockHeight = () => Math.floor(itemListHeight() * 0.04);
|
|
||||||
|
|
||||||
const menuNavigationWidth = () => Math.floor(CANVAS_WIDTH() * 0.5);
|
|
||||||
const menuNavigationHeight = () => Math.floor(CANVAS_HEIGHT() * 0.3);
|
|
||||||
const menuNavigationX = () => Math.floor(CANVAS_WIDTH() * 0.5);
|
|
||||||
const menuNavigationY = () => Math.floor(CANVAS_HEIGHT() * 0.7);
|
|
||||||
|
|
||||||
const menuMainWidth = () => Math.floor(CANVAS_WIDTH() * 0.4);
|
|
||||||
const menuMainHeight = () => Math.floor(CANVAS_HEIGHT() * 0.5);
|
|
||||||
const menuMainX = () => Math.floor(CANVAS_WIDTH() * 0.65);
|
|
||||||
const menuMainY = () => headerHeight();
|
|
||||||
|
|
||||||
const homeMainWidth = () => Math.floor(CANVAS_WIDTH() * 0.6);
|
|
||||||
const homeMainHeight = () => Math.floor(CANVAS_HEIGHT() * 0.5);
|
|
||||||
const homeMainX = () => Math.floor(CANVAS_WIDTH() * 0.4);
|
|
||||||
const homeMainY = () => headerHeight();
|
|
||||||
|
|
||||||
const combatWidth = () => CANVAS_WIDTH();
|
|
||||||
const combatHeight = () => CANVAS_HEIGHT() - headerHeight();
|
|
||||||
const combatY = () => headerHeight();
|
|
||||||
const combatX = () => 0;
|
|
||||||
const combatConstructMargin = () => Math.floor((CANVAS_HEIGHT() - headerHeight()) / 4.5);
|
|
||||||
const combatTextMargin = () => Math.floor((CANVAS_HEIGHT() - headerHeight()) / 35);
|
|
||||||
|
|
||||||
const statsWidth = () => Math.floor(CANVAS_WIDTH() - menuConstructListWidth());
|
|
||||||
const statsHeight = () => CANVAS_HEIGHT() - headerHeight();
|
|
||||||
const statsY = () => headerHeight();
|
|
||||||
const statsX = () => menuConstructListWidth();
|
|
||||||
const statsKnownX = () => Math.floor(statsX() + statsWidth() / 4);
|
|
||||||
const statsLearnableX = () => Math.floor(statsX() + statsWidth() / 2);
|
|
||||||
const statsTextMargin = () => 24;
|
|
||||||
const statsLearnableMargin = () => 12;
|
|
||||||
|
|
||||||
const logWidth = () => Math.floor(combatWidth() * 0.5);
|
|
||||||
const logHeight = () => Math.floor(combatHeight() * 0.3);
|
|
||||||
const logY = () => Math.floor(headerHeight() + (combatHeight() * 0.7));
|
|
||||||
const logX = () => Math.floor(combatWidth() * 0.2);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
TEXT: {
|
|
||||||
NORMAL: { fontFamily: 'Jura', fontSize: 18, color: '#ffffff' },
|
|
||||||
LEARNABLE: { fontFamily: 'Jura', fontSize: 18, color: '#ffffff' },
|
|
||||||
HEADER: { fontFamily: 'Jura', fontSize: 24, color: '#ffffff', fontStyle: 'bold' },
|
|
||||||
HOVER: { fontFamily: 'Jura', fontSize: 16, color: '#ffffff', backgroundColor: '#222222' },
|
|
||||||
},
|
|
||||||
|
|
||||||
POSITIONS: {
|
|
||||||
HEADER: {
|
|
||||||
width: headerWidth,
|
|
||||||
height: headerHeight,
|
|
||||||
},
|
|
||||||
|
|
||||||
CONSTRUCT_LIST: {
|
|
||||||
x: menuConstructListX,
|
|
||||||
y: menuConstructListY,
|
|
||||||
width: menuConstructListWidth,
|
|
||||||
height: menuConstructListHeight,
|
|
||||||
},
|
|
||||||
|
|
||||||
MENU_MAIN: {
|
|
||||||
x: menuMainX,
|
|
||||||
y: menuMainY,
|
|
||||||
width: menuMainWidth,
|
|
||||||
height: menuMainHeight,
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
HOME_MAIN: {
|
|
||||||
x: homeMainX,
|
|
||||||
y: homeMainY,
|
|
||||||
width: homeMainWidth,
|
|
||||||
height: homeMainHeight,
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
NAVIGATION: {
|
|
||||||
x: menuNavigationX,
|
|
||||||
y: menuNavigationY,
|
|
||||||
width: menuNavigationWidth,
|
|
||||||
height: menuNavigationHeight,
|
|
||||||
},
|
|
||||||
|
|
||||||
ITEM_LIST: {
|
|
||||||
x: itemListX,
|
|
||||||
y: itemListY,
|
|
||||||
width: itemListWidth,
|
|
||||||
height: itemListHeight,
|
|
||||||
itemWidth: itemBlockWidth,
|
|
||||||
itemHeight: itemBlockHeight,
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
STATS: {
|
|
||||||
x: statsX,
|
|
||||||
y: statsY,
|
|
||||||
width: statsWidth,
|
|
||||||
height: statsHeight,
|
|
||||||
knownX: statsKnownX,
|
|
||||||
learnableX: statsLearnableX,
|
|
||||||
textMargin: statsTextMargin,
|
|
||||||
learnableMargin: statsLearnableMargin,
|
|
||||||
},
|
|
||||||
|
|
||||||
COMBAT: {
|
|
||||||
x: combatX,
|
|
||||||
y: combatY,
|
|
||||||
width: combatWidth,
|
|
||||||
height: combatHeight,
|
|
||||||
constructMargin: combatConstructMargin,
|
|
||||||
textMargin: combatTextMargin,
|
|
||||||
|
|
||||||
|
|
||||||
LOG: {
|
|
||||||
x: logX,
|
|
||||||
y: logY,
|
|
||||||
width: logWidth,
|
|
||||||
height: logHeight,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
COLOURS: {
|
|
||||||
BLUE: 0x004bfe,
|
|
||||||
CYAN: 0x27e7c0,
|
|
||||||
PURPLE: 0x61008c,
|
|
||||||
YELLOW: 0xfdfe02,
|
|
||||||
ORANGE: 0xff9215,
|
|
||||||
PINK: 0xe766b6,
|
|
||||||
GRAY: 0x9d9ea0,
|
|
||||||
LBLUE: 0x87c6f2,
|
|
||||||
GREEN: 0x166c4f,
|
|
||||||
BROWN: 0x583108,
|
|
||||||
BLACK: 0x000000,
|
|
||||||
RED: 0xff0000,
|
|
||||||
WHITE: 0xffffff,
|
|
||||||
|
|
||||||
SELECT: 0x003300,
|
|
||||||
},
|
|
||||||
|
|
||||||
DELAYS: {
|
|
||||||
MOVE_CREEP: 500,
|
|
||||||
DAMAGE_TICK: 500,
|
|
||||||
ANIMATION_DURATION: 1000,
|
|
||||||
// wall: [500],
|
|
||||||
// spit: [300, 500],
|
|
||||||
// gravBomb: [300, 500],
|
|
||||||
// gravBlast: [300, 500],
|
|
||||||
// chargeBall: [300, 500],
|
|
||||||
},
|
|
||||||
|
|
||||||
ITEMS: {
|
|
||||||
SKILLS: {
|
|
||||||
Amplify: {
|
|
||||||
description: 'increase the magic damage dealt by a construct',
|
|
||||||
colours: '1 Green 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Attack: {
|
|
||||||
description: 'a fast attack with red damage',
|
|
||||||
upgrades: 'combine with 2 red / blue / green - red + blue attack not implemented',
|
|
||||||
},
|
|
||||||
|
|
||||||
Banish: {
|
|
||||||
description: 'target construct is prevented from casting any skills and taking any damage',
|
|
||||||
colours: '1 Red 1 Green',
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
Blast: {
|
|
||||||
description: 'blast the target with magic damage',
|
|
||||||
colours: '2 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Block: {
|
|
||||||
description: 'decreases incoming red damage for 1T',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Buff: {
|
|
||||||
description: 'increase target construct speed',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Clutch: {
|
|
||||||
description: '??????',
|
|
||||||
colours: '1 Red 1 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Corrupt: {
|
|
||||||
description: 'Inflicts a dot to attacker while active',
|
|
||||||
colours: '2 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Curse: {
|
|
||||||
description: 'target construct takes increased magic damage',
|
|
||||||
colours: '2 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Debuff: {
|
|
||||||
description: 'reduce target construct speed',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Decay: {
|
|
||||||
description: 'afflict a construct with a blue damage based damage over time debuff',
|
|
||||||
colours: '1 Green 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Empower: {
|
|
||||||
description: 'increase the red damage dealt by a construct',
|
|
||||||
colours: '2 Red',
|
|
||||||
},
|
|
||||||
|
|
||||||
Haste: {
|
|
||||||
description: 'magical skill that increases speed of target construct',
|
|
||||||
colours: '1 Red 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Heal: {
|
|
||||||
description: 'heal a construct with blue damage',
|
|
||||||
colours: '2 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Hex: {
|
|
||||||
description: 'magical bsed skill that prevents target construct from using any skills',
|
|
||||||
colours: '1 Red 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Hostility: {
|
|
||||||
description: 'magical bsed skill that prevents target construct from using any skills',
|
|
||||||
colours: '2 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Invert: {
|
|
||||||
description: 'reverse ???',
|
|
||||||
colours: '1 Red 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Parry: {
|
|
||||||
description: 'prevents all red damage for 1T',
|
|
||||||
colours: '2 Red',
|
|
||||||
},
|
|
||||||
|
|
||||||
Purge: {
|
|
||||||
description: 'remove magical buffs from target construct',
|
|
||||||
colours: '2 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Purify: {
|
|
||||||
description: 'remove magical debuffs from target construct',
|
|
||||||
colours: '1 Red 1 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Recharge: {
|
|
||||||
description: 'restore something',
|
|
||||||
colours: '1 Red 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Reflect: {
|
|
||||||
description: 'reflect damage back to attacker',
|
|
||||||
colours: '2 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Riposte: {
|
|
||||||
description: '???',
|
|
||||||
},
|
|
||||||
|
|
||||||
Ruin: {
|
|
||||||
description: 'Stun the entire enemy team',
|
|
||||||
colours: '2 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Shield: {
|
|
||||||
description: 'grants immunity to magical skills to target construct',
|
|
||||||
colours: '1 Green 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Silence: {
|
|
||||||
description: 'prevent target construct from casting magical skills',
|
|
||||||
colours: '1 Green 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Siphon: {
|
|
||||||
description: 'siphon hp from target construct with a blue damage based debuff',
|
|
||||||
colours: '1 Green 1 Blue',
|
|
||||||
},
|
|
||||||
|
|
||||||
Slay: {
|
|
||||||
description: '????',
|
|
||||||
},
|
|
||||||
|
|
||||||
Slow: {
|
|
||||||
description: 'magical skill that reduces speed of target construct',
|
|
||||||
colours: '1 Red 1 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Snare: {
|
|
||||||
description: 'prevents red skills from being used for 2T',
|
|
||||||
colours: '2 Red',
|
|
||||||
},
|
|
||||||
|
|
||||||
Strangle: {
|
|
||||||
description: 'Stun the enemy and inflict physical damage over 3T',
|
|
||||||
colours: '2 Red',
|
|
||||||
},
|
|
||||||
|
|
||||||
Strike: {
|
|
||||||
description: 'Fast attacking red skill',
|
|
||||||
colours: '2 Red',
|
|
||||||
},
|
|
||||||
|
|
||||||
Stun: {
|
|
||||||
description: 'red skill hat prevents target construct from using any skills',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
Taunt: {
|
|
||||||
description: 'Enemy skills will prioritise constructs with this skill active',
|
|
||||||
colours: '1 Red 1 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Throw: {
|
|
||||||
description: 'stuns and makes the target take increased red damage',
|
|
||||||
colours: '2 Green',
|
|
||||||
},
|
|
||||||
|
|
||||||
Triage: {
|
|
||||||
description: 'grants a blue damage based healing over time buff',
|
|
||||||
colours: '2 Green',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
SPECS: {
|
|
||||||
Damage: {
|
|
||||||
description: 'Increase red / green / blue power stats construct',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
Hp: {
|
|
||||||
description: 'Increases health of construct',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
Speed: {
|
|
||||||
description: 'Increases speed of construct',
|
|
||||||
upgrades: 'combine with 2 red / blue / green',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
COLOURS: {
|
|
||||||
Red: {
|
|
||||||
description: 'Used to create offensive type combos - fast and chaotic',
|
|
||||||
},
|
|
||||||
|
|
||||||
Green: {
|
|
||||||
description: 'Used to create defensive / healing type combos',
|
|
||||||
},
|
|
||||||
|
|
||||||
Blue: {
|
|
||||||
description: 'Used to create offensive type combos - slow and reliable',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const Header = require('./header');
|
|
||||||
const Home = require('./home');
|
|
||||||
const Menu = require('./menu');
|
|
||||||
const Combat = require('./combat');
|
|
||||||
|
|
||||||
// const Background = require('./background');
|
|
||||||
|
|
||||||
function renderConstructs() {
|
|
||||||
const config = {
|
|
||||||
type: Phaser.CANVAS,
|
|
||||||
// backgroundColor: '#181818',
|
|
||||||
resolution: window.devicePixelRatio,
|
|
||||||
scale: {
|
|
||||||
mode: Phaser.Scale.FIT,
|
|
||||||
width: Math.floor(window.innerHeight * 1.6),
|
|
||||||
height: Math.floor(window.innerHeight),
|
|
||||||
max: {
|
|
||||||
width: Math.floor(window.innerHeight * 1.6),
|
|
||||||
height: Math.floor(window.innerHeight),
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
antialias: true,
|
|
||||||
physics: {
|
|
||||||
default: 'arcade',
|
|
||||||
arcade: {
|
|
||||||
debug: false,
|
|
||||||
gravity: { y: 0 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scene: [
|
|
||||||
// Background,
|
|
||||||
Header,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const game = new Phaser.Game(config);
|
|
||||||
|
|
||||||
|
|
||||||
function changeData(parent, key, data) {
|
|
||||||
// Don't load other scenes if you're not logged in
|
|
||||||
if (!game.registry.get('account')) return false;
|
|
||||||
|
|
||||||
if (key === 'home') {
|
|
||||||
if (data) return game.scene.add('Home', Home, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === 'menu') {
|
|
||||||
if (!data || game.registry.get('inMenu')) return false;
|
|
||||||
if (data) return game.scene.add('Menu', Menu, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === 'game') {
|
|
||||||
if (!data || game.registry.get('inGame')) return false;
|
|
||||||
return game.scene.add('Combat', Combat, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
game.registry.events.on('changedata', changeData);
|
|
||||||
game.registry.events.on('setdata', changeData);
|
|
||||||
|
|
||||||
window.addEventListener('mouseup', () => game.registry.set('pan', false));
|
|
||||||
window.addEventListener('mousedown', () => game.registry.set('pan', true));
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
game.scale.displaySize.maxWidth = window.innerHeight * 1.6;
|
|
||||||
game.scale.displaySize.maxHeight = window.innerHeight;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return game;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = renderConstructs;
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { TEXT } = require('.././constants');
|
|
||||||
|
|
||||||
const BOX = `
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision mediump float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#extension GL_OES_standard_derivatives : enable
|
|
||||||
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision mediump float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#extension GL_OES_standard_derivatives : enable
|
|
||||||
|
|
||||||
uniform float time;
|
|
||||||
uniform vec2 resolution;
|
|
||||||
uniform vec2 dimensions;
|
|
||||||
uniform vec2 offset;
|
|
||||||
uniform vec3 colour;
|
|
||||||
uniform sampler2D uMainSampler;
|
|
||||||
|
|
||||||
|
|
||||||
varying vec2 outTexCoord;
|
|
||||||
varying vec4 outTint;
|
|
||||||
|
|
||||||
float sdBox( in vec2 p, in vec2 b )
|
|
||||||
{
|
|
||||||
vec2 d = abs(p)-b;
|
|
||||||
return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
|
|
||||||
vec2 p = (gl_FragCoord.xy / resolution.xy);
|
|
||||||
p.x -= offset.x / resolution.x + dimensions.x / (2.0 * resolution.x);
|
|
||||||
p.y -= -1.0 * offset.y / resolution.y + ((resolution.y - dimensions.y) / (2.0 * resolution.y)) + 0.5;
|
|
||||||
vec2 dim = 0.5 * dimensions / resolution.xy;
|
|
||||||
float d = sdBox(p, dim);
|
|
||||||
float tb = abs(sin(time)) + 0.9;
|
|
||||||
|
|
||||||
vec3 col = tb * colour - sign(d) * vec3(0.1);
|
|
||||||
col *= 0.0 + exp(-100.0 * abs(d));
|
|
||||||
col += colour * 0.8;
|
|
||||||
vec4 texel = texture2D(uMainSampler, outTexCoord);
|
|
||||||
texel *= vec4(outTint.rgb * outTint.a, outTint.a);
|
|
||||||
|
|
||||||
gl_FragColor = vec4(col, 1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
|
|
||||||
class CustomPipeline extends Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline {
|
|
||||||
constructor(game) {
|
|
||||||
super({ game, renderer: game.renderer, fragShader: BOX });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
const getHex = (c) => {
|
|
||||||
const hex = Math.floor(c * 255).toString(16);
|
|
||||||
return hex.length === 1 ? `0${hex}` : hex;
|
|
||||||
};
|
|
||||||
return `0x${getHex(rgb[0])}${getHex(rgb[1])}${getHex(rgb[2])}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BoxEffect extends Phaser.GameObjects.Graphics {
|
|
||||||
constructor(scene, x, y, width, height, colour, tag) {
|
|
||||||
super(scene);
|
|
||||||
this.tag = tag;
|
|
||||||
this.customPipeline = scene.game.renderer.addPipeline(tag, new CustomPipeline(scene.game));
|
|
||||||
this.customPipeline.setFloat2('resolution', 1600, 1000);
|
|
||||||
this.customPipeline.setFloat2('offset', x, y);
|
|
||||||
this.customPipeline.setFloat2('dimensions', width, height);
|
|
||||||
this.customPipeline.setFloat3('colour', colour[0], colour[1], colour[2]);
|
|
||||||
this.bgTime = 10.0;
|
|
||||||
|
|
||||||
const radius = height / 2;
|
|
||||||
this.fillStyle(rgbToHex(colour), 1.0);
|
|
||||||
this.fillRect(x + radius, y, width - radius * 2, height);
|
|
||||||
this.fillCircle(x + radius, y + radius, radius);
|
|
||||||
this.fillCircle(x + width - radius, y + radius, radius);
|
|
||||||
|
|
||||||
|
|
||||||
this.on('destroy', () => {
|
|
||||||
scene.game.renderer.removePipeline(tag);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
activate() {
|
|
||||||
this.setPipeline(this.tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
deactivate() {
|
|
||||||
this.resetPipeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.bgTime += 0.05;
|
|
||||||
this.customPipeline.setFloat1('time', this.bgTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Button extends Phaser.GameObjects.Group {
|
|
||||||
constructor(scene, props) {
|
|
||||||
const {
|
|
||||||
x, y, width, height, colour, glTag, bText, callback,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
super(scene, { classType: BoxEffect, runChildUpdate: true });
|
|
||||||
|
|
||||||
const leaveGame = scene.add
|
|
||||||
.rectangle(x, y, width, height, 0xaaaaaa, 0xffffff)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
|
|
||||||
const effect = scene.add.existing(new BoxEffect(scene, x, y, width, height, colour, glTag));
|
|
||||||
this.add(effect);
|
|
||||||
|
|
||||||
leaveGame
|
|
||||||
.on('pointerdown', callback)
|
|
||||||
.on('pointerover', () => effect.activate())
|
|
||||||
.on('pointerout', () => effect.deactivate());
|
|
||||||
|
|
||||||
this.buttonText = scene.add.text(leaveGame.getCenter().x, leaveGame.getCenter().y, bText, TEXT.HEADER).setOrigin(0.5, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Button;
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { TEXT, POSITIONS: { COMBAT }, COLOURS } = require('.././constants');
|
|
||||||
|
|
||||||
const CONSTRUCT_MARGIN = COMBAT.constructMargin();
|
|
||||||
const TEXT_MARGIN = COMBAT.textMargin();
|
|
||||||
|
|
||||||
const statBarDimensions = (team, iter, margin) => {
|
|
||||||
const statBarWidth = COMBAT.width() * 0.07;
|
|
||||||
const statBarHeight = TEXT_MARGIN / 1.5;
|
|
||||||
const statBarX = (COMBAT.width() - statBarWidth) * team;
|
|
||||||
const statBarY = COMBAT.y() + TEXT_MARGIN * (margin + 1) + CONSTRUCT_MARGIN * iter + COMBAT.height() * 0.07;
|
|
||||||
return { statBarX, statBarY, statBarWidth, statBarHeight };
|
|
||||||
};
|
|
||||||
|
|
||||||
const statTextCoord = (team, iter, margin) => {
|
|
||||||
const statTextX = team ? COMBAT.width() - COMBAT.width() * 0.075 : COMBAT.width() * 0.075;
|
|
||||||
const statTextY = COMBAT.y() + TEXT_MARGIN * (margin + 1) + CONSTRUCT_MARGIN * iter + COMBAT.height() * 0.07;
|
|
||||||
return { statTextX, statTextY };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class StatBar extends Phaser.GameObjects.Graphics {
|
|
||||||
constructor(scene, construct, type) {
|
|
||||||
super(scene);
|
|
||||||
this.constructObj = construct;
|
|
||||||
this.type = type;
|
|
||||||
|
|
||||||
if (type === 'HP') {
|
|
||||||
this.val = this.constructObj.construct.hp.value;
|
|
||||||
this.max = this.constructObj.construct.hp.max;
|
|
||||||
this.margin = 0;
|
|
||||||
} else if (type === 'Red Shield') {
|
|
||||||
this.val = this.constructObj.construct.red_shield.value;
|
|
||||||
this.max = this.constructObj.construct.red_shield.max;
|
|
||||||
this.margin = 1;
|
|
||||||
} else if (type === 'Blue Shield') {
|
|
||||||
this.val = this.constructObj.construct.blue_shield.value;
|
|
||||||
this.max = this.constructObj.construct.blue_shield.max;
|
|
||||||
this.margin = 2;
|
|
||||||
} else if (type === 'Evasion') {
|
|
||||||
this.val = this.constructObj.construct.evasion.value;
|
|
||||||
this.max = this.constructObj.construct.evasion.max;
|
|
||||||
this.margin = 3;
|
|
||||||
}
|
|
||||||
const { statTextX, statTextY } = statTextCoord(construct.team, construct.iter, this.margin);
|
|
||||||
this.statText = scene.add.text(statTextX, statTextY, '', TEXT.NORMAL).setOrigin(construct.team, 0);
|
|
||||||
this.drawStatBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawStatBar() {
|
|
||||||
this.clear();
|
|
||||||
const {
|
|
||||||
statBarX, statBarY, statBarWidth, statBarHeight,
|
|
||||||
} = statBarDimensions(this.constructObj.team, this.constructObj.iter, this.margin);
|
|
||||||
this.statText.text = `${this.val.toString()} / ${this.max.toString()} ${this.type}`;
|
|
||||||
// Draw Black Border
|
|
||||||
this.fillStyle(COLOURS.BLACK);
|
|
||||||
this.fillRect(statBarX, statBarY, statBarWidth, statBarHeight);
|
|
||||||
// White fill
|
|
||||||
this.fillStyle(COLOURS.WHITE);
|
|
||||||
this.fillRect(statBarX + 2, statBarY + 2, statBarWidth - 4, statBarHeight - 4);
|
|
||||||
// Fill the health bar
|
|
||||||
const statPercentage = this.val / this.max;
|
|
||||||
if (statPercentage < 0.3) {
|
|
||||||
this.fillStyle(COLOURS.RED);
|
|
||||||
} else if (statPercentage < 0.65) {
|
|
||||||
this.fillStyle(COLOURS.YELLOW);
|
|
||||||
} else {
|
|
||||||
this.fillStyle(0x00ff00); // str8 up green
|
|
||||||
}
|
|
||||||
const statWidth = statBarWidth * statPercentage;
|
|
||||||
this.fillRect(statBarX + 2, statBarY + 2, statWidth, statBarHeight - 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
takeDamage(value) {
|
|
||||||
if (value > 0) {
|
|
||||||
this.val = (value >= this.val) ? 0 : this.val -= value;
|
|
||||||
} else {
|
|
||||||
this.val = (this.val - value > this.max) ? this.max : this.val -= value;
|
|
||||||
}
|
|
||||||
if (this.val === 0 && this.type === 'HP') this.constructObj.setKo();
|
|
||||||
this.drawStatBar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = StatBar;
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const {
|
|
||||||
TEXT,
|
|
||||||
COLOURS,
|
|
||||||
} = require('../constants');
|
|
||||||
|
|
||||||
function FindColour(item) {
|
|
||||||
// Future add skills and use a constants lookup file ??
|
|
||||||
switch (item) {
|
|
||||||
case 'Green': return 0x396E26;
|
|
||||||
case 'Red': return 0x622433;
|
|
||||||
case 'Blue': return 0x223158;
|
|
||||||
// case 'Green': return 0x043003;
|
|
||||||
// case 'Red': return 0x5C0202;
|
|
||||||
// case 'Blue': return 0x040345;
|
|
||||||
|
|
||||||
default: return 0x222222;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Item extends Phaser.GameObjects.Container {
|
|
||||||
constructor(scene, item, index, x, y, width, height) {
|
|
||||||
super(scene, x, y);
|
|
||||||
|
|
||||||
this.scene = scene;
|
|
||||||
this.item = item;
|
|
||||||
this.index = index;
|
|
||||||
this.origX = x;
|
|
||||||
this.origY = y;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
|
|
||||||
this.colour = FindColour(item);
|
|
||||||
this.box = scene.add
|
|
||||||
.rectangle(0, 0, width, height, this.colour);
|
|
||||||
|
|
||||||
this.text = scene.add
|
|
||||||
// .text(0, 0, `${action} x${count}`, TEXT.NORMAL)
|
|
||||||
.text(0, 0, `${item}`, TEXT.NORMAL)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
this.add(this.box);
|
|
||||||
this.add(this.text);
|
|
||||||
|
|
||||||
this.setSize(width, height);
|
|
||||||
this.setInteractive();
|
|
||||||
}
|
|
||||||
|
|
||||||
changeOrigin(x, y) {
|
|
||||||
this.origX = x + this.width / 2;
|
|
||||||
this.origY = y + this.height / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Item;
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
class LineBox extends Phaser.GameObjects.Graphics {
|
|
||||||
constructor(scene, x, y, width, height, colour, speed) {
|
|
||||||
super(scene);
|
|
||||||
this.colour = colour;
|
|
||||||
this.x0 = x; this.x1 = x + width;
|
|
||||||
this.y0 = y; this.y1 = y + height;
|
|
||||||
const margin = Math.abs(Math.floor((this.x1 - this.x0) / 4));
|
|
||||||
this.lineCoord = [this.x0 + margin, this.x1 - margin, this.y0, this.y0, 0];
|
|
||||||
this.speed = speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.clear();
|
|
||||||
|
|
||||||
let vertX = this.x1;
|
|
||||||
let horizY = this.y0;
|
|
||||||
const genLine = () => {
|
|
||||||
switch (this.lineCoord[4]) {
|
|
||||||
case 0:
|
|
||||||
if (this.lineCoord[1] < this.x1) return [1, 1, 0, 0, 0];
|
|
||||||
return [0, 0, 0, 0, 1];
|
|
||||||
case 1:
|
|
||||||
if (this.lineCoord[0] < this.x1) return [1, 0, 0, 1, 1];
|
|
||||||
return [0, 0, 0, 0, 2];
|
|
||||||
case 2:
|
|
||||||
if (this.lineCoord[3] < this.y1) return [0, 0, 1, 1, 2];
|
|
||||||
return [0, 0, 0, 0, 3];
|
|
||||||
case 3:
|
|
||||||
horizY = this.y1;
|
|
||||||
if (this.lineCoord[2] < this.y1) return [-1, 0, 1, 0, 3];
|
|
||||||
return [0, 0, 0, 0, 4];
|
|
||||||
case 4:
|
|
||||||
horizY = this.y1;
|
|
||||||
if (this.lineCoord[0] > this.x0) return [-1, -1, 0, 0, 4];
|
|
||||||
return [0, 0, 0, 0, 5];
|
|
||||||
case 5:
|
|
||||||
horizY = this.y1;
|
|
||||||
vertX = this.x0;
|
|
||||||
if (this.lineCoord[1] > this.x0) return [0, -1, -1, 0, 5];
|
|
||||||
return [0, 0, 0, 0, 6];
|
|
||||||
case 6:
|
|
||||||
vertX = this.x0;
|
|
||||||
if (this.lineCoord[2] >= this.y0) return [0, 0, -1, -1, 6];
|
|
||||||
return [0, 0, 0, 0, 7];
|
|
||||||
case 7:
|
|
||||||
vertX = this.x0;
|
|
||||||
if (this.lineCoord[3] >= this.y0) return [0, 1, 0, -1, 7];
|
|
||||||
return [0, 0, 0, 0, 0];
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (let i = 0; i < this.speed; i += 1) {
|
|
||||||
const delta = genLine();
|
|
||||||
this.lineCoord = this.lineCoord.map((x, j) => {
|
|
||||||
if (j < 4) return (x + delta[j]);
|
|
||||||
return delta[j];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.lineStyle(5, this.colour, 1);
|
|
||||||
this.lineBetween(this.lineCoord[0], horizY, this.lineCoord[1], horizY);
|
|
||||||
this.lineBetween(vertX, this.lineCoord[2], vertX, this.lineCoord[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LineGroup extends Phaser.GameObjects.Group {
|
|
||||||
constructor(scene) {
|
|
||||||
super(scene, { classType: LineBox, runChildUpdate: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { LineGroup, LineBox }
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { TEXT, POSITIONS: { MENU_MAIN } } = require('./constants');
|
|
||||||
|
|
||||||
const X = MENU_MAIN.x();
|
|
||||||
const Y = MENU_MAIN.y();
|
|
||||||
const WIDTH = MENU_MAIN.width();
|
|
||||||
const HEIGHT = MENU_MAIN.height();
|
|
||||||
const ROW_SIZE = 50;
|
|
||||||
const LOBBY_WIDTH = WIDTH / 2;
|
|
||||||
|
|
||||||
class GameList extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'GameList' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(gameList) {
|
|
||||||
this.cameras.main.setViewport(X, Y, WIDTH, HEIGHT);
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
|
|
||||||
this.add.text(WIDTH / 3, 0, 'PVP open games', TEXT.HEADER);
|
|
||||||
const gameRow = (game, i) => {
|
|
||||||
const GAME_X = WIDTH / 6;
|
|
||||||
const GAME_Y = 1.3 * ROW_SIZE * (i + 1);
|
|
||||||
|
|
||||||
const gameBox = this.add
|
|
||||||
.rectangle(GAME_X, GAME_Y, LOBBY_WIDTH, ROW_SIZE, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
|
|
||||||
const TITLE = `${game.teams[0].constructs.map(c => c.name).join(', ')} - ${game.team_size}v${game.team_size}`;
|
|
||||||
|
|
||||||
this.add
|
|
||||||
.text(gameBox.getCenter().x, gameBox.getCenter().y, TITLE, TEXT.NORMAL)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
gameBox.on('pointerdown', () => {
|
|
||||||
const constructs = this.registry.get('constructs');
|
|
||||||
const team = constructs.filter(c => c.active).map(c => c.id);
|
|
||||||
ws.sendGameJoin(game.id, team);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
gameList.forEach(gameRow);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = GameList;
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const { TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const aztecAtlas = require('../../assets/aztec.atlas.json');
|
|
||||||
|
|
||||||
|
|
||||||
class Header extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Header', active: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
const aztecImg = new Image();
|
|
||||||
aztecImg.src = `data:image/png;base64,${new Buffer.from(fs.readFileSync('./assets/aztec.clean.png')).toString('base64')}`;
|
|
||||||
aztecImg.onload = () => {
|
|
||||||
this.textures.addAtlas('aztec', aztecImg, aztecAtlas);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.add.text(0, 0, 'constructs.gg', TEXT.HEADER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Header;
|
|
||||||
@ -1,142 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { remove } = require('lodash');
|
|
||||||
|
|
||||||
const { TEXT, COLOURS, POSITIONS: { CONSTRUCT_LIST } } = require('./constants');
|
|
||||||
const genAvatar = require('./avatar');
|
|
||||||
const { LineGroup, LineBox } = require('./elements/outline.rotate');
|
|
||||||
|
|
||||||
const ROW_HEIGHT = CONSTRUCT_LIST.height() * 0.1;
|
|
||||||
const ROW_WIDTH = CONSTRUCT_LIST.width();
|
|
||||||
|
|
||||||
const menuY = CONSTRUCT_LIST.height() * 0.8;
|
|
||||||
|
|
||||||
const KEY_MAP = [
|
|
||||||
'keydown-ONE',
|
|
||||||
'keydown-TWO',
|
|
||||||
'keydown-THREE',
|
|
||||||
];
|
|
||||||
|
|
||||||
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
|
|
||||||
|
|
||||||
class HomeConstructList extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeConstructs' });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'constructList') {
|
|
||||||
KEY_MAP.forEach(k => this.input.keyboard.removeListener(k));
|
|
||||||
this.scene.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
// this.cameras.main.setViewport(CONSTRUCT_LIST.x(), CONSTRUCT_LIST.y(), CONSTRUCT_LIST.width(), CONSTRUCT_LIST.height());
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.events.on('setdata', this.updateData, this);
|
|
||||||
const constructs = this.registry.get('constructList');
|
|
||||||
const lineGroup = this.add.existing(new LineGroup(this));
|
|
||||||
|
|
||||||
if (!constructs) return true;
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
this.activeConstructs = [];
|
|
||||||
// We only display 3 constructs others can be viewed in construct list (soon TM)
|
|
||||||
for (let i = 0; i < constructs.length; i += 1) {
|
|
||||||
const construct = constructs[i];
|
|
||||||
const BOX_WIDTH = Math.floor(ROW_WIDTH / 5);
|
|
||||||
const ROW_X = BOX_WIDTH * 2 * (i % 3);
|
|
||||||
const ROW_Y = CONSTRUCT_LIST.y() + (Math.floor(i / 3)) * ROW_HEIGHT * 1.5;
|
|
||||||
const ACTIVE_FILL = 0.2;
|
|
||||||
|
|
||||||
const FILL = Object.values(COLOURS)[i];
|
|
||||||
// Selection of constructs
|
|
||||||
|
|
||||||
// Construct avatar and interaction box
|
|
||||||
const cReady = this.add
|
|
||||||
.rectangle(ROW_X, ROW_Y + ROW_HEIGHT * 0.2, BOX_WIDTH * 2, ROW_HEIGHT, FILL)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
cReady.setAlpha(0.2);
|
|
||||||
cReady.on('pointerdown', () => {
|
|
||||||
lineGroup.clear(true, true);
|
|
||||||
if (this.activeConstructs.includes(cReady)) {
|
|
||||||
remove(this.activeConstructs, n => n === cReady);
|
|
||||||
cReady.setAlpha(0.2);
|
|
||||||
} else {
|
|
||||||
this.activeConstructs.push(cReady);
|
|
||||||
cReady.setAlpha(0.75);
|
|
||||||
lineGroup.add(this.add.existing(
|
|
||||||
new LineBox(this, cReady.x, cReady.y, cReady.width, cReady.height, cReady.fillColor, 3)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cReady.itemSelect = () => {
|
|
||||||
cReady.setFillStyle(COLOURS.SELECT);
|
|
||||||
};
|
|
||||||
cReady.itemDeselect = () => {
|
|
||||||
cReady.setFillStyle(FILL, ACTIVE_FILL);
|
|
||||||
};
|
|
||||||
|
|
||||||
cReady.construct = construct;
|
|
||||||
this.add.image(
|
|
||||||
cReady.getCenter().x,
|
|
||||||
cReady.getCenter().y,
|
|
||||||
'aztec',
|
|
||||||
genAvatar(construct.name)
|
|
||||||
);
|
|
||||||
this.add.text(ROW_X + BOX_WIDTH, ROW_Y, construct.name, TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Spawn Construct Option
|
|
||||||
const spawn = this.add
|
|
||||||
.rectangle(ROW_WIDTH * 0.05, menuY, ROW_WIDTH * 0.2, ROW_HEIGHT * 0.5, 0x888888)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
this.game.events.emit('CONSTRUCT_SPAWN');
|
|
||||||
});
|
|
||||||
this.add
|
|
||||||
.text(spawn.getCenter().x, spawn.getCenter().y, '+', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
const joinNormal = this.add
|
|
||||||
.rectangle(ROW_WIDTH * 0.3, menuY, ROW_WIDTH * 0.4, ROW_HEIGHT * 0.5, 0x888888)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
const playerConstructs = [];
|
|
||||||
this.activeConstructs.forEach(obj => playerConstructs.push(obj.construct.id));
|
|
||||||
ws.sendPlayerConstructsSet(NULL_UUID, playerConstructs);
|
|
||||||
});
|
|
||||||
this.add
|
|
||||||
.text(joinNormal.getCenter().x, joinNormal.getCenter().y, 'Join Normal', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
const joinInstance = this.add
|
|
||||||
.rectangle(ROW_WIDTH * 0.8, menuY, ROW_WIDTH * 0.4, ROW_HEIGHT * 0.5, 0x888888)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
const playerConstructs = [];
|
|
||||||
this.activeConstructs.forEach(obj => playerConstructs.push(obj.construct.id));
|
|
||||||
ws.sendInstanceJoin(playerConstructs);
|
|
||||||
});
|
|
||||||
this.add
|
|
||||||
.text(joinInstance.getCenter().x, joinInstance.getCenter().y, 'New Instance', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
KEY_MAP.forEach(k => this.input.keyboard.removeListener(k));
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeConstructList;
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { HOME_MAIN }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const X = HOME_MAIN.x();
|
|
||||||
const Y = HOME_MAIN.y();
|
|
||||||
const WIDTH = HOME_MAIN.width();
|
|
||||||
const HEIGHT = HOME_MAIN.height();
|
|
||||||
|
|
||||||
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
|
|
||||||
|
|
||||||
class HomeRankings extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeInstances' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.add.text(X, Y, 'Instances Scene', TEXT.HEADER);
|
|
||||||
const playerList = this.registry.get('playerList');
|
|
||||||
const addInstance = (player, i) => {
|
|
||||||
const joinNormal = this.add
|
|
||||||
.rectangle(X, Y + HEIGHT * 0.15 * (i + 1), WIDTH * 0.5, HEIGHT * 0.1, 0x888888)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
if (player.ready) {
|
|
||||||
this.registry.set('player', player);
|
|
||||||
this.registry.get('ws').sendInstanceReady(player.instance);
|
|
||||||
} else {
|
|
||||||
this.game.events.emit('SET_PLAYER', player);
|
|
||||||
this.registry.get('ws').sendInstanceScores(player.instance);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const name = player.instance === NULL_UUID ? 'Normal Mode' : `${player.instance.substring(0, 5)}`;
|
|
||||||
const disp = player.ready ? name.concat(' - in progress') : name;
|
|
||||||
this.add
|
|
||||||
.text(joinNormal.getCenter().x, joinNormal.getCenter().y, disp, TEXT.NORMAL)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
};
|
|
||||||
|
|
||||||
playerList.forEach(addInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeRankings;
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
|
|
||||||
const HomeConstructs = require('./home.constructs');
|
|
||||||
const HomeNavigation = require('./home.navigation');
|
|
||||||
|
|
||||||
const HomeRankings = require('./home.rankings');
|
|
||||||
const HomeNews = require('./home.news');
|
|
||||||
const HomeShop = require('./home.shop');
|
|
||||||
const HomeInstances = require('./home.instances');
|
|
||||||
|
|
||||||
const FIXED_SCENES = [
|
|
||||||
'HomeConstructs',
|
|
||||||
'HomeNavigation',
|
|
||||||
];
|
|
||||||
|
|
||||||
const VAR_SCENES = [
|
|
||||||
'HomeRankings',
|
|
||||||
'HomeNews',
|
|
||||||
'HomeShop',
|
|
||||||
'HomeInstances',
|
|
||||||
];
|
|
||||||
|
|
||||||
class Home extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Home', active: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.registry.get('ws').sendAccountInstances();
|
|
||||||
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.events.on('setdata', this.updateData, this);
|
|
||||||
this.scene.manager.add('HomeConstructs', HomeConstructs, true);
|
|
||||||
this.scene.manager.add('HomeNavigation', HomeNavigation, true);
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (!data) return false;
|
|
||||||
// Controls which scene shows in the main top right section
|
|
||||||
switch (key) {
|
|
||||||
case 'game': return this.cleanUp();
|
|
||||||
case 'menu': return this.cleanUp();
|
|
||||||
case 'homeInstances': return this.newMainScene('HomeInstances', HomeInstances, data);
|
|
||||||
case 'homeRankings': return this.newMainScene('HomeRankings', HomeRankings, data);
|
|
||||||
case 'homeNews': return this.newMainScene('HomeNews', HomeNews, data);
|
|
||||||
case 'homeShop': return this.newMainScene('HomeShop', HomeShop, data);
|
|
||||||
|
|
||||||
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newMainScene(key, scene, data) {
|
|
||||||
let addScene = true;
|
|
||||||
// List of scenes which could be occupying the main section of the menu
|
|
||||||
VAR_SCENES.forEach((sKey) => {
|
|
||||||
if (this.scene.manager.keys[sKey]) {
|
|
||||||
if (key === sKey) {
|
|
||||||
// If there is new data for the current scene restart
|
|
||||||
this.scene.manager.keys[sKey].scene.restart(data);
|
|
||||||
addScene = false;
|
|
||||||
} else {
|
|
||||||
// Delete the old scene
|
|
||||||
this.scene.manager.keys[sKey].cleanUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (addScene) this.scene.manager.add(key, scene, true, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
// Delete scenes which could be showing before switching to battle scene
|
|
||||||
|
|
||||||
const removeScenes = (sKey) => {
|
|
||||||
if (this.scene.get(sKey)) this.scene.get(sKey).cleanUp();
|
|
||||||
};
|
|
||||||
FIXED_SCENES.forEach(removeScenes);
|
|
||||||
VAR_SCENES.forEach(removeScenes);
|
|
||||||
|
|
||||||
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Home;
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const { TEXT, POSITIONS: { NAVIGATION } } = require('./constants');
|
|
||||||
|
|
||||||
const X = NAVIGATION.x();
|
|
||||||
const Y = NAVIGATION.y();
|
|
||||||
const WIDTH = NAVIGATION.width();
|
|
||||||
const HEIGHT = NAVIGATION.height();
|
|
||||||
|
|
||||||
const BTN_WIDTH = Math.floor(WIDTH / 6);
|
|
||||||
const BTN_HEIGHT = Math.floor(HEIGHT / 3);
|
|
||||||
|
|
||||||
class HomeNavigation extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeNavigation' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
/* const ranks = this.add
|
|
||||||
.rectangle(X, Y, BTN_WIDTH, BTN_HEIGHT, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
this.add
|
|
||||||
.text(ranks.getCenter().x, ranks.getCenter().y, 'Rankings', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
ranks.on('pointerdown', () => this.registry.set('homeRankings', true));
|
|
||||||
|
|
||||||
const news = this.add
|
|
||||||
.rectangle(X + BTN_WIDTH * 1.5, Y, BTN_WIDTH, BTN_HEIGHT, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
this.add
|
|
||||||
.text(news.getCenter().x, news.getCenter().y, 'News', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
news.on('pointerdown', () => this.registry.set('homeNews', true));
|
|
||||||
|
|
||||||
const shop = this.add
|
|
||||||
.rectangle(X + BTN_WIDTH * 3, Y, BTN_WIDTH, BTN_HEIGHT, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
this.add
|
|
||||||
.text(shop.getCenter().x, shop.getCenter().y, 'Shop', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
shop.on('pointerdown', () => this.registry.set('homeShop', true));
|
|
||||||
|
|
||||||
const instances = this.add
|
|
||||||
.rectangle(X + BTN_WIDTH * 4.5, Y, BTN_WIDTH, BTN_HEIGHT, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
this.add
|
|
||||||
.text(instances.getCenter().x, instances.getCenter().y, 'Instances', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
instances.on('pointerdown', () => this.registry.set('homeInstances', true));*/
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeNavigation;
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { HOME_MAIN }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const X = HOME_MAIN.x();
|
|
||||||
const Y = HOME_MAIN.y();
|
|
||||||
const WIDTH = HOME_MAIN.width();
|
|
||||||
const HEIGHT = HOME_MAIN.height();
|
|
||||||
|
|
||||||
class HomeNews extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeNews' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.add.text(X, Y, 'News Scene', TEXT.HEADER);
|
|
||||||
this.add.text(X, Y + HEIGHT * 0.1, 'some other stuff here', TEXT.NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeNews;
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { HOME_MAIN }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const X = HOME_MAIN.x();
|
|
||||||
const Y = HOME_MAIN.y();
|
|
||||||
const WIDTH = HOME_MAIN.width();
|
|
||||||
const HEIGHT = HOME_MAIN.height();
|
|
||||||
|
|
||||||
class HomeRankings extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeRankings' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.add.text(X, Y, 'Rankings Scene', TEXT.HEADER);
|
|
||||||
this.add.text(X, Y + HEIGHT * 0.1, 'some stuff here', TEXT.NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeRankings;
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { HOME_MAIN }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const X = HOME_MAIN.x();
|
|
||||||
const Y = HOME_MAIN.y();
|
|
||||||
const WIDTH = HOME_MAIN.width();
|
|
||||||
const HEIGHT = HOME_MAIN.height();
|
|
||||||
|
|
||||||
class HomeShop extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'HomeShop' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.add.text(X, Y, 'Shop Scene', TEXT.HEADER);
|
|
||||||
this.add.text(X, Y + HEIGHT * 0.1, 'rulul', TEXT.NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = HomeShop;
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { MENU_MAIN }, TEXT, ITEMS: { SKILLS, SPECS, COLOURS } } = require('./constants');
|
|
||||||
|
|
||||||
const X = MENU_MAIN.x();
|
|
||||||
const Y = MENU_MAIN.y();
|
|
||||||
const WIDTH = MENU_MAIN.width();
|
|
||||||
const HEIGHT = MENU_MAIN.height();
|
|
||||||
|
|
||||||
const UNEQUIP_Y = Y + Math.floor(HEIGHT * 0.7);
|
|
||||||
const UNEQUIP_WIDTH = Math.floor(WIDTH * 0.4);
|
|
||||||
const UNEQUIP_HEIGHT = Math.floor(HEIGHT * 0.15);
|
|
||||||
|
|
||||||
class ItemInfo extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'ItemInfo' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(props) {
|
|
||||||
const { item, construct } = props;
|
|
||||||
if (!item) return false;
|
|
||||||
|
|
||||||
// Default item text
|
|
||||||
let title = item;
|
|
||||||
let description = 'Description missing';
|
|
||||||
let upgrades = '';
|
|
||||||
let colours = '';
|
|
||||||
|
|
||||||
// Replace item text with constants if it exists
|
|
||||||
if (SKILLS[item]) {
|
|
||||||
title = `Skill Item - ${item}`;
|
|
||||||
({ description } = SKILLS[item]);
|
|
||||||
if (SKILLS[item].upgrades) ({ upgrades } = SKILLS[item]);
|
|
||||||
if (SKILLS[item].colours) ({ colours } = SKILLS[item]);
|
|
||||||
} else if (SPECS[item]) {
|
|
||||||
title = `Spec Item - ${item}`;
|
|
||||||
({ description } = SPECS[item]);
|
|
||||||
if (SPECS[item].upgrades) ({ upgrades } = SPECS[item]);
|
|
||||||
} else if (COLOURS[item]) {
|
|
||||||
title = `Colour Item - ${item}`;
|
|
||||||
({ description } = COLOURS[item]);
|
|
||||||
if (COLOURS[item].upgrades) ({ upgrades } = COLOURS[item]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add text objects
|
|
||||||
this.add.text(X, Y, title, TEXT.HEADER);
|
|
||||||
this.add
|
|
||||||
.text(X, Y + HEIGHT * 0.1, description, TEXT.NORMAL)
|
|
||||||
.setWordWrapWidth(WIDTH * 0.75);
|
|
||||||
this.add
|
|
||||||
.text(X, Y + HEIGHT * 0.25, upgrades, TEXT.NORMAL)
|
|
||||||
.setWordWrapWidth(WIDTH * 0.75);
|
|
||||||
if (colours !== '') {
|
|
||||||
this.add
|
|
||||||
.text(X, Y + HEIGHT * 0.35, `Adds ${colours} to construct`, TEXT.NORMAL)
|
|
||||||
.setWordWrapWidth(WIDTH * 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!construct) return true;
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
const { vbox } = this.registry.get('player');
|
|
||||||
const unEquip = this.add.rectangle(X, UNEQUIP_Y, UNEQUIP_WIDTH, UNEQUIP_HEIGHT, 0x222222)
|
|
||||||
.setOrigin(0, 0)
|
|
||||||
.setInteractive()
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
ws.sendVboxUnequip(vbox.instance, construct.id, item);
|
|
||||||
this.registry.set('constructStats', construct);
|
|
||||||
});
|
|
||||||
this.add.text(unEquip.getCenter().x, unEquip.getCenter().y, 'unequip', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ItemInfo;
|
|
||||||
@ -1,323 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const Item = require('./elements/item');
|
|
||||||
|
|
||||||
const {
|
|
||||||
TEXT,
|
|
||||||
POSITIONS: { ITEM_LIST },
|
|
||||||
} = require('./constants');
|
|
||||||
|
|
||||||
const X = ITEM_LIST.x();
|
|
||||||
const Y = ITEM_LIST.y();
|
|
||||||
const WIDTH = ITEM_LIST.width();
|
|
||||||
const HEIGHT = ITEM_LIST.height();
|
|
||||||
const ITEM_WIDTH = ITEM_LIST.itemWidth();
|
|
||||||
const ITEM_HEIGHT = ITEM_LIST.itemHeight();
|
|
||||||
|
|
||||||
const BOX_X = X + ITEM_WIDTH * 0.5;
|
|
||||||
const BOX_Y = Y + ITEM_HEIGHT + ITEM_HEIGHT * 2;
|
|
||||||
const BOX_ROWS = 6;
|
|
||||||
const BOX_COLUMNS = 3;
|
|
||||||
|
|
||||||
const INV_X = X + ITEM_WIDTH * 0.5;
|
|
||||||
const INV_Y = Y + ITEM_HEIGHT * 12;
|
|
||||||
const INV_ROWS = 3;
|
|
||||||
const INV_COLUMNS = 3;
|
|
||||||
|
|
||||||
const COMB_X = X + ITEM_WIDTH * 0.5;
|
|
||||||
const COMB_Y = Y + ITEM_HEIGHT * 19;
|
|
||||||
const COMB_ROWS = 1;
|
|
||||||
const COMB_COLUMNS = 3;
|
|
||||||
|
|
||||||
const drawVbox = (graphics) => {
|
|
||||||
const boxDrawX = BOX_X - ITEM_WIDTH * 0.05;
|
|
||||||
const boxDrawY = BOX_Y - ITEM_HEIGHT * 0.05;
|
|
||||||
graphics.strokeRect(boxDrawX, boxDrawY, ITEM_WIDTH * 1.1 * BOX_COLUMNS, ITEM_HEIGHT * 1.1 * BOX_ROWS);
|
|
||||||
|
|
||||||
for (let i = 0; i < (BOX_COLUMNS - 1); i += 1) {
|
|
||||||
const x = boxDrawX + (i + 1) * ITEM_WIDTH * 1.1;
|
|
||||||
graphics.lineBetween(x, boxDrawY, x, boxDrawY + ITEM_HEIGHT * 1.1 * BOX_ROWS);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < (BOX_ROWS - 1); i += 1) {
|
|
||||||
const y = boxDrawY + (i + 1) * ITEM_HEIGHT * 1.1;
|
|
||||||
graphics.lineBetween(boxDrawX, y, boxDrawX + ITEM_WIDTH * 1.1 * BOX_COLUMNS, y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawInventory = (graphics) => {
|
|
||||||
const invDrawX = INV_X - ITEM_WIDTH * 0.05;
|
|
||||||
const invDrawY = INV_Y - ITEM_HEIGHT * 0.05;
|
|
||||||
graphics.strokeRect(invDrawX, invDrawY, ITEM_WIDTH * 1.1 * INV_COLUMNS, ITEM_HEIGHT * 1.1 * INV_ROWS);
|
|
||||||
|
|
||||||
for (let i = 0; i < (INV_COLUMNS - 1); i += 1) {
|
|
||||||
const x = invDrawX + (i + 1) * ITEM_WIDTH * 1.1;
|
|
||||||
graphics.lineBetween(x, invDrawY, x, invDrawY + ITEM_HEIGHT * 1.1 * INV_ROWS);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < (INV_ROWS - 1); i += 1) {
|
|
||||||
const y = invDrawY + (i + 1) * ITEM_HEIGHT * 1.1;
|
|
||||||
graphics.lineBetween(invDrawX, y, invDrawX + ITEM_WIDTH * 1.1 * INV_COLUMNS, y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawCombiner = (graphics) => {
|
|
||||||
const combDrawX = COMB_X - ITEM_WIDTH * 0.05;
|
|
||||||
const combDrawY = COMB_Y - ITEM_HEIGHT * 0.05;
|
|
||||||
graphics.strokeRect(combDrawX, combDrawY, ITEM_WIDTH * 1.1 * COMB_COLUMNS, ITEM_HEIGHT * 1.1 * COMB_ROWS);
|
|
||||||
|
|
||||||
for (let i = 0; i < (COMB_COLUMNS - 1); i += 1) {
|
|
||||||
const x = combDrawX + (i + 1) * ITEM_WIDTH * 1.1;
|
|
||||||
graphics.lineBetween(x, combDrawY, x, combDrawY + ITEM_HEIGHT * 1.1 * COMB_ROWS);
|
|
||||||
}
|
|
||||||
for (let i = 0; i <= (COMB_ROWS - 1); i += 1) {
|
|
||||||
const y = combDrawY + (i + 1) * ITEM_HEIGHT * 1.1;
|
|
||||||
graphics.lineBetween(combDrawX, y, combDrawX + ITEM_WIDTH * 1.1 * COMB_COLUMNS, y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CombinerHitBox extends Phaser.GameObjects.Rectangle {
|
|
||||||
constructor(scene, x, y, i) {
|
|
||||||
super(scene, x, y, ITEM_WIDTH, ITEM_HEIGHT, 0x000000);
|
|
||||||
this.setOrigin(0);
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.slot = i;
|
|
||||||
this.item = false;
|
|
||||||
this.itemSelect = () => this.setFillStyle(0x222222);
|
|
||||||
this.itemDeselect = () => this.setFillStyle(0x000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
allocate(item) {
|
|
||||||
if (this.item) this.deallocate();
|
|
||||||
item.setPosition(this.x + item.width / 2, this.y + item.height / 2);
|
|
||||||
this.item = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
deallocate() {
|
|
||||||
if (this.item) this.item.setPosition(this.item.origX, this.item.origY);
|
|
||||||
this.item = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeleteHitBox extends Phaser.GameObjects.Rectangle {
|
|
||||||
constructor(scene, x, y) {
|
|
||||||
super(scene, x, y, ITEM_WIDTH * 3.4, ITEM_HEIGHT * 1.25, 0x444444);
|
|
||||||
this.setOrigin(0);
|
|
||||||
this.itemSelect = () => this.setFillStyle(0xff0000);
|
|
||||||
this.itemDeselect = () => this.setFillStyle(0x444444);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const itemCheckHitbox = (scene, pointer) => {
|
|
||||||
const { list } = scene.scene.get('MenuConstructList').children;
|
|
||||||
const hitboxes = list.filter(c => c.construct)
|
|
||||||
.concat(scene.children.list.filter(c => c instanceof CombinerHitBox || c instanceof DeleteHitBox));
|
|
||||||
|
|
||||||
let found;
|
|
||||||
for (let i = 0; i < hitboxes.length; i += 1) {
|
|
||||||
if (Phaser.Geom.Rectangle.ContainsPoint(hitboxes[i].getBounds(), pointer.position)) {
|
|
||||||
found = hitboxes[i];
|
|
||||||
} else {
|
|
||||||
hitboxes[i].itemDeselect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ItemList extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'ItemList', active: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'player' || key === 'scores') {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
this.scene.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
const player = this.registry.get('player');
|
|
||||||
const scores = this.registry.get('scores') || [];
|
|
||||||
if (!player) return false;
|
|
||||||
const { vbox } = player;
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.events.on('setdata', this.updateData, this);
|
|
||||||
if (!vbox.bound) return false;
|
|
||||||
if (!this.combinerItems || vbox.bound.length < this.registry.get('boundLength')) {
|
|
||||||
this.combinerItems = [-1, -1, -1];
|
|
||||||
}
|
|
||||||
this.registry.set('boundLength', vbox.bound.length);
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
|
|
||||||
// Static Elements
|
|
||||||
const graphics = this.add.graphics();
|
|
||||||
graphics.lineStyle(5, 0x808080, 1.0);
|
|
||||||
drawCombiner(graphics);
|
|
||||||
drawInventory(graphics);
|
|
||||||
drawVbox(graphics);
|
|
||||||
|
|
||||||
this.add.text(X + ITEM_WIDTH * 0.5, Y + ITEM_HEIGHT * 0.5, `vBox - ${vbox.bits}b`, TEXT.HEADER);
|
|
||||||
this.add.text(X + ITEM_WIDTH * 0.5, Y + ITEM_HEIGHT * 11, 'inventory', TEXT.HEADER);
|
|
||||||
this.add.text(X + ITEM_WIDTH * 0.5, Y + ITEM_HEIGHT * 18, 'iCombinator', TEXT.HEADER);
|
|
||||||
this.add.text(X + ITEM_WIDTH * 0.5, Y + ITEM_HEIGHT * 23, `Wins: ${player.score.wins}`, TEXT.HEADER);
|
|
||||||
this.add.text(X + ITEM_WIDTH * 0.5, Y + ITEM_HEIGHT * 24, `Losses: ${player.score.losses}`, TEXT.HEADER);
|
|
||||||
|
|
||||||
const discard = this.add
|
|
||||||
.rectangle(X + ITEM_WIDTH * 0.4, Y + ITEM_HEIGHT * 1.5, ITEM_WIDTH * 3.4, ITEM_HEIGHT * 1.25, 0x444444)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => this.registry.get('ws').sendVboxDiscard(vbox.instance));
|
|
||||||
this.add.text(discard.getCenter().x, discard.getCenter().y, 'discard - 5b', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
const combine = this.add
|
|
||||||
.rectangle(X + ITEM_WIDTH * 0.4, Y + ITEM_HEIGHT * 20.25, ITEM_WIDTH * 3.4, ITEM_HEIGHT * 1.25, 0x444444)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => {
|
|
||||||
ws.sendVboxCombine(vbox.instance, this.combinerItems);
|
|
||||||
this.combinerItems = [-1, -1, -1];
|
|
||||||
this.children.list.filter(obj => obj instanceof CombinerHitBox).forEach(cBox => cBox.deallocate());
|
|
||||||
});
|
|
||||||
this.add.text(combine.getCenter().x, combine.getCenter().y, 'combine', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
for (let i = 0; i < 3; i += 1) {
|
|
||||||
const ITEM_X = ITEM_WIDTH * 1.1 * (i % COMB_COLUMNS) + COMB_X;
|
|
||||||
const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / COMB_COLUMNS) + COMB_Y;
|
|
||||||
this.add.existing(new CombinerHitBox(this, ITEM_X, ITEM_Y, i));
|
|
||||||
}
|
|
||||||
const del = this.add.existing(new DeleteHitBox(this, X + ITEM_WIDTH * 0.4, Y + ITEM_HEIGHT * 15.5));
|
|
||||||
this.add.text(del.getCenter().x, del.getCenter().y, 'drop', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
// Generate Items
|
|
||||||
vbox.bound.forEach((item, i) => {
|
|
||||||
const ITEM_X = ITEM_WIDTH * 1.1 * (i % INV_COLUMNS) + INV_X + ITEM_WIDTH * 0.5;
|
|
||||||
const ITEM_Y = ITEM_HEIGHT * 1.1 * Math.floor(i / INV_COLUMNS) + INV_Y + ITEM_HEIGHT * 0.5;
|
|
||||||
const clickFn = () => this.registry.set('itemInfo', { item });
|
|
||||||
const itemBox = new Item(this, item, i, ITEM_X, ITEM_Y, ITEM_WIDTH, ITEM_HEIGHT);
|
|
||||||
itemBox.on('pointerdown', clickFn);
|
|
||||||
|
|
||||||
this.input.setDraggable(itemBox);
|
|
||||||
this.add.existing(itemBox);
|
|
||||||
});
|
|
||||||
|
|
||||||
vbox.free.forEach((type, i) => {
|
|
||||||
type.forEach((item, j) => {
|
|
||||||
const ITEM_X = ITEM_WIDTH * 1.1 * i + BOX_X + ITEM_WIDTH * 0.5;
|
|
||||||
const ITEM_Y = ITEM_HEIGHT * 1.1 * j + BOX_Y + ITEM_HEIGHT * 0.5;
|
|
||||||
const clickFn = () => {
|
|
||||||
this.registry.set('itemInfo', { item });
|
|
||||||
ws.sendVboxAccept(vbox.instance, i, j);
|
|
||||||
};
|
|
||||||
const itemBox = new Item(this, item, i, ITEM_X, ITEM_Y, ITEM_WIDTH, ITEM_HEIGHT);
|
|
||||||
itemBox.on('pointerdown', clickFn);
|
|
||||||
this.add.existing(itemBox);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Restore previous combiner item slots
|
|
||||||
this.combinerItems.forEach((index, i) => {
|
|
||||||
if (index === -1) return false;
|
|
||||||
const item = this.children.list.filter(obj => obj instanceof Item).find(it => it.index === index);
|
|
||||||
const hitBox = this.children.list.filter(obj => obj instanceof CombinerHitBox).find(hb => hb.slot === i);
|
|
||||||
if (item) hitBox.allocate(item);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// allocation functions
|
|
||||||
const allocate = (item, hitBox) => {
|
|
||||||
hitBox.allocate(item);
|
|
||||||
this.combinerItems[hitBox.slot] = item.index;
|
|
||||||
this.registry.set('combinerItems', this.combinerItems);
|
|
||||||
};
|
|
||||||
|
|
||||||
const deallocate = (item) => {
|
|
||||||
const clearIndex = this.combinerItems.indexOf(item.index);
|
|
||||||
if (clearIndex !== -1) {
|
|
||||||
this.children.list.filter(obj => obj instanceof CombinerHitBox)
|
|
||||||
.forEach((cBox) => {
|
|
||||||
if (cBox.item === item) cBox.deallocate();
|
|
||||||
});
|
|
||||||
this.combinerItems[clearIndex] = -1;
|
|
||||||
this.registry.set('combinerItems', this.combinerItems);
|
|
||||||
}
|
|
||||||
item.setPosition(item.origX, item.origY);
|
|
||||||
};
|
|
||||||
|
|
||||||
const findUnallocated = () => {
|
|
||||||
for (let i = 0; i <= 2; i += 1) {
|
|
||||||
if (this.combinerItems[i] === -1) {
|
|
||||||
return this.children.list.filter(obj => obj instanceof CombinerHitBox).find(hb => hb.slot === i);
|
|
||||||
}
|
|
||||||
} return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this.add.text(ITEM_WIDTH * 11, ITEM_HEIGHT * 1.1, 'Scoreboard', TEXT.HEADER);
|
|
||||||
// scores.forEach(([name, score], i) => {
|
|
||||||
// const SCORE_X = ITEM_WIDTH * 11;
|
|
||||||
// const SCORE_Y = ITEM_HEIGHT * 1.1 * (i + 2);
|
|
||||||
// this.add.text(SCORE_X, SCORE_Y, `${score.wins} - ${score.losses} | ${name}`, TEXT.NORMAL);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Add Handlers
|
|
||||||
this.input.on('dragstart', (pointer, item) => {
|
|
||||||
if (!(item instanceof Item)) return false;
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.input.on('drag', (pointer, item, dragX, dragY) => {
|
|
||||||
if (!(item instanceof Item)) return false;
|
|
||||||
item.setPosition(dragX, dragY);
|
|
||||||
const hitBox = itemCheckHitbox(this, pointer);
|
|
||||||
if (hitBox) hitBox.itemSelect();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.input.on('dragend', (pointer, item) => {
|
|
||||||
if (!(item instanceof Item)) return false;
|
|
||||||
// Check first for hitbox interaction
|
|
||||||
const hitBox = itemCheckHitbox(this, pointer);
|
|
||||||
if (hitBox) {
|
|
||||||
// hitbox can only be the combinerhitbox, deletehitbox or construct avatar
|
|
||||||
hitBox.itemDeselect();
|
|
||||||
if (hitBox instanceof CombinerHitBox) {
|
|
||||||
if (hitBox.item === item) deallocate(item);
|
|
||||||
else allocate(item, hitBox);
|
|
||||||
} else if (hitBox instanceof DeleteHitBox) {
|
|
||||||
ws.sendVboxReclaim(vbox.instance, item.index);
|
|
||||||
} else {
|
|
||||||
ws.sendVboxApply(vbox.instance, hitBox.construct.id, item.index);
|
|
||||||
deallocate(item);
|
|
||||||
} return true;
|
|
||||||
}
|
|
||||||
// If not interacting with hitbox and didn't move much try to allocate the item
|
|
||||||
if (Math.hypot(item.x - item.origX, item.y - item.origY) < Math.hypot(item.width, item.height)) {
|
|
||||||
// Check theres a free combiner slot
|
|
||||||
const cBox = findUnallocated();
|
|
||||||
if (cBox) {
|
|
||||||
allocate(item, cBox);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the item hasn't been allocated above reset to natural location
|
|
||||||
// Check if item needs to be deallocated
|
|
||||||
// Scene will restart if there is vbox change
|
|
||||||
deallocate(item);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ItemList;
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const { TEXT, COLOURS, POSITIONS: { CONSTRUCT_LIST } } = require('./constants');
|
|
||||||
const genAvatar = require('./avatar');
|
|
||||||
const Item = require('./elements/item');
|
|
||||||
|
|
||||||
const BOX_WIDTH = Math.floor(CONSTRUCT_LIST.width());
|
|
||||||
const BOX_HEIGHT = Math.floor(CONSTRUCT_LIST.height() / 3.34);
|
|
||||||
|
|
||||||
const TEXT_MARGIN = 24;
|
|
||||||
|
|
||||||
const KEY_MAP = [
|
|
||||||
'keydown-ONE',
|
|
||||||
'keydown-TWO',
|
|
||||||
'keydown-THREE',
|
|
||||||
];
|
|
||||||
|
|
||||||
class MenuConstructList extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'MenuConstructList' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.events.on('setdata', this.updateData, this);
|
|
||||||
const player = this.registry.get('player');
|
|
||||||
if (player) this.drawConstructs(player.constructs);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'player') {
|
|
||||||
this.drawConstructs(data.constructs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawConstructs(constructs) {
|
|
||||||
if (!constructs) return true;
|
|
||||||
if (this.constructGroup) this.constructGroup.destroy(true);
|
|
||||||
this.constructGroup = this.add.group();
|
|
||||||
const addConstruct = (construct, i) => {
|
|
||||||
const ROW_X = CONSTRUCT_LIST.x();
|
|
||||||
const ROW_Y = CONSTRUCT_LIST.y() + BOX_HEIGHT * i * 1.1;
|
|
||||||
|
|
||||||
|
|
||||||
const ACTIVE_FILL = 0.2;
|
|
||||||
|
|
||||||
const FILL = Object.values(COLOURS)[i];
|
|
||||||
// Selection of constructs
|
|
||||||
const selectFn = () => {
|
|
||||||
this.registry.set('constructStats', construct);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Construct interaction box for adding items
|
|
||||||
const constructInteract = this.add
|
|
||||||
.rectangle(ROW_X, ROW_Y, BOX_WIDTH, BOX_HEIGHT, FILL, ACTIVE_FILL)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', selectFn);
|
|
||||||
constructInteract.itemSelect = () => {
|
|
||||||
constructInteract.setFillStyle(COLOURS.SELECT);
|
|
||||||
};
|
|
||||||
constructInteract.itemDeselect = () => {
|
|
||||||
constructInteract.setFillStyle(FILL, ACTIVE_FILL);
|
|
||||||
};
|
|
||||||
constructInteract.construct = construct;
|
|
||||||
|
|
||||||
// Construct Avatar
|
|
||||||
const { name } = construct;
|
|
||||||
const constructImage = this.add.image(
|
|
||||||
constructInteract.getCenter().x - constructInteract.width / 4,
|
|
||||||
constructInteract.getCenter().y,
|
|
||||||
'aztec',
|
|
||||||
genAvatar(name)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add text info
|
|
||||||
const yConstructTextAlgin = Math.floor(constructInteract.y + TEXT_MARGIN / 2);
|
|
||||||
const xConstructNameAlign = Math.floor(constructInteract.x + constructInteract.width * 1 / 10);
|
|
||||||
const constructInfoText = this.add.text(xConstructNameAlign, yConstructTextAlgin, name, TEXT.HEADER);
|
|
||||||
const colourText = (c, j) => {
|
|
||||||
// Placeholder for when gems are implemented
|
|
||||||
const gemText = this.add.text(constructInteract.x + constructInteract.width * (j + 3) / 6, yConstructTextAlgin, `${c[0]} - ${c[1]}`, TEXT.HEADER);
|
|
||||||
this.constructGroup.add(gemText);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { red, green, blue } = construct.colours;
|
|
||||||
const CONSTRUCT_COLOURS = [
|
|
||||||
['R', red],
|
|
||||||
['G', green],
|
|
||||||
['B', blue],
|
|
||||||
];
|
|
||||||
CONSTRUCT_COLOURS.forEach(colourText);
|
|
||||||
|
|
||||||
this.constructGroup.addMultiple([constructInteract, constructImage, constructInfoText]);
|
|
||||||
|
|
||||||
const constructSkill = (stat, j) => {
|
|
||||||
const SKILL_WIDTH = Math.floor(BOX_WIDTH / 2);
|
|
||||||
const SKILL_HEIGHT = Math.floor(BOX_HEIGHT / 8);
|
|
||||||
const SKILL_X = constructInteract.getCenter().x + constructInteract.width / 4;
|
|
||||||
const SKILL_Y = constructInteract.y + SKILL_HEIGHT * 1.15 * (j + 1.6);
|
|
||||||
const itemObj = new Item(this, stat.skill, j, SKILL_X, SKILL_Y, SKILL_WIDTH, SKILL_HEIGHT);
|
|
||||||
this.add.existing(itemObj);
|
|
||||||
itemObj.setInteractive();
|
|
||||||
const itemInfo = { item: stat.skill, construct };
|
|
||||||
itemObj.on('pointerdown', () => this.registry.set('itemInfo', itemInfo));
|
|
||||||
this.constructGroup.add(itemObj);
|
|
||||||
};
|
|
||||||
construct.skills.forEach(constructSkill);
|
|
||||||
|
|
||||||
const constructSpec = (spec, j) => {
|
|
||||||
const SKILL_WIDTH = Math.floor(BOX_WIDTH * 0.15);
|
|
||||||
const SKILL_HEIGHT = Math.floor(BOX_HEIGHT * 0.2);
|
|
||||||
const SKILL_X = Math.floor(constructInteract.x + BOX_WIDTH * (0.6 + j) * 0.175);
|
|
||||||
const SKILL_Y = Math.floor(constructInteract.y + BOX_HEIGHT * 0.875);
|
|
||||||
const itemObj = new Item(this, spec, j, SKILL_X, SKILL_Y, SKILL_WIDTH, SKILL_HEIGHT);
|
|
||||||
itemObj.setInteractive();
|
|
||||||
const itemInfo = { item: spec, construct };
|
|
||||||
itemObj.on('pointerdown', () => this.registry.set('itemInfo', itemInfo));
|
|
||||||
this.add.existing(itemObj);
|
|
||||||
this.constructGroup.add(itemObj);
|
|
||||||
};
|
|
||||||
construct.specs.forEach(constructSpec);
|
|
||||||
};
|
|
||||||
constructs.forEach(addConstruct);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
KEY_MAP.forEach(k => this.input.keyboard.removeListener(k));
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MenuConstructList;
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
// Scenes constantly showing
|
|
||||||
const MenuConstructList = require('./menu.constructs.list');
|
|
||||||
const MenuNavigation = require('./menu.navigation');
|
|
||||||
const ItemList = require('./item.list');
|
|
||||||
// Scenes which change depending on menu context
|
|
||||||
const Zones = require('./zones');
|
|
||||||
const GameList = require('./game.list');
|
|
||||||
const StatSheet = require('./statsheet');
|
|
||||||
const ItemInfo = require('./item.info');
|
|
||||||
|
|
||||||
const FIXED_MENU_SCENES = [
|
|
||||||
'MenuConstructList',
|
|
||||||
'MenuNavigation',
|
|
||||||
'ItemList',
|
|
||||||
];
|
|
||||||
|
|
||||||
const MAIN_MENU_SCENES = [
|
|
||||||
'Zones',
|
|
||||||
'GameList',
|
|
||||||
'StatSheet',
|
|
||||||
'ItemInfo',
|
|
||||||
];
|
|
||||||
|
|
||||||
class Menu extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Menu', active: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
this.registry.events.on('setdata', this.updateData, this);
|
|
||||||
|
|
||||||
// Request the latest player state when we load the scene
|
|
||||||
const player = this.registry.get('player');
|
|
||||||
this.registry.get('ws').sendPlayerState(player.instance);
|
|
||||||
// When we load the menu request the latest items
|
|
||||||
// Item list will restart when the data comes in
|
|
||||||
this.scene.manager.add('MenuConstructList', MenuConstructList, true);
|
|
||||||
this.scene.manager.add('MenuNavigation', MenuNavigation, true);
|
|
||||||
this.scene.manager.add('ItemList', ItemList, true);
|
|
||||||
this.registry.set('inMenu', true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (!data) return false;
|
|
||||||
// Controls which scene shows in the main top right section
|
|
||||||
switch (key) {
|
|
||||||
case 'game': return this.cleanUp();
|
|
||||||
case 'home': return this.cleanUp();
|
|
||||||
case 'zone': return this.newMainScene('Zones', Zones, data);
|
|
||||||
case 'gameList': return this.newMainScene('GameList', GameList, data);
|
|
||||||
case 'constructStats': return this.newMainScene('StatSheet', StatSheet, data);
|
|
||||||
case 'itemInfo': return this.newMainScene('ItemInfo', ItemInfo, data);
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newMainScene(key, scene, data) {
|
|
||||||
let addScene = true;
|
|
||||||
// List of scenes which could be occupying the main section of the menu
|
|
||||||
MAIN_MENU_SCENES.forEach((sKey) => {
|
|
||||||
if (this.scene.manager.keys[sKey]) {
|
|
||||||
if (key === sKey) {
|
|
||||||
// If there is new data for the current scene restart
|
|
||||||
this.scene.manager.keys[sKey].scene.restart(data);
|
|
||||||
addScene = false;
|
|
||||||
} else {
|
|
||||||
// Delete the old scene
|
|
||||||
this.scene.manager.keys[sKey].cleanUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (addScene) this.scene.manager.add(key, scene, true, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.registry.events.off('setdata', this.updateData, this);
|
|
||||||
// Delete scenes which could be showing before switching to battle scene
|
|
||||||
const removeScenes = (sKey) => {
|
|
||||||
if (this.scene.get(sKey)) this.scene.get(sKey).cleanUp();
|
|
||||||
};
|
|
||||||
FIXED_MENU_SCENES.forEach(removeScenes);
|
|
||||||
MAIN_MENU_SCENES.forEach(removeScenes);
|
|
||||||
this.registry.set('inMenu', false);
|
|
||||||
this.combinerItems = this.registry.set('combinerItems', null);
|
|
||||||
|
|
||||||
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Menu;
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const { TEXT, POSITIONS: { NAVIGATION } } = require('./constants');
|
|
||||||
|
|
||||||
const X = NAVIGATION.x();
|
|
||||||
const Y = NAVIGATION.y();
|
|
||||||
const WIDTH = NAVIGATION.width();
|
|
||||||
const HEIGHT = NAVIGATION.height();
|
|
||||||
|
|
||||||
const BTN_WIDTH = Math.floor(WIDTH / 4);
|
|
||||||
const BTN_HEIGHT = Math.floor(HEIGHT / 2);
|
|
||||||
|
|
||||||
class MenuNavigation extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'MenuNavigation' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
const ws = this.registry.get('ws');
|
|
||||||
const player = this.registry.get('player');
|
|
||||||
this.cameras.main.setViewport(X, Y, WIDTH, HEIGHT);
|
|
||||||
|
|
||||||
const ready = this.add
|
|
||||||
.rectangle(BTN_WIDTH * 3, 0, BTN_WIDTH, BTN_HEIGHT, 0x222222)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
this.add
|
|
||||||
.text(ready.getCenter().x, ready.getCenter().y, 'Ready', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
ready.on('pointerdown', () => {
|
|
||||||
ws.sendInstanceReady(player.instance);
|
|
||||||
});
|
|
||||||
|
|
||||||
const menu = this.add
|
|
||||||
.rectangle(BTN_WIDTH * 3, BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT, 0x440000)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0)
|
|
||||||
.on('pointerdown', () => this.registry.set('home', true));
|
|
||||||
|
|
||||||
this.add
|
|
||||||
.text(menu.getCenter().x, menu.getCenter().y, 'Menu', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MenuNavigation;
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const { POSITIONS: { MENU_MAIN }, TEXT, SKILLS } = require('./constants');
|
|
||||||
const Item = require('./elements/item');
|
|
||||||
|
|
||||||
const X = MENU_MAIN.x();
|
|
||||||
const Y = MENU_MAIN.y();
|
|
||||||
const WIDTH = MENU_MAIN.width();
|
|
||||||
const HEIGHT = MENU_MAIN.height();
|
|
||||||
const TEXT_MARGIN = 24;
|
|
||||||
|
|
||||||
const SKILL_WIDTH = Math.floor(WIDTH / 10);
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteHitBox extends Phaser.GameObjects.Rectangle {
|
|
||||||
constructor(scene, x, y) {
|
|
||||||
super(scene, x, y, SKILL_WIDTH, SKILL_WIDTH, 0x222222);
|
|
||||||
this.setOrigin(0);
|
|
||||||
this.itemSelect = () => this.setFillStyle(0xff0000);
|
|
||||||
this.itemDeselect = () => this.setFillStyle(0x222222);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemCheckHitbox = (scene, pointer) => {
|
|
||||||
const { list } = scene.scene.get('MenuConstructList').children;
|
|
||||||
const hitboxes = list.filter(c => c.construct)
|
|
||||||
.concat(scene.children.list.filter(c => c instanceof DeleteHitBox));
|
|
||||||
|
|
||||||
let found;
|
|
||||||
for (let i = 0; i < hitboxes.length; i += 1) {
|
|
||||||
if (Phaser.Geom.Rectangle.ContainsPoint(hitboxes[i].getBounds(), pointer.position)) {
|
|
||||||
found = hitboxes[i];
|
|
||||||
} else {
|
|
||||||
hitboxes[i].itemDeselect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StatSheet extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'StatSheet' });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
updateData(parent, key, data) {
|
|
||||||
if (key === 'player') {
|
|
||||||
console.log('grep');
|
|
||||||
console.log(data);
|
|
||||||
const construct = data.constructs.find(c => c.id === this.construct.id);
|
|
||||||
this.scene.restart(construct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create(construct) {
|
|
||||||
this.registry.events.on('changedata', this.updateData, this);
|
|
||||||
// const ws = this.registry.get('ws');
|
|
||||||
|
|
||||||
const player = this.registry.get('player');
|
|
||||||
if (!player) return false;
|
|
||||||
// const { vbox } = player;
|
|
||||||
|
|
||||||
this.construct = construct;
|
|
||||||
|
|
||||||
/*
|
|
||||||
const del = this.add.existing(new DeleteHitBox(this, X + WIDTH * 0.7, Y + HEIGHT * 0.6));
|
|
||||||
this.add.text(del.getCenter().x, del.getCenter().y, 'unequip', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.add.text(X, Y, construct.name, TEXT.HEADER);
|
|
||||||
|
|
||||||
const constructStat = (stat, i) => {
|
|
||||||
const STAT_X = X;
|
|
||||||
const STAT_Y = Y + (i + 2) * TEXT_MARGIN;
|
|
||||||
this.add.text(STAT_X, STAT_Y, `${stat.stat}: ${stat.base} -> ${stat.value}`, TEXT.NORMAL);
|
|
||||||
};
|
|
||||||
|
|
||||||
const CONSTRUCT_STATS = [
|
|
||||||
construct.hp,
|
|
||||||
construct.red_shield,
|
|
||||||
construct.blue_shield,
|
|
||||||
construct.evasion,
|
|
||||||
construct.red_damage,
|
|
||||||
construct.blue_damage,
|
|
||||||
construct.speed,
|
|
||||||
];
|
|
||||||
|
|
||||||
CONSTRUCT_STATS.forEach(constructStat);
|
|
||||||
/*
|
|
||||||
const knownSkill = (skill, i) => {
|
|
||||||
const SKILL_X = X + WIDTH * 0.4 + WIDTH * 0.125 * i;
|
|
||||||
const SKILL_Y = Y + HEIGHT * 0.15;
|
|
||||||
const itemObj = new Item(this, skill.skill, i, SKILL_X, SKILL_Y, SKILL_WIDTH, Math.floor(SKILL_WIDTH / 2));
|
|
||||||
// itemObj.on('pointerdown', () => );
|
|
||||||
this.input.setDraggable(itemObj);
|
|
||||||
this.add.existing(itemObj);
|
|
||||||
};
|
|
||||||
construct.skills.forEach(knownSkill);
|
|
||||||
this.add.text(X + WIDTH * 0.35, Y, 'Skills', TEXT.HEADER);
|
|
||||||
|
|
||||||
this.add.text(X + WIDTH * 0.35, Y + HEIGHT * 0.25, 'Specs', TEXT.HEADER);
|
|
||||||
const knownSpec = (spec, i) => {
|
|
||||||
const SKILL_X = X + WIDTH * 0.4 + WIDTH * 0.125 * i;
|
|
||||||
const SKILL_Y = Y + HEIGHT * 0.4;
|
|
||||||
const itemObj = new Item(this, spec, i, SKILL_X, SKILL_Y, SKILL_WIDTH, Math.floor(SKILL_WIDTH / 2));
|
|
||||||
// itemObj.on('pointerdown', () => );
|
|
||||||
this.input.setDraggable(itemObj);
|
|
||||||
this.add.existing(itemObj);
|
|
||||||
};
|
|
||||||
construct.specs.forEach(knownSpec);
|
|
||||||
|
|
||||||
|
|
||||||
this.input.on('drag', (pointer, item, dragX, dragY) => {
|
|
||||||
if (!(item instanceof Item)) return false;
|
|
||||||
item.setPosition(dragX, dragY);
|
|
||||||
const hitBox = itemCheckHitbox(this, pointer);
|
|
||||||
if (hitBox) hitBox.itemSelect();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.input.on('dragend', (pointer, item) => {
|
|
||||||
if (!(item instanceof Item)) return false;
|
|
||||||
item.setPosition(item.origX, item.origY);
|
|
||||||
const hitBox = itemCheckHitbox(this, pointer);
|
|
||||||
if (hitBox) {
|
|
||||||
hitBox.itemDeselect();
|
|
||||||
// add socket function for unlearn here
|
|
||||||
ws.sendVboxUnequip(vbox.instance, construct.id, item.item);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.registry.events.off('changedata', this.updateData, this);
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = StatSheet;
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
const { TEXT, POSITIONS: { MENU_MAIN } } = require('./constants');
|
|
||||||
|
|
||||||
const X = MENU_MAIN.x();
|
|
||||||
const Y = MENU_MAIN.y();
|
|
||||||
const WIDTH = MENU_MAIN.width();
|
|
||||||
const HEIGHT = MENU_MAIN.height();
|
|
||||||
|
|
||||||
class ZoneControls extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'ZoneControls' });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(zoneId) {
|
|
||||||
this.cameras.main.setViewport(X, Y, WIDTH, HEIGHT);
|
|
||||||
|
|
||||||
const menu = this.add
|
|
||||||
.rectangle(Math.floor(WIDTH * 0.7), Math.floor(HEIGHT * 0.8), Math.floor(WIDTH * 0.2), Math.floor(HEIGHT * 0.2), 0x888888)
|
|
||||||
.setInteractive()
|
|
||||||
.setOrigin(0);
|
|
||||||
|
|
||||||
this.add
|
|
||||||
.text(menu.getCenter().x, menu.getCenter().y, 'Clear', TEXT.HEADER)
|
|
||||||
.setOrigin(0.5, 0.5);
|
|
||||||
|
|
||||||
menu.on('pointerdown', () => {
|
|
||||||
this.registry.get('ws').sendZoneClose(zoneId);
|
|
||||||
this.scene.get('Zones').cleanUp();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ZoneControls;
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
|
|
||||||
class ZoneNode extends Phaser.GameObjects.Sprite {
|
|
||||||
constructor(scene, x, y, id, success, tag) {
|
|
||||||
super(scene, x, y);
|
|
||||||
this.setTexture('eye');
|
|
||||||
this.scene = scene;
|
|
||||||
this.success = success;
|
|
||||||
// this.text = (text.indexOf(',') > -1) ? text.split(',') : text;
|
|
||||||
this.id = id;
|
|
||||||
this.setPosition(x, y);
|
|
||||||
|
|
||||||
const nodeNoDigits = tag.replace(/[0-9]/g, '');
|
|
||||||
switch (nodeNoDigits) {
|
|
||||||
case 'BOSS':
|
|
||||||
this.setScale(0.25);
|
|
||||||
break;
|
|
||||||
case 'MINIBOSS':
|
|
||||||
this.setScale(0.1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.setScale(0.05);
|
|
||||||
}
|
|
||||||
if (this.success) {
|
|
||||||
this.setTint(0xff0000);
|
|
||||||
}
|
|
||||||
this.text = tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ZoneNode;
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
const Phaser = require('phaser');
|
|
||||||
const Node = require('./zone.node');
|
|
||||||
const ZoneControls = require('./zone.controls');
|
|
||||||
const { POSITIONS: { MENU_MAIN }, TEXT } = require('./constants');
|
|
||||||
|
|
||||||
const X = MENU_MAIN.x();
|
|
||||||
const Y = MENU_MAIN.y();
|
|
||||||
const WIDTH = MENU_MAIN.width();
|
|
||||||
const HEIGHT = MENU_MAIN.height();
|
|
||||||
|
|
||||||
|
|
||||||
// Mouse click hold to move, Q + E to zoom in and out
|
|
||||||
// Press 'A' to reset allocated passive nodes
|
|
||||||
|
|
||||||
class Zones extends Phaser.Scene {
|
|
||||||
constructor() {
|
|
||||||
super({ key: 'Zones' });
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
this.load.image('eye', 'https://labs.phaser.io/assets/particles/green-orb.png');
|
|
||||||
}
|
|
||||||
|
|
||||||
create(zone) {
|
|
||||||
if (!zone) return false;
|
|
||||||
if (!this.scene.get('ZoneControls')) this.scene.manager.add('ZoneControls', ZoneControls, true, zone.id);
|
|
||||||
this.graphics = this.add.graphics();
|
|
||||||
this.cameras.main.setViewport(X, Y, WIDTH, HEIGHT);
|
|
||||||
this.addNodes(zone.graph.nodes);
|
|
||||||
this.drawEdges(zone.graph.edges);
|
|
||||||
this.addCameraControl();
|
|
||||||
this.addEvents(zone.id);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addNodes(nodeData) {
|
|
||||||
this.nodes = [];
|
|
||||||
nodeData.forEach((n, i) => {
|
|
||||||
this.nodes[i] = this.add.existing(
|
|
||||||
new Node(this, n.x * 50 + 200, n.y * 50 + 200, i, n.success, n.tag)
|
|
||||||
).setInteractive();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addCameraControl() {
|
|
||||||
this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl({
|
|
||||||
camera: this.cameras.main,
|
|
||||||
zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
|
|
||||||
zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
|
|
||||||
acceleration: 0.005,
|
|
||||||
drag: 0.0005,
|
|
||||||
maxSpeed: 0.001,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addEvents(zoneId) {
|
|
||||||
this.input.on('pointerover', (pointer, gameObjects) => {
|
|
||||||
if (gameObjects[0] instanceof Node) {
|
|
||||||
this.displayNodeText(gameObjects[0], pointer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.input.on('pointerout', (pointer, gameObjects) => {
|
|
||||||
if (gameObjects[0] instanceof Node) {
|
|
||||||
this.nodeText.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.input.on('pointerup', (pointer, gameObjects) => {
|
|
||||||
if (Math.abs(pointer.upX - pointer.downX) < 5
|
|
||||||
&& Math.abs(pointer.upY - pointer.downY) < 5) {
|
|
||||||
// Check cursor hasn't significantly moved during point allocation
|
|
||||||
// If panning and mouse release is on node it won't allocate
|
|
||||||
if (gameObjects[0] instanceof Node) {
|
|
||||||
const team = this.registry.get('constructs').filter(c => c.active).map(c => c.id);
|
|
||||||
if (gameObjects[0].success) return false;
|
|
||||||
this.registry.get('ws').sendZoneJoin(zoneId, gameObjects[0].id, team);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
this.input.on('pointermove', (pointer) => {
|
|
||||||
const zoomFactor = 2 / this.cameras.main.zoom;
|
|
||||||
if (this.registry.get('pan')) {
|
|
||||||
const points = pointer.getInterpolatedPosition(2);
|
|
||||||
this.cameras.main.scrollX -= zoomFactor * (points[1].x - points[0].x);
|
|
||||||
this.cameras.main.scrollY -= zoomFactor * (points[1].y - points[0].y);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawEdges(edgeData) {
|
|
||||||
this.graphics.clear();
|
|
||||||
edgeData.forEach((e) => {
|
|
||||||
const nodeA = this.nodes[e[0]];
|
|
||||||
const nodeB = this.nodes[e[1]];
|
|
||||||
if (nodeA.success && nodeB.success) {
|
|
||||||
this.graphics.lineStyle(10, 0xfff00f, 0.2);
|
|
||||||
} else {
|
|
||||||
this.graphics.lineStyle(2, 0xffffff, 0.2);
|
|
||||||
}
|
|
||||||
this.graphics.lineBetween(nodeA.x, nodeA.y, nodeB.x, nodeB.y);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
displayNodeText(node, pointer) {
|
|
||||||
if (this.nodeText) this.nodeText.destroy();
|
|
||||||
this.nodeText = this.add.text(node.x, node.y, node.text, TEXT.HOVER).setPadding(32);
|
|
||||||
this.nodeText.setAlpha(0.8);
|
|
||||||
this.nodeText.setOrigin(pointer.x >= WIDTH * 0.65 ? 1 : 0,
|
|
||||||
pointer.y >= HEIGHT * 0.25 ? 1 : 0);
|
|
||||||
this.nodeText.setWordWrapWidth(450);
|
|
||||||
this.nodeText.setScale(1 / this.cameras.main.zoom);
|
|
||||||
}
|
|
||||||
|
|
||||||
camPan(bool) {
|
|
||||||
this.pan = bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(delta) {
|
|
||||||
this.controls.update(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp() {
|
|
||||||
if (this.scene.get('ZoneControls')) this.scene.get('ZoneControls').cleanUp();
|
|
||||||
this.scene.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Zones;
|
|
||||||
@ -1,335 +0,0 @@
|
|||||||
const toast = require('izitoast');
|
|
||||||
const cbor = require('borc');
|
|
||||||
|
|
||||||
|
|
||||||
const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://constructs.gg/ws' : 'ws://localhost:40000';
|
|
||||||
|
|
||||||
function errorToast(err) {
|
|
||||||
console.error(err);
|
|
||||||
return toast.error({
|
|
||||||
title: 'BEEP BOOP',
|
|
||||||
message: err,
|
|
||||||
position: 'topRight',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSocket(events) {
|
|
||||||
let ws;
|
|
||||||
|
|
||||||
// handle account auth within the socket itself
|
|
||||||
// https://www.christian-schneider.net/CrossSiteWebSocketHijacking.html
|
|
||||||
let account = null;
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
// Outgoing
|
|
||||||
// -------------
|
|
||||||
function send(msg) {
|
|
||||||
console.log('outgoing msg', msg);
|
|
||||||
msg.token = account && account.token;
|
|
||||||
ws.send(cbor.encode(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountLogin(name, password) {
|
|
||||||
send({ method: 'account_login', params: { name, password } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountCreate(name, password) {
|
|
||||||
send({ method: 'account_create', params: { name, password } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountDemo() {
|
|
||||||
send({ method: 'account_demo', params: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountConstructs() {
|
|
||||||
send({ method: 'account_constructs', params: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountInstances() {
|
|
||||||
send({ method: 'account_instances', params: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAccountZone() {
|
|
||||||
send({ method: 'account_zone', params: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendConstructSpawn(name) {
|
|
||||||
send({ method: 'construct_spawn', params: { name } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendConstructLearn(id, skill) {
|
|
||||||
send({ method: 'construct_learn', params: { id, skill } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendConstructForget(id, skill) {
|
|
||||||
send({ method: 'construct_forget', params: { id, skill } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGameState(id) {
|
|
||||||
send({ method: 'game_state', params: { id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGamePve(constructIds, mode) {
|
|
||||||
send({ method: 'game_pve', params: { construct_ids: constructIds, mode } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGamePvp(constructIds) {
|
|
||||||
send({ method: 'game_pvp', params: { construct_ids: constructIds } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGameJoin(gameId, constructIds) {
|
|
||||||
send({ method: 'game_join', params: { game_id: gameId, construct_ids: constructIds } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendSpecForget(id, spec) {
|
|
||||||
send({ method: 'construct_unspec', params: { id, spec } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendPlayerConstructsSet(instanceId, constructIds) {
|
|
||||||
send({ method: 'player_constructs_set', params: { instance_id: instanceId, construct_ids: constructIds } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendPlayerState(instanceId) {
|
|
||||||
send({ method: 'player_state', params: { instance_id: instanceId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxAccept(instanceId, group, index) {
|
|
||||||
send({ method: 'player_vbox_accept', params: { instance_id: instanceId, group, index } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxApply(instanceId, constructId, index) {
|
|
||||||
send({ method: 'player_vbox_apply', params: { instance_id: instanceId, construct_id: constructId, index } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxUnequip(instanceId, constructId, target) {
|
|
||||||
send({ method: 'player_vbox_unequip', params: { instance_id: instanceId, construct_id: constructId, target } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxDiscard(instanceId) {
|
|
||||||
send({ method: 'player_vbox_discard', params: { instance_id: instanceId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxCombine(instanceId, indices) {
|
|
||||||
send({ method: 'player_vbox_combine', params: { instance_id: instanceId, indices } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxReclaim(instanceId, index) {
|
|
||||||
send({ method: 'player_vbox_reclaim', params: { instance_id: instanceId, index } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGameSkill(gameId, constructId, targetConstructId, skill) {
|
|
||||||
send({
|
|
||||||
method: 'game_skill',
|
|
||||||
params: {
|
|
||||||
game_id: gameId, construct_id: constructId, target_construct_id: targetConstructId, skill,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
events.setActiveSkill(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGameTarget(gameId, constructId, skillId) {
|
|
||||||
send({ method: 'game_target', params: { game_id: gameId, construct_id: constructId, skill_id: skillId } });
|
|
||||||
events.setActiveSkill(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendZoneCreate() {
|
|
||||||
send({ method: 'zone_create', params: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendZoneJoin(zoneId, nodeId, constructIds) {
|
|
||||||
send({ method: 'zone_join', params: { zone_id: zoneId, node_id: nodeId, construct_ids: constructIds } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendZoneClose(zoneId) {
|
|
||||||
send({ method: 'zone_close', params: { zone_id: zoneId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendInstanceJoin(constructs) {
|
|
||||||
send({ method: 'instance_join', params: { construct_ids: constructs, pve: true } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendInstanceReady(instanceId) {
|
|
||||||
send({ method: 'instance_ready', params: { instance_id: instanceId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendInstanceScores(instanceId) {
|
|
||||||
send({ method: 'instance_scores', params: { instance_id: instanceId } });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
// Incoming
|
|
||||||
// -------------
|
|
||||||
function accountLogin(res) {
|
|
||||||
const [struct, login] = res;
|
|
||||||
|
|
||||||
account = login;
|
|
||||||
events.setAccount(login);
|
|
||||||
sendAccountConstructs();
|
|
||||||
}
|
|
||||||
|
|
||||||
function accountInstanceList(res) {
|
|
||||||
const [struct, instanceList] = res;
|
|
||||||
events.setInstanceList(instanceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
function accountConstructs(response) {
|
|
||||||
const [structName, constructs] = response;
|
|
||||||
events.setConstructList(constructs);
|
|
||||||
}
|
|
||||||
|
|
||||||
function gameState(response) {
|
|
||||||
const [structName, game] = response;
|
|
||||||
events.setGame(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
function constructSpawn(response) {
|
|
||||||
const [structName, construct] = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gamePve(response) {
|
|
||||||
const [structName, game] = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
function zoneState(response) {
|
|
||||||
const [structName, zone] = response;
|
|
||||||
events.setZone(zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerState(response) {
|
|
||||||
const [structName, player] = response;
|
|
||||||
events.setPlayer(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
function instanceScores(response) {
|
|
||||||
const [structName, scores] = response;
|
|
||||||
events.setScores(scores);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
// Setup
|
|
||||||
// -------------
|
|
||||||
|
|
||||||
// when the server sends a reply it will have one of these message types
|
|
||||||
// this object wraps the reply types to a function
|
|
||||||
const handlers = {
|
|
||||||
construct_spawn: constructSpawn,
|
|
||||||
construct_forget: () => true,
|
|
||||||
construct_learn: () => true,
|
|
||||||
game_pve: gamePve,
|
|
||||||
game_state: gameState,
|
|
||||||
account_login: accountLogin,
|
|
||||||
account_create: accountLogin,
|
|
||||||
account_constructs: accountConstructs,
|
|
||||||
account_instances: accountInstanceList,
|
|
||||||
instance_scores: instanceScores,
|
|
||||||
zone_create: res => console.log(res),
|
|
||||||
zone_state: zoneState,
|
|
||||||
zone_close: res => console.log(res),
|
|
||||||
player_state: playerState,
|
|
||||||
};
|
|
||||||
|
|
||||||
function errHandler(error) {
|
|
||||||
switch (error) {
|
|
||||||
case 'no active zone': return sendZoneCreate();
|
|
||||||
case 'no constructs selected': return events.errorPrompt('select_constructs');
|
|
||||||
case 'node requirements not met': return events.errorPrompt('complete_nodes');
|
|
||||||
case 'construct at max skills (4)': return events.errorPrompt('max_skills');
|
|
||||||
|
|
||||||
default: return errorToast(error);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decodes the cbor and
|
|
||||||
// calls the handlers defined above based on message type
|
|
||||||
function onMessage(event) {
|
|
||||||
// decode binary msg from server
|
|
||||||
const blob = new Uint8Array(event.data);
|
|
||||||
const res = cbor.decode(blob);
|
|
||||||
const { method, params } = res;
|
|
||||||
|
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
// check for error and split into response type and data
|
|
||||||
if (res.err) return errHandler(res.err);
|
|
||||||
if (!handlers[method]) return errorToast(`${method} handler missing`);
|
|
||||||
return handlers[method](params);
|
|
||||||
}
|
|
||||||
|
|
||||||
function connect() {
|
|
||||||
ws = new WebSocket(SOCKET_URL);
|
|
||||||
ws.binaryType = 'arraybuffer';
|
|
||||||
|
|
||||||
// Connection opened
|
|
||||||
ws.addEventListener('open', () => {
|
|
||||||
toast.info({
|
|
||||||
message: 'connected',
|
|
||||||
position: 'topRight',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!account) events.loginPrompt();
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
// send({ method: 'account_login', params: { name: 'ntr', password: 'grepgrepgrep' } });
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen for messages
|
|
||||||
ws.addEventListener('message', onMessage);
|
|
||||||
|
|
||||||
ws.addEventListener('error', (event) => {
|
|
||||||
console.error('WebSocket error', event);
|
|
||||||
// account = null;
|
|
||||||
// return setTimeout(connect, 5000);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.addEventListener('close', (event) => {
|
|
||||||
console.error('WebSocket closed', event);
|
|
||||||
toast.warning({
|
|
||||||
message: 'disconnected',
|
|
||||||
position: 'topRight',
|
|
||||||
});
|
|
||||||
return setTimeout(connect, 5000);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ws;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendAccountLogin,
|
|
||||||
sendAccountCreate,
|
|
||||||
sendAccountDemo,
|
|
||||||
sendAccountConstructs,
|
|
||||||
sendAccountInstances,
|
|
||||||
sendAccountZone,
|
|
||||||
sendGameState,
|
|
||||||
sendGamePve,
|
|
||||||
sendGamePvp,
|
|
||||||
sendGameJoin,
|
|
||||||
sendGameSkill,
|
|
||||||
sendGameTarget,
|
|
||||||
sendConstructSpawn,
|
|
||||||
sendConstructLearn,
|
|
||||||
sendConstructForget,
|
|
||||||
sendSpecForget,
|
|
||||||
sendZoneCreate,
|
|
||||||
sendZoneJoin,
|
|
||||||
sendZoneClose,
|
|
||||||
sendInstanceJoin,
|
|
||||||
sendInstanceReady,
|
|
||||||
sendInstanceScores,
|
|
||||||
sendPlayerConstructsSet,
|
|
||||||
sendPlayerState,
|
|
||||||
sendVboxAccept,
|
|
||||||
sendVboxApply,
|
|
||||||
sendVboxReclaim,
|
|
||||||
sendVboxCombine,
|
|
||||||
sendVboxDiscard,
|
|
||||||
sendVboxUnequip,
|
|
||||||
connect,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = createSocket;
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
const toast = require('izitoast');
|
|
||||||
|
|
||||||
const OK_BUTTON = '<button type="submit">OK</button>';
|
|
||||||
const NO_MORE_BUTTON = '<button type="submit">Enough already...</button>';
|
|
||||||
|
|
||||||
function noMore(instance, thisToast) {
|
|
||||||
window.localStorage.setItem('tutorial', 'none');
|
|
||||||
return instance.hide({ transitionOut: 'fadeOut' }, thisToast);
|
|
||||||
}
|
|
||||||
|
|
||||||
const WELCOME_MESSAGE = `
|
|
||||||
Welcome to constructs.gg
|
|
||||||
Enter a username and password and press register to sign up,
|
|
||||||
or just press DEMO to quick start.
|
|
||||||
`;
|
|
||||||
|
|
||||||
const HOMEPAGE_MESSAGE = `
|
|
||||||
This homepage shows your constructs, joinable online games, PVE options and your items.\n
|
|
||||||
If you have no constructs yet, press SPAWN and give your construct a name to create one.
|
|
||||||
Once you have made a construct, click on them to visit their stat page and teach them some SKILLS.
|
|
||||||
The stat page also has descriptions of each skill and their effects.
|
|
||||||
constructs have 3 basic stats: hp, red damage and magic damage.
|
|
||||||
Toggle whether a construct is selected for your team by clicking the coloured stripes next to the construct or press 1,2,3.
|
|
||||||
Once you have a team ready press the New PVE Game button to start playing.
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SKILL_PHASE_MESSAGE = `
|
|
||||||
A constructs battle has two main phases. This first phase is called the SKILL PHASE.
|
|
||||||
Your constructs are positioned on the left, your opponent's are on the right.
|
|
||||||
In the centre are your constructs' SKILLS, grayed out SKILLS are currently ON COOLDOWN.
|
|
||||||
A skill's cooldown reduces on every turn that construct does not use a skill with a cooldown.
|
|
||||||
For the moment, drag ATTACK onto the opponent team to have your constructs attack them with red damage.
|
|
||||||
`;
|
|
||||||
|
|
||||||
// const TARGET_PHASE_MESSAGE = `
|
|
||||||
// This phase is the TARGET PHASE.
|
|
||||||
// In constructs you do not directly attack your opponent's constructs, you attack the opponent as a team
|
|
||||||
// and you and your opponent choose which construct is the TARGET of each ability.
|
|
||||||
// Drag the incoming ATTACKS from the right hand side onto your own constructs.
|
|
||||||
// It's wise to spread the damage around!
|
|
||||||
// `;
|
|
||||||
|
|
||||||
const RESOLUTION_PHASE_MESSAGE = `
|
|
||||||
The second phase is called the RESOLUTION PHASE.
|
|
||||||
This phase happens automatically, every skill is RESOLVED in order of its SPEED.
|
|
||||||
This is important because attacks only RESOLVE while their caster is still able to use the skill,
|
|
||||||
a fast skill that does a small amount of damage may KO an opponent construct, causing any SKILLS
|
|
||||||
they have used to no longer RESOLVE!
|
|
||||||
Another example of this is the skill STUN. STUN causes an opponent construct to be unable to use any
|
|
||||||
abilities for TWO TURNS including the turn it resolves on. In other words it lasts for the rest of the turn it resolves on
|
|
||||||
and the whole next turn.
|
|
||||||
Try it now!
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FINISH_PHASE_MESSAGE = `
|
|
||||||
gg! The game has now concluded, if you were the winner you have been awarded with a STAT REROLL ITEM.
|
|
||||||
You can use this to reroll a stat on a construct which may be lacking.
|
|
||||||
A good metric is that if a stat is more than 1/2 of its STAMINA that's a good roll.
|
|
||||||
Now that you have learned the basics, press BACKSPACE to return to the main menu
|
|
||||||
and experiment with some combinations of SKILLS or replace the ones your constructs know in the STAT PAGE.
|
|
||||||
glhf!
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STEPS = [
|
|
||||||
'init',
|
|
||||||
'welcome',
|
|
||||||
'homepage',
|
|
||||||
'skillPhase',
|
|
||||||
// 'targetPhase',
|
|
||||||
'resolutionPhase',
|
|
||||||
'finishPhase',
|
|
||||||
'none',
|
|
||||||
];
|
|
||||||
|
|
||||||
function showTutorial(message, step, nextStep) {
|
|
||||||
const existing = document.querySelector(`#${step}`); // Selector of your toast
|
|
||||||
|
|
||||||
if (existing) return false;
|
|
||||||
|
|
||||||
toast.info({
|
|
||||||
id: step,
|
|
||||||
theme: 'dark',
|
|
||||||
color: 'black',
|
|
||||||
timeout: false,
|
|
||||||
drag: false,
|
|
||||||
title: 'TUTORIAL',
|
|
||||||
position: 'bottomCenter',
|
|
||||||
maxWidth: window.innerWidth / 2,
|
|
||||||
close: false,
|
|
||||||
buttons: [
|
|
||||||
[NO_MORE_BUTTON, noMore],
|
|
||||||
[OK_BUTTON, (instance, thisToast) => {
|
|
||||||
const thisStep = STEPS.indexOf(step);
|
|
||||||
const storageStep = STEPS.indexOf(window.localStorage.getItem('tutorial'));
|
|
||||||
if (thisStep >= storageStep) {
|
|
||||||
window.localStorage.setItem('tutorial', nextStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance.hide({ transitionOut: 'fadeOut' }, thisToast);
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tutorial() {
|
|
||||||
function show(step) {
|
|
||||||
const currentStage = window.localStorage.getItem('tutorial');
|
|
||||||
if (currentStage === 'none') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const thisStep = STEPS.indexOf(step);
|
|
||||||
const storageStep = STEPS.indexOf(window.localStorage.getItem('tutorial'));
|
|
||||||
|
|
||||||
if (thisStep < storageStep) return false;
|
|
||||||
|
|
||||||
if (step === 'welcome') return showTutorial(WELCOME_MESSAGE, 'welcome', 'homepage');
|
|
||||||
if (step === 'homepage') return showTutorial(HOMEPAGE_MESSAGE, 'homepage', 'skillPhase');
|
|
||||||
if (step === 'skillPhase') return showTutorial(SKILL_PHASE_MESSAGE, 'skillPhase', 'targetPhase');
|
|
||||||
// if (step === 'targetPhase') return showTutorial(TARGET_PHASE_MESSAGE, 'targetPhase', 'resolutionPhase');
|
|
||||||
if (step === 'resolutionPhase') return showTutorial(RESOLUTION_PHASE_MESSAGE, 'resolutionPhase', 'finishPhase');
|
|
||||||
if (step === 'finishPhase') return showTutorial(FINISH_PHASE_MESSAGE, 'finishPhase', 'none');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.localStorage.getItem('tutorial') !== 'none') window.localStorage.setItem('tutorial', 'init');
|
|
||||||
|
|
||||||
return show;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = tutorial;
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
const get = require('lodash/get');
|
|
||||||
|
|
||||||
const stringSort = (k, desc) => {
|
|
||||||
if (desc) {
|
|
||||||
return (a, b) => {
|
|
||||||
if (!get(a, k)) return 1;
|
|
||||||
if (!get(b, k)) return -1;
|
|
||||||
return get(b, k).localeCompare(get(a, k));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return (a, b) => {
|
|
||||||
if (!get(a, k)) return 1;
|
|
||||||
if (!get(b, k)) return -1;
|
|
||||||
return get(a, k).localeCompare(get(b, k));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const numSort = (k, desc) => {
|
|
||||||
if (desc) {
|
|
||||||
return (a, b) => {
|
|
||||||
if (!get(a, k)) return 1;
|
|
||||||
if (!get(b, k)) return -1;
|
|
||||||
return get(b, k) - get(a, k);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return (a, b) => {
|
|
||||||
if (!get(a, k)) return 1;
|
|
||||||
if (!get(b, k)) return -1;
|
|
||||||
return get(a, k) - get(b, k);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
stringSort,
|
|
||||||
numSort,
|
|
||||||
};
|
|
||||||