Merge branch 'release/1.11.2'

This commit is contained in:
ntr 2020-01-08 15:53:27 +10:00
commit 4b465361fb
13 changed files with 104 additions and 114 deletions

View File

@ -1 +1 @@
1.11.1 1.11.2

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.11.1", "version": "1.11.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -7,7 +7,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="mnml"> <meta name="application-name" content="mnml">
<meta name="description" content="mnml pvp tbs"> <meta name="description" content="1v1 pvp tbs">
<meta name="author" content="ntr@smokestack.io"> <meta name="author" content="ntr@smokestack.io">
<title>MNML - abstract strategy</title> <title>MNML - abstract strategy</title>
<link rel="manifest" href="manifest.webmanifest"> <link rel="manifest" href="manifest.webmanifest">

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.11.1", "version": "1.11.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -27,6 +27,7 @@ class GameConstructEffects extends preact.Component {
&& (type === 'Effect' || type === 'Removal')) return true; && (type === 'Effect' || type === 'Removal')) return true;
} }
if (newProps.construct !== this.props.construct) return true; if (newProps.construct !== this.props.construct) return true;
if (newProps.gameSkillInfo !== this.props.gameSkillInfo) return true;
return false; return false;
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml_core" name = "mnml_core"
version = "1.11.1" version = "1.11.2"
authors = ["ntr <ntr@smokestack.io>", "mashy <mashy@mnml.gg>"] authors = ["ntr <ntr@smokestack.io>", "mashy <mashy@mnml.gg>"]
[dependencies] [dependencies]

View File

@ -499,7 +499,7 @@ impl Construct {
return None; return None;
} }
info!("reduced effect {:?}", effect); // info!("reduced effect {:?}", effect);
return Some(effect); return Some(effect);
}).collect::<Vec<ConstructEffect>>(); }).collect::<Vec<ConstructEffect>>();

View File

