Merge branch 'release/1.8.1'
This commit is contained in:
commit
7e1a9d8585
306
CHANGELOG.md
306
CHANGELOG.md
@ -1,9 +1,39 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
## [1.8.1] - 2019-11-07
|
||||
|
||||
## [1.8.0] - 2019-10-31
|
||||
# Added
|
||||
### Fixed
|
||||
- An issue where skills would not be put on cooldown after being used.
|
||||
|
||||
### Changed
|
||||
- Game phase
|
||||
- Background for text overlapping with avatars in game phase (mobile)
|
||||
- Fixed issue where effect text would show when not highlighted
|
||||
- Avatar size doesn't decrease as effects are applied (now overlap)
|
||||
- Added back KO! event when a construct is knocked out
|
||||
|
||||
- Invert
|
||||
- Now reverses recharge into damage
|
||||
|
||||
- Link
|
||||
- Reworked completely
|
||||
- Now stuns target for 1T with 1T CD
|
||||
- Deals 20/45/70% blue power multiplied by number of effects on target as blue damage
|
||||
- Applies stun before effect multiplier calculation
|
||||
|
||||
- Restrict
|
||||
- Changed cooldown from 2T -> 1T
|
||||
- Duration now 2T at all levels
|
||||
|
||||
- Ruin
|
||||
- Cooldown now 2T at all levels (down from 3T)
|
||||
- Now deals damage to each target (40/70/100)%
|
||||
|
||||
- Silence
|
||||
- Changed cooldown from 2T -> 1T
|
||||
- Duration now 2T at all levels
|
||||
|
||||
|
||||
## [1.8.0] - 2019-11-06
|
||||
### Added
|
||||
- Drag and drop for vbox interactions can be used instead of single click / double click
|
||||
|
||||
- Base white items and be directly equipped from vbox rather than going through the inventory
|
||||
@ -11,7 +41,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
- You can swap skills and specs between constructs without using the inventory
|
||||
|
||||
# Changed
|
||||
### Changed
|
||||
|
||||
- Construct life changed
|
||||
- You now start with 800 green life (down from 950)
|
||||
@ -28,7 +58,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Game constructs and animations are much larger in mobile view
|
||||
|
||||
- Amplify
|
||||
Now increases green power
|
||||
- Now increases green power
|
||||
|
||||
- Absorb
|
||||
- Reduced duration and cooldown from 2T -> 1T (Absorption duration unchanged)
|
||||
@ -36,13 +66,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Now recharges blue life based on 95 / 120 / 155 blue power
|
||||
|
||||
- Banish
|
||||
Reduced cooldown to 1T
|
||||
- Reduced cooldown to 1T
|
||||
|
||||
- Decay
|
||||
Removed cooldown
|
||||
- Removed cooldown
|
||||
|
||||
- Haste / Hybrid
|
||||
Fixed issue when hybridblast and hastestrike wouldn't trigger from upgraded + skills
|
||||
- Fixed issue when hybridblast and hastestrike wouldn't trigger from upgraded + skills
|
||||
|
||||
- Intercept
|
||||
- Reduced duration to 1T down from 2T
|
||||
@ -50,7 +80,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [1.7.0] - 2019-10-31
|
||||
# Added
|
||||
### Added
|
||||
- Step by step tutorial
|
||||
- Will activate during the learn game for the first round
|
||||
- There is a button which will exit tutorial so you can continune the normal practice mode
|
||||
@ -59,7 +89,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- You can now preview what item combos will create!
|
||||
- Click into the item in the info section table (top right) and it will be replaced with the new item
|
||||
|
||||
# Changed
|
||||
### Changed
|
||||
- Vbox phase
|
||||
- Made general performance improvements
|
||||
- Removed the default info state (should be smoother to navigate now)
|
||||
@ -71,7 +101,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Made general performance improvements
|
||||
- Now has default tutorial text for the first round (tells the player to select skills and then the targets)
|
||||
|
||||
- Moved the login page demo to a new info tab, increased the speed of demo and it now creates random combos
|
||||
- Moved the login page demo to a new info tab
|
||||
- Increased the speed of demo and it now creates random combos
|
||||
|
||||
- Banish
|
||||
- Cooldown reduced to 2T (was 3T)
|
||||
@ -131,18 +162,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [1.6.6] - 2019-10-27
|
||||
# Added
|
||||
### Added
|
||||
- Offering of draws
|
||||
- Neither player receives a point if they agree to a draw
|
||||
- Bots automatically agree to draws
|
||||
|
||||
## [1.6.5] - 2019-10-25
|
||||
# Fixed
|
||||
### Fixed
|
||||
- Stripe being blocked no longer causes unrecoverable error
|
||||
- Automatic ready up is now throttled after abandons
|
||||
- Player width styling
|
||||
|
||||
# Changed
|
||||
### Changed
|
||||
- Improved wiggle animation
|
||||
- Intercept is now considered defensive by bots
|
||||
- Password restrictions relaxed
|
||||
@ -214,245 +245,4 @@ We've updated the UI during the vbox / buy phase to give a better indication of
|
||||
* You can no longer select invalid combinations.
|
||||
|
||||
* Controls
|
||||
* Abandon button now asks for confirmation.
|
||||
|
||||
## [1.1.5] - 2019-10-10
|
||||
### Changed
|
||||
`Recharge` Skill multiplier reduced 85/130/200 -> 70/110/170
|
||||
`Absorption` Skill duration reduced 5/7/9 -> 3/5/7
|
||||
|
||||
## [1.1.4 2019-09-18]
|
||||
|
||||
### Changed
|
||||
Removed self targetting, all skills can be used on any target
|
||||
|
||||
`Reflect` No cooldown, 1T duration
|
||||
`Purify` No cooldown
|
||||
`Recharge` No cooldown
|
||||
|
||||
`Banish`
|
||||
Now deals 40 / 75 / 125% target red / blue life before applying banish debuff
|
||||
Constant 2T duration at all levels
|
||||
Constant 3T cooldown at all levels
|
||||
|
||||
`Link` reworked ->
|
||||
Stuns caster for 3/2/1T
|
||||
If target has higher green life than caster:
|
||||
Deal blue damage to target equal to difference between green life
|
||||
Heal with green damage to source equal to difference between green life
|
||||
|
||||
`Counter` effect no longer applies immunities
|
||||
Counter no cooldown
|
||||
Counter applies for 1T
|
||||
Counter skill now applies block at 40% / 60% / 80% reduction for 1T
|
||||
Counter no longer recharges red life
|
||||
|
||||
`Electrify`
|
||||
No Cooldown
|
||||
Duration -> 1T
|
||||
Electrocute duration now 2/3/4T
|
||||
|
||||
`Sustain`
|
||||
Now has 1T cooldown at all levels
|
||||
Has 1T duration at all levels
|
||||
Now recharges red life to target (120 / 150 / 230)%
|
||||
|
||||
|
||||
## [0.1.3 2019-??-??]
|
||||
|
||||
### Added
|
||||
|
||||
Added `Buff` as a skill
|
||||
Increases Speed and RedDamage by 25%
|
||||
Duration 2T
|
||||
No CD
|
||||
|
||||
### Changed
|
||||
|
||||
`Sustain` now grants immunity to disables.
|
||||
|
||||
## [0.1.2] - 2019-05-07
|
||||
### Added
|
||||
|
||||
New skill `Link `
|
||||
Combines - Buff + BB
|
||||
Links targets together so dmg taken is split
|
||||
Recharge 140% source blue damage as blue life to target
|
||||
|
||||
New skill `Hybrid`
|
||||
Combines - Buff + GB
|
||||
New buff that does the following -
|
||||
Increase target green damage by 50%
|
||||
Blue attacks do an additional blast equal to 25% source green damage
|
||||
|
||||
### Fixed
|
||||
|
||||
- Ruin sends a skill event so ruin only casts once, followed by debuffs
|
||||
- Client side skip for source strangling effect straight to POST_SKILL
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed Empower (Buff + RR) -> combined effect with amplify
|
||||
- Skill Slow removed
|
||||
|
||||
- Debuff is now a usable skill `(add buff as a usable skill also)`
|
||||
Applies slow effect previously applied by skill Slow
|
||||
Slow effect lasts 3T
|
||||
Cooldown 1T
|
||||
|
||||
- Amplify
|
||||
Changed to Buff + RB (was Buff + BB)
|
||||
Inc red and blue multiplier changed 200% -> 150%
|
||||
Increases both red and blue power.
|
||||
|
||||
- Attack
|
||||
Multiplier changed 100% -> 80%
|
||||
|
||||
- Blast
|
||||
Multiplier changed 130% -> 110%
|
||||
|
||||
- Chaos
|
||||
Base Multiplier changed 50% -> 40%
|
||||
RNG range changed from (0 - 20%) -> (0 - 30%)
|
||||
Same dmg range but more RNG
|
||||
|
||||
- Curse
|
||||
Inc red and blue multiplier changed 200% -> 150%
|
||||
`(More reworks soon to make this skill fun)`
|
||||
|
||||
- Haste
|
||||
Changed to Buff + RG (was Buff + RB)
|
||||
Buff causes target to deal an extra attack when using red attack base skills (strike / slay / chaos)
|
||||
Extra attack does 25% source speed as red damage
|
||||
Cooldown increased to 2T
|
||||
Speed bonus reduced 200% -> 150%
|
||||
|
||||
- Heal
|
||||
Changed multiplier 120% -> 130%
|
||||
|
||||
- Counter
|
||||
Changed duration 1T -> 2T
|
||||
Changed cooldown 0T -> 2T
|
||||
Now recharges 110% red damage as red life
|
||||
CounterAttack multiplier reduced 100% -> 70%
|
||||
|
||||
- Siphon
|
||||
Multiplier changed 30% -> 40%
|
||||
|
||||
- Strangle
|
||||
No longer provides immunity to source or target
|
||||
Damage multiplier for strangle tick changed 30% -> 65%
|
||||
|
||||
- Strike
|
||||
Change multipliers T1/T2/T3 (110/130/150 -> 90/110/130)
|
||||
|
||||
- Intercept
|
||||
Changed to Buff + RR (was Buff + RG)
|
||||
Now recharges 80% source red damage as red life to target
|
||||
|
||||
- Break
|
||||
Stun duration reduced from 2T -> 1T
|
||||
Vulnerable dmg bonus reduced 200% -> 150%
|
||||
|
||||
- Triage
|
||||
Multiplier changed 65% -> 75%
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
## [0.1.1] - 2019-05-03
|
||||
>>>>>>> rebalance
|
||||
### Added
|
||||
Event::Skill
|
||||
needed to convey the use of skill which is followed by other events
|
||||
used for skill Purify to show that it is used and then followed by removal and other events
|
||||
New Skill `Sleep`
|
||||
Combined using Stun + GG
|
||||
Stuns target for 3T (might need to be 4T)
|
||||
Deals 240% green damage (heal)
|
||||
Concept - high duration stun with the drawback of a big heal on the target
|
||||
Base cooldown 3T
|
||||
(Could be played aggressively or defensively)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
Switch purify with reflect
|
||||
- Purify
|
||||
Now GG + block (was GB + block)
|
||||
Now applies a small heal 45% multiplier green damage (power) for each debuff removed
|
||||
|
||||
- Reflect
|
||||
Now GB + block (was GG + block)
|
||||
Recharges blue life at 45% blue damage
|
||||
|
||||
- Server function recharge changed to take skill, red amount and blue amount as inputs
|
||||
|
||||
- Recharge Skill reworked
|
||||
No longer restores full Red and Blue life
|
||||
Now restores Red life and Blue life based on respective red and blue damage
|
||||
Recharge value calculated at 85% multiplier with red and blue damage
|
||||
|
||||
Silence
|
||||
No longer Stun + GB (already exists as debuff BB)
|
||||
Now also deals damage amount of 55% base blue damage
|
||||
This damage amount does 45% more damage per blue skill blocked
|
||||
Maximum = (0.55)(1.35)*base_blue_damage
|
||||
Cooldown changed 1T -> 2T
|
||||
Debuff duration increased 2T -> 3T
|
||||
Restrict
|
||||
Now also deals damage amount of 40% base blue damage
|
||||
This damage amount does 45% more damage per red skill blocked
|
||||
Maximum = (0.40)(1.35)*base_red_damage
|
||||
Cooldown changed 1T -> 2T
|
||||
Debuff duration increased 2T -> 3T
|
||||
|
||||
|
||||
Switch sustain with intercept
|
||||
Sustain now GR + Block (was GR + Buff)
|
||||
Intercept now GR + Buff
|
||||
No longer self-target only
|
||||
|
||||
|
||||
Hex is now Stun + GB (was Stun + RB)
|
||||
Banish is now Stun + RB (was Stun + RG) for rng theme
|
||||
Break is now Stun + RG (was Stun + GG)
|
||||
- Better fit as it applies inc Red taken debuff (vulnerability)
|
||||
|
||||
|
||||
## [0.1.0] - 2019-05-02
|
||||
### Added
|
||||
New skill `Chaos`
|
||||
- 50% base red & blue with an additional rng 20% blue & red
|
||||
- Combo'd with Attack + Red + Blue
|
||||
|
||||
New skill `Slay`
|
||||
- 70% base red, heals (green damage) for equivalent dmg dealt
|
||||
- Combo'd with Attack + Red + Green
|
||||
|
||||
New effect `Wither`
|
||||
- Reduces green damage taken by 50%
|
||||
|
||||
### Fixed
|
||||
- Siphon deals damage before applying heal
|
||||
- Changed tests to incorporate skill damage multipliers
|
||||
|
||||
### Changed
|
||||
- Changed Decay, Siphon and Purify vbox items
|
||||
`Decay`
|
||||
- 1 blue + 1 green + debuff
|
||||
- now also applies new debuff `Wither`
|
||||
- Cooldown increased 0T -> 1T
|
||||
`Siphon`
|
||||
- 1 blue + 1 green + attack
|
||||
- Cooldown reduced 1T -> 0T
|
||||
`Purify` 1 blue + 1 green + block
|
||||
|
||||
- Changed skill damage multipliers
|
||||
`Blast` 100% -> 130%
|
||||
`ElectrocuteTick` 100% -> 80%
|
||||
`Decay` 50% -> 25%
|
||||
`Heal` 100% -> 120%
|
||||
`SiphonTick` 100% -> 30%
|
||||
`StrangleTick` 100% -> 30%
|
||||
`Strike` 100% -> 110%
|
||||
`TriageTick` 100% -> 65%
|
||||
* Abandon button now asks for confirmation.
|
||||
91
WORKLOG.md
91
WORKLOG.md
@ -8,15 +8,30 @@
|
||||
|
||||
* mobile info page
|
||||
|
||||
* Invert recharge
|
||||
|
||||
## SOON
|
||||
|
||||
* supporter gold name in instance (anyone whos put any money into game)
|
||||
|
||||
* change cooldowns to delay & recharge
|
||||
- delay is cooldown before skill can first be used
|
||||
- recharge is cooldown after using skill
|
||||
- every x speed reduces delay of skills
|
||||
|
||||
* audio
|
||||
|
||||
* elo + leaderboards
|
||||
* reconnect based on time delta
|
||||
|
||||
* ACP
|
||||
* essential
|
||||
|
||||
## LATER
|
||||
|
||||
* theme toasts
|
||||
* rework vecs into sets
|
||||
* remove names so games/instances are copy
|
||||
* consolidate game and instance
|
||||
|
||||
* combo rework
|
||||
- reduce number of items for creating t2/t3 items from 3 -> 2
|
||||
- add lost complexity by adding skill spec items
|
||||
@ -27,55 +42,11 @@
|
||||
- Strike + SpeedRR -> StrikeSpeed (strike has Y% more speed)
|
||||
- Strike + LifeRR -> StrikeLife (Strike recharges X% of damage as red life)
|
||||
|
||||
* ACP
|
||||
* essential
|
||||
|
||||
* audio
|
||||
* treats
|
||||
* susbcriber gold name in instance
|
||||
* client animation bpm
|
||||
* background colour changes depending on time of day
|
||||
|
||||
* rework vecs into sets
|
||||
* remove names so games/instances are copy
|
||||
|
||||
*$$$*
|
||||
* instead of red noise, red and black bar gradient
|
||||
* eth adapter
|
||||
* illusions
|
||||
* vaporwave
|
||||
* crop circles
|
||||
* insects
|
||||
* sacred geometry
|
||||
* skulls / day of the dead
|
||||
* Aztec
|
||||
* youkai
|
||||
* Industrial
|
||||
|
||||
*CLIENT*
|
||||
theme toasts
|
||||
|
||||
reconnect based on time delta
|
||||
consolidate game and instance
|
||||
|
||||
* return of the combat log (last few events with condensed descriptions)
|
||||
- click in to scroll
|
||||
* elo + leaderboards
|
||||
|
||||
* reflect event stages (for animations)
|
||||
* mnml tv
|
||||
|
||||
## LATER
|
||||
* constants
|
||||
* bot game grind
|
||||
* (maybe) return of the combat log (last few events with condensed descriptions)
|
||||
- click in to scroll
|
||||
|
||||
$$$
|
||||
* Items
|
||||
* Colour scheme
|
||||
* targeting highlight colour
|
||||
* number of constructs
|
||||
* Highlight (dota) colour
|
||||
* fx colours + styles
|
||||
* mnml tv
|
||||
|
||||
* modules
|
||||
* troll life -> dmg
|
||||
@ -84,6 +55,28 @@ $$$
|
||||
* fuck magic
|
||||
* empower on ko
|
||||
|
||||
## $$$
|
||||
* Items
|
||||
* instead of red noise, red and black bar gradient
|
||||
* eth adapter
|
||||
*sets*
|
||||
* illusions
|
||||
* vaporwave
|
||||
* crop circles
|
||||
* insects
|
||||
* sacred geometry
|
||||
* skulls / day of the dead
|
||||
* Aztec
|
||||
* youkai
|
||||
* Industrial
|
||||
* Colour scheme
|
||||
* targeting highlight colour
|
||||
* Highlight (dota) colour
|
||||
* fx colours + styles
|
||||
* treats
|
||||
* client animation bpm
|
||||
* background colour changes depending on time of day
|
||||
|
||||
# Mechanics
|
||||
* 10d chaos maths, not rock paper scissors
|
||||
* phys is faster and chaotic
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mnml-client",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -1,14 +1,3 @@
|
||||
require('./assets/styles/styles.less');
|
||||
require('./assets/styles/menu.less');
|
||||
require('./assets/styles/nav.less');
|
||||
require('./assets/styles/footer.less');
|
||||
require('./assets/styles/account.less');
|
||||
require('./assets/styles/controls.less');
|
||||
require('./assets/styles/instance.less');
|
||||
require('./assets/styles/vbox.less');
|
||||
require('./assets/styles/game.less');
|
||||
require('./assets/styles/player.less');
|
||||
require('./assets/styles/styles.mobile.less');
|
||||
require('./assets/styles/instance.mobile.less');
|
||||
|
||||
require('./src/animations.test.jsx');
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
.account {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ svg {
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
button, button:hover, button:active {
|
||||
&.blue {
|
||||
border-color: @blue;
|
||||
}
|
||||
@ -150,6 +150,16 @@ button {
|
||||
&.green {
|
||||
border-color: @green;
|
||||
}
|
||||
|
||||
&.red-border {
|
||||
border-color: @red;
|
||||
}
|
||||
&.blue-border {
|
||||
border-color: @blue;
|
||||
}
|
||||
&.green-border {
|
||||
border-color: @green;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rgb {
|
||||
@ -181,3 +191,12 @@ button {
|
||||
color: @blue;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes target-ko {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
aside {
|
||||
grid-area: ctrl;
|
||||
display: grid;
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
@import 'colours.less';
|
||||
/* GAME */
|
||||
|
||||
.game {
|
||||
overflow: hidden;
|
||||
// display: grid;
|
||||
@ -10,10 +7,6 @@
|
||||
// "opponent"
|
||||
// "target "
|
||||
// "player ";
|
||||
|
||||
.skill-description {
|
||||
font-size: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
.game .team, .faceoff .team {
|
||||
@ -35,6 +28,14 @@
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 50%;
|
||||
|
||||
.avatar {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.opponent {
|
||||
@ -53,6 +54,13 @@
|
||||
"right"
|
||||
"left";
|
||||
|
||||
.avatar {
|
||||
position: absolute;
|
||||
top: 3em;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
@ -60,7 +68,7 @@
|
||||
grid-template-areas:
|
||||
"stats"
|
||||
"name"
|
||||
"avatar";
|
||||
"avatar"
|
||||
}
|
||||
|
||||
.effects {
|
||||
@ -86,7 +94,7 @@
|
||||
justify-items: center;
|
||||
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 2fr;
|
||||
grid-template-rows: minmax(min-content, 1fr) min-content;
|
||||
grid-template-areas:
|
||||
"left"
|
||||
"right";
|
||||
@ -130,6 +138,10 @@
|
||||
margin-bottom: 0.25em;
|
||||
text-align: center;
|
||||
grid-area: name;
|
||||
z-index: 2;
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.skills {
|
||||
@ -138,9 +150,15 @@
|
||||
width: 100%;
|
||||
height: 2em;
|
||||
margin-right: 1em;
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
button.active {
|
||||
background: #2c2c2c;
|
||||
span {
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +169,9 @@
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.stats {
|
||||
@ -177,6 +198,10 @@
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
&.ko-transition {
|
||||
animation: target-ko 1s ease-in-out 0s 1;
|
||||
}
|
||||
|
||||
&.ko {
|
||||
animation: none;
|
||||
opacity: 0.20;
|
||||
@ -214,24 +239,36 @@
|
||||
top: 35%;
|
||||
height: 15%;
|
||||
width: calc(90% - 1.25em);
|
||||
z-index: 2;
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.resolving-skill {
|
||||
grid-area: target;
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
height: auto;
|
||||
// height: auto;
|
||||
svg {
|
||||
display: inline;
|
||||
height: 1em;
|
||||
margin-right: 0.1em
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.skill-description {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
text-align: center;
|
||||
z-index: 2;
|
||||
span {
|
||||
background-color: black;
|
||||
}
|
||||
svg {
|
||||
display: inline;
|
||||
height: 1em;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
.instance {
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
@ -349,7 +347,7 @@
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr 0.5fr 1.5fr;
|
||||
grid-template-rows: 1fr 0.5fr 1fr;
|
||||
grid-template-areas:
|
||||
"opponent"
|
||||
"text"
|
||||
@ -379,11 +377,15 @@
|
||||
|
||||
.faceoff-text {
|
||||
grid-area: text;
|
||||
font-size: 200%;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1em;
|
||||
font-weight: bold;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
color: @black;
|
||||
animation: faceoff 4s ease-in-out 0s 2 alternate;
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
// tablet / ipad
|
||||
@media (max-width: 1100px) {
|
||||
.instance {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
.menu {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
.player-box {
|
||||
display: grid;
|
||||
overflow: hidden;
|
||||
|
||||
@ -1,4 +1,15 @@
|
||||
@import 'colours.less';
|
||||
@import 'account.less';
|
||||
@import 'menu.less';
|
||||
@import 'nav.less';
|
||||
@import 'footer.less';
|
||||
@import 'controls.less';
|
||||
@import 'instance.less';
|
||||
@import 'vbox.less';
|
||||
@import 'game.less';
|
||||
@import 'player.less';
|
||||
@import 'styles.mobile.less';
|
||||
@import 'instance.mobile.less';
|
||||
|
||||
html body {
|
||||
margin: 0;
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1em;
|
||||
height: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,6 +54,13 @@
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.skill-description {
|
||||
font-size: 0.8em;
|
||||
svg {
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.player {
|
||||
.game-construct {
|
||||
grid-template-areas:
|
||||
@ -85,7 +92,7 @@
|
||||
}
|
||||
|
||||
.avatar {
|
||||
bottom: 0px;
|
||||
top: 3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import 'colours.less';
|
||||
|
||||
.vbox {
|
||||
margin-bottom: 2em;
|
||||
|
||||
|
||||
@ -1,15 +1,4 @@
|
||||
require('./assets/styles/styles.less');
|
||||
require('./assets/styles/account.less');
|
||||
require('./assets/styles/menu.less');
|
||||
require('./assets/styles/nav.less');
|
||||
require('./assets/styles/footer.less');
|
||||
require('./assets/styles/controls.less');
|
||||
require('./assets/styles/instance.less');
|
||||
require('./assets/styles/vbox.less');
|
||||
require('./assets/styles/game.less');
|
||||
require('./assets/styles/player.less');
|
||||
require('./assets/styles/styles.mobile.less');
|
||||
require('./assets/styles/instance.mobile.less');
|
||||
|
||||
// kick it off
|
||||
require('./src/app');
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mnml-client",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -30,46 +30,54 @@ function createSocket(store) {
|
||||
if (animating) return false;
|
||||
store.dispatch(actions.setAnimating(true));
|
||||
// stop fetching the game state til animations are done
|
||||
|
||||
return eachSeries(newRes, (r, cb) => {
|
||||
if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
|
||||
|
||||
// convert server enum into anims keywords
|
||||
// todo make serersideonly
|
||||
const sequence = animations.getSequence(r);
|
||||
const timeout = animations.getTime(sequence);
|
||||
const anims = animations.getObjects(r, sequence, game, account);
|
||||
const text = animations.getText(r, sequence);
|
||||
if (!r.event) return cb();
|
||||
const timeout = animations.getTime(r.stages);
|
||||
const anims = animations.getObjects(r, game, account);
|
||||
const text = animations.getText(r);
|
||||
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
|
||||
if (anims.animSkill) store.dispatch(actions.setAnimSkill(anims.animSkill));
|
||||
|
||||
if (sequence.includes('START_SKILL') && anims.animSource) store.dispatch(actions.setAnimSource(anims.animSource));
|
||||
if (sequence.includes('END_SKILL') && anims.animTarget) {
|
||||
if (r.stages.includes('START_SKILL') && anims.animSource) {
|
||||
store.dispatch(actions.setAnimSource(anims.animSource));
|
||||
}
|
||||
|
||||
if (r.stages.includes('END_SKILL') && anims.animTarget) {
|
||||
store.dispatch(actions.setAnimTarget(anims.animTarget));
|
||||
if (!['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) store.dispatch(actions.setAnimCb(cb));
|
||||
if (animations.isCbAnim(anims.animSkill)) store.dispatch(actions.setAnimCb(cb));
|
||||
}
|
||||
if (sequence.includes('POST_SKILL' && text)) {
|
||||
|
||||
if (r.stages.includes('POST_SKILL') && text) {
|
||||
// timeout to prevent text classes from being added too soon
|
||||
setTimeout(
|
||||
() => store.dispatch(actions.setAnimText(text)),
|
||||
timeout - TIMES.POST_SKILL_DURATION_MS
|
||||
);
|
||||
if (timeout === TIMES.POST_SKILL_DURATION_MS) {
|
||||
store.dispatch(actions.setAnimText(text));
|
||||
} else {
|
||||
setTimeout(
|
||||
() => store.dispatch(actions.setAnimText(text)),
|
||||
timeout - TIMES.POST_SKILL_DURATION_MS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return setTimeout(() => {
|
||||
store.dispatch(actions.setAnimSkill(null));
|
||||
store.dispatch(actions.setAnimSource(null));
|
||||
store.dispatch(actions.setAnimTarget(null));
|
||||
store.dispatch(actions.setAnimText(null));
|
||||
store.dispatch(actions.setAnimFocus([]));
|
||||
if (!sequence.includes('END_SKILL')
|
||||
|| ['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) return cb();
|
||||
return true;
|
||||
if (r.stages.includes('END_SKILL') && animations.isCbAnim(anims.animSkill)) return true;
|
||||
return cb();
|
||||
}, timeout);
|
||||
}, err => {
|
||||
if (err) return console.error(err);
|
||||
// clear animation state
|
||||
store.dispatch(actions.setAnimSkill(null));
|
||||
store.dispatch(actions.setAnimSource(null));
|
||||
store.dispatch(actions.setAnimTarget(null));
|
||||
store.dispatch(actions.setAnimText(null));
|
||||
store.dispatch(actions.setAnimating(false));
|
||||
|
||||
store.dispatch(actions.setGameEffectInfo(null));
|
||||
store.dispatch(actions.setSkip(false));
|
||||
|
||||
// set the game state so resolutions don't fire twice
|
||||
|
||||
@ -111,7 +111,7 @@ function getText(resolution) {
|
||||
function generatePostSkill() {
|
||||
const [type, event] = resolution.event;
|
||||
if (type === 'Ko') {
|
||||
return { text: 'KO!', css: 'ko' };
|
||||
return { text: 'KO!', css: 'ko-transition' };
|
||||
}
|
||||
|
||||
if (type === 'Disable') {
|
||||
|
||||
@ -20,6 +20,7 @@ function projectile(x, y, radius, colour) {
|
||||
cy={y}
|
||||
r={radius}
|
||||
fill={colour}
|
||||
stroke="none"
|
||||
filter={colour === '#a52a2a' ? 'url(#chaosRedFilter)' : 'url(#chaosBlueFilter)'}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -18,7 +18,7 @@ class Refl extends Component {
|
||||
this.animations = [];
|
||||
}
|
||||
|
||||
render({ team }) {
|
||||
render({ player }) {
|
||||
const oneX = anime.random(32, 96);
|
||||
const twoX = anime.random(192, 224);
|
||||
|
||||
@ -28,7 +28,7 @@ class Refl extends Component {
|
||||
version="1.1"
|
||||
id="reflect"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={{ transform: team ? '' : 'rotate3d(1, 0, 0, 180deg)' }}
|
||||
style={{ transform: player ? '' : 'rotate3d(1, 0, 0, 180deg)' }}
|
||||
viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<filter id="reflectFilterGreen">
|
||||
|
||||
@ -20,6 +20,7 @@ function projectile(x, y, radius, colour) {
|
||||
<circle
|
||||
cx={x}
|
||||
cy={y}
|
||||
stroke="none"
|
||||
r={radius}
|
||||
fill={colour}
|
||||
/>
|
||||
@ -28,7 +29,7 @@ function projectile(x, y, radius, colour) {
|
||||
|
||||
function sword(colour) {
|
||||
return (
|
||||
<polygon points='150,150 100,75, 150,300, 200,75' fill={colour} id="sword" filter="url(#slayFilter)"></polygon>
|
||||
<polygon points='150,150 100,75, 150,300, 200,75' stroke="none" fill={colour} id="sword" filter="url(#slayFilter)"></polygon>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -8,33 +8,33 @@ module.exports = {
|
||||
Slay: () => 'red-green-border',
|
||||
Siphon: () => 'blue-green-border',
|
||||
// Stun
|
||||
Link: () => 'blue-green-border',
|
||||
Bash: () => 'red-border',
|
||||
Sleep: () => 'green-border',
|
||||
Ruin: () => 'blue-border',
|
||||
Break: () => 'red-green-border',
|
||||
Sleep: () => 'green-border',
|
||||
Banish: () => 'red-blue-border',
|
||||
Break: () => 'red-green-border',
|
||||
Link: () => 'blue-green-border',
|
||||
// Block
|
||||
Counter: () => 'red-border',
|
||||
Purify: () => 'green-border',
|
||||
Electrify: () => 'blue-border',
|
||||
Purify: () => 'green-border',
|
||||
Recharge: () => 'red-blue-border',
|
||||
Sustain: () => 'red-green-border',
|
||||
Reflect: () => 'blue-green-border',
|
||||
Recharge: () => 'blue-red-border',
|
||||
// Buff
|
||||
Intercept: () => 'red-border',
|
||||
Triage: () => 'green-border',
|
||||
Haste: () => 'red-green-border',
|
||||
Absorb: () => 'blue-border',
|
||||
Hybrid: () => 'blue-green-border',
|
||||
Triage: () => 'green-border',
|
||||
Amplify: () => 'red-blue-border',
|
||||
Haste: () => 'red-green-border',
|
||||
Hybrid: () => 'blue-green-border',
|
||||
// Debuff
|
||||
Restrict: () => 'red-border',
|
||||
Purge: () => 'green-border',
|
||||
Silence: () => 'blue-border',
|
||||
Purge: () => 'green-border',
|
||||
Curse: () => 'red-blue-border',
|
||||
Invert: () => 'red-green-border',
|
||||
Decay: () => 'blue-green-border',
|
||||
Curse: () => 'red-blue-border',
|
||||
|
||||
// // Lifes Upgrades
|
||||
// LifeGG: () => 'green-border',
|
||||
|
||||
@ -111,7 +111,7 @@ function constructText(props) {
|
||||
? animText.text
|
||||
: construct.name;
|
||||
|
||||
return <h3 class={'name'}>{text}</h3>;
|
||||
return <h3 class={'name'}><span>{text}</span></h3>;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@ -117,7 +117,8 @@ class GameConstruct extends Component {
|
||||
setGameEffectInfo,
|
||||
} = this.props;
|
||||
|
||||
const ko = construct.green_life.value === 0 ? 'ko' : '';
|
||||
const koEvent = animText ? animText.text === 'KO!' && animText.constructId === construct.id : false;
|
||||
const ko = construct.green_life.value === 0 && !koEvent ? 'ko' : '';
|
||||
const classes = eventClasses(animating, animFocus, construct, animText);
|
||||
|
||||
const stats = ['RedLife', 'GreenLife', 'BlueLife'].map((s, j) => (
|
||||
@ -143,21 +144,21 @@ class GameConstruct extends Component {
|
||||
const fullInfo = itemInfo.items.find(k => k.item === gameSkillInfo.skill) || INFO[gameSkillInfo.skill];
|
||||
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
|
||||
const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]());
|
||||
const speed = <div> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </div>;
|
||||
const speed = <span> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </span>;
|
||||
return (
|
||||
<div class="skill-description">
|
||||
<h2> {gameSkillInfo.skill} </h2>
|
||||
<div> {infoDescription} </div>
|
||||
<h2><span> {gameSkillInfo.skill} </span></h2>
|
||||
<span>{infoDescription} </span>
|
||||
{speed}
|
||||
</div>);
|
||||
}
|
||||
const effects = construct.effects.length
|
||||
? construct.effects.map(c =>
|
||||
<div
|
||||
key={c.effect}
|
||||
onMouseOver={e => hoverInfo(e, c)}
|
||||
onMouseOut={e => hoverInfo(e, null)}
|
||||
> {c.effect} - {c.duration}T</div>)
|
||||
<div key={c.effect}>
|
||||
<span key={c.effect} onMouseOver={e => hoverInfo(e, c)}
|
||||
onMouseOut={e => hoverInfo(e, null)}> {c.effect} - {c.duration}T
|
||||
</span>
|
||||
</div>)
|
||||
: null;
|
||||
return (<div class="effects"> {effects} </div>);
|
||||
};
|
||||
|
||||
@ -4,7 +4,6 @@ const { connect } = require('preact-redux');
|
||||
const Main = require('./main');
|
||||
// const Nav = require('./nav');
|
||||
const Controls = require('./controls');
|
||||
const Footer = require('./footer');
|
||||
|
||||
const addState = connect(
|
||||
({ game, instance }) => ({ game, instance })
|
||||
@ -24,7 +23,6 @@ function Mnml(args) {
|
||||
<div id="mnml">
|
||||
<Main />
|
||||
<Controls />
|
||||
<Footer />
|
||||
<div id="rotate" class={rotateClass} >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -91,7 +91,7 @@ function Skill(props) {
|
||||
onMouseOut={e => hoverInfo(e, null)}
|
||||
type="submit"
|
||||
onClick={onClick}>
|
||||
{s.skill} {cdText}
|
||||
<span>{s.skill} {cdText}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ class TargetSvg extends Component {
|
||||
itemInfo,
|
||||
} = props;
|
||||
const { width, height } = state;
|
||||
|
||||
if (!game) return false; // game will be null when battle ends
|
||||
if (game.phase === 'Finished') return false; // Clear everything if its over (in case of abandon)
|
||||
|
||||
@ -59,7 +60,7 @@ class TargetSvg extends Component {
|
||||
if (tutorialGame) {
|
||||
return (
|
||||
<div class="resolving-skill">
|
||||
<h2> Select your skills, click on targets and then hit <b>READY</b>.</h2>
|
||||
<h2>Select your skills, click on targets and then hit <b>READY</b>.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -73,7 +74,7 @@ class TargetSvg extends Component {
|
||||
return (
|
||||
<div class="resolving-skill">
|
||||
<h1>{gameEffectInfo.effect}</h1>
|
||||
<div> {infoDescription} </div>
|
||||
<div>{infoDescription}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -91,7 +92,7 @@ class TargetSvg extends Component {
|
||||
return (
|
||||
<div class="resolving-skill">
|
||||
<h1>{animSkill}</h1>
|
||||
<div> {itemSourceDescription} </div>
|
||||
<div>{itemSourceDescription}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ function registerEvents(store) {
|
||||
// stop fetching the game state til animations are done
|
||||
const newRes = game.resolved.slice(currentGame.resolved.length);
|
||||
return eachSeries(newRes, (r, cb) => {
|
||||
if (!r.event || r.stages === '') return cb();
|
||||
if (!r.event) return cb();
|
||||
const timeout = animations.getTime(r.stages);
|
||||
const anims = animations.getObjects(r, game, account);
|
||||
const text = animations.getText(r);
|
||||
|
||||
@ -240,6 +240,8 @@ function convertItem(v) {
|
||||
}
|
||||
|
||||
function effectInfo(i) {
|
||||
const hybridBlast = 25;
|
||||
const hasteStrike = 30;
|
||||
function multiplier(s) { // Update later to use server info in future
|
||||
if (s === 'CounterAttack') return 120;
|
||||
if (s === 'CounterAttack+') return 160;
|
||||
@ -270,9 +272,9 @@ function effectInfo(i) {
|
||||
case 'Buff': return `Increases construct RedPower BluePower SpeedStat by ${i.meta[1] - 100}%`;
|
||||
case 'Sustain': return 'Construct cannot be KO while active. Additionally provides immunity to disables';
|
||||
case 'Curse': return `Construct will take ${i.meta[1] - 100}% increased red and blue damage`;
|
||||
case 'Haste': return `Construct has ${i.meta[1] - 100}% increased SpeedStat. Red attack skills will trigger a HasteStrike dealing 30% SpeedStat as red damage.`;
|
||||
case 'Hybrid': return `Construct has ${i.meta[1] - 100}% increased GreenPower. Blue attack skills will trigger a HybridBlast dealing 25% GreenPower as red damage.`;
|
||||
case 'Invert': return 'Reverses damage and healing. Healing will damage this construct and damage will heal.';
|
||||
case 'Haste': return `Construct has ${i.meta[1] - 100}% increased SpeedStat. Red attack skills will trigger a HasteStrike dealing ${hasteStrike}% SpeedStat as red damage.`;
|
||||
case 'Hybrid': return `Construct has ${i.meta[1] - 100}% increased GreenPower. Blue attack skills will trigger a HybridBlast dealing ${hybridBlast}% GreenPower as red damage.`;
|
||||
case 'Invert': return 'Reverse healing/recharge into damage and damage into healing/recharge.';
|
||||
case 'Counter': return `Red damage taken by this construct will trigger a CounterAttack. CounterAttack deals ${multiplier(i.meta[1])}% RedPower as red damage.`;
|
||||
case 'Purge': return 'Disable construct from casting any green skills';
|
||||
case 'Reflect': return 'Reflect blue skills back to caster';
|
||||
|
||||
2
ops/package.json
Executable file → Normal file
2
ops/package.json
Executable file → Normal file
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mnml-ops",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mnml"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
authors = ["ntr <ntr@smokestack.io>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@ -549,36 +549,104 @@ impl Construct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recharge(&mut self, skill: Skill, red_amount: u64, blue_amount: u64) -> Event {
|
||||
pub fn recharge(&mut self, skill: Skill, red_amount: u64, blue_amount: u64) -> Vec<Event> {
|
||||
let mut events = vec![];
|
||||
|
||||
// Should red type immunity block recharge???
|
||||
if let Some(immunity) = self.immune(skill) {
|
||||
return Event::Immunity {
|
||||
skill,
|
||||
immunity,
|
||||
};
|
||||
if !self.is_ko() {
|
||||
events.push(Event::Immunity { skill, immunity });
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
// Do we need inversion?
|
||||
let current_red_life = self.red_life();
|
||||
self.red_life.increase(red_amount);
|
||||
let new_red_life = self.red_life.value;
|
||||
let red = new_red_life - current_red_life;
|
||||
match self.affected(Effect::Invert) {
|
||||
false => {
|
||||
// Do we need inversion?
|
||||
let current_red_life = self.red_life();
|
||||
self.red_life.increase(red_amount);
|
||||
let new_red_life = self.red_life.value;
|
||||
let red = new_red_life - current_red_life;
|
||||
|
||||
let current_blue_life = self.blue_life();
|
||||
self.blue_life.increase(blue_amount);
|
||||
let new_blue_life = self.blue_life.value;
|
||||
let blue = new_blue_life - current_blue_life;
|
||||
let current_blue_life = self.blue_life();
|
||||
self.blue_life.increase(blue_amount);
|
||||
let new_blue_life = self.blue_life.value;
|
||||
let blue = new_blue_life - current_blue_life;
|
||||
|
||||
Event::Recharge { red, blue, skill }
|
||||
if red != 0 || blue != 0 {
|
||||
events.push(Event::Recharge { red, blue, skill });
|
||||
}
|
||||
},
|
||||
true => {
|
||||
// Recharge takes a red and blue amount so check for them
|
||||
if red_amount != 0 {
|
||||
let red_mods = self.effects.iter()
|
||||
.filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken))
|
||||
.map(|e| (e.effect, e.meta))
|
||||
.collect::<Vec<(Effect, Option<EffectMeta>)>>();
|
||||
|
||||
let red_modified_power = red_mods.iter()
|
||||
.fold(red_amount, |acc, fx| fx.0.apply(acc, fx.1));
|
||||
|
||||
|
||||
let red_remainder = red_modified_power.saturating_sub(self.red_life.value);
|
||||
let red_mitigation = red_modified_power.saturating_sub(red_remainder);
|
||||
|
||||
// reduce red_life by mitigation amount
|
||||
self.red_life.reduce(red_mitigation);
|
||||
|
||||
// deal remainder to green_life
|
||||
let red_current_green_life = self.green_life();
|
||||
self.reduce_green_life(red_remainder);
|
||||
let red_damage_amount = red_current_green_life - self.green_life();
|
||||
|
||||
events.push(Event::Damage {
|
||||
skill,
|
||||
amount: red_damage_amount,
|
||||
mitigation: red_mitigation,
|
||||
colour: Colour::Red
|
||||
});
|
||||
}
|
||||
|
||||
if blue_amount != 0 {
|
||||
let blue_mods = self.effects.iter()
|
||||
.filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken))
|
||||
.map(|e| (e.effect, e.meta))
|
||||
.collect::<Vec<(Effect, Option<EffectMeta>)>>();
|
||||
|
||||
let blue_modified_power = blue_mods.iter()
|
||||
.fold(blue_amount, |acc, fx| fx.0.apply(acc, fx.1));
|
||||
|
||||
|
||||
let blue_remainder = blue_modified_power.saturating_sub(self.blue_life.value);
|
||||
let blue_mitigation = blue_modified_power.saturating_sub(blue_remainder);
|
||||
|
||||
// reduce blue_life by mitigation amount
|
||||
self.blue_life.reduce(blue_mitigation);
|
||||
|
||||
// deal remainder to green_life
|
||||
let blue_current_green_life = self.green_life();
|
||||
self.reduce_green_life(blue_remainder);
|
||||
let blue_damage_amount = blue_current_green_life - self.green_life();
|
||||
|
||||
events.push(Event::Damage {
|
||||
skill,
|
||||
amount: blue_damage_amount,
|
||||
mitigation: blue_mitigation,
|
||||
colour: Colour::Blue
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
pub fn deal_green_damage(&mut self, skill: Skill, amount: u64) -> Vec<Event> {
|
||||
let mut events = vec![];
|
||||
if let Some(immunity) = self.immune(skill) {
|
||||
events.push(Event::Immunity {
|
||||
immunity,
|
||||
skill,
|
||||
});
|
||||
if !self.is_ko() {
|
||||
events.push(Event::Immunity { skill, immunity });
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
@ -629,10 +697,9 @@ impl Construct {
|
||||
let mut events = vec![];
|
||||
|
||||
if let Some(immunity) = self.immune(skill) {
|
||||
events.push(Event::Immunity {
|
||||
skill,
|
||||
immunity,
|
||||
});
|
||||
if !self.is_ko() {
|
||||
events.push(Event::Immunity { skill, immunity });
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
@ -702,10 +769,9 @@ impl Construct {
|
||||
let mut events = vec![];
|
||||
|
||||
if let Some(immunity) = self.immune(skill) {
|
||||
events.push(Event::Immunity {
|
||||
skill,
|
||||
immunity,
|
||||
});
|
||||
if !self.is_ko() {
|
||||
events.push(Event::Immunity { skill, immunity });
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
|
||||
@ -469,6 +469,14 @@ impl Game {
|
||||
|
||||
let mut resolutions = resolution_steps(&cast, &mut self);
|
||||
r_animation_ms = resolutions.iter().fold(r_animation_ms, |acc, r| acc + r.clone().get_delay());
|
||||
|
||||
|
||||
// the cast itself goes into this temp vec to handle cooldowns
|
||||
// if theres no resolution events, the skill didn't trigger (disable etc)
|
||||
if resolutions.len() > 0 {
|
||||
casts.push(cast);
|
||||
}
|
||||
|
||||
self.resolved.append(&mut resolutions);
|
||||
|
||||
// while let Some(resolution) = resolutions.pop() {
|
||||
@ -477,10 +485,6 @@ impl Game {
|
||||
// self.resolved.push(resolution);
|
||||
// }
|
||||
|
||||
// the cast itself goes into this temp vec
|
||||
// to handle cooldowns
|
||||
casts.push(cast);
|
||||
|
||||
// sort the stack again in case speeds have changed
|
||||
self.stack_sort_speed();
|
||||
};
|
||||
@ -506,14 +510,11 @@ impl Game {
|
||||
}
|
||||
|
||||
// only reduce cooldowns if no cd was used
|
||||
// have to borrow self for the skill check
|
||||
{
|
||||
if let Some(skill) = resolved.iter().find(|s| s.source_construct_id == construct.id) {
|
||||
if skill.used_cooldown() {
|
||||
if let Some(skill) = resolved.iter()
|
||||
.filter(|s| s.source_construct_id == construct.id)
|
||||
.find(|s| s.used_cooldown()) {
|
||||
construct.skill_set_cd(skill.skill);
|
||||
} else {
|
||||
construct.reduce_cooldowns();
|
||||
}
|
||||
} else {
|
||||
construct.reduce_cooldowns();
|
||||
}
|
||||
@ -984,7 +985,9 @@ mod tests {
|
||||
.learn(Skill::Siphon)
|
||||
.learn(Skill::Amplify)
|
||||
.learn(Skill::Stun)
|
||||
.learn(Skill::Block);
|
||||
.learn(Skill::Block)
|
||||
.learn(Skill::Sleep)
|
||||
.learn(Skill::Decay);
|
||||
|
||||
let mut y = Construct::new()
|
||||
.named(&"lemongrass tea".to_string())
|
||||
@ -1199,6 +1202,55 @@ mod tests {
|
||||
assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sleep_cooldown_test() {
|
||||
let mut game = create_test_game();
|
||||
|
||||
let x_player = game.players[0].clone();
|
||||
let y_player = game.players[1].clone();
|
||||
|
||||
let x_construct = x_player.constructs[0].clone();
|
||||
let y_construct = y_player.constructs[0].clone();
|
||||
|
||||
|
||||
for _n in 1..10 {
|
||||
// should auto progress back to skill phase
|
||||
assert!(game.phase == Phase::Skill);
|
||||
|
||||
// Sleep 2T CD
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none());
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some());
|
||||
|
||||
game.player_ready(x_player.id).unwrap();
|
||||
game.player_ready(y_player.id).unwrap();
|
||||
game = game.resolve_phase_start();
|
||||
|
||||
// Sleep 1T CD
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none());
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some());
|
||||
|
||||
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap();
|
||||
// game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap();
|
||||
game.player_ready(x_player.id).unwrap();
|
||||
game.player_ready(y_player.id).unwrap();
|
||||
game = game.resolve_phase_start();
|
||||
|
||||
// Sleep 0T CD (we use it here)
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none());
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_none());
|
||||
|
||||
game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Sleep).unwrap();
|
||||
game.player_ready(x_player.id).unwrap();
|
||||
game.player_ready(y_player.id).unwrap();
|
||||
game = game.resolve_phase_start();
|
||||
|
||||
// Sleep back to 2T CD
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none());
|
||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counter_test() {
|
||||
let mut game = create_test_game();
|
||||
@ -1390,6 +1442,7 @@ mod tests {
|
||||
true
|
||||
},
|
||||
Event::AoeSkill { skill: _ } => false,
|
||||
Event::Damage { amount: _, mitigation: _, colour: _, skill: _ } => false,
|
||||
_ => panic!("ruin result not effect {:?}", event),
|
||||
}
|
||||
false => false,
|
||||
@ -1428,7 +1481,7 @@ mod tests {
|
||||
|
||||
game = game.resolve_phase_start();
|
||||
|
||||
assert!(game.resolved.len() == 5);
|
||||
assert!(game.resolved.len() == 4);
|
||||
while let Some(r) = game.resolved.pop() {
|
||||
let Resolution { source , target, event: _, stages: _ } = r;
|
||||
if [i_construct.id, j_construct.id].contains(&source.id) {
|
||||
|
||||
@ -807,8 +807,8 @@ impl Item {
|
||||
Item::Invert|
|
||||
Item::InvertPlus |
|
||||
Item::InvertPlusPlus => format!(
|
||||
"Reverse healing into damage and damage into healing.
|
||||
Any excess red or blue damage is converted into shield recharge.
|
||||
"Reverse healing/recharge into damage and damage into healing/recharge.
|
||||
Any excess red or blue damage is converted into shield recharge after healing.
|
||||
Lasts {:?}T.",
|
||||
self.into_skill().unwrap().effect()[0].get_duration()),
|
||||
|
||||
@ -851,17 +851,18 @@ impl Item {
|
||||
Item::Ruin|
|
||||
Item::RuinPlus |
|
||||
Item::RuinPlusPlus => format!(
|
||||
"Team wide Stun for {:?}T. Stunned constructs are unable to cast skills.",
|
||||
self.into_skill().unwrap().effect()[0].get_duration()),
|
||||
"Team wide skill. Stun each construct for {:?}T.
|
||||
Deal {:?}% BluePower as blue damage to each construct.",
|
||||
self.into_skill().unwrap().effect()[0].get_duration(),
|
||||
self.into_skill().unwrap().multiplier()),
|
||||
|
||||
Item::Link|
|
||||
Item::LinkPlus |
|
||||
Item::LinkPlusPlus => format!(
|
||||
"Swap {:?}% of green life difference as blue damage to the target and healing to the caster.
|
||||
The swap only occurs if the target construct has more green life than caster.
|
||||
Stuns caster for {:?}T in the process.",
|
||||
self.into_skill().unwrap().multiplier(),
|
||||
self.into_skill().unwrap().effect()[0].get_duration()),
|
||||
"Stun target for {:?}T.
|
||||
Deal blue damage of {:?}% BluePower multiplied by number of effects on target.",
|
||||
self.into_skill().unwrap().effect()[0].get_duration(),
|
||||
self.into_skill().unwrap().multiplier()),
|
||||
|
||||
Item::Silence|
|
||||
Item::SilencePlus |
|
||||
|
||||
@ -353,8 +353,8 @@ fn post_resolve(_skill: Skill, game: &mut Game, mut resolutions: Resolutions) ->
|
||||
};
|
||||
|
||||
if target.is_ko() {
|
||||
// resolutions.push(Resolution::new(&source, &target).event(Event::Ko()).stages(EventStages::PostOnly));
|
||||
target.effects.clear();
|
||||
resolutions.push(Resolution::new(&source, &target).event(Event::Ko()).stages(EventStages::PostOnly));
|
||||
}
|
||||
|
||||
game.update_construct(&mut source);
|
||||
@ -433,8 +433,6 @@ pub enum EventStages {
|
||||
EndOnly, // Skip Anim Skip
|
||||
#[serde(rename = "POST_SKILL")]
|
||||
PostOnly, // Skip Skip Anim
|
||||
#[serde(rename = "")]
|
||||
NoStages, // Skip Skip Skip
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
|
||||
@ -490,7 +488,6 @@ impl Resolution {
|
||||
EventStages::EndPost => target_duration + post_skill, // Skip Anim Anim
|
||||
EventStages::EndOnly => target_duration, // Skip Anim Skip
|
||||
EventStages::PostOnly => post_skill, // Skip Skip Anim
|
||||
EventStages::NoStages => 0, // Skip Skip Skip
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -764,48 +761,48 @@ impl Skill {
|
||||
// Attack Base
|
||||
Skill::Attack => 80, // Base
|
||||
|
||||
Skill::Blast=> 105, // BB
|
||||
Skill::Blast => 105, // BB
|
||||
Skill::BlastPlus => 140, // BB
|
||||
Skill::BlastPlusPlus => 200, // BB
|
||||
|
||||
Skill::Chaos=> 40, // BR
|
||||
Skill::Chaos => 40, // BR
|
||||
Skill::ChaosPlus => 65, // BR
|
||||
Skill::ChaosPlusPlus => 90, // BR
|
||||
|
||||
Skill::Heal=> 125, //GG
|
||||
Skill::Heal => 125, //GG
|
||||
Skill::HealPlus => 185, //GG
|
||||
Skill::HealPlusPlus => 270, //GG
|
||||
|
||||
Skill::SiphonTick=> 25, // GB
|
||||
Skill::SiphonTick => 25, // GB
|
||||
Skill::SiphonTickPlus => 30,
|
||||
Skill::SiphonTickPlusPlus => 40,
|
||||
|
||||
Skill::Slay=> 45, // RG
|
||||
Skill::Slay => 45, // RG
|
||||
Skill::SlayPlus => 65,
|
||||
Skill::SlayPlusPlus => 100,
|
||||
|
||||
Skill::Strike=> 90, //RR
|
||||
Skill::Strike => 90, //RR
|
||||
Skill::StrikePlus => 140,
|
||||
Skill::StrikePlusPlus => 200,
|
||||
|
||||
// Block Base
|
||||
Skill::ElectrocuteTick=> 80,
|
||||
Skill::ElectrocuteTick => 80,
|
||||
Skill::ElectrocuteTickPlus => 100,
|
||||
Skill::ElectrocuteTickPlusPlus => 130,
|
||||
|
||||
Skill::CounterAttack=> 120,
|
||||
Skill::CounterAttack => 120,
|
||||
Skill::CounterAttackPlus => 160,
|
||||
Skill::CounterAttackPlusPlus => 230,
|
||||
|
||||
Skill::Purify=> 45, //Green dmg (heal)
|
||||
Skill::Purify => 45, //Green dmg (heal)
|
||||
Skill::PurifyPlus => 70,
|
||||
Skill::PurifyPlusPlus => 105,
|
||||
|
||||
Skill::Reflect=> 45, //Recharge blue life (heal)
|
||||
Skill::Reflect => 45, //Recharge blue life (heal)
|
||||
Skill::ReflectPlus => 70,
|
||||
Skill::ReflectPlusPlus => 100,
|
||||
|
||||
Skill::Recharge=> 70, //Recharge red and blue life (heal)
|
||||
Skill::Recharge => 70, //Recharge red and blue life (heal)
|
||||
Skill::RechargePlus => 110,
|
||||
Skill::RechargePlusPlus => 170,
|
||||
|
||||
@ -814,29 +811,36 @@ impl Skill {
|
||||
Skill::SustainPlusPlus => 230,
|
||||
|
||||
// Stun Base
|
||||
Skill::Sleep=> 200, //Green dmg (heal)
|
||||
Skill::Sleep => 200, //Green dmg (heal)
|
||||
Skill::SleepPlus => 290,
|
||||
Skill::SleepPlusPlus => 400,
|
||||
|
||||
Skill::Banish=> 40, //Green dmg (heal)
|
||||
Skill::Banish => 40, //Green dmg (heal)
|
||||
Skill::BanishPlus => 75,
|
||||
Skill::BanishPlusPlus => 125,
|
||||
|
||||
Skill::Bash=> 45,
|
||||
Skill::Bash => 45,
|
||||
Skill::BashPlus => 65,
|
||||
Skill::BashPlusPlus => 100,
|
||||
|
||||
Skill::Link=> 75,
|
||||
Skill::LinkPlus => 100,
|
||||
Skill::LinkPlusPlus => 150,
|
||||
Skill::Link => 25,
|
||||
Skill::LinkPlus => 40,
|
||||
Skill::LinkPlusPlus => 70,
|
||||
|
||||
Skill::Ruin => 40,
|
||||
Skill::RuinPlus => 70,
|
||||
Skill::RuinPlusPlus => 100,
|
||||
|
||||
// Debuff Base
|
||||
Skill::DecayTick=> 33,
|
||||
Skill::DecayTick => 33,
|
||||
Skill::DecayTickPlus => 45,
|
||||
Skill::DecayTickPlusPlus => 70,
|
||||
Skill::Silence=> 55, // Deals more per blue skill on target
|
||||
|
||||
Skill::Silence => 55, // Deals more per blue skill on target
|
||||
Skill::SilencePlus => 80,
|
||||
Skill::SilencePlusPlus => 110,
|
||||
Skill::Restrict=> 40, // Deals more per red skill on target
|
||||
|
||||
Skill::Restrict => 40, // Deals more per red skill on target
|
||||
Skill::RestrictPlus => 65,
|
||||
Skill::RestrictPlusPlus => 100,
|
||||
|
||||
@ -849,11 +853,11 @@ impl Skill {
|
||||
Skill::AbsorbPlus => 120,
|
||||
Skill::AbsorbPlusPlus => 155,
|
||||
|
||||
Skill::Intercept=> 80,
|
||||
Skill::Intercept => 80,
|
||||
Skill::InterceptPlus => 110,
|
||||
Skill::InterceptPlusPlus => 150,
|
||||
|
||||
Skill::TriageTick=> 75,
|
||||
Skill::TriageTick => 75,
|
||||
Skill::TriageTickPlus => 110,
|
||||
Skill::TriageTickPlusPlus => 140,
|
||||
|
||||
@ -971,19 +975,19 @@ impl Skill {
|
||||
|
||||
Skill::Ruin => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
Skill::RuinPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
Skill::RuinPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}],
|
||||
Skill::RuinPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
|
||||
Skill::Purge => vec![ConstructEffect {effect: Effect::Purge, duration: 2, meta: None, tick: None}],
|
||||
Skill::PurgePlus => vec![ConstructEffect {effect: Effect::Purge, duration: 3, meta: None, tick: None}],
|
||||
Skill::PurgePlusPlus => vec![ConstructEffect {effect: Effect::Purge, duration: 4, meta: None, tick: None}],
|
||||
|
||||
Skill::Link => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}],
|
||||
Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}],
|
||||
Skill::Link => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
Skill::LinkPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}],
|
||||
|
||||
Skill::Silence => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}],
|
||||
Skill::SilencePlus => vec![ConstructEffect {effect: Effect::Silence, duration: 3, meta: None, tick: None}],
|
||||
Skill::SilencePlusPlus => vec![ConstructEffect {effect: Effect::Silence, duration: 4, meta: None, tick: None}],
|
||||
Skill::SilencePlus => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}],
|
||||
Skill::SilencePlusPlus => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}],
|
||||
|
||||
Skill::Siphon => vec![ConstructEffect {effect: Effect::Siphon, duration: 2,
|
||||
meta: Some(EffectMeta::Skill(Skill::SiphonTick)), tick: None}],
|
||||
@ -997,8 +1001,8 @@ impl Skill {
|
||||
Skill::SleepPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 4, meta: None, tick: None}],
|
||||
|
||||
Skill::Restrict => vec![ConstructEffect {effect: Effect::Restrict, duration: 2, meta: None, tick: None}],
|
||||
Skill::RestrictPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 3, meta: None, tick: None}],
|
||||
Skill::RestrictPlusPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 4, meta: None, tick: None}],
|
||||
Skill::RestrictPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 2, meta: None, tick: None}],
|
||||
Skill::RestrictPlusPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 2, meta: None, tick: None}],
|
||||
|
||||
Skill::Bash => vec![ConstructEffect {effect: Effect::Stun, duration: 2,
|
||||
meta: Some(EffectMeta::Skill(Skill::Bash)), tick: None}],
|
||||
@ -1027,24 +1031,25 @@ impl Skill {
|
||||
pub fn base_cd(&self) -> Cooldown {
|
||||
match self {
|
||||
Skill::Attack => None,
|
||||
Skill::Debuff => Some(1),
|
||||
Skill::Block => None, // reduce damage
|
||||
Skill::Buff => None,
|
||||
Skill::Debuff => Some(1),
|
||||
Skill::Stun => Some(2),
|
||||
|
||||
Skill::Strike=> None,
|
||||
Skill::StrikePlus => None,
|
||||
Skill::StrikePlusPlus => None,
|
||||
Skill::Block => None, // reduce damage
|
||||
|
||||
Skill::Counter|
|
||||
Skill::CounterPlus |
|
||||
Skill::CounterPlusPlus => None, // avoid all damage
|
||||
|
||||
Skill::Restrict=> Some(2),
|
||||
Skill::RestrictPlus => Some(2),
|
||||
Skill::Restrict |
|
||||
Skill::RestrictPlus |
|
||||
Skill::RestrictPlusPlus => Some(2),
|
||||
Skill::Stun => Some(2),
|
||||
|
||||
Skill::Bash=> Some(2),
|
||||
Skill::BashPlus => Some(2),
|
||||
Skill::Bash |
|
||||
Skill::BashPlus |
|
||||
Skill::BashPlusPlus => Some(2),
|
||||
|
||||
Skill::Heal=> None,
|
||||
@ -1055,30 +1060,31 @@ impl Skill {
|
||||
Skill::TriagePlus => None, // hot
|
||||
Skill::TriagePlusPlus => None, // hot
|
||||
|
||||
Skill::Break=> Some(1), // no damage stun, adds vulnerable
|
||||
Skill::BreakPlus => Some(1),
|
||||
Skill::Break | // no damage stun, adds vulnerable
|
||||
Skill::BreakPlus |
|
||||
Skill::BreakPlusPlus => Some(1),
|
||||
|
||||
Skill::Blast=> None,
|
||||
Skill::BlastPlus => None,
|
||||
Skill::Blast |
|
||||
Skill::BlastPlus |
|
||||
Skill::BlastPlusPlus => None,
|
||||
|
||||
Skill::Chaos=> None,
|
||||
Skill::ChaosPlus => None,
|
||||
Skill::Chaos |
|
||||
Skill::ChaosPlus |
|
||||
Skill::ChaosPlusPlus => None,
|
||||
|
||||
Skill::Amplify=> Some(1),
|
||||
Skill::AmplifyPlus => Some(1),
|
||||
Skill::Amplify |
|
||||
Skill::AmplifyPlus |
|
||||
Skill::AmplifyPlusPlus => Some(1),
|
||||
Skill::Hybrid|
|
||||
|
||||
Skill::Hybrid |
|
||||
Skill::HybridPlus |
|
||||
Skill::HybridPlusPlus => Some(1),
|
||||
|
||||
Skill::Invert=> Some(2),
|
||||
Skill::InvertPlus => Some(2),
|
||||
Skill::Invert |
|
||||
Skill::InvertPlus |
|
||||
Skill::InvertPlusPlus => Some(2),
|
||||
|
||||
Skill::Decay=> None, // dot
|
||||
Skill::Decay => None, // dot
|
||||
Skill::DecayPlus => None,
|
||||
Skill::DecayPlusPlus => None,
|
||||
|
||||
@ -1086,59 +1092,59 @@ impl Skill {
|
||||
Skill::SiphonPlus |
|
||||
Skill::SiphonPlusPlus => None,
|
||||
|
||||
Skill::Curse=> Some(1),
|
||||
Skill::CursePlus => Some(1),
|
||||
Skill::Curse |
|
||||
Skill::CursePlus |
|
||||
Skill::CursePlusPlus => Some(1),
|
||||
|
||||
Skill::Link=> Some(2),
|
||||
Skill::LinkPlus => Some(2),
|
||||
Skill::LinkPlusPlus => Some(2),
|
||||
Skill::Link |
|
||||
Skill::LinkPlus |
|
||||
Skill::LinkPlusPlus => Some(1),
|
||||
|
||||
Skill::Silence=> Some(2),
|
||||
Skill::SilencePlus => Some(2),
|
||||
Skill::Silence |
|
||||
Skill::SilencePlus |
|
||||
Skill::SilencePlusPlus => Some(2),
|
||||
|
||||
Skill::Purify |
|
||||
Skill::PurifyPlus |
|
||||
Skill::PurifyPlusPlus => None,
|
||||
|
||||
Skill::Purge=> Some(1),
|
||||
Skill::PurgePlus => Some(1),
|
||||
Skill::Purge |
|
||||
Skill::PurgePlus |
|
||||
Skill::PurgePlusPlus => Some(1),
|
||||
|
||||
Skill::Banish |
|
||||
Skill::BanishPlus |
|
||||
Skill::BanishPlusPlus => Some(1),
|
||||
|
||||
Skill::Haste=> Some(1),
|
||||
Skill::HastePlus => Some(1),
|
||||
Skill::Haste |
|
||||
Skill::HastePlus |
|
||||
Skill::HastePlusPlus => Some(1),
|
||||
|
||||
Skill::Reflect |
|
||||
Skill::ReflectPlus |
|
||||
Skill::ReflectPlusPlus => None,
|
||||
|
||||
Skill::Recharge=> None,
|
||||
Skill::RechargePlus => None,
|
||||
Skill::Recharge |
|
||||
Skill::RechargePlus |
|
||||
Skill::RechargePlusPlus => None,
|
||||
|
||||
Skill::Ruin=> Some(3),
|
||||
Skill::RuinPlus => Some(2),
|
||||
Skill::Ruin |
|
||||
Skill::RuinPlus |
|
||||
Skill::RuinPlusPlus => Some(2),
|
||||
|
||||
Skill::Slay=> None,
|
||||
Skill::SlayPlus => None,
|
||||
Skill::SlayPlusPlus => None,
|
||||
|
||||
Skill::Sleep=> Some(2),
|
||||
Skill::SleepPlus => Some(2),
|
||||
Skill::Sleep |
|
||||
Skill::SleepPlus |
|
||||
Skill::SleepPlusPlus => Some(2),
|
||||
|
||||
Skill::Sustain |
|
||||
Skill::SustainPlus |
|
||||
Skill::SustainPlusPlus => Some(1),
|
||||
|
||||
Skill::Intercept=> Some(1),
|
||||
Skill::Intercept => Some(1),
|
||||
Skill::InterceptPlus => Some(1),
|
||||
Skill::InterceptPlusPlus => Some(1),
|
||||
|
||||
@ -1146,8 +1152,7 @@ impl Skill {
|
||||
Skill::ElectrifyPlus |
|
||||
Skill::ElectrifyPlusPlus => None,
|
||||
|
||||
|
||||
Skill::Absorb|
|
||||
Skill::Absorb |
|
||||
Skill::AbsorbPlus |
|
||||
Skill::AbsorbPlusPlus => Some(1),
|
||||
|
||||
@ -1184,17 +1189,17 @@ impl Skill {
|
||||
|
||||
pub fn ko_castable(&self) -> bool {
|
||||
match self {
|
||||
Skill::ElectrocuteTick|
|
||||
Skill::ElectrocuteTick |
|
||||
Skill::ElectrocuteTickPlus |
|
||||
Skill::ElectrocuteTickPlusPlus |
|
||||
Skill::DecayTick|
|
||||
Skill::DecayTick |
|
||||
Skill::DecayTickPlus |
|
||||
Skill::DecayTickPlusPlus |
|
||||
Skill::SiphonTick|
|
||||
Skill::SiphonTick |
|
||||
Skill::SiphonTickPlus |
|
||||
Skill::SiphonTickPlusPlus |
|
||||
|
||||
Skill::TriageTick|
|
||||
Skill::TriageTick |
|
||||
Skill::TriageTickPlus |
|
||||
Skill::TriageTickPlusPlus => true,
|
||||
_ => false,
|
||||
@ -1203,17 +1208,16 @@ impl Skill {
|
||||
|
||||
pub fn is_tick(&self) -> bool {
|
||||
match self {
|
||||
Skill::ElectrocuteTick|
|
||||
Skill::ElectrocuteTick |
|
||||
Skill::ElectrocuteTickPlus |
|
||||
Skill::ElectrocuteTickPlusPlus |
|
||||
Skill::DecayTick|
|
||||
Skill::DecayTick |
|
||||
Skill::DecayTickPlus |
|
||||
Skill::DecayTickPlusPlus |
|
||||
Skill::SiphonTick|
|
||||
Skill::SiphonTick |
|
||||
Skill::SiphonTickPlus |
|
||||
Skill::SiphonTickPlusPlus |
|
||||
|
||||
Skill::TriageTick|
|
||||
Skill::TriageTick |
|
||||
Skill::TriageTickPlus |
|
||||
Skill::TriageTickPlusPlus => true,
|
||||
|
||||
@ -1223,19 +1227,19 @@ impl Skill {
|
||||
|
||||
pub fn speed(&self) -> u64 {
|
||||
match self {
|
||||
Skill::SiphonTick|
|
||||
Skill::SiphonTick |
|
||||
Skill::SiphonTickPlus |
|
||||
Skill::SiphonTickPlusPlus => Skill::Siphon.speed(),
|
||||
|
||||
Skill::DecayTick|
|
||||
Skill::DecayTick |
|
||||
Skill::DecayTickPlus |
|
||||
Skill::DecayTickPlusPlus => Skill::Decay.speed(),
|
||||
|
||||
Skill::TriageTick|
|
||||
Skill::TriageTick |
|
||||
Skill::TriageTickPlus |
|
||||
Skill::TriageTickPlusPlus => Skill::Triage.speed(),
|
||||
|
||||
Skill::ElectrocuteTick|
|
||||
Skill::ElectrocuteTick |
|
||||
Skill::ElectrocuteTickPlus |
|
||||
Skill::ElectrocuteTickPlusPlus => Skill::Electrify.speed(),
|
||||
|
||||
@ -1245,7 +1249,7 @@ impl Skill {
|
||||
|
||||
pub fn aoe(&self) -> bool {
|
||||
match self {
|
||||
Skill::Ruin|
|
||||
Skill::Ruin |
|
||||
Skill::RuinPlus |
|
||||
Skill::RuinPlusPlus => true,
|
||||
_ => false,
|
||||
@ -1260,44 +1264,44 @@ impl Skill {
|
||||
Skill::AmplifyPlus |
|
||||
Skill::AmplifyPlusPlus |
|
||||
Skill::Block |
|
||||
Skill::Sustain|
|
||||
Skill::Sustain |
|
||||
Skill::SustainPlus |
|
||||
Skill::SustainPlusPlus |
|
||||
Skill::Electrify|
|
||||
Skill::Electrify |
|
||||
Skill::ElectrifyPlus |
|
||||
Skill::ElectrifyPlusPlus |
|
||||
Skill::Haste|
|
||||
Skill::Haste |
|
||||
Skill::HastePlus |
|
||||
Skill::HastePlusPlus |
|
||||
Skill::Heal|
|
||||
Skill::Heal |
|
||||
Skill::HealPlus |
|
||||
Skill::HealPlusPlus |
|
||||
Skill::Absorb|
|
||||
Skill::Absorb |
|
||||
Skill::AbsorbPlus |
|
||||
Skill::AbsorbPlusPlus |
|
||||
Skill::Invert|
|
||||
Skill::Invert |
|
||||
Skill::InvertPlus |
|
||||
Skill::InvertPlusPlus |
|
||||
Skill::Intercept|
|
||||
Skill::Intercept |
|
||||
Skill::InterceptPlus |
|
||||
Skill::InterceptPlusPlus |
|
||||
Skill::Counter|
|
||||
Skill::Counter |
|
||||
Skill::CounterPlus |
|
||||
Skill::CounterPlusPlus |
|
||||
Skill::Purify|
|
||||
Skill::Purify |
|
||||
Skill::PurifyPlus |
|
||||
Skill::PurifyPlusPlus |
|
||||
Skill::Recharge|
|
||||
Skill::Recharge |
|
||||
Skill::RechargePlus |
|
||||
Skill::RechargePlusPlus |
|
||||
Skill::Reflect|
|
||||
Skill::Reflect |
|
||||
Skill::ReflectPlus |
|
||||
Skill::ReflectPlusPlus |
|
||||
Skill::Triage|
|
||||
Skill::Triage |
|
||||
Skill::TriagePlus |
|
||||
Skill::TriagePlusPlus => true,
|
||||
|
||||
Skill::Banish|
|
||||
Skill::Banish |
|
||||
Skill::BanishPlus |
|
||||
Skill::BanishPlusPlus => rng.gen_bool(0.5),
|
||||
|
||||
@ -1401,21 +1405,12 @@ fn sleep(source: &mut Construct, target: &mut Construct, mut results: Resolution
|
||||
}
|
||||
|
||||
fn sustain(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||
let red_amount = source.red_power().pct(skill.multiplier());
|
||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||
let e = target.recharge(skill, red_amount, 0);
|
||||
let stages = match e {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||
else { EventStages::NoStages }
|
||||
}
|
||||
_ => {
|
||||
warn!("no recharge event found {:?}", e);
|
||||
EventStages::NoStages
|
||||
}
|
||||
};
|
||||
|
||||
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||
let red_amount = source.red_power().pct(skill.multiplier());
|
||||
target.recharge(skill, red_amount, 0)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
return results;
|
||||
}
|
||||
@ -1425,18 +1420,9 @@ fn intercept(source: &mut Construct, target: &mut Construct, mut results: Resolu
|
||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, intercept)));
|
||||
|
||||
let red_amount = source.red_power().pct(skill.multiplier());
|
||||
let e = target.recharge(skill, red_amount, 0);
|
||||
let stages = match e {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||
else { EventStages::NoStages }
|
||||
}
|
||||
_ => {
|
||||
warn!("no recharge event found {:?}", e);
|
||||
EventStages::NoStages
|
||||
}
|
||||
};
|
||||
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||
target.recharge(skill, red_amount, 0)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
return results;
|
||||
}
|
||||
@ -1684,6 +1670,11 @@ fn electrocute_tick(source: &mut Construct, target: &mut Construct, mut results:
|
||||
}
|
||||
|
||||
fn ruin(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||
let amount = source.blue_power().pct(skill.multiplier());
|
||||
target.deal_blue_damage(skill, amount)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
results.push(Resolution::new(source, target)
|
||||
.event(target.add_effect(skill, skill.effect()[0]))
|
||||
.stages(EventStages::PostOnly));
|
||||
@ -1693,18 +1684,9 @@ fn ruin(source: &mut Construct, target: &mut Construct, mut results: Resolutions
|
||||
fn absorb(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||
let blue_amount = source.blue_power().pct(skill.multiplier());
|
||||
let e = target.recharge(skill, 0, blue_amount);
|
||||
let stages = match e {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||
else { EventStages::NoStages }
|
||||
}
|
||||
_ => {
|
||||
warn!("no recharge event found {:?}", e);
|
||||
EventStages::NoStages
|
||||
}
|
||||
};
|
||||
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||
target.recharge(skill, 0, blue_amount)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
return results;;
|
||||
}
|
||||
|
||||
@ -1743,36 +1725,21 @@ fn reflect(source: &mut Construct, target: &mut Construct, mut results: Resoluti
|
||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||
|
||||
let blue_amount = source.blue_power().pct(skill.multiplier());
|
||||
let e = target.recharge(skill, 0, blue_amount);
|
||||
let stages = match e {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||
else { EventStages::NoStages }
|
||||
}
|
||||
_ => {
|
||||
warn!("no recharge event found {:?}", e);
|
||||
EventStages::NoStages
|
||||
}
|
||||
};
|
||||
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||
target.recharge(skill, 0, blue_amount)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
return results;;
|
||||
}
|
||||
|
||||
fn recharge(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||
results.push(Resolution::new(source, target).event(Event::Skill { skill }).stages(EventStages::StartEnd));
|
||||
let red_amount = source.red_power().pct(skill.multiplier());
|
||||
let blue_amount = source.blue_power().pct(skill.multiplier());
|
||||
let e = target.recharge(skill, red_amount, blue_amount);
|
||||
let stages = match e {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
if red > 0 || blue > 0 { EventStages::AllStages }
|
||||
else { EventStages::StartEnd }
|
||||
}
|
||||
_ => {
|
||||
warn!("no recharge event found {:?}", e);
|
||||
EventStages::NoStages
|
||||
}
|
||||
};
|
||||
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||
target.recharge(skill, red_amount, blue_amount)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -1819,27 +1786,12 @@ fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Reso
|
||||
}
|
||||
|
||||
fn link(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||
let swap = match target.green_life().checked_sub(source.green_life()) {
|
||||
Some(s) => s.pct(skill.multiplier()),
|
||||
None => 0
|
||||
};
|
||||
|
||||
let link_events = target.deal_blue_damage(skill, swap);
|
||||
for e in link_events {
|
||||
match e {
|
||||
Event::Damage { amount, mitigation: _, colour: _, skill: _ } => {
|
||||
results.push(Resolution::new(source, target).event(e));
|
||||
let heal = source.deal_green_damage(skill, amount);
|
||||
for h in heal {
|
||||
results.push(Resolution::new(source, source).event(h).stages(EventStages::PostOnly));
|
||||
};
|
||||
},
|
||||
_ => results.push(Resolution::new(source, target).event(e)),
|
||||
}
|
||||
}
|
||||
|
||||
results.push(Resolution::new(source, source)
|
||||
.event(source.add_effect(skill, skill.effect()[0])).stages(EventStages::PostOnly));
|
||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||
|
||||
let amount = source.blue_power().pct(skill.multiplier().saturating_mul(target.effects.len() as u64));
|
||||
target.deal_blue_damage(skill, amount)
|
||||
.into_iter()
|
||||
.for_each(|e| results.push(Resolution::new(source, target).event(e).stages(EventStages::PostOnly)));
|
||||
|
||||
return results;
|
||||
}
|
||||
@ -2183,6 +2135,7 @@ mod tests {
|
||||
|
||||
let mut results = recharge(&mut x, &mut y, vec![], Skill::Recharge);
|
||||
|
||||
results.remove(0);
|
||||
let Resolution { source: _, target: _, event, stages: _ } = results.remove(0);
|
||||
match event {
|
||||
Event::Recharge { red, blue, skill: _ } => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user