Merge remote-tracking branch 'origin' into skilltiers

This commit is contained in:
Mashy 2019-05-27 15:16:22 +10:00
commit 7d2ad82800
131 changed files with 1604 additions and 11137 deletions

View File

@ -22,8 +22,8 @@ Added `Buff` as a skill
*BALANCE*
- purify
- 1 effect from all cryps at level 2
- removes all effects from all cryps at l3
- 1 effect from all constructs at level 2
- removes all effects from all constructs at l3
- invert
- fx for buffs when applied to enemies

View File

@ -5,7 +5,7 @@ specs [spec [bonus amount, [r g b]]
# Playthrough
cryps join game
constructs join game
stats randomised
initial stash drops

View File

@ -23,9 +23,9 @@ Base specs have a base 3 cost
### Actual Costs
- Costs increase as more of an item is used on cryps in the game
- Costs increase as more of an item is used on constructs in the game
- The cost increases by the base cost for every 6 allocations of base item
- Allocation is based on all cryps in the game
- Allocation is based on all constructs in the game
### Example ###
@ -33,15 +33,15 @@ Round #1
All costs are base costs
# Player #1 and Player #2 (They both bought the same things)
Cryp #1 Strike (Attack + RR), (2 + 1 + 1) = (4) cost
Cryp #1 Empower (Buff + RR), (2 + 1 + 1) = (4) cost
Cryp #3 Attack, 2 cost
Construct #1 Strike (Attack + RR), (2 + 1 + 1) = (4) cost
Construct #1 Empower (Buff + RR), (2 + 1 + 1) = (4) cost
Construct #3 Attack, 2 cost
Total cost - 10
Round #2
Items used on cryps include:
Items used on constructs include:
Red x 8
Attack x 4
@ -52,9 +52,9 @@ The costs of red for round #2 are now (1 + 1) = 2
If they were to buy the same skill setup it would be as follows:
# Player #1 and Player #2 (They both bought the same things)
Cryp #1 Strike (Attack + RR), (2 + 2 + 2) = (6) cost
Cryp #1 Empower (Buff + RR), (2 + 2 + 2) = (6) cost
Cryp #3 Attack, 2 cost
Construct #1 Strike (Attack + RR), (2 + 2 + 2) = (6) cost
Construct #1 Empower (Buff + RR), (2 + 2 + 2) = (6) cost
Construct #3 Attack, 2 cost
Total cost - 14

View File

@ -46,4 +46,4 @@ Rare `increased speed, increased cooldowns`
- Increased stat
- ??? Related Notables
# ??? Cryps need to have a minimum of X of the cryp stat to learn a skill #
# ??? Constructs need to have a minimum of X of the construct stat to learn a skill #

View File

@ -1,4 +1,4 @@
# Cryps ("creeps")
# Constructs ("creeps")
## Combat
@ -30,7 +30,7 @@ resolve phase:
| reduction | absorption? | durations |
## Cryp Alignments
## Construct Alignments
Natural Selection
================
@ -92,7 +92,7 @@ Path to Destruction
Damage & Destruction
-------------------------
cryps walking the path to destruction have forsaken themselves in order to gain ruinous power.
constructs walking the path to destruction have forsaken themselves in order to gain ruinous power.
no price is too high, they gladly harm themselves and allies to amplify the destruction they wreak on everything around them
specialise in magical damage dealing
@ -124,7 +124,7 @@ Universal Chaos
The only constant is change.
----------------------------
Cryps aligning themselves with the forces of chaos believe that constant change is the only truth in the universe.
Constructs aligning themselves with the forces of chaos believe that constant change is the only truth in the universe.
They harness its power to manipulate physical reality as well as control and disrupt the flow of battle.
They blend between physical and astral forms, constantly shifting throughout time and space.

View File

@ -22,7 +22,7 @@ Combat animations
Make in game shop
Payment processors / CC etc
Handler for game purchases
MTX - Cryp Avatars
MTX - Construct Avatars
MTX - Skill anims
Setup company bank accounts
@ -42,3 +42,22 @@ Marketing materials
Twitch
Advertisments?
Information
# china shit
You need to read the details more carefully. Playsaurus messed up:
1. They launched in China without registering a trademark
2. A competitor registered the trademark after 3 months of their launch
3. They continued to sell for 4 years under a name trademarked by another company, making $73,000+ yearly from that one country
Now, they complain about it on Reddit, even though China is a 'First to File' company.
The fault lies entirely with Playsaurus, nothing illegal occurred here.
https://www.trademarknow.com/blog/first-to-file-versus-first...
This situation could have occurred in many other countries - the difference is probably that the competitor is content to just sell in China, under a Chinese name, whereas products sold anywhere else would need to use the English name.

View File

@ -4,16 +4,16 @@ Numbers are placeholder
`Specs get a bonus dependent on the total of Red / Green / Blue in player skills & specs`
# Example to meet 5 red gem bonus from skills only
In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `Snare`
In your player Construct #1 has `Strike`, Construct #2 has `Slay` and `Heal`, Construct #3 has `Snare`
- RR skill `Strike` contributes 2 red gems to the total red gems (2 total)
- RG skill `Slay` contributes 1 red gem to the total red gems (3 total)
- GG skill `Heal` contirubtes 0 red gems to the total red gems (3 total)
- RR skill `Snare` contirubtes 2 red gems to the total red gems (5 total)
# Advanced specs also require a minimum number of Red / Green / Blue gems on the cryp to take effect
# Advanced specs also require a minimum number of Red / Green / Blue gems on the construct to take effect
- Tier 1 Basic specs (Damage / Health / Defense) will have no requirements
- Advanced specs will require a certain threshold of red / green / blue gems to be enabled
- Provided spec requirements are met, all specs will add gems to the cryp
- Provided spec requirements are met, all specs will add gems to the construct
# Starting from scratch with a vbox
@ -26,9 +26,9 @@ In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has
Combine 2 Red + 'Attack' -> Strike
Combine 2 Red + 'Basic Damage Spec' -> Red Damage
Cryp #1 -> Give Strike & Red Damage Spec -> Strike + 1 x Red Damage Spec
Cryp #2 -> Give Attack -> Attack
Cryp #3 -> Give Stun -> Stun
Construct #1 -> Give Strike & Red Damage Spec -> Strike + 1 x Red Damage Spec
Construct #2 -> Give Attack -> Attack
Construct #3 -> Give Stun -> Stun
Player Total (4 Red + 2 Basic gems)
@ -37,17 +37,17 @@ In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has
- Buy 2 reds & 2 green & 2 blue (all available colour items)
- Buy 2 Basic Damage Spec (item)
- Cryp #2 Unequip Attack
- Construct #2 Unequip Attack
- Combine 2 Green + 'Attack' -> Heal
- Cryp #3 Unequip Stun
- Construct #3 Unequip Stun
- Combine 2 Blue + 'Stun' -> Ruin
- Combine 2 Red + 'Basic Damage Spec' -> Red Damage
Cryp #1 -> Give Red Damage items -> Strike + 2 x Red Damage Spec (6R)
Cryp #2 -> Give Heal item -> Heal (2G)
Cryp #3 -> Give Ruin item -> Ruin (2B)
Construct #1 -> Give Red Damage items -> Strike + 2 x Red Damage Spec (6R)
Construct #2 -> Give Heal item -> Heal (2G)
Construct #3 -> Give Ruin item -> Ruin (2B)
## Round 3
@ -58,9 +58,9 @@ In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has
- Combine 2 Red + 'Stun' -> Strangle
- Combine 2 Red + 'Block' -> Parry
Cryp #1 -> Give 'Stun' & 'Strangle' -> Strike, Stun, Strangle + 2 x Red Damage Spec (10R)
Cryp #2 -> 'No change' -> Heal (2G)
Cryp #3 -> Give Attack item & 2 Basic Damage Spec -> Attack + Ruin + 2 x Basic Damage Spec (2B)
Construct #1 -> Give 'Stun' & 'Strangle' -> Strike, Stun, Strangle + 2 x Red Damage Spec (10R)
Construct #2 -> 'No change' -> Heal (2G)
Construct #3 -> Give Attack item & 2 Basic Damage Spec -> Attack + Ruin + 2 x Basic Damage Spec (2B)
## Round 4
@ -70,18 +70,18 @@ In your player Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has
- Combine 2 Red + 'Attack' -> Strike
- Combine 2 Red + 'Buff' -> Empower
- Cryp #1 Unequip 2 x Red Damage spec, Equip Empower -> Strike, Stun, Strangle, Empower (8R)
- Construct #1 Unequip 2 x Red Damage spec, Equip Empower -> Strike, Stun, Strangle, Empower (8R)
- Combine 'Strike' + 2 x Red Damage spec -> 'Increased Strike Damage spec'
### Note 'Increased Strike Damage spec' requires 8R on the cryp
### Note 'Increased Strike Damage spec' requires 8R on the construct
Cryp #1 Equip Increased Strike Damage spec -> Strike, Stun, Strangle, Empower + Increased Strike Damage Spec (14R)
Cryp #2 -> 'No change' -> Heal
Cryp #3 -> 'No change' -> Attack + Ruin + 2 x Basic Damage Spec
Construct #1 Equip Increased Strike Damage spec -> Strike, Stun, Strangle, Empower + Increased Strike Damage Spec (14R)
Construct #2 -> 'No change' -> Heal
Construct #3 -> 'No change' -> Attack + Ruin + 2 x Basic Damage Spec
## Round 5
We already lost cause we went all in on 1 red cryp like a noob
We already lost cause we went all in on 1 red construct like a noob
### Generic Specs
@ -96,7 +96,7 @@ Maximum 35% inc hp
Maximum 50% inc speed
# Basic Class Spec
`Base` -> +2 red, +2 green +2 blue gems on cryp
`Base` -> +2 red, +2 green +2 blue gems on construct
# Basic Duration
### Increased Damage Combos ###
@ -182,32 +182,32 @@ Maximum +35% inc blue shield and 35% inc red shield
## Upgraded Attack Spec Combos
# Increased Strike Damage (Combine Strike + Red Damage Spec x 2)
Cryp Requires `8 red gems`
Construct Requires `8 red gems`
Adds `6 red gems`
`Base` -> 15% increased strike damage
`Player Bonus` 15 red gems -> +15% // 20 red gems -> +20% // 30 red gems -> +30%
Maximum 80% increased strike damage
# Improved Heal (Combine Heal + Healing Spec x 2)
Cryp Requires `8 green gems`
Construct Requires `8 green gems`
`Base` -> 15% increased heal healing
`Player Bonus` 15 green gems -> +15% // 20 green gems -> +20% // 30 green gems -> +30%
Maximum 80% increased heal healing
# Increased Blast Damage (Combine Blast + Blue Spec x 2)
Cryp Requires `8 blue gems`
Construct Requires `8 blue gems`
`Base` -> 15% increased blast damage
`Player Bonus` 15 blue gems -> +15% // 20 blue gems -> +20% // 30 blue gems -> +30%
Maximum 80% increased blast damage
# Increased Slay Damage (Combine Slay + Red Damage Spec + Healing Spec)
Cryp Requires `4 red 4 green gems`
Construct Requires `4 red 4 green gems`
`Base` -> 15% increased slay damage
`Player Bonus` (8R + 8G) gems -> +15% // (10R + 10G) gems -> +20% // (15R + 15G) gems -> +30%
Maximum 80% increased slay damage
# Increased Banish Damage (Combine Slay + Red Damage Spec + Blue Damage Spec)
Cryp Requires `4 red 4 blue gems`
Construct Requires `4 red 4 blue gems`
`Base` -> 15% increased slay damage
`Player Bonus` (8R + 8B) gems -> +15% // (10R + 10B) gems -> +20% // (15R + 15B) gems -> +30%
Maximum 80% increased banish damage

View File

@ -24,8 +24,8 @@ Tidy edges on game UI
blue + defensive green
- purify
- 1 effect from all cryps at level 2
- removes all effects from all cryps at l3
- 1 effect from all constructs at level 2
- removes all effects from all constructs at l3
- invert
- fx for buffs when applied to enemies
@ -102,7 +102,7 @@ push events
$$$
* Items
* Colour scheme
* number of cryps
* number of constructs
* Highlight (dota) colour
* fx colours + styles

View File

@ -36,7 +36,7 @@
}
.opponent .game-cryp {
.opponent .game-construct {
align-items: flex-start;
grid-template-rows: min-content min-content min-content 2fr;
grid-template-columns: 1fr 1fr;
@ -47,12 +47,12 @@
"avatar target";
}
.opponent .game-cryp .name {
.opponent .game-construct .name {
margin-bottom: 0;
margin-top: 0.25em;
}
.game-cryp {
.game-construct {
display: grid;
/*justify-items: center;*/
@ -74,7 +74,7 @@
transition-timing-function: ease;
}
.game-cryp .targeting {
.game-construct .targeting {
grid-area: target;
display: flex;
flex-flow: column;
@ -84,40 +84,36 @@
white-space: nowrap;
}
.game-cryp .img {
.game-construct .img {
grid-area: avatar;
}
.game-cryp .name {
.game-construct .name {
width: 100%;
margin-bottom: 0.25em;
text-align: center;
grid-area: name;
}
.game-cryp .stats {
.game-construct .stats {
grid-area: stats;
display: flex;
flex-flow: row;
}
.game-cryp figure {
.game-construct figure {
padding: 0 0.5em;
display: flex;
flex-flow: column;
}
.game-cryp figcaption {
.game-construct figcaption {
white-space: nowrap;
font-size: 100%;
}
@media (max-width: 1500px) {
.game {
font-size: 12pt;
}
.game-cryp figure {
.game-construct figure {
padding: 0 0.25em;
}
@ -127,7 +123,7 @@
}
*/}
.game-cryp .skills {
.game-construct .skills {
grid-area: skills;
display: flex;
flex-flow: column-reverse;
@ -135,13 +131,13 @@
}
/*@media (max-width: 1000px) {
.game-cryp .skills {
.game-construct .skills {
flex-flow: column;
}
}
*/
.game-cryp .effects {
.game-construct .effects {
grid-area: effects;
font-size: 1.5em;
white-space: nowrap;
@ -157,7 +153,7 @@
margin-right: 0.5em;
}
.game-cryp button {
.game-construct button {
color: #888;
flex: 1 1 100%;
padding: 0;
@ -165,36 +161,35 @@
border-width: 0px;
}
.game-cryp button.active {
.game-construct button.active {
color: whitesmoke;
}
.game-cryp button[disabled], .game-cryp button[disabled]:hover {
.game-construct button[disabled], .game-construct button[disabled]:hover {
color: #333333;
font-size: 14pt;
text-decoration: line-through
}
.game-cryp button:hover {
.game-construct button:hover {
color: whitesmoke;
}
.game-cryp.ko {
.game-construct.ko {
animation: none;
opacity: 0.35;
filter: grayscale(100%);
}
.game-cryp.ko button:hover {
.game-construct.ko button:hover {
color: #333;
}
.game-cryp.unfocus {
.game-construct.unfocus {
opacity: 0.65;
filter: blur(5px);
}
.game-cryp.unfocus.ko {
.game-construct.unfocus.ko {
filter: blur(5px) grayscale(100%);
}
@ -207,18 +202,18 @@
left: 50%;
}
CRYP DAMAGE
CONSTRUCT DAMAGE
.game-cryp.active-skill {
.game-construct.active-skill {
filter: drop-shadow(0 0 0.2em silver);
/*border-color: silver;*/
}
.game-cryp.red-damage {
.game-construct.red-damage {
filter: drop-shadow(0 0 0.2em red);
color: red;
/*ensure cryp doesn't get opacity lowered because of being KO before the KO animation*/
/*ensure construct doesn't get opacity lowered because of being KO before the KO animation*/
opacity: 1;
/*border-color: red;*/
@ -237,7 +232,7 @@ CRYP DAMAGE
/*border-top: 1px solid red;*/
}
.game-cryp.blue-damage {
.game-construct.blue-damage {
filter: drop-shadow(0 0 0.2em blue);
color: blue;
opacity: 1;
@ -257,7 +252,7 @@ CRYP DAMAGE
/*border-top: 1px solid blue;*/
}
.game-cryp.green-damage {
.game-construct.green-damage {
filter: drop-shadow(0 0 0.2em green);
color: green;
opacity: 1;
@ -277,7 +272,7 @@ CRYP DAMAGE
/*border-top: 1px solid green;*/
}
.game-cryp.purple-damage {
.game-construct.purple-damage {
filter: drop-shadow(0 0 0.2em purple);
color: purple;
border-color: purple;

View File

@ -11,7 +11,7 @@
"top top info"
"vbox vbox info"
"equip equip info"
"cryps cryps info";
"constructs constructs info";
}
@media (max-width: 1920px) {
@ -22,6 +22,10 @@
.instance .info table td svg {
height: 50%;
}
.instance svg {
height: 1.5em;
}
}
.instance .top {
@ -29,7 +33,7 @@
}
.instance .scoreboard {
grid-area: cryps;
grid-area: constructs;
}
.instance-ui-btn {
@ -56,8 +60,8 @@
margin-top: 1.5em;
}
.instance .cryps {
grid-area: cryps;
.instance .constructs {
grid-area: constructs;
}
.instance .equip {
@ -144,16 +148,16 @@
cursor: pointer;
}
/* CRYP LIST */
/* CONSTRUCT LIST */
.cryp-list {
grid-area: cryps;
.construct-list {
grid-area: constructs;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.instance-cryp, .instance-cryp-active {
.instance-construct, .instance-construct-active {
display: grid;
grid-template-rows: min-content min-content min-content 1fr min-content;
grid-template-areas:
@ -173,17 +177,17 @@
transition-timing-function: ease;
*/}
.instance-cryp:first-child {
.instance-construct:first-child, .instance-construct-active:first-child {
margin-left: 0;
border-left-width: 1px;
}
.cryp-list .name {
.construct-list .name {
grid-area: name;
margin-bottom: 0.5em;
}
.cryp-list .avatar {
.construct-list .avatar {
grid-area: avatar;
object-fit: contain;
background-size: contain;
@ -192,28 +196,28 @@
pointer-events: none;
}
.cryp-list .name {
.construct-list .name {
text-align: center;
}
.cryp-list .avatar figure {
.construct-list .avatar figure {
margin: 0;
height: 80%;
text-align: center;
box-sizing: border-box;
}
.cryp-list .avatar figcaption {
.construct-list .avatar figcaption {
font-size: 90%;
}
.cryp-list .skills {
.construct-list .skills {
grid-area: skills;
display: flex;
border-width: 0px;
}
.cryp-list .skills button {
.construct-list .skills button {
flex: 1;
border-width: 0px;
}
@ -232,7 +236,7 @@
}
}
*/
.cryp-list .specs {
.construct-list .specs {
margin-top: 1em;
grid-area: specs;
display: flex;
@ -241,18 +245,18 @@
border-width: 0px;
}
.cryp-list .specs figure {
.construct-list .specs figure {
flex: 1;
border: 0;
align-items: center;
text-align: center;
}
.cryp-list .specs figcaption {
.construct-list .specs figcaption {
font-size: 75%;
}
.cryp-list .stats {
.construct-list .stats {
grid-area: stats;
display: grid;
grid-template-rows: 1fr 3fr;
@ -263,11 +267,11 @@
border-width: 0px;
}
.cryp-list .stats figcaption {
.construct-list .stats figcaption {
font-size: 75%;
}
.cryp-list .stats .icons {
.construct-list .stats .icons {
grid-area: st;
display: flex;
flex-flow: row;
@ -285,25 +289,25 @@
fill: none;
}
.cryp-list .stat-icon {
.construct-list .stat-icon {
width: 100%;
}
.cryp-list .stats .damage-label {
.construct-list .stats .damage-label {
grid-area: dl;
display: flex;
justify-content: center;
color: #666;
}
.cryp-list .stats .speed-label {
.construct-list .stats .speed-label {
grid-area: sl;
display: flex;
justify-content: center;
color: #666;
}
.cryp-list .stats .life-label {
.construct-list .stats .life-label {
grid-area: ll;
display: flex;
justify-content: center;

View File

@ -1,20 +1,20 @@
@media (max-height: 800px), (max-width: 1000px) {
.instance {
display: grid;
grid-template-columns: 100%;
grid-template-rows: repeat(4, min-content);
grid-template-columns: 1fr;
grid-template-rows: min-content, min-content, min-content, 1fr;
grid-template-areas:
"top"
"controls"
"first"
"second"
"vbox"
"constructs"
}
/* Default view */
.instance .equip { display: none; }
.instance .info { display: none; }
.instance .cryp-list { display: none; }
.instance .construct-list { display: none; }
.vbox {
grid-area: first;
grid-area: vbox;
display: grid;
grid-template-rows: min-content min-content min-content;
grid-template-columns: 1fr;
@ -31,13 +31,13 @@
.vbox-combiner {
margin-left: 0;
}
/* Toggled view (cryps)*/
/* Toggled view (constructs)*/
#toggle-vbox-label {
text-align: center;
border: 2px solid #555;
}
#toggle-vbox-label:after{
content: "Cryps";
content: "Constructs";
}
#toggle-vbox:checked ~ #toggle-vbox-label:after{
@ -47,22 +47,21 @@
#toggle-vbox:checked ~ .vbox { display: none; }
#toggle-vbox:checked ~ .equip {
display: initial;
grid-area: first;
grid-area: vbox;
}
#toggle-vbox:checked ~ .highlight {
display: initial;
}
#toggle-vbox:checked ~ .cryp-list {
grid-area: second;
display: flex;
#toggle-vbox:checked ~ .construct-list {
grid-area: constructs;
display: grid;
justify-content: center;
flex-flow: row wrap;
flex: 1;
width: 100%;
}
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
#toggle-vbox { display: none; }
@ -76,15 +75,15 @@
margin-right: 0.5em;
}
.cryp-list .skills {
.construct-list .skills {
flex-flow: row;
align-items: stretch;
}
.instance-cryp {
flex: 1;
.instance-construct {
grid-row: 2;
display: grid;
grid-template-rows: min-content min-content;
grid-template-rows: min-content 1fr;
grid-template-areas:
"name "
"avatar ";
@ -95,28 +94,25 @@
transition-delay: 0;
transition-timing-function: ease;
}
.instance-cryp img {
width: 35px;
}
.instance-cryp .skills {
.instance-construct .skills {
display: none;
}
.instance-cryp .specs {
.instance-construct .specs {
display: none;
}
.instance-cryp .stats {
.instance-construct .stats {
display: none;
}
.instance-cryp-active {
flex: 1;
order: -1;
.instance-construct-active {
grid-row: 1;
grid-column: 1 / 3;
display: grid;
grid-template-rows: min-content min-content min-content min-content min-content;
grid-template-rows: min-content min-content min-content 1fr min-content;
grid-template-areas:
"name "
"skills "
@ -133,11 +129,11 @@
transition-timing-function: ease;
}
.instance-cryp-active img {
.instance-construct-active img {
width: 55px;
}
/* Cryp Stuff */
/* Construct Stuff */
}

View File

@ -2,7 +2,7 @@
GLOBAL
*/
html, body, #cryps {
html, body, #constructs {
/*width: 100%;*/
margin: 0;
@ -61,7 +61,7 @@ figure {
text-align: center;
}
#cryps {
#constructs {
padding: 0 2em;
display: grid;
grid-template-columns: 1fr 8fr;
@ -170,6 +170,11 @@ button.left:hover, button.left:focus {
box-shadow: inset 0.5em 0 0 0 whitesmoke;
}
a {
color: whitesmoke;
font-size: 150%;
}
svg {
fill: none;
stroke: whitesmoke;
@ -277,13 +282,13 @@ button[disabled] {
flex-flow: column;
}
#cryps input, #cryps select {
#constructs input, #constructs select {
border-color: #444;
background-color: #333;
border-radius: 0;
}
#cryps input:focus {
#constructs input:focus {
border-color: whitesmoke;
}
@ -349,7 +354,7 @@ header {
MENU
*/
.menu-cryps {
.menu-constructs {
display: grid;
grid-template-rows: min-content min-content;
@ -358,14 +363,14 @@ header {
"list";
}
.menu-cryps .list {
.menu-constructs .list {
grid-area: list;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.menu-cryp-ctr {
.menu-construct-ctr {
/*flex: 0 0 30%;*/
display: flex;
@ -374,7 +379,7 @@ header {
justify-content: center;
}
.spawn-btn .menu-cryp {
.spawn-btn .menu-construct {
border: 1px solid #333;
color: #333;
display: flex;
@ -399,7 +404,7 @@ header {
opacity: 0
}
.menu-cryp {
.menu-construct {
height: 100%;
margin: 0.5em;
box-sizing: border-box;
@ -512,7 +517,7 @@ main .top {
}
@media (max-height: 900px), (max-width: 1500px) {
#cryps {
#constructs {
font-size: 75%;
}

View File

@ -1,6 +1,6 @@
@media (max-height: 800px), (max-width: 1000px) {
#cryps {
font-size: 12pt;
#constructs {
font-size: 8pt;
padding: 0;
grid-template-columns: min-content 1fr;
grid-template-rows: min-content 1fr;
@ -9,6 +9,10 @@
"main main";
}
button {
font-size: 8pt;
}
table td {
height: 2.5em;
}
@ -27,15 +31,8 @@
-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
}
}
/* main {
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
}
*/
#toggle-nav { display: none; }
#toggle-nav-label {

View File

@ -1,12 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>cryps.gg - mnml pvp atbs</title>
<title>mnml.gg</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name=apple-mobile-web-app-capable content=yes>
<meta name=apple-mobile-web-app-status-bar-style content=black>
<meta name="description" content="cryps.gg - mnml pvp atbs">
<meta name="description" content="mnml pvp tbs">
<meta name="author" content="ntr@smokestack.io">
<link rel="manifest" href="manifest.webmanifest">
<link rel="stylesheet" href="./node_modules/izitoast/dist/css/iziToast.min.css"></script>

View File

@ -1,7 +1,7 @@
{
"name": "cryps.gg - mnml pvp atbs",
"description": "cryps.gg - mnml pvp atbs",
"short_name": "cryps.gg",
"name": "constructs.gg - mnml pvp atbs",
"description": "constructs.gg - mnml pvp atbs",
"short_name": "constructs.gg",
"icons": [
{
"src": "./assets/icons/726.png",

View File

@ -1,5 +1,5 @@
{
"name": "cryps-client",
"name": "mnml-client",
"version": "1.0.0",
"description": "",
"main": "index.js",

View File

@ -1,5 +1,5 @@
export const setAccount = value => ({ type: 'SET_ACCOUNT', value });
export const setCryps = value => ({ type: 'SET_CRYPS', value });
export const setConstructs = value => ({ type: 'SET_CONSTRUCTS', value });
export const setItemInfo = value => ({ type: 'SET_ITEM_INFO', value });
export const setSkip = value => ({ type: 'SET_SKIP', value });
export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
@ -11,9 +11,9 @@ export const setGame = value => ({ type: 'SET_GAME', value });
export const setResolution = value => ({ type: 'SET_RESOLUTION', value });
export const setShowLog = value => ({ type: 'SET_SHOW_LOG', value });
export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) });
export const setTeam = value => ({ type: 'SET_SELECTED_CRYPS', value: Array.from(value) });
export const setActiveSkill = (crypId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: crypId ? { crypId, skill } : null });
export const setActiveCryp = value => ({ type: 'SET_ACTIVE_CRYP', value });
export const setTeam = value => ({ type: 'SET_SELECTED_CONSTRUCTS', value: Array.from(value) });
export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null });
export const setActiveConstruct = value => ({ type: 'SET_ACTIVE_CONSTRUCT', value });
export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value });
export const setInfo = value => ({ type: 'SET_INFO', value });
export const setItemEquip = value => ({ type: 'SET_ITEM_EQUIP', value });

View File

@ -28,8 +28,8 @@ document.fonts.load('16pt "Jura"').then(() => {
store.dispatch(actions.setWs(ws));
ws.connect();
const Cryps = () => (
<div id="cryps" >
const Constructs = () => (
<div id="constructs" >
<input type="checkbox" id="toggle-nav"/>
<label id="toggle-nav-label" htmlFor="toggle-nav"><i className="fa fa-bars"></i></label>
<Header />
@ -40,7 +40,7 @@ document.fonts.load('16pt "Jura"').then(() => {
const App = () => (
<Provider store={store}>
<Cryps />
<Constructs />
</Provider>
);

View File

@ -1,6 +1,6 @@
const preact = require('preact');
function renderSpawnButton({ account, sendCrypSpawn }) {
function renderSpawnButton({ account, sendConstructSpawn }) {
let name = '';
if (!account) return <div>...</div>;
@ -13,7 +13,7 @@ function renderSpawnButton({ account, sendCrypSpawn }) {
<input
className="input"
type="text"
placeholder="cryp name"
placeholder="construct name"
onChange={e => (name = e.target.value)}
/>
</div>
@ -21,7 +21,7 @@ function renderSpawnButton({ account, sendCrypSpawn }) {
<button
className="button"
type="submit"
onClick={() => sendCrypSpawn(name)}>
onClick={() => sendConstructSpawn(name)}>
Spawn 👾
</button>
</div>

View File

@ -0,0 +1,16 @@
const { connect } = require('react-redux');
const ConstructSpawnButton = require('./construct.spawn.button');
const addState = connect(
function receiveState(state) {
const { ws } = state;
function sendConstructSpawn(name) {
return ws.sendConstructSpawn(name);
}
return { account: state.account, sendConstructSpawn };
}
);
module.exports = addState(ConstructSpawnButton);

View File

@ -1,16 +0,0 @@
const { connect } = require('react-redux');
const CrypSpawnButton = require('./cryp.spawn.button');
const addState = connect(
function receiveState(state) {
const { ws } = state;
function sendCrypSpawn(name) {
return ws.sendCrypSpawn(name);
}
return { account: state.account, sendCrypSpawn };
}
);
module.exports = addState(CrypSpawnButton);

View File

@ -1,7 +1,7 @@
const preact = require('preact');
const { STATS, eventClasses, getCombatText, crypAvatar } = require('../utils');
const { STATS, eventClasses, getCombatText, constructAvatar } = require('../utils');
const { animationDivs } = require('../animations');
const GameCryp = require('./game.cryp');
const GameConstruct = require('./game.construct');
function GamePanel(props) {
const {
@ -10,7 +10,7 @@ function GamePanel(props) {
resolution,
activeSkill,
setActiveSkill,
setActiveCryp,
setActiveConstruct,
selectSkillTarget,
sendInstanceState,
sendGameReady,
@ -76,9 +76,9 @@ function GamePanel(props) {
</div>
);
function findCryp(id) {
const team = game.players.find(t => t.cryps.find(c => c.id === id));
if (team) return team.cryps.find(c => c.id === id);
function findConstruct(id) {
const team = game.players.find(t => t.constructs.find(c => c.id === id));
if (team) return team.constructs.find(c => c.id === id);
return null;
}
@ -109,39 +109,39 @@ function GamePanel(props) {
);
function PlayerTeam(team) {
const cryps = team.cryps.map((c, i) => <GameCryp key={c.id} cryp={c} />);
const constructs = team.constructs.map((c, i) => <GameConstruct key={c.id} construct={c} />);
return (
<div className="team player">
{cryps}
{constructs}
</div>
);
}
function OpponentCryp(cryp, i) {
const ko = cryp.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, cryp);
function OpponentConstruct(construct, i) {
const ko = construct.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, construct);
const stats = [STATS.greenLife, STATS.redLife, STATS.blueLife].map((s, j) => (
<figure key={j} alt={s.stat}>
{s.svg(`stat-icon ${s.colour}`)}
<figcaption>{cryp[s.stat].value} / {cryp[s.stat].max}</figcaption>
<figcaption>{construct[s.stat].value} / {construct[s.stat].max}</figcaption>
</figure>
));
const [combatText, combatClass] = getCombatText(cryp, resolution);
const [combatText, combatClass] = getCombatText(construct, resolution);
const combatTextClass = `combat-text ${combatClass}`;
const combatTextEl = combatText
? <div className={combatTextClass}>{combatText}</div>
: null;
const effects = cryp.effects.length
? cryp.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
const effects = construct.effects.length
? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
: <div>&nbsp;</div>;
const playerTeamIds = playerTeam.cryps.map(c => c.id);
const playerTeamIds = playerTeam.constructs.map(c => c.id);
const targeting = game.stack
.filter(s => playerTeamIds.includes(s.source_cryp_id) && s.target_cryp_id === cryp.id)
.filter(s => playerTeamIds.includes(s.source_construct_id) && s.target_construct_id === construct.id)
.map((s, i) => <h3 key={i}>{`< ${s.skill}`}</h3>);
const anim = (
@ -153,17 +153,17 @@ function GamePanel(props) {
return (
<div
key={i}
className={`game-cryp ${ko} ${classes}`}
className={`game-construct ${ko} ${classes}`}
style={ activeSkill ? { cursor: 'pointer' } : {}}
onClick={() => selectSkillTarget(cryp.id)} >
onClick={() => selectSkillTarget(construct.id)} >
<div className="stats">{stats}</div>
<h3 className="name" >{cryp.name}</h3>
<h3 className="name" >{construct.name}</h3>
<div className="effects">{effects}</div>
<div className="targeting">{targeting}</div>
<figure
className="img"
onClick={() => selectSkillTarget(cryp.id)} >
{crypAvatar(cryp.name)}
onClick={() => selectSkillTarget(construct.id)} >
{constructAvatar(construct.name, construct.id)}
{combatTextEl}
{anim}
</figure>
@ -173,10 +173,10 @@ function GamePanel(props) {
function OpponentTeam(team) {
const cryps = team.cryps.map(OpponentCryp);
const constructs = team.constructs.map(OpponentConstruct);
return (
<div className="team opponent">
{cryps}
{constructs}
</div>
);
}
@ -185,7 +185,7 @@ function GamePanel(props) {
function gameClick(e) {
e.stopPropagation();
setActiveCryp(null);
setActiveConstruct(null);
}
return (

View File

@ -3,7 +3,7 @@ const preact = require('preact');
const range = require('lodash/range');
const actions = require('../actions');
const { STATS, eventClasses, getCombatText, crypAvatar } = require('../utils');
const { STATS, eventClasses, getCombatText, constructAvatar } = require('../utils');
const { animationDivs } = require('../animations');
const SkillBtn = require('./skill.btn');
@ -18,16 +18,16 @@ const addState = connect(
activeSkill,
} = state;
function selectSkillTarget(targetCrypId) {
function selectSkillTarget(targetConstructId) {
if (activeSkill) {
return ws.sendGameSkill(game.id, activeSkill.crypId, targetCrypId, activeSkill.skill);
return ws.sendGameSkill(game.id, activeSkill.constructId, targetConstructId, activeSkill.skill);
}
return false;
}
// intercept self casting skills
if (activeSkill && activeSkill.skill.self_targeting) {
ws.sendGameSkill(game.id, activeSkill.crypId, null, activeSkill.skill.skill);
ws.sendGameSkill(game.id, activeSkill.constructId, null, activeSkill.skill.skill);
}
return {
@ -40,48 +40,48 @@ const addState = connect(
},
);
function GameCryp(props) {
function GameConstruct(props) {
const {
game,
account,
cryp,
construct,
resolution,
activeSkill,
setActiveCryp,
setActiveConstruct,
selectSkillTarget,
} = props;
const ko = cryp.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, cryp);
const ko = construct.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, construct);
const skills = range(0, 3)
.map(i => <SkillBtn key={i} cryp={cryp} i={i} />);
.map(i => <SkillBtn key={i} construct={construct} i={i} />);
const stats = [STATS.greenLife, STATS.redLife, STATS.blueLife].map((s, j) => {
// i've seen this happen ;/
if (cryp[s.stat].value < 0) console.warn(cryp);
if (construct[s.stat].value < 0) console.warn(construct);
return <figure key={j} alt={s.stat}>
{s.svg(`stat-icon ${s.colour}`)}
<figcaption>{cryp[s.stat].value} / {cryp[s.stat].max}</figcaption>
<figcaption>{construct[s.stat].value} / {construct[s.stat].max}</figcaption>
</figure>
});
const [combatText, combatClass] = getCombatText(cryp, resolution);
const [combatText, combatClass] = getCombatText(construct, resolution);
const combatTextClass = `combat-text ${combatClass}`;
const combatTextEl = combatText
? <div className={combatTextClass}>{combatText}</div>
: null;
const effects = cryp.effects.length
? cryp.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
const effects = construct.effects.length
? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
: <div>&nbsp;</div>;
const playerTeam = game.players.find(t => t.id === account.id);
const playerTeamIds = playerTeam.cryps.map(c => c.id);
const playerTeamIds = playerTeam.constructs.map(c => c.id);
const targeting = game.stack
.filter(s => playerTeamIds.includes(s.source_cryp_id) && s.target_cryp_id === cryp.id)
.filter(s => playerTeamIds.includes(s.source_construct_id) && s.target_construct_id === construct.id)
.map((s, i) => <h3 key={i}>{`< ${s.skill}`}</h3>);
const anim = (
@ -93,9 +93,9 @@ function GameCryp(props) {
return (
<div
style={ activeSkill ? { cursor: 'pointer' } : {}}
className={`game-cryp ${ko} ${classes}`} >
className={`game-construct ${ko} ${classes}`} >
<h3 className="name">
{cryp.name}
{construct.name}
</h3>
<div className="skills">
{skills}
@ -105,8 +105,8 @@ function GameCryp(props) {
</div>
<figure
className="img"
onClick={() => selectSkillTarget(cryp.id)} >
{crypAvatar(cryp.name, cryp.id)}
onClick={() => selectSkillTarget(construct.id)} >
{constructAvatar(construct.name, construct.id)}
{combatTextEl}
{anim}
</figure>
@ -120,4 +120,4 @@ function GameCryp(props) {
);
}
module.exports = addState(GameCryp);
module.exports = addState(GameConstruct);

View File

@ -13,12 +13,12 @@ const addState = connect(
resolution,
showLog,
activeSkill,
activeCryp,
activeConstruct,
} = state;
function selectSkillTarget(targetCrypId) {
function selectSkillTarget(targetConstructId) {
if (activeSkill) {
return ws.sendGameSkill(game.id, activeSkill.crypId, targetCrypId, activeSkill.skill);
return ws.sendGameSkill(game.id, activeSkill.constructId, targetConstructId, activeSkill.skill);
}
return false;
}
@ -34,7 +34,7 @@ const addState = connect(
// intercept self casting skills
if (activeSkill && activeSkill.skill.self_targeting) {
ws.sendGameSkill(game.id, activeSkill.crypId, null, activeSkill.skill.skill);
ws.sendGameSkill(game.id, activeSkill.constructId, null, activeSkill.skill.skill);
}
return {
@ -43,7 +43,7 @@ const addState = connect(
account,
resolution,
activeSkill,
activeCryp,
activeConstruct,
selectSkillTarget,
sendInstanceState,
sendGameReady,
@ -51,13 +51,13 @@ const addState = connect(
},
function receiveDispatch(dispatch) {
function setActiveSkill(crypId, skill) {
dispatch(actions.setActiveSkill(crypId, skill));
// particlesJS(`particles-${crypId}`, config);
function setActiveSkill(constructId, skill) {
dispatch(actions.setActiveSkill(constructId, skill));
// particlesJS(`particles-${constructId}`, config);
}
function setActiveCryp(cryp) {
dispatch(actions.setActiveCryp(cryp));
function setActiveConstruct(construct) {
dispatch(actions.setActiveConstruct(construct));
}
function quit() {
@ -73,7 +73,7 @@ const addState = connect(
dispatch(actions.setSkip(true));
}
return { setActiveSkill, setActiveCryp, quit, toggleLog, skip };
return { setActiveSkill, setActiveConstruct, quit, toggleLog, skip };
}
);

View File

@ -23,7 +23,7 @@ function renderHeader(args) {
return (
<header>
<h1 className="header-title">
cryps.gg
mnml.gg
</h1>
{accountStatus}
</header>

View File

@ -27,10 +27,10 @@ function Info(args) {
let red = 0;
let blue = 0;
let green = 0;
player.cryps.forEach(cryp => {
red += cryp.colours.red;
blue += cryp.colours.blue;
green += cryp.colours.green;
player.constructs.forEach(construct => {
red += construct.colours.red;
blue += construct.colours.blue;
green += construct.colours.green;
});
const teamColours = { red, blue, green };

View File

@ -3,7 +3,7 @@ const { connect } = require('react-redux');
const Vbox = require('./vbox.component');
const InfoContainer = require('./info.container');
const InstanceCrypsContainer = require('./instance.cryps');
const InstanceConstructsContainer = require('./instance.constructs');
const EquipmentContainer = require('./instance.equip');
const actions = require('../actions');
@ -137,7 +137,7 @@ function Instance(args) {
<Vbox />
<InfoContainer />
<EquipmentContainer />
<InstanceCrypsContainer />
<InstanceConstructsContainer />
</main>
);
}

View File

@ -3,24 +3,24 @@ const preact = require('preact');
const range = require('lodash/range');
const shapes = require('./shapes');
const { SPECS, STATS, instanceCryp } = require('../utils');
const { SPECS, STATS, instanceConstruct } = require('../utils');
const actions = require('../actions');
const addState = connect(
function receiveState(state) {
const { ws, instance, account, itemInfo, itemEquip, activeCryp } = state;
const { ws, instance, account, itemInfo, itemEquip, activeConstruct } = state;
const player = instance.players.find(p => p.id === account.id);
function sendInstanceReady() {
return ws.sendInstanceReady(instance.id);
}
function sendVboxApply(crypId, i) {
return ws.sendVboxApply(instance.id, crypId, i);
function sendVboxApply(constructId, i) {
return ws.sendVboxApply(instance.id, constructId, i);
}
function sendUnequip(crypId, item) {
return ws.sendVboxUnequip(instance.id, crypId, item);
function sendUnequip(constructId, item) {
return ws.sendVboxUnequip(instance.id, constructId, item);
}
return {
@ -31,7 +31,7 @@ const addState = connect(
sendVboxApply,
itemInfo,
itemEquip,
activeCryp,
activeConstruct,
sendUnequip,
};
},
@ -45,8 +45,8 @@ const addState = connect(
dispatch(actions.setInfo(item));
}
function setActiveCryp(value) {
dispatch(actions.setActiveCryp(value));
function setActiveConstruct(value) {
dispatch(actions.setActiveConstruct(value));
}
function clearInfo() {
@ -61,19 +61,19 @@ const addState = connect(
return dispatch(actions.setItemUnequip(v));
}
return { quit, clearInfo, setInfo, setActiveCryp, setItemUnequip, setItemEquip };
return { quit, clearInfo, setInfo, setActiveConstruct, setItemUnequip, setItemEquip };
}
);
function Cryp(props) {
function Construct(props) {
const {
activeCryp,
activeConstruct,
itemEquip,
cryp,
construct,
player,
sendVboxApply,
setActiveCryp,
setActiveConstruct,
setItemUnequip,
setItemEquip,
itemInfo,
@ -84,9 +84,9 @@ function Cryp(props) {
function onClick(e) {
e.stopPropagation();
e.preventDefault();
if (itemEquip !== null) sendVboxApply(cryp.id, itemEquip);
if (itemEquip !== null) sendVboxApply(construct.id, itemEquip);
setItemEquip(null);
return setActiveCryp(cryp);
return setActiveConstruct(construct);
}
function hoverInfo(e, info) {
@ -100,7 +100,7 @@ function Cryp(props) {
const specList = itemInfo.items.filter(v => v.spec).map(v => v.item);
const skills = range(0, 3).map(i => {
const skill = cryp.skills[i];
const skill = construct.skills[i];
const s = skill
? skill.skill
: (<span className="gray">+</span>);
@ -108,15 +108,15 @@ function Cryp(props) {
function skillClick(e) {
if (!skill) return false;
setItemUnequip(skill.skill);
setActiveCryp(cryp);
setActiveConstruct(construct);
e.stopPropagation();
return true;
}
function skillDblClick(e) {
if (!skill) return false;
sendUnequip(cryp.id, skill.skill);
setActiveCryp(null);
sendUnequip(construct.id, skill.skill);
setActiveConstruct(null);
setItemUnequip(null);
e.stopPropagation();
e.preventDefault();
@ -140,7 +140,7 @@ function Cryp(props) {
});
const specs = range(0, 6).map(i => {
const s = cryp.specs[i];
const s = construct.specs[i];
if (!s) {
const equip = specList.includes(vbox.bound[itemEquip]) ? 'equip-spec' : 'gray';
@ -155,12 +155,12 @@ function Cryp(props) {
function specClick(e) {
e.stopPropagation();
setItemUnequip(s);
setActiveCryp(cryp);
setActiveConstruct(construct);
}
function specDblClick(e) {
sendUnequip(cryp.id, s);
setActiveCryp(null);
sendUnequip(construct.id, s);
setActiveConstruct(null);
setItemUnequip(null);
e.stopPropagation();
e.preventDefault();
@ -183,14 +183,14 @@ function Cryp(props) {
const stats = Object.values(STATS).map(s => (
<figure key={s.stat} alt={s.stat} className={s.stat}>
{s.svg(`stat-icon ${s.colour} stat`)}
<figcaption>{cryp[s.stat].value}</figcaption>
<figcaption>{construct[s.stat].value}</figcaption>
</figure>
));
const activeId = activeCryp ? activeCryp.id : false;
const crypClass = activeId === cryp.id ? 'instance-cryp-active' : 'instance-cryp';
const activeId = activeConstruct ? activeConstruct.id : false;
const constructClass = activeId === construct.id ? 'instance-construct-active' : 'instance-construct';
// const cTotal = cryp.colours.red + cryp.colours.blue + cryp.colours.green;
// const colours = mapValues(cryp.colours, c => {
// const cTotal = construct.colours.red + construct.colours.blue + construct.colours.green;
// const colours = mapValues(construct.colours, c => {
// if (cTotal === 0) return 245;
// return Math.floor(c / cTotal * 255);
// });
@ -204,18 +204,18 @@ function Cryp(props) {
// const border = { border: `${thickness(cTotal)}px solid rgba(${colours.red}, ${colours.green}, ${colours.blue}, ${alpha})` };
return (
<div key={cryp.id} className={crypClass} onClick={onClick} >
{instanceCryp(cryp.name, cryp.id)}
<h2 className="name" >{cryp.name}</h2>
<div className="skills" onMouseOver={e => hoverInfo(e, 'crypSkills')} >
<div key={construct.id} className={constructClass} onClick={onClick} >
{instanceConstruct(construct.name, construct.id)}
<h2 className="name" >{construct.name}</h2>
<div className="skills" onMouseOver={e => hoverInfo(e, 'constructSkills')} >
{skills}
</div>
<div className="specs" onMouseOver={e => hoverInfo(e, 'crypSpecs')} >
<div className="specs" onMouseOver={e => hoverInfo(e, 'constructSpecs')} >
{specs}
</div>
<div className="stats">
<div className="damage-label label">
Damage
Power
</div>
<div className="speed-label label">
Speed
@ -231,15 +231,15 @@ function Cryp(props) {
);
}
function InstanceCryps(props) {
function InstanceConstructs(props) {
const {
activeCryp,
activeConstruct,
itemEquip,
player,
instance,
// clearInfo,
setInfo,
setActiveCryp,
setActiveConstruct,
sendVboxApply,
itemInfo,
@ -252,27 +252,27 @@ function InstanceCryps(props) {
if (!player) return false;
if (instance.phase === 'Lobby') return false;
const cryps = player.cryps.map((c, i) => Cryp({
cryp: c,
activeCryp,
const constructs = player.constructs.map((c, i) => Construct({
construct: c,
activeConstruct,
itemEquip,
setItemUnequip,
setItemEquip,
player,
sendVboxApply,
setInfo,
setActiveCryp,
setActiveConstruct,
itemInfo,
setVboxHighlight,
sendUnequip,
}));
const classes = `cryp-list`;
const classes = `construct-list`;
return (
<div className={classes} onClick={() => setActiveCryp(null)}>
{cryps}
<div className={classes} onClick={() => setActiveConstruct(null)}>
{constructs}
</div>
);
}
module.exports = addState(InstanceCryps);
module.exports = addState(InstanceConstructs);

View File

@ -6,9 +6,9 @@ const addState = connect(
function receiveState(state) {
const { ws, team } = state;
function sendInstanceNew(sCryps, name, players) {
if (sCryps.length) {
return ws.sendInstanceNew(sCryps, name, players);
function sendInstanceNew(sConstructs, name, players) {
if (sConstructs.length) {
return ws.sendInstanceNew(sConstructs, name, players);
}
return false;
}

View File

@ -8,14 +8,14 @@ const { convertItem, SPECS } = require('./../utils');
const addState = connect(
function receiveState(state) {
const { account, activeCryp, itemInfo, info, ws, instance, itemUnequip } = state;
const { account, activeConstruct, itemInfo, info, ws, instance, itemUnequip } = state;
const player = instance.players.find(p => p.id === account.id);
function sendUnequip(crypId, item) {
return ws.sendVboxUnequip(instance.id, crypId, item);
function sendUnequip(constructId, item) {
return ws.sendVboxUnequip(instance.id, constructId, item);
}
return { player, itemInfo, instance, info, sendUnequip, activeCryp, itemUnequip };
return { player, itemInfo, instance, info, sendUnequip, activeConstruct, itemUnequip };
},
function receiveDispatch(dispatch) {
@ -48,7 +48,7 @@ function Equipment(props) {
itemUnequip,
setItemEquip,
setItemUnequip,
activeCryp,
activeConstruct,
itemInfo,
sendUnequip,
@ -65,7 +65,7 @@ function Equipment(props) {
const isSpec = fullInfo && fullInfo.spec;
function skillClick(e, i) {
if (itemUnequip && activeCryp) return false;
if (itemUnequip && activeConstruct) return false;
const value = vbox.bound[i];
setItemEquip(i);
return false;
@ -74,9 +74,9 @@ function Equipment(props) {
function unequipClick(e) {
e.stopPropagation();
if (!itemUnequip) return false;
if (!activeCryp) return false;
if (!activeConstruct) return false;
setItemUnequip(null);
return sendUnequip(activeCryp.id, itemUnequip);
return sendUnequip(activeConstruct.id, itemUnequip);
}
function hoverInfo(e, info) {

View File

@ -7,7 +7,7 @@ const InstanceCreateForm = require('./instance.create.form');
const addState = connect(
function receiveState(state) {
const { ws, cryps, team, instances, account } = state;
const { ws, constructs, team, instances, account } = state;
function sendInstanceJoin(instance) {
if (team.length) {
@ -26,7 +26,7 @@ const addState = connect(
return {
account,
cryps,
constructs,
team,
sendInstanceJoin,
sendInstanceState,

View File

@ -1,11 +1,10 @@
// eslint-disable-next-line
const preact = require('preact');
const { useState } = require('preact/hooks');
function renderLogin({ submitLogin, submitRegister, submitDemo }) {
const details = {
name: '',
password: '',
};
function renderLogin({ submitLogin, submitRegister }) {
const [name, setName] = useState('');
const [password, setPassword] = useState('');
return (
<div className="login">
@ -13,28 +12,28 @@ function renderLogin({ submitLogin, submitRegister, submitDemo }) {
className="login-input"
type="email"
placeholder="username"
onChange={e => (details.name = e.target.value)}
onInput={e => setName(e.target.value)}
/>
<input
className="login-input"
type="password"
placeholder="password"
onChange={e => (details.password = e.target.value)}
onInput={e => setPassword(e.target.value)}
/>
<button
className="login-btn"
onClick={() => submitLogin(details.name, details.password)}>
onClick={() => submitLogin(name, password)}>
Login
</button>
<button
className="login-btn"
onClick={() => submitRegister(details.name, details.password)}>
onClick={() => submitRegister(name, password)}>
Register
</button>
<button
className="login-btn"
onClick={() => submitDemo()}>
demo
onClick={() => document.location.assign('https://discord.gg/YJJgurM')}>
Discord + Invites
</button>
</div>
);

View File

@ -9,12 +9,10 @@ const addState = connect(
return ws.sendAccountLogin(name, password);
}
function submitRegister(name, password) {
console.log(name, password);
return ws.sendAccountCreate(name, password);
}
function submitDemo() {
return ws.sendAccountDemo();
}
return { account: state.account, submitLogin, submitRegister, submitDemo };
return { account: state.account, submitLogin, submitRegister };
},
);

View File

@ -3,7 +3,7 @@ const range = require('lodash/range');
const { NULL_UUID } = require('./../utils');
const { stringSort, crypAvatar } = require('./../utils');
const { stringSort, constructAvatar } = require('./../utils');
const SpawnButton = require('./spawn.button');
const InstanceCreateForm = require('./instance.create.form');
@ -19,14 +19,14 @@ const COLOURS = [
function Menu(args) {
const {
account,
cryps,
constructs,
team,
setTeam,
sendInstanceState,
sendPlayerMmCrypsSet,
sendPlayerMmConstructsSet,
sendInstanceJoin,
sendInstanceList,
sendCrypSpawn,
sendConstructSpawn,
instances,
} = args;
@ -61,7 +61,7 @@ function Menu(args) {
// <button
// className={'menu-instance-btn left'}
// disabled={instanceJoinHidden}
// onClick={() => sendPlayerMmCrypsSet()}>
// onClick={() => sendPlayerMmConstructsSet()}>
// Set Matchmaking Team
// </button>
// );
@ -88,12 +88,12 @@ function Menu(args) {
);
}
function crypList() {
if (!cryps) return <div></div>;
function constructList() {
if (!constructs) return <div></div>;
// redux limitation + suggested workaround
// so much for dumb components
function selectCryp(id) {
function selectConstruct(id) {
// remove
const i = team.findIndex(sid => sid === id);
if (i > -1) {
@ -108,37 +108,37 @@ function Menu(args) {
return setTeam(team);
}
const crypPanels = cryps.sort(idSort).map(cryp => {
const colour = team.indexOf(cryp.id);
const constructPanels = constructs.sort(idSort).map(construct => {
const colour = team.indexOf(construct.id);
const selected = colour > -1;
const borderColour = selected ? COLOURS[colour] : '#000000';
return (
<div
key={cryp.id}
className="menu-cryp-ctr">
key={construct.id}
className="menu-construct-ctr">
<div
className="menu-cryp"
className="menu-construct"
style={ { 'border-color': borderColour || 'whitesmoke' } }
onClick={() => selectCryp(cryp.id)} >
{crypAvatar(cryp.name)}
<h2>{cryp.name}</h2>
onClick={() => selectConstruct(construct.id)} >
{constructAvatar(construct.name)}
<h2>{construct.name}</h2>
</div>
</div>
);
});
const spawnButtonsNum = cryps.length < 3
? (3 - cryps.length)
const spawnButtonsNum = constructs.length < 3
? (3 - constructs.length)
: 1;
const spawnButtons = range(spawnButtonsNum)
.map(i => <SpawnButton key={i} i={i} spawn={name => sendCrypSpawn(name)} />);
.map(i => <SpawnButton key={i} i={i} spawn={name => sendConstructSpawn(name)} />);
return (
<div className="menu-cryps">
{crypPanels}
<div className="menu-constructs">
{constructPanels}
{spawnButtons}
</div>
);

View File

@ -5,7 +5,7 @@ const actions = require('./../actions');
const addState = connect(
function receiveState(state) {
const { ws, cryps, team, instances, account } = state;
const { ws, constructs, team, instances, account } = state;
function sendInstanceJoin(instance) {
if (team.length) {
@ -14,15 +14,15 @@ const addState = connect(
return false;
}
function sendPlayerMmCrypsSet() {
function sendPlayerMmConstructsSet() {
if (team.length) {
return ws.sendPlayerMmCrypsSet(team);
return ws.sendPlayerMmConstructsSet(team);
}
return false;
}
function sendCrypSpawn(name) {
return ws.sendCrypSpawn(name);
function sendConstructSpawn(name) {
return ws.sendConstructSpawn(name);
}
function sendInstanceState(instance) {
@ -35,20 +35,20 @@ const addState = connect(
return {
account,
cryps,
constructs,
team,
sendInstanceJoin,
sendInstanceState,
sendInstanceList,
sendCrypSpawn,
sendPlayerMmCrypsSet,
sendConstructSpawn,
sendPlayerMmConstructsSet,
instances,
};
},
function receiveDispatch(dispatch) {
function setTeam(crypIds) {
dispatch(actions.setTeam(crypIds));
function setTeam(constructIds) {
dispatch(actions.setTeam(constructIds));
}
return {

View File

@ -1,9 +1,12 @@
const { connect } = require('react-redux');
const preact = require('preact');
const { Fragment } = require('preact');
const actions = require('../actions');
const testGame = require('./../test.game');
const testInstance = require('./../test.instance');
const testGame = process.env.NODE_ENV === 'development' && require('./../test.game');
const testInstance = process.env.NODE_ENV === 'development' && require('./../test.instance');
console.log('env', process.env.NODE_ENV);
const addState = connect(
function receiveState(state) {
@ -12,7 +15,7 @@ const addState = connect(
account,
instances,
team,
cryps,
constructs,
game,
} = state;
@ -24,7 +27,7 @@ const addState = connect(
account,
instances,
team,
cryps,
constructs,
game,
sendInstanceState,
};
@ -57,7 +60,7 @@ function Nav(args) {
account,
sendInstanceState,
team,
cryps,
constructs,
instances,
game,
@ -78,12 +81,21 @@ function Nav(args) {
const teamElements = team.map((c, i) => {
if (c) {
const cryp = cryps.find(f => f.id === c);
return <button key={c} onClick={() => navTo('team')}>{cryp.name}</button>;
const construct = constructs.find(f => f.id === c);
return <button key={c} onClick={() => navTo('team')}>{construct.name}</button>;
}
return <button key={i} onClick={() => navTo('team')}>+</button>;
});
const haxSection = process.env.NODE_ENV === 'development'
? (
<Fragment>
<h2>Hax</h2>
<button onClick={() => setTestGame(account.id)}>Test Game</button>
<button onClick={() => setTestInstance(account.id)}>Test Instance</button>
</Fragment>)
: null;
return (
<nav>
<h2>Team</h2>
@ -93,9 +105,7 @@ function Nav(args) {
<button onClick={() => navTo('list')}>2. Join</button>
<hr />
{joined}
<h2>Hax</h2>
<button onClick={() => setTestGame(account.id)}>Test Game</button>
<button onClick={() => setTestInstance(account.id)}>Test Instance</button>
{haxSection}
</nav>
);
}

View File

@ -17,8 +17,8 @@ const addState = connect(
},
function receiveDispatch(dispatch) {
function setActiveSkill(crypId, skill) {
dispatch(actions.setActiveSkill(crypId, skill));
function setActiveSkill(constructId, skill) {
dispatch(actions.setActiveSkill(constructId, skill));
}
return { setActiveSkill };
@ -28,7 +28,7 @@ const addState = connect(
function Skill(props) {
const {
cryp,
construct,
game,
i,
mobile,
@ -36,14 +36,14 @@ function Skill(props) {
setActiveSkill,
} = props;
const s = cryp.skills[i];
const ko = cryp.green_life.value === 0 ? 'ko' : '';
const s = construct.skills[i];
const ko = construct.green_life.value === 0 ? 'ko' : '';
if (!s) {
return (
<button
disabled='true'
className='cryp-skill-btn disabled'>
className='construct-skill-btn disabled'>
</button>
);
}
@ -52,25 +52,25 @@ function Skill(props) {
? 'top'
: '';
const cdText = cryp.skills[i].cd > 0
const cdText = construct.skills[i].cd > 0
? `- ${s.cd}T`
: '';
const highlight = activeSkill
? activeSkill.crypId === cryp.id && activeSkill.skill === s.skill
? activeSkill.constructId === construct.id && activeSkill.skill === s.skill
: false;
function onClick(e) {
e.stopPropagation();
return setActiveSkill(cryp.id, s.skill);
return setActiveSkill(construct.id, s.skill);
}
const targeting = game.stack.some(stack => stack.source_cryp_id === cryp.id && stack.skill === s.skill);
const targeting = game.stack.some(stack => stack.source_construct_id === construct.id && stack.skill === s.skill);
return (
<button
disabled={!!cdText || ko}
className={`cryp-skill-btn ${side} ${(targeting || highlight) ? 'active' : ''}`}
className={`construct-skill-btn ${side} ${(targeting || highlight) ? 'active' : ''}`}
type="submit"
onClick={onClick}>
{s.skill} {cdText}

View File

@ -13,7 +13,6 @@ class SpawnButton extends Component {
}
handleInput(event) {
console.log(event.target.value);
this.setState({ value: event.target.value });
}
@ -31,9 +30,9 @@ class SpawnButton extends Component {
return (
<div
key={this.props.i}
className="menu-cryp-ctr spawn-btn">
className="menu-construct-ctr spawn-btn">
<div
className="menu-cryp"
className="menu-construct"
onClick={() => this.enable()} >
<h2>+</h2>
<input

View File

@ -11,17 +11,17 @@ function TargetSvg(args) {
const playerTeam = game.players.find(t => t.id === account.id);
const otherTeam = game.players.find(t => t.id !== account.id);
const playerTeamIds = playerTeam.cryps.map(c => c.id);
const outgoing = game.stack.filter(stack => playerTeamIds.includes(stack.source_cryp_id));
const playerTeamIds = playerTeam.constructs.map(c => c.id);
const outgoing = game.stack.filter(stack => playerTeamIds.includes(stack.source_construct_id));
function getPath(cast) {
const source = playerTeam.cryps.findIndex(c => c.id === cast.source_cryp_id);
const defensive = playerTeamIds.includes(cast.target_cryp_id);
const source = playerTeam.constructs.findIndex(c => c.id === cast.source_construct_id);
const defensive = playerTeamIds.includes(cast.target_construct_id);
const target = defensive
? playerTeam.cryps.findIndex(c => c.id === cast.target_cryp_id)
: otherTeam.cryps.findIndex(c => c.id === cast.target_cryp_id);
? playerTeam.constructs.findIndex(c => c.id === cast.target_construct_id)
: otherTeam.constructs.findIndex(c => c.id === cast.target_construct_id);
const skillIndex = playerTeam.cryps[source].skills.findIndex(s => s.skill === cast.skill);
const skillIndex = playerTeam.constructs[source].skills.findIndex(s => s.skill === cast.skill);
const skillOffset = (100 * skillIndex) + 50;
const sourceY = 0;

View File

@ -4,7 +4,7 @@ const range = require('lodash/range');
const actions = require('./../actions');
const { NULL_UUID } = require('./../utils');
const { stringSort, crypAvatar } = require('./../utils');
const { stringSort, constructAvatar } = require('./../utils');
const SpawnButton = require('./spawn.button');
const idSort = stringSort('id');
@ -17,23 +17,23 @@ const COLOURS = [
const addState = connect(
function receiveState(state) {
const { ws, cryps, team, account } = state;
const { ws, constructs, team, account } = state;
function sendCrypSpawn(name) {
return ws.sendCrypSpawn(name);
function sendConstructSpawn(name) {
return ws.sendConstructSpawn(name);
}
return {
account,
cryps,
constructs,
team,
sendCrypSpawn,
sendConstructSpawn,
};
},
function receiveDispatch(dispatch) {
function setTeam(crypIds) {
dispatch(actions.setTeam(crypIds));
function setTeam(constructIds) {
dispatch(actions.setTeam(constructIds));
}
function navToList() {
@ -53,19 +53,19 @@ const addState = connect(
function Team(args) {
const {
account,
cryps,
constructs,
team,
setTeam,
sendCrypSpawn,
sendConstructSpawn,
navToList,
} = args;
if (!cryps) return <div></div>;
if (!constructs) return <div></div>;
// redux limitation + suggested workaround
// so much for dumb components
function selectCryp(id) {
function selectConstruct(id) {
// remove
const i = team.findIndex(sid => sid === id);
if (i > -1) {
@ -80,31 +80,31 @@ function Team(args) {
return setTeam(team);
}
const crypPanels = cryps.sort(idSort).map(cryp => {
const colour = team.indexOf(cryp.id);
const constructPanels = constructs.sort(idSort).map(construct => {
const colour = team.indexOf(construct.id);
const selected = colour > -1;
const borderColour = selected ? COLOURS[colour] : '#000000';
return (
<div
key={cryp.id}
className="menu-cryp-ctr">
key={construct.id}
className="menu-construct-ctr">
<div
className="menu-cryp"
className="menu-construct"
style={ { 'border-color': borderColour || 'whitesmoke' } }
onClick={() => selectCryp(cryp.id)} >
{crypAvatar(cryp.name, cryp.id)}
<h2>{cryp.name}</h2>
onClick={() => selectConstruct(construct.id)} >
{constructAvatar(construct.name, construct.id)}
<h2>{construct.name}</h2>
</div>
</div>
);
});
const spawnButtonsNum = (3 - cryps.length % 3);
const spawnButtonsNum = (3 - constructs.length % 3);
const spawnButtons = range(spawnButtonsNum)
.map(i => <SpawnButton key={i} i={i} spawn={name => sendCrypSpawn(name)} />);
.map(i => <SpawnButton key={i} i={i} spawn={name => sendConstructSpawn(name)} />);
const header = (
@ -119,10 +119,10 @@ function Team(args) {
);
return (
<main className="menu-cryps">
<main className="menu-constructs">
{header}
<div className="list">
{crypPanels}
{constructPanels}
{spawnButtons}
</div>
</main>

View File

@ -45,19 +45,19 @@ module.exports = {
},
equipSkills: {
item: 'QUICK ACCESS - SKILLS',
description: 'Click to select \nClick target CRYP to equip',
description: 'Click to select \nClick target CONSTRUCT to equip',
},
equipSpecs: {
item: 'QUICK ACCESS - SPECS',
description: 'Click to select \nClick target CRYP to equip',
description: 'Click to select \nClick target CONSTRUCT to equip',
},
crypSkills: {
constructSkills: {
item: 'SKILLS',
description: 'Skills are used by Cryps in-game.\nClick a SKILL above and select a CRYP to equip.\nDouble-click to unequip.',
description: 'Skills are used by Constructs in-game.\nClick a SKILL above and select a CONSTRUCT to equip.\nDouble-click to unequip.',
},
crypSpecs: {
constructSpecs: {
item: 'SPECS',
description: 'SPECS increase the STATS of a CRYP.\nSPECS have increased effect once they reach a THRESHOLD across your whole team.\nClick a SPEC above and select a CRYP to equip.\nDouble-click to unequip.',
description: 'SPECS increase the STATS of a CONSTRUCT.\nSPECS have increased effect once they reach a THRESHOLD across your whole team.\nClick a SPEC above and select a CONSTRUCT to equip.\nDouble-click to unequip.',
},
},

View File

@ -3,13 +3,13 @@ const eachSeries = require('async/eachSeries');
const actions = require('./actions');
const { TIMES } = require('./constants');
const { getCombatSequence, resoCrypHealth } = require('./utils');
const { getCombatSequence, resoConstructHealth } = require('./utils');
function registerEvents(store) {
// timeout handlers
store.subscribe(() => {
const { game, instance, cryps, ws } = store.getState();
const { game, instance, constructs, ws } = store.getState();
if (!game) ws.clearGameStateTimeout();
if (!instance) ws.clearInstanceStateTimeout();
@ -19,12 +19,12 @@ function registerEvents(store) {
store.dispatch(actions.setPing(ping));
}
function setCryps(cryps) {
console.log('EVENT ->', 'cryps', cryps);
function setConstructs(constructs) {
console.log('EVENT ->', 'constructs', constructs);
}
function setCrypList(cryps) {
store.dispatch(actions.setCryps(cryps));
function setConstructList(constructs) {
store.dispatch(actions.setConstructs(constructs));
}
function setWs(ws) {
@ -50,8 +50,8 @@ function registerEvents(store) {
const stagedR = Object.create(r);
stagedR.stage = stage;
// Apply damage for each cryp
if (stage === 'POST_SKILL') resoCrypHealth(stagedR, currentGame);
// Apply damage for each construct
if (stage === 'POST_SKILL') resoConstructHealth(stagedR, currentGame);
store.dispatch(actions.setResolution(stagedR));
return setTimeout(sCb, TIMES[stage]);
@ -98,7 +98,7 @@ function registerEvents(store) {
function clearInfo() {
store.dispatch(actions.setInfo(null));
store.dispatch(actions.setActiveCryp(null));
store.dispatch(actions.setActiveConstruct(null));
console.log('event clear item');
}
@ -132,8 +132,8 @@ function registerEvents(store) {
console.log('EVENT ->', 'gameList', gameList);
}
function setCrypStatusUpdate(id, skill, target) {
console.log('EVENT ->', 'crypStatusUpdate', { id, skill, target });
function setConstructStatusUpdate(id, skill, target) {
console.log('EVENT ->', 'constructStatusUpdate', { id, skill, target });
}
function setItemInfo(v) {
@ -142,22 +142,22 @@ function registerEvents(store) {
// events.on('SET_PLAYER', setInstance);
// events.on('SEND_SKILL', function skillActive(gameId, crypId, targetCrypId, skill) {
// ws.sendGameSkill(gameId, crypId, targetCrypId, skill);
// setCrypStatusUpdate(crypId, skill, targetCrypId);
// events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) {
// ws.sendGameSkill(gameId, constructId, targetConstructId, skill);
// setConstructStatusUpdate(constructId, skill, targetConstructId);
// });
// events.on('CRYP_ACTIVE', function crypActiveCb(cryp) {
// for (let i = 0; i < cryps.length; i += 1) {
// if (cryps[i].id === cryp.id) cryps[i].active = !cryps[i].active;
// events.on('CONSTRUCT_ACTIVE', function constructActiveCb(construct) {
// for (let i = 0; i < constructs.length; i += 1) {
// if (constructs[i].id === construct.id) constructs[i].active = !constructs[i].active;
// }
// return setCryps(cryps);
// return setConstructs(constructs);
// });
const errMessages = {
select_cryps: 'Select your cryps before battle using the numbered buttons next to the cryp avatar',
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 cryp can only learn a maximum of 4 skills',
max_skills: 'Your construct can only learn a maximum of 4 skills',
};
@ -185,8 +185,8 @@ function registerEvents(store) {
setAccount,
setActiveSkill,
setActiveItem,
setCryps,
setCrypList,
setConstructs,
setConstructList,
setGame,
clearInfo,
setMenu,

View File

@ -7,7 +7,7 @@ function setupKeys(store) {
key('esc', () => store.dispatch(actions.setCombiner([null, null, null])));
key('esc', () => store.dispatch(actions.setReclaiming(false)));
key('esc', () => store.dispatch(actions.setActiveSkill(null)));
key('esc', () => store.dispatch(actions.setActiveCryp(null)));
key('esc', () => store.dispatch(actions.setActiveConstruct(null)));
key('esc', () => store.dispatch(actions.setInfo(null)));
key('esc', () => store.dispatch(actions.setItemEquip(null)));
key('esc', () => store.dispatch(actions.setItemUnequip(null)));

View File

@ -12,11 +12,11 @@ function createReducer(defaultState, actionType) {
/* eslint-disable key-spacing */
module.exports = {
account: createReducer(null, 'SET_ACCOUNT'),
activeCryp: createReducer(null, 'SET_ACTIVE_CRYP'),
activeConstruct: createReducer(null, 'SET_ACTIVE_CONSTRUCT'),
activeItem: createReducer(null, 'SET_ACTIVE_VAR'),
activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'),
combiner: createReducer([null, null, null], 'SET_COMBINER'),
cryps: createReducer([], 'SET_CRYPS'),
constructs: createReducer([], 'SET_CONSTRUCTS'),
game: createReducer(null, 'SET_GAME'),
info: createReducer(null, 'SET_INFO'),
instance: createReducer(null, 'SET_INSTANCE'),
@ -30,7 +30,7 @@ module.exports = {
resolution: createReducer(null, 'SET_RESOLUTION'),
showLog: createReducer(false, 'SET_SHOW_LOG'),
skip: createReducer(false, 'SET_SKIP'),
team: createReducer([null, null, null], 'SET_SELECTED_CRYPS'),
team: createReducer([null, null, null], 'SET_SELECTED_CONSTRUCTS'),
vboxHighlight: createReducer([], 'SET_VBOX_HIGHLIGHT'),
ws: createReducer(null, 'SET_WS'),
};

View File

@ -1,7 +1,7 @@
const toast = require('izitoast');
const cbor = require('borc');
const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://cryps.gg/ws' : 'ws://localhost:40000';
const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://mnml.gg/ws' : 'ws://localhost:40000';
function errorToast(err) {
console.error(err);
@ -47,12 +47,8 @@ function createSocket(events) {
send({ method: 'account_create', params: { name, password } });
}
function sendAccountDemo() {
send({ method: 'account_demo', params: {} });
}
function sendAccountCryps() {
send({ method: 'account_cryps', params: {} });
function sendAccountConstructs() {
send({ method: 'account_constructs', params: {} });
}
function sendAccountInstances() {
@ -63,8 +59,8 @@ function createSocket(events) {
send({ method: 'account_zone', params: {} });
}
function sendCrypSpawn(name) {
send({ method: 'cryp_spawn', params: { name } });
function sendConstructSpawn(name) {
send({ method: 'construct_spawn', params: { name } });
}
function sendGameState(id) {
@ -76,11 +72,11 @@ function createSocket(events) {
}
function sendSpecForget(id, spec) {
send({ method: 'cryp_unspec', params: { id, spec } });
send({ method: 'construct_unspec', params: { id, spec } });
}
function sendPlayerMmCrypsSet(crypIds) {
send({ method: 'player_mm_cryps_set', params: { cryp_ids: crypIds } });
function sendPlayerMmConstructsSet(constructIds) {
send({ method: 'player_mm_constructs_set', params: { construct_ids: constructIds } });
}
function sendInstanceState(instanceId) {
@ -91,13 +87,13 @@ function createSocket(events) {
send({ method: 'player_vbox_accept', params: { instance_id: instanceId, group, index } });
}
function sendVboxApply(instanceId, crypId, index) {
send({ method: 'player_vbox_apply', params: { instance_id: instanceId, cryp_id: crypId, index } });
function sendVboxApply(instanceId, constructId, index) {
send({ method: 'player_vbox_apply', params: { instance_id: instanceId, construct_id: constructId, index } });
events.setActiveItem(null);
}
function sendVboxUnequip(instanceId, crypId, target) {
send({ method: 'player_vbox_unequip', params: { instance_id: instanceId, cryp_id: crypId, target } });
function sendVboxUnequip(instanceId, constructId, target) {
send({ method: 'player_vbox_unequip', params: { instance_id: instanceId, construct_id: constructId, target } });
events.clearInfo();
}
@ -118,18 +114,18 @@ function createSocket(events) {
send({ method: 'item_info', params: {} });
}
function sendGameSkill(gameId, crypId, targetCrypId, skill) {
function sendGameSkill(gameId, constructId, targetConstructId, skill) {
send({
method: 'game_skill',
params: {
game_id: gameId, cryp_id: crypId, target_cryp_id: targetCrypId, skill,
game_id: gameId, construct_id: constructId, target_construct_id: targetConstructId, skill,
},
});
events.setActiveSkill(null);
}
function sendGameTarget(gameId, crypId, skillId) {
send({ method: 'game_target', params: { game_id: gameId, cryp_id: crypId, skill_id: skillId } });
function sendGameTarget(gameId, constructId, skillId) {
send({ method: 'game_target', params: { game_id: gameId, construct_id: constructId, skill_id: skillId } });
events.setActiveSkill(null);
}
@ -137,20 +133,20 @@ function createSocket(events) {
send({ method: 'zone_create', params: {} });
}
function sendZoneJoin(zoneId, nodeId, crypIds) {
send({ method: 'zone_join', params: { zone_id: zoneId, node_id: nodeId, cryp_ids: crypIds } });
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(instanceId, cryps) {
send({ method: 'instance_join', params: { instance_id: instanceId, cryp_ids: cryps } });
function sendInstanceJoin(instanceId, constructs) {
send({ method: 'instance_join', params: { instance_id: instanceId, construct_ids: constructs } });
}
function sendInstanceNew(cryps, name, players) {
send({ method: 'instance_new', params: { cryp_ids: cryps, name, players } });
function sendInstanceNew(constructs, name, players) {
send({ method: 'instance_new', params: { construct_ids: constructs, name, players } });
}
function sendInstanceReady(instanceId) {
@ -171,7 +167,7 @@ function createSocket(events) {
account = login;
localStorage.setItem('account', JSON.stringify(login));
events.setAccount(login);
sendAccountCryps();
sendAccountConstructs();
sendAccountInstances();
}
@ -180,9 +176,9 @@ function createSocket(events) {
events.setInstanceList(playerList);
}
function accountCryps(response) {
const [structName, cryps] = response;
events.setCrypList(cryps);
function accountConstructs(response) {
const [structName, constructs] = response;
events.setConstructList(constructs);
}
function gameState(response) {
@ -201,8 +197,8 @@ function createSocket(events) {
clearTimeout(gameStateTimeout);
}
function crypSpawn(response) {
const [structName, cryp] = response;
function constructSpawn(response) {
const [structName, construct] = response;
}
function zoneState(response) {
@ -244,11 +240,11 @@ function createSocket(events) {
// 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 = {
cryp_spawn: crypSpawn,
construct_spawn: constructSpawn,
game_state: gameState,
account_login: accountLogin,
account_create: accountLogin,
account_cryps: accountCryps,
account_constructs: accountConstructs,
account_instances: accountInstanceList,
zone_create: res => console.log(res),
zone_state: zoneState,
@ -268,9 +264,9 @@ function createSocket(events) {
switch (error) {
case 'invalid token': return logout();
case 'no active zone': return sendZoneCreate();
case 'no cryps selected': return events.errorPrompt('select_cryps');
case 'no constructs selected': return events.errorPrompt('select_constructs');
case 'node requirements not met': return events.errorPrompt('complete_nodes');
case 'cryp at max skills (4)': return events.errorPrompt('max_skills');
case 'construct at max skills (4)': return events.errorPrompt('max_skills');
default: return errorToast(error);
@ -307,7 +303,7 @@ function createSocket(events) {
if (account) {
events.setAccount(account);
sendAccountInstances();
sendAccountCryps();
sendAccountConstructs();
setTimeout(sendItemInfo, 2000);
}
@ -342,15 +338,14 @@ function createSocket(events) {
clearInstanceStateTimeout,
sendAccountLogin,
sendAccountCreate,
sendAccountDemo,
sendAccountCryps,
sendAccountConstructs,
sendAccountInstances,
sendAccountZone,
sendGameState,
sendGameReady,
sendGameSkill,
sendGameTarget,
sendCrypSpawn,
sendConstructSpawn,
sendSpecForget,
sendZoneCreate,
sendZoneJoin,
@ -359,7 +354,7 @@ function createSocket(events) {
sendInstanceReady,
sendInstanceNew,
sendInstanceScores,
sendPlayerMmCrypsSet,
sendPlayerMmConstructsSet,
sendInstanceState,
sendVboxAccept,
sendVboxApply,

View File

@ -2,7 +2,7 @@
function testGame(uuid) {
return {
"id": "667ad344-dc76-40b9-bb9c-0d20f0f7f5d2",
"player_cryps": 3,
"player_constructs": 3,
"player_num": 2,
"players": [
{
@ -19,9 +19,9 @@ function testGame(uuid) {
],
[
"Speed",
"Damage",
"Power",
"Life",
"Damage",
"Power",
"Life",
"Life"
]
@ -32,7 +32,7 @@ function testGame(uuid) {
"wins": 0,
"losses": 0
},
"cryps": [
"constructs": [
{
"id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b",
"account": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1",
@ -282,7 +282,7 @@ function testGame(uuid) {
],
[
"Speed",
"Damage",
"Power",
"Speed",
"Life",
"Speed",
@ -295,7 +295,7 @@ function testGame(uuid) {
"wins": 0,
"losses": 0
},
"cryps": [
"constructs": [
{
"id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"account": uuid,
@ -543,8 +543,8 @@ function testGame(uuid) {
{
"id": "15ef2068-0eec-4eda-b2b2-5abe78e4ff9a",
"source_player_id": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1",
"source_cryp_id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b",
"target_cryp_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"source_construct_id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b",
"target_construct_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"skill": "Attack",
"speed": 0,
"resolutions": []
@ -552,8 +552,8 @@ function testGame(uuid) {
{
"id": "4fbe9c95-8f40-4f65-9f0e-b77d5eb64b17",
"source_player_id": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1",
"source_cryp_id": "ea302c35-d326-475c-a867-8ad5b162165a",
"target_cryp_id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"source_construct_id": "ea302c35-d326-475c-a867-8ad5b162165a",
"target_construct_id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"skill": "Attack",
"speed": 0,
"resolutions": []
@ -561,8 +561,8 @@ function testGame(uuid) {
{
"id": "c2f398b8-6f5a-4fda-8c8d-b1be53819040",
"source_player_id": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1",
"source_cryp_id": "82e8b940-411c-42a1-8fc2-484ec7207734",
"target_cryp_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"source_construct_id": "82e8b940-411c-42a1-8fc2-484ec7207734",
"target_construct_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"skill": "Attack",
"speed": 0,
"resolutions": []
@ -570,8 +570,8 @@ function testGame(uuid) {
{
"id": "6bc9c3ce-587e-4bbe-ac81-2bc536ebbce4",
"source_player_id": uuid,
"source_cryp_id": "5d49fe65-27f0-4372-90a3-334ef906a0f5",
"target_cryp_id": "82e8b940-411c-42a1-8fc2-484ec7207734",
"source_construct_id": "5d49fe65-27f0-4372-90a3-334ef906a0f5",
"target_construct_id": "82e8b940-411c-42a1-8fc2-484ec7207734",
"skill": "Attack",
"speed": 0,
"resolutions": []
@ -579,8 +579,8 @@ function testGame(uuid) {
{
"id": "9d2fc857-51c7-4640-a17c-a08496480830",
"source_player_id": uuid,
"source_cryp_id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"target_cryp_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"source_construct_id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"target_construct_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"skill": "Attack",
"speed": 0,
"resolutions": []
@ -588,8 +588,8 @@ function testGame(uuid) {
{
"id": "e1bd2d77-181a-4f2d-a4f6-78c9ad3c5b3b",
"source_player_id": uuid,
"source_cryp_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"target_cryp_id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b",
"source_construct_id": "50e5d94e-8ebe-495c-a916-3eb509ff4683",
"target_construct_id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b",
"skill": "Attack",
"speed": 0,
"resolutions": []

View File

@ -22,9 +22,9 @@ function testInstance(uuid) {
"Block"
],
[
"Damage",
"Power",
"Life",
"Damage",
"Power",
"Speed"
]
],
@ -34,7 +34,7 @@ function testInstance(uuid) {
"wins": 12,
"losses": 4
},
"cryps": [
"constructs": [
{
"id": "32ffeb78-e69d-4796-ba16-624a8db678c1",
"account": "681626d4-1c39-4968-a159-0921cf0fe497",
@ -308,7 +308,7 @@ function testInstance(uuid) {
"Attack"
],
[
"Damage",
"Power",
"Speed",
"Life"
]
@ -319,7 +319,7 @@ function testInstance(uuid) {
"wins": 13,
"losses": 3
},
"cryps": [
"constructs": [
{
"id": "d9bb5a7f-86d4-4075-9783-c899c91b48f4",
"account": "04e4bdbb-54d6-4d3a-9987-366520c05a04",
@ -608,7 +608,7 @@ function testInstance(uuid) {
"wins": 1,
"losses": 15
},
"cryps": [
"constructs": [
{
"id": "4098d753-2196-46dc-98e0-bd5c86e3fbaa",
"account": "cbb7a327-1cec-464d-972c-96e4298d3941",
@ -886,7 +886,7 @@ function testInstance(uuid) {
],
[
"Speed",
"Damage",
"Power",
"Speed",
"Speed"
]
@ -897,7 +897,7 @@ function testInstance(uuid) {
"wins": 4,
"losses": 12
},
"cryps": [
"constructs": [
{
"id": "b9c41633-73c1-4ce5-b9c6-3f18196b94d4",
"account": "04a13f79-145f-4cd4-bb4c-9108637f4c04",
@ -1174,7 +1174,7 @@ function testInstance(uuid) {
"Debuff"
],
[
"Damage",
"Power",
"Life",
"Speed",
"Speed"
@ -1186,7 +1186,7 @@ function testInstance(uuid) {
"wins": 6,
"losses": 10
},
"cryps": [
"constructs": [
{
"id": "c7106871-91b4-4e13-96c8-13cf95878896",
"account": "d59b2bd4-01b3-4802-9e4d-d716b9f63114",
@ -1466,7 +1466,7 @@ function testInstance(uuid) {
"Speed",
"Speed",
"Speed",
"Damage"
"Power"
]
],
"bound": []
@ -1475,7 +1475,7 @@ function testInstance(uuid) {
"wins": 6,
"losses": 10
},
"cryps": [
"constructs": [
{
"id": "52e54ac6-a254-4f74-aee7-0c8df4e92133",
"account": "64ddef5a-0af4-480d-8ed3-24e7fc3c0761",
@ -1754,7 +1754,7 @@ function testInstance(uuid) {
[
"Life",
"Speed",
"Damage",
"Power",
"Life"
]
],
@ -1764,7 +1764,7 @@ function testInstance(uuid) {
"wins": 8,
"losses": 8
},
"cryps": [
"constructs": [
{
"id": "13d638ba-d738-42eb-9080-e0b9c6bbccd2",
"account": "fcdfcb93-da2e-4027-a360-7bc5a6328cd1",
@ -2044,7 +2044,7 @@ function testInstance(uuid) {
"Speed",
"Life",
"Speed",
"Damage"
"Power"
]
],
"bound": []
@ -2053,7 +2053,7 @@ function testInstance(uuid) {
"wins": 11,
"losses": 5
},
"cryps": [
"constructs": [
{
"id": "363f3902-8410-4984-bde8-cb7f77dc621f",
"account": "1f1145ad-def5-4e0e-b4f9-97310c1a58fb",
@ -2342,7 +2342,7 @@ function testInstance(uuid) {
"wins": 9,
"losses": 7
},
"cryps": [
"constructs": [
{
"id": "9c490d3e-5509-439b-b197-f6fa80b8bee5",
"account": "eba6a766-7a95-4dc7-95a1-00a5a203921d",
@ -2622,7 +2622,7 @@ function testInstance(uuid) {
"Life",
"Speed",
"Speed",
"Damage"
"Power"
]
],
"bound": []
@ -2631,7 +2631,7 @@ function testInstance(uuid) {
"wins": 9,
"losses": 7
},
"cryps": [
"constructs": [
{
"id": "104f82e0-a053-4b77-b01b-7598998d5014",
"account": "78531f40-7e44-4ac9-90ae-23f51c3dea5a",
@ -2908,10 +2908,10 @@ function testInstance(uuid) {
"Stun"
],
[
"Damage",
"Damage",
"Power",
"Power",
"Speed",
"Damage"
"Power"
]
],
"bound": []
@ -2920,7 +2920,7 @@ function testInstance(uuid) {
"wins": 12,
"losses": 4
},
"cryps": [
"constructs": [
{
"id": "6f1b51bd-b9ff-4269-b92e-b9d6629650f7",
"account": "74980fc0-c0ad-4a1d-a28e-e1f6ddc6bdc2",
@ -3197,10 +3197,10 @@ function testInstance(uuid) {
"Stun"
],
[
"Damage",
"Power",
"Speed",
"Damage",
"Damage"
"Power",
"Power"
]
],
"bound": []
@ -3209,7 +3209,7 @@ function testInstance(uuid) {
"wins": 6,
"losses": 10
},
"cryps": [
"constructs": [
{
"id": "55116a6e-c872-464a-a470-e021cc7e80b6",
"account": "1dc41566-262e-4a95-b5f8-b347b532acec",
@ -3486,9 +3486,9 @@ function testInstance(uuid) {
"Buff"
],
[
"Damage",
"Power",
"Speed",
"Damage",
"Power",
"Life"
]
],
@ -3498,7 +3498,7 @@ function testInstance(uuid) {
"wins": 14,
"losses": 2
},
"cryps": [
"constructs": [
{
"id": "8a34f320-ddc0-4d4b-99da-479da18fdb3a",
"account": "43e54b00-627d-459c-9d89-931e5c163602",
@ -3783,7 +3783,7 @@ function testInstance(uuid) {
"wins": 15,
"losses": 1
},
"cryps": [
"constructs": [
{
"id": "0f93d522-3dce-429d-b373-9d3c0f97c4c1",
"account": "06e8a7b5-ca97-45cb-a8db-9aa1bfec5d23",
@ -4068,7 +4068,7 @@ function testInstance(uuid) {
"wins": 2,
"losses": 14
},
"cryps": [
"constructs": [
{
"id": "ad0ba069-c20a-403e-b90e-024af247e5d6",
"account": "a5867e13-b591-47c7-b9e8-3bd7fe56e17e",
@ -4348,9 +4348,9 @@ function testInstance(uuid) {
[
"Life",
"Speed",
"Damage",
"Power",
"Speed",
"Damage",
"Power",
"Life"
]
],
@ -4367,7 +4367,7 @@ function testInstance(uuid) {
"wins": 0,
"losses": 16
},
"cryps": [
"constructs": [
{
"id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd",
"account": uuid,

View File

@ -56,8 +56,34 @@ function requestAvatar(name) {
.then(svg => svg);
}
function crypAvatar(name, id) {
useEffect(() => animateCryp(id));
const animations = {};
function animateConstruct(id) {
if (animations[id]) return false;
animations[id] = true;
const duration = anime.random(2000, 8000);
const target = document.getElementById(id);
return anime({
targets: target,
translateX: () => anime.random(-20, 20),
translateY: () => anime.random(0, -40),
rotate: () => anime.random(-15, 15),
duration,
direction: 'alternate',
easing: 'linear',
loop: true,
complete: () => animations[id] = false,
});
}
function clearAnimation(id) {
animations[id] = false;
}
function constructAvatar(name, id) {
useEffect(() => {
animateConstruct(id);
return () => clearAnimation(id);
});
return (
<img
@ -69,8 +95,11 @@ function crypAvatar(name, id) {
);
}
function instanceCryp(name, id) {
useEffect(() => animateCryp(id));
function instanceConstruct(name, id) {
useEffect(() => {
animateConstruct(id);
return () => clearAnimation(id);
});
return (
<div
@ -84,18 +113,18 @@ function instanceCryp(name, id) {
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
const STATS = {
redDamage: {
stat: 'red_damage',
redPower: {
stat: 'red_power',
colour: 'red',
svg: shapes.circle,
},
greenDamage: {
stat: 'green_damage',
greenPower: {
stat: 'green_power',
colour: 'green',
svg: shapes.circle,
},
blueDamage: {
stat: 'blue_damage',
bluePower: {
stat: 'blue_power',
colour: 'blue',
svg: shapes.circle,
},
@ -164,45 +193,45 @@ const SPECS = {
svg: shapes.square
},
Damage: {
Power: {
colour: 'white',
caption: 'Damage',
caption: 'Power',
thresholds: [],
svg: shapes.circle
},
RedDamageI: {
RedPowerI: {
colour: 'red',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [5, 10, 20],
svg: shapes.circle
},
BlueDamageI: {
BluePowerI: {
colour: 'blue',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [5, 10, 20],
svg: shapes.circle
},
GreenDamageI: {
GreenPowerI: {
colour: 'green',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [5, 10, 20],
svg: shapes.circle,
},
GRDI: {
colour: 'yellow',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [2, 5, 10],
svg: shapes.circle
},
GBDI: {
colour: 'cyan',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [2, 5, 10],
svg: shapes.circle,
},
RBDI: {
colour: 'purple',
caption: 'DamageI',
caption: 'PowerI',
thresholds: [2, 5, 10],
svg: shapes.circle,
},
@ -257,52 +286,52 @@ const COLOUR_ICONS = {
green: { colour: 'green', caption: 'green', svg: shapes.square },
};
function resoCrypHealth(resolution, currentGame) {
function resoConstructHealth(resolution, currentGame) {
if (!resolution) return false;
const modifyHealth = cryp => {
if (cryp.id !== resolution.target.id) return false; // not target
const modifyHealth = construct => {
if (construct.id !== resolution.target.id) return false; // not target
const [type, event] = resolution.event;
if (type === 'Damage') {
const { amount, mitigation, colour } = event;
cryp.green_life.value -= amount;
construct.green_life.value -= amount;
if (colour === 'Red') {
cryp.red_life.value -= mitigation;
construct.red_life.value -= mitigation;
}
if (colour === 'Blue') {
cryp.blue_life.value -= mitigation;
construct.blue_life.value -= mitigation;
}
}
if (type === 'Healing') {
const { amount } = event;
cryp.green_life.value += amount;
construct.green_life.value += amount;
}
if (type === 'Recharge') {
const { red, blue } = event;
cryp.red_life.value += red;
cryp.blue_life.value += blue;
construct.red_life.value += red;
construct.blue_life.value += blue;
}
return true;
};
currentGame.players.forEach(player => player.cryps.forEach(modifyHealth));
currentGame.players.forEach(player => player.constructs.forEach(modifyHealth));
return true;
}
function eventClasses(resolution, cryp) {
function eventClasses(resolution, construct) {
if (!resolution) return '';
const startSkill = resolution.stage === 'START_SKILL';
const endSkill = resolution.stage === 'END_SKILL';
const postSkill = resolution.stage === 'POST_SKILL';
const source = cryp.id === resolution.source.id;
const target = cryp.id === resolution.target.id;
const source = construct.id === resolution.source.id;
const target = construct.id === resolution.target.id;
// not involved at all. blur them
if (!(source || target)) return 'unfocus';
// not the target. just ignore for now
// if (cryp.id !== resolution.target.id) return '';
// if (construct.id !== resolution.target.id) return '';
const [type, event] = resolution.event;
@ -328,7 +357,7 @@ function eventClasses(resolution, cryp) {
if (source && startSkill) return 'active-skill';
if (target && endSkill) return 'active-skill';
// Deal damage to cryp and return effect
// Deal damage to construct and return effect
if (target && postSkill) {
if (colour === 'Red') {
return 'red-damage';
@ -416,7 +445,7 @@ function getCombatSequence(event) {
&& (['Ruin', 'Taunt', 'Strangling', 'Parry'].includes(event[1].skill)
|| (event[1].skill === 'Decay' && event[1].effect === 'Wither'))) return ['POST_SKILL'];
if (['Damage'].includes(event[0])
if (['Power'].includes(event[0])
&& ((event[1].skill === 'Chaos' && event[1].colour === 'Red')
|| event[1].skill === 'Silence'
|| event[1].skill === 'Snare')) return ['POST_SKILL'];
@ -428,13 +457,13 @@ function getCombatSequence(event) {
return ['START_SKILL', 'END_SKILL', 'POST_SKILL'];
}
function getCombatText(cryp, resolution) {
function getCombatText(construct, resolution) {
if (!resolution) return ['', ''];
const [type, event] = resolution.event;
const source = cryp.id === resolution.source.id;
const target = cryp.id === resolution.target.id;
const source = construct.id === resolution.source.id;
const target = construct.id === resolution.target.id;
const startSkill = resolution.stage === 'START_SKILL';
const endSkill = resolution.stage === 'END_SKILL';
const postSkill = resolution.stage === 'POST_SKILL';
@ -537,34 +566,19 @@ function convertItem(v) {
// return;
}
function animateCryp(id) {
const target = document.getElementById(id);
return anime({
targets: target,
translateX: () => anime.random(-20, 20),
translateY: () => anime.random(0, -40),
rotate: () => anime.random(-15, 15),
duration: () => anime.random(2000, 5000),
delay: () => anime.random(0, 2000),
direction: 'alternate',
easing: 'linear',
loop: true,
});
}
module.exports = {
animateCryp,
animateConstruct,
stringSort,
convertItem,
numSort,
genAvatar,
crypAvatar,
instanceCryp,
constructAvatar,
instanceConstruct,
requestAvatar,
eventClasses,
getCombatSequence,
getCombatText,
resoCrypHealth,
resoConstructHealth,
NULL_UUID,
STATS,
SPECS,

View File

@ -2,10 +2,10 @@
# sudo apt-get install -y postgresql postgresql-contrib
sudo service postgresql start
sudo -u postgres dropdb cryps
sudo -u postgres createdb cryps
sudo -u postgres createuser --encrypted cryps
sudo -u postgres psql -c "alter user cryps with encrypted password 'craftbeer';"
sudo -u postgres dropdb mnml
sudo -u postgres createdb mnml
sudo -u postgres createuser --encrypted mnml
sudo -u postgres psql -c "alter user mnml with encrypted password 'craftbeer';"
# npm i
npm run migrate

View File

@ -3,8 +3,8 @@
const local = {
client: 'postgresql',
connection: {
database: 'cryps',
user: 'cryps',
database: 'mnml',
user: 'mnml',
password: 'craftbeer'
},
pool: {

View File

@ -1,6 +1,7 @@
exports.up = async knex => {
return knex.schema.createTable('cryps', table => {
return knex.schema.createTable('constructs', table => {
table.uuid('id').primary();
table.timestamps(true, true);
table.uuid('account').notNullable()
table.foreign('account')
.references('id')

View File

@ -1,5 +1,3 @@
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
exports.up = async knex => {
await knex.schema.createTable('games', table => {
table.uuid('id').primary();
@ -67,14 +65,6 @@ exports.up = async knex => {
.inTable('games')
.onDelete('NO ACTION');
});
// not really sure if this is a good idea
await knex('instances').insert({
id: NULL_UUID,
data: 'INVALID',
open: false,
});
};
exports.down = async () => {};

View File

@ -1,28 +0,0 @@
exports.up = async knex => {
await knex.schema.createTable('zones', async (table) => {
table.uuid('id').primary();
table.index('id');
table.timestamps(true, true);
table.binary('data').notNullable();
table.boolean('active')
.defaultTo(true)
.notNullable();
table.uuid('account').notNullable()
table.foreign('account')
.references('id')
.inTable('accounts')
.onDelete('CASCADE');
table.index('account');
await knex.schema.raw(
// eslint-disable-next-line max-len
'CREATE UNIQUE INDEX zones_account_active ON zones (account) WHERE active = true;'
);
});
};
exports.down = async () => {};

View File

@ -1,4 +1,4 @@
upstream cryps {
upstream mnml {
server 127.0.0.1:40000;
}
@ -8,10 +8,18 @@ map $http_upgrade $connection_upgrade {
}
server {
root /home/git/cryps/client/dist/;
root /home/git/mnml/client/dist/;
index index.html;
server_name cryps.gg; # managed by Certbot
server_name mnml.gg; # managed by Certbot
if ($host = minimal.gg) {
return 301 https://mnml.gg$request_uri;
} # managed by Certbot
if ($host = cryps.gg) {
return 301 https://mnml.gg$request_uri;
} # managed by Certbot
location / {
try_files $uri $uri/ =404;
@ -19,13 +27,13 @@ server {
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/cryps.gg/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/cryps.gg/privkey.pem; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mnml.gg/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mnml.gg/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location /ws {
proxy_pass http://cryps;
proxy_pass http://mnml;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
@ -33,13 +41,18 @@ server {
}
}
# http -> https
server {
if ($host = cryps.gg) {
server_name mnml.gg;
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 ;
listen [::]:80 ;
server_name cryps.gg;
return 404; # managed by Certbot
}
server {
server_name minimal.gg;
return 301 https://mnml.gg$request_uri;
}
server {
server_name cryps.gg;
return 301 https://mnml.gg$request_uri;
}

View File

@ -1,5 +1,5 @@
{
"name": "cryps-ops",
"name": "constructs-ops",
"version": "1.0.0",
"description": "",
"main": "index.js",

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
package-lock.json
node_modules/
dist/
.cache/
assets/molecules

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -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
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -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%);
}

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>cryps.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>

View File

@ -1,4 +0,0 @@
require('./cryps.css');
// kick it off
require('./src/main');

View File

@ -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;
};

View File

@ -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;

View File

@ -1,33 +0,0 @@
{
"name": "cryps-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"
}
}

View File

@ -1,219 +0,0 @@
const toast = require('izitoast');
function registerEvents(registry, events, tutorial) {
function setCryps(cryps) {
registry.set('cryps', cryps);
tutorial('homepage');
}
function setCrypList(cryps) {
registry.set('crypList', cryps);
}
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 setCrypStatusUpdate(id, skill, target) {
registry.set('crypStatusUpdate', { id, skill, target });
}
events.on('SET_PLAYER', setPlayer);
events.on('SEND_SKILL', function skillActive(gameId, crypId, targetCrypId, skill) {
const ws = registry.get('ws');
ws.sendGameSkill(gameId, crypId, targetCrypId, skill);
setCrypStatusUpdate(crypId, skill, targetCrypId);
});
events.on('CRYP_ACTIVE', function crypActiveCb(cryp) {
const cryps = registry.get('cryps');
for (let i = 0; i < cryps.length; i += 1) {
if (cryps[i].id === cryp.id) cryps[i].active = !cryps[i].active;
}
return setCryps(cryps);
});
const errMessages = {
select_cryps: 'Select your cryps before battle using the numbered buttons next to the cryp avatar',
complete_nodes: 'You need to complete the previously connected nodes first',
max_skills: 'Your cryp 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('CRYP_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.sendCrypSpawn(NAME);
instance.hide({ transitionOut: 'fadeOut' }, thisToast, 'button');
}
toast.question({
theme: 'dark',
color: 'black',
timeout: false,
// overlay: true,
drag: false,
close: true,
title: 'SPAWN CRYP',
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,
setCryps,
setCrypList,
setGame,
setMenu,
setPlayer,
setPlayerList,
setVbox,
setWs,
setGameList,
setZone,
setScores,
};
}
module.exports = registerEvents;

View File

@ -1,17 +0,0 @@
const renderCryps = require('./scenes/cryps');
const createSocket = require('./socket');
const registerEvents = require('./events');
const createTutorial = require('./tutorial');
document.fonts.load('10pt "Jura"').then(() => {
const game = renderCryps();
const tutorial = createTutorial();
const events = registerEvents(game.registry, game.events, tutorial);
const ws = createSocket(events);
// events.setWs(ws);
// events.setGameList([]);
ws.connect();
});

View File

@ -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;

View File

@ -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;

View File

@ -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 } = getCrypPosition(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;

View File

@ -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 CRYP_MARGIN = COMBAT.crypMargin();
const TEXT_MARGIN = COMBAT.textMargin();
const crypAvatarText = (team, iter) => {
const nameX = COMBAT.width() * team;
const nameY = COMBAT.y() + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
const statusX = COMBAT.width() * team;
const statusY = COMBAT.y() + TEXT_MARGIN * 6 + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
return { statusX, statusY, nameX, nameY };
};
const crypEffects = (team, iter) => {
const crypEffectsX = team ? COMBAT.width() - COMBAT.width() / 6.5 : COMBAT.width() / 6.5;
const crypEffectsY = TEXT_MARGIN * 2 + CRYP_MARGIN * iter;
return { crypEffectsX, crypEffectsY };
};
const crypPosition = (team, iter) => {
const crypAvatarX = team ? COMBAT.width() - COMBAT.width() / 6 : COMBAT.width() / 6;
const crypAvatarY = TEXT_MARGIN * 5 + CRYP_MARGIN * iter;
return { crypAvatarX, crypAvatarY };
};
class Effects extends Phaser.GameObjects.Group {
constructor(scene, team, iter) {
super(scene);
this.scene = scene;
const { crypEffectsX, crypEffectsY } = crypEffects(team, iter);
this.x = crypEffectsX; this.y = crypEffectsY;
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 CrypImage extends Phaser.GameObjects.Image {
constructor(scene, team, iter, cryp) {
// Get coords
const { crypAvatarX, crypAvatarY } = crypPosition(team, iter);
const { statusX, statusY, nameX, nameY } = crypAvatarText(team, iter);
// Cryp display
// const avatar = team ? 'magmar' : 'alk';
super(scene, crypAvatarX, crypAvatarY, 'aztec', genAvatar(cryp.name));
this.setScale(0.5);
if (!team) this.flipX = true;
// Save position and cryp details
this.scene = scene;
this.iter = iter;
this.team = team;
this.cryp = cryp;
this.state = 'deselect';
// Add cryp name
scene.add.text(nameX, nameY, cryp.name, TEXT.NORMAL).setOrigin(team, 0);
// Add cryp 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 CombatCryps extends Phaser.Scene {
constructor() {
super({ key: 'CombatCryps' });
}
create(game) {
this.cryps = this.add.group();
this.phase = game.phase;
this.account = this.registry.get('account');
this.drawCryps(game);
this.registry.events.on('changedata', this.updateData, this);
this.registry.set('crypStatusUpdate', 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.cryps.children.entries.forEach(c => c.clearStatus());
this.drawCryps(this.game);
}
}
if (key === 'crypStatusUpdate' && data) {
this.updateCrypStatus(data);
}
return true;
}
drawCryps(game) {
const renderCryp = (cryp, iter, team) => {
// Add Image Avatar Class
const crypObj = new CrypImage(this, team, iter, cryp);
this.add.existing(crypObj);
this.cryps.add(crypObj);
return crypObj;
};
const renderTeam = (cryp, iter, team) => {
const crypObj = this.cryps.children.entries
.find(c => c.cryp.id === cryp.id)
|| renderCryp(cryp, iter, team);
crypObj.health.val = cryp.hp.value;
crypObj.red_shield.val = cryp.red_shield.value;
crypObj.blue_shield.val = cryp.red_shield.value;
crypObj.health.drawStatBar();
crypObj.red_shield.drawStatBar();
crypObj.blue_shield.drawStatBar();
crypObj.effects.update(cryp.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.cryps.forEach((cryp, i) => renderTeam(cryp, i, 0));
if (!enemyTeam) return false;
enemyTeam.cryps.forEach((cryp, i) => renderTeam(cryp, i, 1));
return true;
}
selectCryp(crypId) {
this.cryps.children.entries.forEach(c => c.deselect());
if (crypId) this.cryps.children.entries.find(c => c.cryp.id === crypId).select();
}
updateCrypStatus(status) {
const sourceCryp = this.cryps.children.entries
.find(c => c.cryp.id === status.id);
const targetCryp = this.cryps.children.entries
.find(c => c.cryp.id === status.target);
if (this.phase === 'Skill') {
sourceCryp.statusText.text = `${status.skill} on ${targetCryp.cryp.name}`;
}
}
cleanUp() {
this.registry.events.off('changedata', this.updateData);
this.scene.remove();
}
}
module.exports = CombatCryps;

View File

@ -1,89 +0,0 @@
const Phaser = require('phaser');
const { POSITIONS: { COMBAT } } = require('./constants');
const CRYP_MARGIN = COMBAT.crypMargin();
const BOX_HEIGHT = CRYP_MARGIN * 0.8;
const BOX_WIDTH = COMBAT.width() * 0.2;
class CrypHitBox extends Phaser.GameObjects.Rectangle {
constructor(scene, iter, team, cback) {
const y = COMBAT.y() + COMBAT.height() * 0.05 + CRYP_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('CombatCryps').cryps;
const skillScene = this.scene.get('CombatSkills');
game.teams.forEach((t) => {
t.cryps.forEach((c) => {
const cback = () => {
const { activeSkill } = skillScene;
if (activeSkill) {
this.scene.get('CombatSkills').clearCrypActive(activeSkill.cryp.id);
activeSkill.activate();
skillScene.activeSkill = null;
this.game.events.emit('SEND_SKILL', game.id, activeSkill.cryp.id, c.id, activeSkill.skill.skill);
}
};
const crypSpawn = group.children.entries.find(s => s.cryp.id === c.id);
const team = c.account === account.id ? 0 : 1;
if (crypSpawn) this.add.existing(new CrypHitBox(this, crypSpawn.iter, team, cback));
});
});
this.scene.moveBelow('Combat');
}
cleanUp() {
this.registry.events.off('changedata', this.updateData);
this.scene.remove();
}
}
module.exports = CombatHitBox;

View File

@ -1,138 +0,0 @@
const Phaser = require('phaser');
const { throttle } = require('lodash');
const { TEXT, POSITIONS: { COMBAT } } = require('./constants');
const CombatLog = require('./combat.log');
const CombatCryps = require('./combat.cryps');
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('CombatCryps', CombatCryps, 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 cryps 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', 'CombatCryps', 'CombatSkills', 'CombatHitBox'];
ACTIVE_SCENES.forEach((sKey) => {
if (this.scene.get(sKey)) this.scene.get(sKey).cleanUp();
});
this.scene.remove();
return true;
}
}
module.exports = Combat;

View File

@ -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;

View File

@ -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 findResolutionCryps(scene, group, resolution, game) {
const sourceSpawn = group.children.entries.find(c => c.cryp.id === resolution.source.id);
/* const sourceCryp = game.teams.find(t => t.cryps.find(c => c.id === resolution.source_cryp_id))
.cryps.find(c => c.id === resolution.source_cryp_id);
const targetCryp = game.teams.find(t => t.cryps.find(c => c.id === resolution.target_cryp_id))
.cryps.find(c => c.id === resolution.target_cryp_id);
*/
const targetSpawn = group.children.entries.find(c => c.cryp.id === resolution.target.id);
return { sourceSpawn, targetSpawn };
}
function calculateTweenParams(sourceSpawn, targetSpawn, account, skill) {
const tweenParams = (targets, centreSpot) => {
const enemy = targets.cryp.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.cryp.account !== targetSpawn.cryp.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('CombatCryps').cryps;
const animations = new CombatAnimations(scene);
const account = scene.registry.get('account');
// Find cryps, targets
const { sourceSpawn, targetSpawn } = findResolutionCryps(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 cryps into position
if (moveSourceBattle) scene.tweens.add(moveSourceBattle);
scene.tweens.add(moveTargetBattle);
return scene.time.delayedCall(MOVE_CREEP, () => {
const sourceAlly = sourceSpawn.cryp.account === account.id;
const targetAlly = targetSpawn.cryp.account === account.id;
// animate animation
animations.getSkill(resolution.event[1].skill, sourceAlly, targetAlly, castLocation);
// Target cryp 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;

View File

@ -1,235 +0,0 @@
const Phaser = require('phaser');
const { TEXT, POSITIONS: { COMBAT } } = require('./constants');
const CRYP_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 CRYP_MARGIN = COMBAT.crypMargin();
const TEXT_MARGIN = COMBAT.textMargin();
const SKILL_WIDTH = COMBAT.width() / 10;
const SKILL_HEIGHT = COMBAT.height() / 30;
const skillPosition = (crypIter, skillIter) => {
const skillTextX = COMBAT.width() / 3.8;
const skillTextY = (TEXT_MARGIN * skillIter) * 1.5 + CRYP_MARGIN * crypIter + 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 CrypSkill extends Phaser.GameObjects.Container {
constructor(scene, x, y, skill, cryp) {
// Avatar will be a property of cryp
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.cryp = cryp;
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('CombatCryps').selectCryp(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, cryp) => {
const skillTextPos = skillPosition(i, j);
const skillObj = new CrypSkill(this, skillTextPos[0], skillTextPos[1], skill, cryp);
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.cryps.forEach((cryp) => {
// return early if KOd
if (cryp.hp.value === 0) return true;
// find the cryp position
const { iter } = this.scene.get('CombatCryps').cryps.children.entries.find(c => c.cryp.id === cryp.id);
// draw the skills
const skillButtons = cryp.skills.map((skill, j) => addSkill(iter, j, skill, cryp));
const bindCrypKeys = () => this.mapSkillKeys(skillButtons, game.id, cryp.id, team.id, enemyTeam.id, iter);
// reset everything
keyboard.on('keydown_ESC', bindCrypKeys, this);
events.on('SEND_SKILL', bindCrypKeys, this);
bindCrypKeys();
return true;
});
return true;
}
// FIXME
// needs to send crypId not team
mapSkillKeys(skillButtons, gameId, crypId, alliesId, enemyId, i) {
const { keyboard } = this.input;
keyboard.removeListener(CRYP_KEY_MAP[i]);
keyboard.on(CRYP_KEY_MAP[i], () => {
SKILL_KEY_MAP.forEach(k => keyboard.removeListener(k));
this.scene.get('CombatCryps').selectCryp(crypId);
skillButtons.forEach((button, j) => {
keyboard.on(SKILL_KEY_MAP[j], () => {
this.activeSkill = button;
button.select();
// clear existing keys
CRYP_KEY_MAP.forEach(k => keyboard.removeListener(k));
TARGET_KEY_MAP.forEach(k => keyboard.removeListener(k));
CRYP_KEY_MAP.forEach(k => keyboard.on(k, () => {
this.clearCrypActive(crypId);
button.activate();
this.activeSkill = null;
this.game.events.emit('SEND_SKILL', gameId, crypId, alliesId, button.skill.skill);
}));
TARGET_KEY_MAP.forEach(k => keyboard.on(k, () => {
this.clearCrypActive(crypId);
button.activate();
this.activeSkill = null;
this.game.events.emit('SEND_SKILL', gameId, crypId, enemyId, button.skill.skill);
}));
}, this);
});
}, this);
return true;
}
clearCrypActive(crypId) {
this.scene.scene.children.list.forEach((s) => {
if (s.cryp.id === crypId && s.state === 'activate') s.deselect();
});
}
clearKeys() {
TARGET_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey));
CRYP_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;

View File

@ -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 menuCrypListWidth = () => Math.floor(CANVAS_WIDTH() * 0.3);
const menuCrypListHeight = () => Math.floor(CANVAS_HEIGHT() - headerHeight());
const menuCrypListX = () => Math.floor(CANVAS_WIDTH() * 0.3);
const menuCrypListY = () => 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 combatCrypMargin = () => Math.floor((CANVAS_HEIGHT() - headerHeight()) / 4.5);
const combatTextMargin = () => Math.floor((CANVAS_HEIGHT() - headerHeight()) / 35);
const statsWidth = () => Math.floor(CANVAS_WIDTH() - menuCrypListWidth());
const statsHeight = () => CANVAS_HEIGHT() - headerHeight();
const statsY = () => headerHeight();
const statsX = () => menuCrypListWidth();
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,
},
CRYP_LIST: {
x: menuCrypListX,
y: menuCrypListY,
width: menuCrypListWidth,
height: menuCrypListHeight,
},
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,
crypMargin: combatCrypMargin,
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 cryp',
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 cryp 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 cryp 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 cryp takes increased magic damage',
colours: '2 Blue',
},
Debuff: {
description: 'reduce target cryp speed',
upgrades: 'combine with 2 red / blue / green',
},
Decay: {
description: 'afflict a cryp with a blue damage based damage over time debuff',
colours: '1 Green 1 Blue',
},
Empower: {
description: 'increase the red damage dealt by a cryp',
colours: '2 Red',
},
Haste: {
description: 'magical skill that increases speed of target cryp',
colours: '1 Red 1 Blue',
},
Heal: {
description: 'heal a cryp with blue damage',
colours: '2 Green',
},
Hex: {
description: 'magical bsed skill that prevents target cryp from using any skills',
colours: '1 Red 1 Blue',
},
Hostility: {
description: 'magical bsed skill that prevents target cryp 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 cryp',
colours: '2 Green',
},
Purify: {
description: 'remove magical debuffs from target cryp',
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 cryp',
colours: '1 Green 1 Blue',
},
Silence: {
description: 'prevent target cryp from casting magical skills',
colours: '1 Green 1 Blue',
},
Siphon: {
description: 'siphon hp from target cryp with a blue damage based debuff',
colours: '1 Green 1 Blue',
},
Slay: {
description: '????',
},
Slow: {
description: 'magical skill that reduces speed of target cryp',
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 cryp from using any skills',
upgrades: 'combine with 2 red / blue / green',
},
Taunt: {
description: 'Enemy skills will prioritise cryps 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 cryp',
upgrades: 'combine with 2 red / blue / green',
},
Hp: {
description: 'Increases health of cryp',
upgrades: 'combine with 2 red / blue / green',
},
Speed: {
description: 'Increases speed of cryp',
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',
},
},
},
};

View File

@ -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 renderCryps() {
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 = renderCryps;

View File

@ -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;

View File

@ -1,86 +0,0 @@
const Phaser = require('phaser');
const { TEXT, POSITIONS: { COMBAT }, COLOURS } = require('.././constants');
const CRYP_MARGIN = COMBAT.crypMargin();
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) + CRYP_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) + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
return { statTextX, statTextY };
};
class StatBar extends Phaser.GameObjects.Graphics {
constructor(scene, cryp, type) {
super(scene);
this.crypObj = cryp;
this.type = type;
if (type === 'HP') {
this.val = this.crypObj.cryp.hp.value;
this.max = this.crypObj.cryp.hp.max;
this.margin = 0;
} else if (type === 'Red Shield') {
this.val = this.crypObj.cryp.red_shield.value;
this.max = this.crypObj.cryp.red_shield.max;
this.margin = 1;
} else if (type === 'Blue Shield') {
this.val = this.crypObj.cryp.blue_shield.value;
this.max = this.crypObj.cryp.blue_shield.max;
this.margin = 2;
} else if (type === 'Evasion') {
this.val = this.crypObj.cryp.evasion.value;
this.max = this.crypObj.cryp.evasion.max;
this.margin = 3;
}
const { statTextX, statTextY } = statTextCoord(cryp.team, cryp.iter, this.margin);
this.statText = scene.add.text(statTextX, statTextY, '', TEXT.NORMAL).setOrigin(cryp.team, 0);
this.drawStatBar();
}
drawStatBar() {
this.clear();
const {
statBarX, statBarY, statBarWidth, statBarHeight,
} = statBarDimensions(this.crypObj.team, this.crypObj.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.crypObj.setKo();
this.drawStatBar();
}
}
module.exports = StatBar;

View File

@ -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;

View File

@ -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 }

View File

@ -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].cryps.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 cryps = this.registry.get('cryps');
const team = cryps.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;

View File

@ -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, 'cryps.gg', TEXT.HEADER);
}
}
module.exports = Header;

View File

@ -1,142 +0,0 @@
const Phaser = require('phaser');
const { remove } = require('lodash');
const { TEXT, COLOURS, POSITIONS: { CRYP_LIST } } = require('./constants');
const genAvatar = require('./avatar');
const { LineGroup, LineBox } = require('./elements/outline.rotate');
const ROW_HEIGHT = CRYP_LIST.height() * 0.1;
const ROW_WIDTH = CRYP_LIST.width();
const menuY = CRYP_LIST.height() * 0.8;
const KEY_MAP = [
'keydown-ONE',
'keydown-TWO',
'keydown-THREE',
];
const NULL_UUID = '00000000-0000-0000-0000-000000000000';
class HomeCrypList extends Phaser.Scene {
constructor() {
super({ key: 'HomeCryps' });
}
updateData(parent, key, data) {
if (key === 'crypList') {
KEY_MAP.forEach(k => this.input.keyboard.removeListener(k));
this.scene.restart();
}
}
create() {
// this.cameras.main.setViewport(CRYP_LIST.x(), CRYP_LIST.y(), CRYP_LIST.width(), CRYP_LIST.height());
this.registry.events.on('changedata', this.updateData, this);
this.registry.events.on('setdata', this.updateData, this);
const cryps = this.registry.get('crypList');
const lineGroup = this.add.existing(new LineGroup(this));
if (!cryps) return true;
const ws = this.registry.get('ws');
this.activeCryps = [];
// We only display 3 cryps others can be viewed in cryp list (soon TM)
for (let i = 0; i < cryps.length; i += 1) {
const cryp = cryps[i];
const BOX_WIDTH = Math.floor(ROW_WIDTH / 5);
const ROW_X = BOX_WIDTH * 2 * (i % 3);
const ROW_Y = CRYP_LIST.y() + (Math.floor(i / 3)) * ROW_HEIGHT * 1.5;
const ACTIVE_FILL = 0.2;
const FILL = Object.values(COLOURS)[i];
// Selection of cryps
// Cryp 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.activeCryps.includes(cReady)) {
remove(this.activeCryps, n => n === cReady);
cReady.setAlpha(0.2);
} else {
this.activeCryps.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.cryp = cryp;
this.add.image(
cReady.getCenter().x,
cReady.getCenter().y,
'aztec',
genAvatar(cryp.name)
);
this.add.text(ROW_X + BOX_WIDTH, ROW_Y, cryp.name, TEXT.HEADER)
.setOrigin(0.5, 0.5);
}
// Add Spawn Cryp 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('CRYP_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 playerCryps = [];
this.activeCryps.forEach(obj => playerCryps.push(obj.cryp.id));
ws.sendPlayerCrypsSet(NULL_UUID, playerCryps);
});
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 playerCryps = [];
this.activeCryps.forEach(obj => playerCryps.push(obj.cryp.id));
ws.sendInstanceJoin(playerCryps);
});
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 = HomeCrypList;

View File

@ -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;

View File

@ -1,91 +0,0 @@
const Phaser = require('phaser');
const HomeCryps = require('./home.cryps');
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 = [
'HomeCryps',
'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('HomeCryps', HomeCryps, 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;

Some files were not shown because too many files have changed in this diff Show More