@ -32,6 +32,7 @@ pub enum Effect {
// electrocute the dmg debuff // electrocute the dmg debuff
Electric, Electric,
Electrocute, Electrocute,
Electrocuted,
// absorbtion is the buff // absorbtion is the buff
// absorb is the increased damage // absorb is the increased damage
@ -75,28 +76,32 @@ impl Effect {
match self { match self {
Effect::Banish => true, Effect::Banish => true,
// these provide immunity for the ticks
// the base skills will still resolve
// but they have early return checks
// to ensure the effect is reapplied but damage is not
Effect::Siphoned => [
Skill::SiphonTick,
].contains(&skill),
Effect::Decayed => [
Skill::DecayTick,
].contains(&skill),
Effect::Triaged => [
Skill::TriageTick,
].contains(&skill),
Effect::Countered => [ Effect::Countered => [
Skill::CounterAttack, Skill::CounterAttack,
Skill::CounterAttackPlus, Skill::CounterAttackPlus,
Skill::CounterAttackPlusPlus, Skill::CounterAttackPlusPlus,
].contains(&skill), ].contains(&skill),
// these provide immunity for the ticks
// the base skills will still resolve
// but they have early return checks
// to ensure the effect is reapplied but damage is not
Effect::Decayed => [
Skill::DecayTick,
].contains(&skill),
Effect::Electrocuted => [
Skill::ElectrocuteTick,
].contains(&skill),
Effect::Siphoned => [
Skill::SiphonTick,
].contains(&skill),
Effect::Triaged => [
Skill::TriageTick,
].contains(&skill),
_ => false, _ => false,
} }
} }
@ -106,10 +111,11 @@ impl Effect {
// and not included in counts // and not included in counts
pub fn hidden(&self) -> bool { pub fn hidden(&self) -> bool {
match self { match self {
Effect::Siphoned => true,
Effect::Decayed => true,
Effect::Triaged => true,
Effect::Countered => true, Effect::Countered => true,
Effect::Decayed => true,
Effect::Electrocuted => true,
Effect::Siphoned => true,
Effect::Triaged => true,
_ => false, _ => false,
} }
} }

View File

@ -518,7 +518,9 @@ impl Game {
.any(|c| !self.construct(c.target).is_ko() && !self.construct(c.target).immune(c.skill).is_some()); .any(|c| !self.construct(c.target).is_ko() && !self.construct(c.target).immune(c.skill).is_some());
if castable { if castable {
if cast.skill.cast_animation() {
self.action(cast, Action::Cast); self.action(cast, Action::Cast);
}
if cast.skill.aoe() { if cast.skill.aoe() {
self.action(cast, Action::HitAoe); self.action(cast, Action::HitAoe);
} }
@ -630,11 +632,11 @@ impl Game {
Value::ColourSkills { construct, colour } => Value::ColourSkills { construct, colour } =>
self.construct(construct).stat(Stat::Skills(colour)), self.construct(construct).stat(Stat::Skills(colour)),
Value::DamageReceived { construct, colour } => Value::DamageReceived { construct } =>
self.events.iter().fold(0, |dmg, e| match e { self.events.iter().fold(0, |dmg, e| match e {
Event::Damage { construct: event_construct, amount, mitigation:_, colour: event_colour, display: _ } => Event::Damage { construct: event_construct, amount, mitigation, colour: _, display: _ } =>
match construct == *event_construct && colour == *event_colour { match construct == *event_construct {
true => dmg + amount, true => amount + mitigation,
false => dmg, false => dmg,
} }
_ => dmg, _ => dmg,
@ -854,7 +856,7 @@ pub enum Value {
ColourSkills { construct: Uuid, colour: Colour }, ColourSkills { construct: Uuid, colour: Colour },
Effects { construct: Uuid }, Effects { construct: Uuid },
Removals { construct: Uuid }, Removals { construct: Uuid },
DamageReceived { construct: Uuid, colour: Colour }, DamageReceived { construct: Uuid },
TickDamage { construct: Uuid, effect: Effect }, TickDamage { construct: Uuid, effect: Effect },
// Affected { construct: Uuid, effect: Effect }, // not an int :( // Affected { construct: Uuid, effect: Effect }, // not an int :(
} }
@ -1293,10 +1295,6 @@ mod tests {
} }
// #[cfg(test)]
// mod tests {
// use skill::*;
// #[test] // #[test]
// fn attack_actions_test() { // fn attack_actions_test() {
// let cast = Cast::new(Uuid::new_v4(), Uuid::new_v4(), Uuid::new_v4(), Skill::Attack); // let cast = Cast::new(Uuid::new_v4(), Uuid::new_v4(), Uuid::new_v4(), Skill::Attack);
@ -1476,48 +1474,6 @@ mod tests {
// }; // };
// } // }
// #[test]
// fn siphon_test() {
// let mut x = Construct::new()
// .named(&"muji".to_string());
// let mut y = Construct::new()
// .named(&"camel".to_string());
// x.blue_power.force(256);
// x.green_power.force(220);
// x.green_life.force(1024);
// y.blue_life.force(0);
// x.green_life.reduce(512);
// cast_actions(Skill::Siphon, &mut x, &mut y, vec![]);
// assert!(y.affected(Effect::Siphon));
// assert!(x.green_life() == (512 + 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier())));
// let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0);
// match event {
// Event::Effect { effect, skill: _, duration: _, construct_effects: _ } => assert_eq!(effect, Effect::Siphon),
// _ => panic!("not siphon"),
// };
// let Event { source: _, target: _, event, stages: _ } = resolutions.remove(0);
// match event {
// Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier())
// + 220.pct(Skill::SiphonTick.multiplier())),
// _ => panic!("not damage siphon"),
// };
// let Event { source: _, target, event, stages: _ } = resolutions.remove(0);
// match event {
// Event::Heal { amount, skill: _, overhealing: _ } => {
// assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier()));
// assert_eq!(target.id, x.id);
// },
// _ => panic!("not healing"),
// };
// }
// #[test] // #[test]
// fn triage_test() { // fn triage_test() {
// let mut x = Construct::new() // let mut x = Construct::new()
@ -2190,7 +2146,7 @@ mod tests {
}).count() == 2); }).count() == 2);
let _siphon_dmg = resolutions.iter().find_map(|r| match r.skill { let siphon_dmg = resolutions.iter().find_map(|r| match r.skill {
Skill::Siphon => { Skill::Siphon => {
match r.event { match r.event {
Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount),
@ -2200,24 +2156,12 @@ mod tests {
_ => None _ => None
}).expect("no siphon dmg"); }).expect("no siphon dmg");
// let hybrid_dmg = resolutions.iter().find_map(|r| match r.skill { assert!(resolutions.iter().any(|r| match r.event {
// Skill::HybridBlast => { Event::Healing { construct, colour, amount, overhealing, display: _ } => {
// match r.event { construct == source && (amount + overhealing) == siphon_dmg && colour == Colour::Green
// Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), },
// _ => None, _ => false,
// } }));
// },
// _ => None
// }).expect("no hybrid dmg");
// assert!(resolutions.iter().any(|r| match r.event {
// Event::Healing { construct, colour, amount, overhealing, display: _ } => {
// construct == source && (amount + overhealing) == siphon_dmg && colour == Colour::Green
// // this works
// // construct == source && (amount + overhealing) == (siphon_dmg + hybrid_dmg) && colour == Colour::Green
// },
// _ => false,
// }));
} }
#[test] #[test]
@ -2258,6 +2202,31 @@ mod tests {
construct == source && amount > 0 && colour == Colour::Blue, construct == source && amount > 0 && colour == Colour::Blue,
_ => false, _ => false,
})); }));
game.resolve(Cast::new(source, player_id, target, Skill::Electrify));
game.resolve(Cast::new(source, player_id, target, Skill::Blast));
let last = game.resolutions.len() - 1;
let resolutions = &game.resolutions[last];
let electrocute_dmg_events = resolutions.iter().filter(|r| match r.event {
Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => match r.skill {
Skill::Electrocute => true,
_ => false
},
_ => false,
}).count();
let effect_events = resolutions.iter().filter(|r| match r.event {
Event::Effect { construct, effect, duration: _, display: _ } =>
construct == source && effect == Effect::Electrocute,
_ => false,
}).count();
assert!(effect_events == 2);
assert!(electrocute_dmg_events == 1); // second electrocute application deals no damage
} }
#[test] #[test]
@ -2333,13 +2302,13 @@ mod tests {
let resolutions = &game.resolutions[last]; let resolutions = &game.resolutions[last];
assert!(resolutions.iter().any(|r| match r.event { assert!(resolutions.iter().any(|r| match r.event {
Event::Damage { construct, colour, amount, mitigation: _, display: _ } => { Event::Damage { construct, colour, amount, mitigation, display: _ } => {
assert!(construct == target && amount > 0 && colour == Colour::Blue && r.skill == Skill::Blast); assert!(construct == target && amount > 0 && colour == Colour::Blue && r.skill == Skill::Blast);
resolutions.iter().any(|r| match r.event { resolutions.iter().any(|r| match r.event {
Event::Meta { construct, effect, meta } => Event::Meta { construct, effect, meta } =>
construct == target && effect == Effect::Absorption && { construct == target && effect == Effect::Absorption && {
match meta { match meta {
EffectMeta::AddedDamage(added_dmg) => added_dmg == amount, EffectMeta::AddedDamage(added_dmg) => added_dmg == amount + mitigation,
_ => false, _ => false,
} }
}, },

View File

@ -559,8 +559,6 @@ impl Skill {
pub fn cast_animation(&self) -> bool { pub fn cast_animation(&self) -> bool {
match self { match self {
Skill::HybridBlast |
Skill::HasteStrike |
Skill::CounterAttack| Skill::CounterAttack|
Skill::CounterAttackPlus | Skill::CounterAttackPlus |
Skill::CounterAttackPlusPlus | // counter Skill::CounterAttackPlusPlus | // counter
@ -1004,7 +1002,7 @@ fn siphon(cast: Cast, game: &mut Game, values: Siphon) {
Action::Heal { Action::Heal {
construct: cast.source, construct: cast.source,
colour: Colour::Green, colour: Colour::Green,
amount: game.value(Value::DamageReceived { construct: cast.target, colour: Colour::Blue }).pct(100), amount: game.value(Value::DamageReceived { construct: cast.target }).pct(100),
}, },
); );
@ -1034,7 +1032,7 @@ fn siphon_tick(cast: Cast, game: &mut Game) {
Action::Heal { Action::Heal {
construct: cast.source, construct: cast.source,
colour: Colour::Green, colour: Colour::Green,
amount: game.value(Value::DamageReceived { construct: cast.target, colour: Colour::Blue }).pct(100), amount: game.value(Value::DamageReceived { construct: cast.target }).pct(100),
}, },
); );
} }
@ -1075,7 +1073,7 @@ fn slay(cast: Cast, game: &mut Game, values: Slay) {
Action::Heal { Action::Heal {
construct: cast.source, construct: cast.source,
colour: Colour::Green, colour: Colour::Green,
amount: game.value(Value::DamageReceived { construct: cast.target, colour: Colour::Red }).pct(values.self_heal_multi()), amount: game.value(Value::DamageReceived { construct: cast.target }).pct(values.self_heal_multi()),
}, },
); );
} }
@ -1320,7 +1318,7 @@ fn absorption(cast: Cast, game: &mut Game, values: Absorption) {
Action::SetEffectMeta { Action::SetEffectMeta {
construct: cast.target, construct: cast.target,
effect: Effect::Absorption, effect: Effect::Absorption,
amount: game.value(Value::DamageReceived { construct: cast.source, colour: Colour::Blue }).pct(100), amount: game.value(Value::DamageReceived { construct: cast.source }).pct(100),
}, },
); );
} }
@ -1691,6 +1689,8 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) {
Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) },
}, },
); );
if !game.affected(cast.target, Effect::Electrocuted) {
game.action(cast, game.action(cast,
Action::Damage { Action::Damage {
construct: cast.target, construct: cast.target,
@ -1698,6 +1698,13 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) {
amount, amount,
}, },
); );
game.action(cast,
Action::Effect {
construct: cast.target,
effect: ConstructEffect { effect: Effect::Electrocuted, duration: 1, meta: None }, // immunity to additional ticks
},
);
}
game.action(cast, game.action(cast,
Action::Remove { Action::Remove {
@ -1715,6 +1722,13 @@ fn electrocute_tick(cast: Cast, game: &mut Game) {
amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Electrocute }), amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Electrocute }),
}, },
); );
game.action(cast,
Action::Effect {
construct: cast.target,
effect: ConstructEffect { effect: Effect::Electrocuted, duration: 1, meta: None }, // immunity to additional ticks
},
);
} }
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-ops", "name": "mnml-ops",
"version": "1.11.1", "version": "1.11.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml" name = "mnml"
version = "1.11.1" version = "1.11.2"
authors = ["ntr <ntr@smokestack.io>"] authors = ["ntr <ntr@smokestack.io>"]
[dependencies] [dependencies]

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-studios", "name": "mnml-studios",
"version": "1.11.1", "version": "1.11.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {