add some skills, revert to log

This commit is contained in:
ntr 2018-11-12 18:15:58 +11:00
parent 2ab5009fe1
commit 8ce0fc4fbb
3 changed files with 163 additions and 67 deletions

View File

@ -10,6 +10,7 @@ use failure::err_msg;
use account::Account;
use rpc::{CrypSpawnParams};
use skill::{Skill, Cooldown, Effect, Tick};
use game::{Log};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub struct CrypSkill {
@ -36,8 +37,8 @@ pub struct CrypEffect {
}
impl CrypEffect {
pub fn tick(&self, cryp: &mut Cryp) -> &CrypEffect {
self.effect.tick(self, cryp);
pub fn tick(&self, cryp: &mut Cryp, log: &mut Log) -> &CrypEffect {
self.effect.tick(self, cryp, log);
self
}
}
@ -175,6 +176,10 @@ impl Cryp {
self.hp.value == 0
}
pub fn immune(&self, skill: Skill) -> bool {
self.effects.iter().any(|e| e.effect.immune(skill))
}
pub fn is_stunned(&self) -> bool {
self.effects.iter().any(|s| s.effect == Effect::Stun)
}
@ -218,10 +223,10 @@ impl Cryp {
self
}
pub fn reduce_effect_durations(&mut self) -> &mut Cryp {
pub fn reduce_effect_durations(&mut self, log: &mut Log) -> &mut Cryp {
self.effects = self.effects.clone().into_iter().filter_map(|mut effect| {
effect.tick(self);
effect.tick(self, log);
effect.duration = effect.duration.saturating_sub(1);
if effect.duration == 0 {

View File

@ -357,8 +357,7 @@ impl Game {
let mut target = self.cryp_by_id(skill.target_cryp_id.unwrap()).unwrap().clone();
// self.log.push(format!("{:?} uses {:?} on {:?}", source.name, skill.skill, target.name));
skill.set_resolution(&mut source, &mut target);
self.log.push(skill.resolution.text.clone());
skill.set_resolution(&mut source, &mut target, &mut self.log);
self.resolved.push(skill.clone());
@ -395,7 +394,7 @@ impl Game {
}
// always reduce durations
cryp.reduce_effect_durations();
cryp.reduce_effect_durations(&mut self.log);
self.update_cryp(&mut cryp);
}

View File

@ -1,7 +1,7 @@
use rand::{thread_rng, Rng};
use uuid::Uuid;
// use game::{Log};
use game::{Log};
use cryp::{Cryp, CrypEffect};
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
@ -30,12 +30,12 @@ impl Cast {
target_cryp_id,
target_team_id,
skill,
resolution: Resolution { base: 0, result: None, text: String::new(), },
resolution: Resolution { base: 0, result: None },
};
}
pub fn set_resolution(&mut self, cryp: &mut Cryp, target: &mut Cryp) -> &mut Cast {
self.resolution = self.skill.resolve(cryp, target);
pub fn set_resolution(&mut self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) -> &mut Cast {
self.resolution = self.skill.resolve(cryp, target, log);
self
}
@ -53,7 +53,6 @@ impl Cast {
pub struct Resolution {
pub base: u64,
pub result: Option<u64>,
pub text: String,
}
pub type Cooldown = Option<u8>;
@ -72,14 +71,16 @@ pub enum Effect {
Fury,
Evasion,
Blind,
Snare,
// magic
Silence,
Hex,
Banish,
Slow,
Haste,
Enslave,
Mesmerise,
Amplify,
// magic immunity
Immune,
@ -95,20 +96,21 @@ pub enum Effect {
}
impl Effect {
pub fn prevents(&self, skill: Skill) -> bool {
pub fn immune(&self, skill: Skill) -> bool {
match self {
Effect::Block => match skill {
Skill::Stun => true,
Skill::Stun |
Skill::Attack => true,
_ => false,
},
_ => false,
}
}
pub fn tick(&self, cryp_effect: &CrypEffect, target: &mut Cryp) -> &Effect {
pub fn tick(&self, cryp_effect: &CrypEffect, target: &mut Cryp, log: &mut Log) -> &Effect {
match self {
Effect::Decay => decay_tick(target, cryp_effect),
// Effect::Triage => triage_tick(target, res),
Effect::Decay => decay_tick(target, cryp_effect, log),
Effect::Triage => triage_tick(target, cryp_effect, log),
_ => (),
}
@ -149,7 +151,7 @@ pub enum Skill {
Swarm,
Orbit,
Repair,
Scout, // track?
Scan, // track?
// -----------------
// Nonviolence
@ -175,7 +177,7 @@ pub enum Skill {
// -----------------
// Purity
// -----------------
Accuracy,
Precision,
Inspire,
Slay,
Shield,
@ -226,7 +228,7 @@ impl Skill {
Skill::Swarm => Some(3),
Skill::Orbit => Some(2),
Skill::Repair => Some(1),
Skill::Scout => Some(2), // track?
Skill::Scan => Some(2), // track?
// -----------------
// Preservation
@ -252,7 +254,7 @@ impl Skill {
// -----------------
// Purity
// -----------------
Skill::Accuracy => Some(1),
Skill::Precision => Some(1),
Skill::Inspire => Some(2),
Skill::Slay => Some(1),
Skill::Shield => Some(1),
@ -305,7 +307,7 @@ impl Skill {
Skill::Swarm => 3,
Skill::Orbit => 2,
Skill::Repair => 1,
Skill::Scout => 2, // track?
Skill::Scan => 2, // track?
// -----------------
// Preservation
@ -331,7 +333,7 @@ impl Skill {
// -----------------
// Purity
// -----------------
Skill::Accuracy => 1,
Skill::Precision => 1,
Skill::Inspire => 2,
Skill::Slay => 1,
Skill::Shield => 1,
@ -357,11 +359,11 @@ impl Skill {
}
}
pub fn resolve(&self, cryp: &mut Cryp, target: &mut Cryp) -> Resolution {
pub fn resolve(&self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) -> Resolution {
let mut rng = thread_rng();
let base: u64 = rng.gen();
let mut res = Resolution { base, result: None, text: String::new() };
let res = Resolution { base, result: None };
// println!("{:?}'s stats", self.name);
// println!("{:064b} <- finalised", roll.result);
@ -374,19 +376,19 @@ impl Skill {
// return Some(roll);
match self {
Skill::Attack => attack(cryp, target, &mut res),
Skill::Attack => attack(cryp, target, log),
// -----------------
// Nature
// -----------------
Skill::Block => block(cryp, target, &mut res),
Skill::Block => block(cryp, target, log),
Skill::Evade => panic!("nyi"), //
Skill::Parry => panic!("nyi"), // avoid all dmg
Skill::Snare => panic!("nyi"),
Skill::Snare => snare(cryp, target, log), // TODO prevent physical moves
Skill::Paralyse => panic!("nyi"), // no physical moves
Skill::Strangle => panic!("nyi"), // no physical moves
Skill::Stun => stun(cryp, target, &mut res),
Skill::Stun => stun(cryp, target, log),
Skill::Evasion => panic!("nyi"), // additional layer of dmg avoidance
// -----------------
@ -396,14 +398,14 @@ impl Skill {
Skill::Swarm => panic!("nyi"),
Skill::Orbit => panic!("nyi"),
Skill::Repair => panic!("nyi"),
Skill::Scout => panic!("nyi"), // track?
Skill::Scan => panic!("nyi"), // track?
// -----------------
// Preservation
// -----------------
Skill::Heal => heal(cryp, target, &mut res),
Skill::Triage => triage(cryp, target, &mut res), // hot
Skill::Throw => panic!("nyi"), // no dmg stun, adds vulnerable
Skill::Heal => heal(cryp, target, log),
Skill::Triage => triage(cryp, target, log), // hot
Skill::Throw => throw(cryp, target, log), // no dmg stun, adds vulnerable
Skill::Charm => panic!("nyi"),
Skill::Calm => panic!("nyi"),
Skill::Rez => panic!("nyi"),
@ -411,9 +413,9 @@ impl Skill {
// -----------------
// Destruction
// -----------------
Skill::Blast => panic!("nyi"),
Skill::Amplify => panic!("nyi"),
Skill::Decay => decay(cryp, target, &mut res), // dot
Skill::Blast => blast(cryp, target, log),
Skill::Amplify => amplify(cryp, target, log), // TODO increase magic dmg
Skill::Decay => decay(cryp, target, log), // dot
Skill::Drain => panic!("nyi"),
Skill::Curse => panic!("nyi"),
Skill::Plague => panic!("nyi"), // aoe dot
@ -422,7 +424,7 @@ impl Skill {
// -----------------
// Purity
// -----------------
Skill::Accuracy => panic!("nyi"),
Skill::Precision => panic!("nyi"),
Skill::Inspire => panic!("nyi"),
Skill::Slay => panic!("nyi"),
Skill::Shield => panic!("nyi"),
@ -433,8 +435,8 @@ impl Skill {
// -----------------
// Chaos
// -----------------
Skill::Banish => panic!("nyi"),
Skill::Hex => panic!("nyi"),
Skill::Banish => banish(cryp, target, log), // TODO prevent all actions
Skill::Hex => hex(cryp, target, log), // todo prevent casting
Skill::Fear => panic!("nyi"),
Skill::Taunt => panic!("nyi"),
Skill::Pause => panic!("nyi"), // speed slow
@ -443,8 +445,8 @@ impl Skill {
// Test
// -----------------
Skill::TestTouch => (),
Skill::TestStun => stun(cryp, target, &mut res),
Skill::TestBlock => block(cryp, target, &mut res),
Skill::TestStun => stun(cryp, target, log),
Skill::TestBlock => block(cryp, target, log),
};
return res;
@ -457,6 +459,7 @@ impl Skill {
Skill::Block => 1,
Skill::Decay => 3,
Skill::Triage => 3,
Skill::TestBlock => 1,
Skill::TestStun => 2,
@ -480,28 +483,48 @@ impl Skill {
}
}
fn attack(cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
res.text = format!("{:?} -> {:?} | Attack for {:?}", cryp.name, target.name, cryp.phys_dmg);
fn attack(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
log.push(format!("{:?} -> {:?} | Attack for {:?}", cryp.name, target.name, cryp.phys_dmg));
target.hp.reduce(cryp.phys_dmg.value);
}
fn stun(cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
if !target.effects.iter().any(|e| e.effect.prevents(Skill::Stun)) {
fn stun(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
if !target.immune(Skill::Stun) {
let stun = CrypEffect { effect: Effect::Stun, duration: Skill::Stun.duration(), tick: None };
target.effects.push(stun);
res.text = format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration);
log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration));
} else {
res.text = format!("{:?} blocks.", target.name);
log.push(format!("{:?} -> {:?} | {:?} immune", cryp.name, target.name, target.name));
}
}
fn block(_cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
let effect = CrypEffect { effect: Effect::Block, duration: Skill::Block.duration(), tick: None };
target.effects.push(effect);
res.text = format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration);
fn throw(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
if !target.immune(Skill::Throw) {
let stun = CrypEffect { effect: Effect::Stun, duration: Skill::Stun.duration(), tick: None };
let vulnerable = CrypEffect { effect: Effect::Vulnerable, duration: Skill::Stun.duration(), tick: None };
target.effects.push(stun);
target.effects.push(vulnerable);
log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration));
log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, vulnerable.effect, vulnerable.duration));
} else {
log.push(format!("{:?} -> {:?} | {:?} immune", cryp.name, target.name, target.name));
}
}
fn heal(cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
fn block(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect { effect: Effect::Block, duration: Skill::Block.duration(), tick: None };
target.effects.push(effect);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn snare(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect { effect: Effect::Snare, duration: Skill::Snare.duration(), tick: None };
target.effects.push(effect);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn heal(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let new_hp = *[
target.hp.value.saturating_add(cryp.spell_dmg.value),
target.stamina.value
@ -510,30 +533,73 @@ fn heal(cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
let healing = new_hp.saturating_sub(target.hp.value);
let overhealing = target.hp.value.saturating_add(cryp.phys_dmg.value).saturating_sub(target.stamina.value);
target.hp.value = new_hp;
res.text = format!("{:?} -> {:?} | Heal for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing);
log.push(format!("{:?} -> {:?} | Heal for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing));
}
fn triage(_cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
let effect = CrypEffect { effect: Effect::Triage, duration: Skill::Triage.duration(), tick: None };
fn triage(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect {
effect: Effect::Triage,
duration: Skill::Triage.duration(),
tick: Some(Tick { amount: cryp.spell_dmg.value.wrapping_div(2) })
};
target.effects.push(effect);
res.text = format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn decay(cryp: &mut Cryp, target: &mut Cryp, res: &mut Resolution) {
fn triage_tick(target: &mut Cryp, effect: &CrypEffect, log: &mut Log) {
let tick = effect.tick.expect("no tick for triage");
let new_hp = *[
target.hp.value.saturating_add(tick.amount),
target.stamina.value
].iter().min().unwrap();
let healing = new_hp.saturating_sub(target.hp.value);
let overhealing = target.hp.value + tick.amount - target.stamina.value;
log.push(format!("{:?} | Triage healing for {:?} ({:?} OH)", target.name, healing, overhealing));
target.hp.value = new_hp;
}
fn blast(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let amount = cryp.spell_dmg.value;
log.push(format!("{:?} -> {:?} | Blast for {:?}", cryp.name, target.name, amount));
target.hp.reduce(amount);
}
fn amplify(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect { effect: Effect::Amplify, duration: Skill::Amplify.duration(), tick: None };
target.effects.push(effect);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn decay(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect {
effect: Effect::Decay,
duration: Skill::Decay.duration(),
tick: Some(Tick { amount: cryp.spell_dmg.value.wrapping_div(2) })
};
target.effects.push(effect);
res.text = format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn decay_tick(target: &mut Cryp, effect: &CrypEffect) {
fn decay_tick(target: &mut Cryp, effect: &CrypEffect, log: &mut Log) {
let tick = effect.tick.expect("no tick for decay");
target.hp.reduce(tick.amount);
log.push(format!("{:?} | Decay damage for {:?}", target.name, tick.amount));
}
fn hex(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect { effect: Effect::Hex, duration: Skill::Hex.duration(), tick: None };
target.effects.push(effect);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
fn banish(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
let effect = CrypEffect { effect: Effect::Banish, duration: Skill::Banish.duration(), tick: None };
target.effects.push(effect);
log.push(format!("{:?} is {:?} for {:?}T", target.name, effect.effect, effect.duration));
}
#[cfg(test)]
mod tests {
use skill::*;
@ -554,10 +620,10 @@ mod tests {
x.hp.reduce(5);
let mut resolution = Resolution { base: 0, result: None, text: String::new() };
heal(&mut y, &mut x, &mut resolution);
let mut log = vec![];
heal(&mut y, &mut x, &mut log);
println!("{:?}", resolution);
println!("{:?}", log);
}
#[test]
@ -565,7 +631,6 @@ mod tests {
let mut x = Cryp::new()
.named(&"muji".to_string())
.level(8)
.learn(Skill::Decay)
.create();
let mut y = Cryp::new()
@ -573,16 +638,43 @@ mod tests {
.level(8)
.create();
let mut resolution = Resolution { base: 0, result: None, text: String::new() };
decay(&mut x, &mut y, &mut resolution);
let mut log = vec![];
decay(&mut x, &mut y, &mut log);
assert!(y.effects.iter().any(|e| e.effect == Effect::Decay));
y.reduce_effect_durations();
y.reduce_effect_durations(&mut log);
let decay = y.effects.iter().find(|e| e.effect == Effect::Decay);
assert!(y.hp.value == y.stamina.value.saturating_sub(decay.unwrap().tick.unwrap().amount));
}
#[test]
fn triage_test() {
let mut x = Cryp::new()
.named(&"muji".to_string())
.level(8)
.create();
let mut y = Cryp::new()
.named(&"pretaliation".to_string())
.level(8)
.create();
let mut log = vec![];
// ensure it doesn't have 0 sd
x.spell_dmg.value = 50;
y.hp.reduce(5);
let prev_hp = y.hp.value;
triage(&mut x, &mut y, &mut log);
assert!(y.effects.iter().any(|e| e.effect == Effect::Triage));
y.reduce_effect_durations(&mut log);
assert!(y.hp.value > prev_hp);
}
}
// #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]