998 lines
30 KiB
Rust
Executable File
998 lines
30 KiB
Rust
Executable File
use rand::{thread_rng, Rng};
|
|
use uuid::Uuid;
|
|
|
|
use game::{Log};
|
|
use cryp::{Cryp, CrypEffect, Stat};
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub struct Cast {
|
|
pub id: Uuid,
|
|
pub skill: Skill, pub source_team_id: Uuid,
|
|
pub source_cryp_id: Uuid,
|
|
pub target_cryp_id: Option<Uuid>,
|
|
pub target_team_id: Uuid,
|
|
}
|
|
|
|
impl Cast {
|
|
pub fn new(source_cryp_id: Uuid, source_team_id: Uuid, target_team_id: Option<Uuid>, skill: Skill) -> Cast {
|
|
|
|
let (target_cryp_id, target_team_id) = match skill.self_targeting() {
|
|
true => (Some(source_cryp_id), source_team_id),
|
|
false => (None, target_team_id.unwrap())
|
|
};
|
|
|
|
return Cast {
|
|
id: Uuid::new_v4(),
|
|
source_cryp_id,
|
|
source_team_id,
|
|
target_cryp_id,
|
|
target_team_id,
|
|
skill,
|
|
};
|
|
}
|
|
|
|
pub fn new_tick(source: &mut Cryp, target: &mut Cryp, skill: Skill) -> Cast {
|
|
let mut cast = Cast::new(source.id, source.account, Some(target.account), skill);
|
|
cast.set_target(target.id);
|
|
return cast;
|
|
}
|
|
|
|
pub fn set_resolution(&mut self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) -> &mut Cast {
|
|
self.skill.resolve(cryp, target, log);
|
|
self
|
|
}
|
|
|
|
pub fn set_target(&mut self, cryp_id: Uuid) -> &mut Cast {
|
|
self.target_cryp_id = Some(cryp_id);
|
|
self
|
|
}
|
|
|
|
pub fn used_cooldown(&self) -> bool {
|
|
return self.skill.cd().is_some();
|
|
}
|
|
}
|
|
|
|
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
|
|
pub struct Resolution {
|
|
pub base: u64,
|
|
pub result: Option<u64>,
|
|
}
|
|
|
|
pub type Cooldown = Option<u8>;
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub enum Effect {
|
|
// physical
|
|
Stun,
|
|
Block,
|
|
Bleed,
|
|
Leech,
|
|
Airborne,
|
|
Untouchable,
|
|
Deadly,
|
|
Vulnerable,
|
|
Fury,
|
|
Evasion,
|
|
Blind,
|
|
Snare,
|
|
|
|
Empower,
|
|
|
|
// magic
|
|
Hex,
|
|
Curse,
|
|
Banish,
|
|
Slow,
|
|
Haste,
|
|
Enslave,
|
|
Mesmerise,
|
|
Amplify,
|
|
Silence,
|
|
|
|
// magic immunity
|
|
Shield,
|
|
|
|
// effects over time
|
|
Triage,
|
|
Decay,
|
|
Regen,
|
|
Drain,
|
|
|
|
SpeedDrain,
|
|
SpeedIncrease,
|
|
}
|
|
|
|
impl Effect {
|
|
pub fn immune(&self, skill: Skill) -> bool {
|
|
match self {
|
|
Effect::Block => match skill {
|
|
Skill::Stun |
|
|
Skill::TestStun |
|
|
Skill::Attack => true,
|
|
_ => false,
|
|
},
|
|
Effect::Shield => match skill.cast_type() {
|
|
Damage::Magic => true,
|
|
Damage::Physical => false,
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn prevents_casting(&self, skill: Skill) -> bool {
|
|
match self {
|
|
Effect::Stun => true,
|
|
Effect::Silence => match skill.cast_type() {
|
|
Damage::Magic => true,
|
|
Damage::Physical => false,
|
|
},
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn modifications(&self) -> Vec<Stat> {
|
|
match self {
|
|
Effect::Amplify => vec![Stat::SpellDmg],
|
|
Effect::Empower => vec![Stat::PhysDmg],
|
|
_ => vec![],
|
|
}
|
|
}
|
|
|
|
// maybe increase by rng
|
|
// roll little endian bits
|
|
// and OR with base stat
|
|
pub fn apply(&self, value: u64) -> u64 {
|
|
match self {
|
|
Effect::Amplify => value << 1,
|
|
Effect::Empower => value << 1,
|
|
_ => panic!("{:?} does not have a mod effect", self),
|
|
}
|
|
}
|
|
|
|
pub fn source(&self) -> Source {
|
|
match self {
|
|
// physical
|
|
Effect::Stun => Source::Debuff,
|
|
Effect::Block => Source::Buff,
|
|
Effect::Bleed => Source::Debuff,
|
|
Effect::Leech => Source::Debuff,
|
|
Effect::Airborne => Source::Buff,
|
|
Effect::Untouchable => Source::Buff,
|
|
Effect::Deadly => Source::Buff,
|
|
Effect::Vulnerable => Source::Debuff,
|
|
Effect::Fury => Source::Buff,
|
|
Effect::Evasion => Source::Buff,
|
|
Effect::Blind => Source::Debuff,
|
|
Effect::Snare => Source::Debuff,
|
|
|
|
Effect::Empower => Source::Buff,
|
|
|
|
// magic
|
|
Effect::Hex => Source::Debuff,
|
|
Effect::Curse => Source::Debuff,
|
|
Effect::Banish => Source::Debuff, // todo randomise
|
|
Effect::Slow => Source::Debuff,
|
|
Effect::Haste => Source::Buff,
|
|
Effect::Enslave => Source::Debuff,
|
|
Effect::Mesmerise => Source::Debuff,
|
|
Effect::Amplify => Source::Buff,
|
|
Effect::Silence => Source::Debuff,
|
|
|
|
// magic immunity
|
|
Effect::Shield => Source::Buff,
|
|
|
|
// effects over time
|
|
Effect::Triage => Source::Buff,
|
|
Effect::Decay => Source::Debuff,
|
|
Effect::Regen => Source::Buff,
|
|
Effect::Drain => Source::Debuff,
|
|
|
|
Effect::SpeedDrain => Source::Debuff,
|
|
Effect::SpeedIncrease => Source::Buff,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub enum Damage {
|
|
Physical,
|
|
Magic,
|
|
}
|
|
|
|
// #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
// enum Style {
|
|
// Offensive,
|
|
// Defensive,
|
|
// }
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub enum Source {
|
|
Buff,
|
|
Debuff,
|
|
Stat,
|
|
}
|
|
|
|
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
pub enum Skill {
|
|
Attack,
|
|
|
|
// -----------------
|
|
// Nature
|
|
// -----------------
|
|
Block, // reduce dmg
|
|
Parry, // avoid all dmg
|
|
Snare,
|
|
|
|
Paralyse,
|
|
|
|
Strangle, // physical dot and disable
|
|
|
|
Stun,
|
|
Evade, // actively evade
|
|
Evasion, // adds evasion to cryp
|
|
|
|
|
|
// -----------------
|
|
// Technology
|
|
// -----------------
|
|
Replicate,
|
|
Swarm,
|
|
Orbit,
|
|
Repair,
|
|
Scan, // track?
|
|
|
|
// -----------------
|
|
// Nonviolence
|
|
// -----------------
|
|
Heal,
|
|
Triage, // hot
|
|
TriageTick,
|
|
Throw, // no dmg stun, adds vulnerable
|
|
Charm,
|
|
Calm,
|
|
Rez,
|
|
|
|
// -------------------
|
|
// Destruction
|
|
// -------------------
|
|
Blast,
|
|
Amplify,
|
|
Decay, // dot
|
|
DecayTick, // dot
|
|
Drain,
|
|
DrainTick,
|
|
Curse,
|
|
Plague, // aoe dot
|
|
Ruin, // aoe
|
|
|
|
// -----------------
|
|
// Purity
|
|
// -----------------
|
|
Empower,
|
|
Slay,
|
|
Shield,
|
|
Silence,
|
|
Inquiry,
|
|
Purify,
|
|
Purge,
|
|
// Precision,
|
|
|
|
// -----------------
|
|
// Chaos
|
|
// -----------------
|
|
Banish,
|
|
Hex,
|
|
Fear,
|
|
Taunt,
|
|
Pause, // speed slow
|
|
|
|
// used by tests, no cd, no dmg
|
|
TestTouch,
|
|
TestStun,
|
|
TestBlock,
|
|
TestDrain,
|
|
}
|
|
|
|
impl Skill {
|
|
pub fn cd(&self) -> Cooldown {
|
|
match self {
|
|
Skill::Attack => None,
|
|
|
|
// -----------------
|
|
// Nature
|
|
// -----------------
|
|
Skill::Block => Some(1), // reduce dmg
|
|
Skill::Parry => Some(1), // avoid all dmg
|
|
Skill::Snare => Some(2),
|
|
|
|
Skill::Paralyse => Some(3),
|
|
Skill::Strangle => Some(3),
|
|
|
|
// Strangle
|
|
|
|
Skill::Stun => Some(1),
|
|
Skill::Evade => Some(2),
|
|
Skill::Evasion => Some(3), // additional layer of dmg avoidance
|
|
|
|
// -----------------
|
|
// Technology
|
|
// -----------------
|
|
Skill::Replicate => Some(1),
|
|
Skill::Swarm => Some(3),
|
|
Skill::Orbit => Some(2),
|
|
Skill::Repair => Some(1),
|
|
Skill::Scan => Some(2), // track?
|
|
|
|
// -----------------
|
|
// Preservation
|
|
// -----------------
|
|
Skill::Heal => Some(1),
|
|
Skill::Triage => Some(1), // hot
|
|
Skill::TriageTick => None,
|
|
Skill::Throw => Some(2), // no dmg stun, adds vulnerable
|
|
Skill::Charm => Some(2),
|
|
Skill::Calm => Some(2),
|
|
Skill::Rez => Some(4),
|
|
|
|
// -----------------
|
|
// Destruction
|
|
// -----------------
|
|
Skill::Blast => Some(1),
|
|
Skill::Amplify => Some(2),
|
|
Skill::Decay => Some(1), // dot
|
|
Skill::DecayTick => None,
|
|
Skill::Drain => Some(2),
|
|
Skill::DrainTick => None,
|
|
Skill::Curse => Some(2),
|
|
Skill::Plague => Some(2), // aoe dot
|
|
Skill::Ruin => Some(3), // aoe
|
|
|
|
// -----------------
|
|
// Purity
|
|
// -----------------
|
|
// Skill::Precision => Some(1),
|
|
Skill::Empower => Some(2),
|
|
Skill::Slay => Some(1),
|
|
Skill::Shield => Some(1),
|
|
Skill::Silence => Some(2),
|
|
Skill::Inquiry => Some(2),
|
|
Skill::Purify => Some(1),
|
|
Skill::Purge => Some(1),
|
|
|
|
// -----------------
|
|
// Chaos
|
|
// -----------------
|
|
Skill::Banish => Some(2),
|
|
Skill::Hex => Some(1),
|
|
Skill::Fear => Some(1),
|
|
Skill::Taunt => Some(2),
|
|
Skill::Pause => Some(2), // speed slow
|
|
|
|
// -----------------
|
|
// Test
|
|
// -----------------
|
|
Skill::TestTouch => None,
|
|
Skill::TestStun => None,
|
|
Skill::TestBlock => None,
|
|
Skill::TestDrain => None,
|
|
}
|
|
}
|
|
|
|
pub fn cast_type(&self) -> Damage {
|
|
match self {
|
|
Skill::Attack => Damage::Physical,
|
|
|
|
// -----------------
|
|
// Nature
|
|
// -----------------
|
|
Skill::Block => Damage::Physical, // reduce dmg
|
|
Skill::Evade => Damage::Physical,
|
|
Skill::Parry => Damage::Physical, // avoid all dmg
|
|
Skill::Snare => Damage::Physical,
|
|
|
|
Skill::Paralyse => Damage::Physical,
|
|
Skill::Strangle => Damage::Physical,
|
|
|
|
// Strangle
|
|
|
|
Skill::Stun => Damage::Physical,
|
|
Skill::Evasion => Damage::Physical, // additional layer of dmg avoidance
|
|
|
|
// -----------------
|
|
// Technology
|
|
// -----------------
|
|
Skill::Replicate => Damage::Physical,
|
|
Skill::Swarm => Damage::Physical,
|
|
Skill::Orbit => Damage::Physical,
|
|
Skill::Repair => Damage::Physical,
|
|
Skill::Scan => Damage::Physical, // track?
|
|
|
|
// -----------------
|
|
// Preservation
|
|
// -----------------
|
|
Skill::Heal => Damage::Physical,
|
|
Skill::Triage => Damage::Physical, // hot
|
|
Skill::TriageTick => Damage::Physical, // hot
|
|
Skill::Throw => Damage::Physical, // no dmg stun, adds vulnerable
|
|
Skill::Charm => Damage::Physical,
|
|
Skill::Calm => Damage::Physical,
|
|
Skill::Rez => Damage::Physical,
|
|
|
|
// -----------------
|
|
// Destruction
|
|
// -----------------
|
|
Skill::Blast => Damage::Magic,
|
|
Skill::Amplify => Damage::Magic,
|
|
Skill::Decay => Damage::Magic, // dot
|
|
Skill::DecayTick => Damage::Magic, // hot
|
|
Skill::Drain => Damage::Magic,
|
|
Skill::DrainTick => Damage::Magic, // hot
|
|
Skill::Curse => Damage::Magic,
|
|
Skill::Plague => Damage::Magic, // aoe dot
|
|
Skill::Ruin => Damage::Magic, // aoe
|
|
|
|
// -----------------
|
|
// Purity
|
|
// -----------------
|
|
// Skill::Precision => 1,
|
|
Skill::Empower => Damage::Physical,
|
|
Skill::Slay => Damage::Physical,
|
|
Skill::Shield => Damage::Magic,
|
|
Skill::Silence => Damage::Magic,
|
|
Skill::Inquiry => Damage::Magic,
|
|
Skill::Purify => Damage::Magic,
|
|
Skill::Purge => Damage::Magic,
|
|
|
|
// -----------------
|
|
// Chaos
|
|
// -----------------
|
|
Skill::Banish => Damage::Magic,
|
|
Skill::Hex => Damage::Magic,
|
|
Skill::Fear => Damage::Magic,
|
|
Skill::Taunt => Damage::Magic,
|
|
Skill::Pause => Damage::Magic, // extend durations
|
|
// Skill::Lag => 2, //
|
|
|
|
// -----------------
|
|
// Test
|
|
// -----------------
|
|
Skill::TestTouch => Damage::Physical,
|
|
Skill::TestStun => Damage::Physical,
|
|
Skill::TestBlock => Damage::Physical,
|
|
Skill::TestDrain => Damage::Magic,
|
|
}
|
|
}
|
|
|
|
pub fn speed(&self) -> u8 {
|
|
match self {
|
|
Skill::Attack => 5,
|
|
|
|
// -----------------
|
|
// Nature
|
|
// -----------------
|
|
Skill::Block => 10, // reduce dmg
|
|
Skill::Evade => 10,
|
|
Skill::Parry => 10, // avoid all dmg
|
|
Skill::Snare => 10,
|
|
|
|
Skill::Paralyse => 5,
|
|
Skill::Strangle => 5,
|
|
|
|
// Strangle
|
|
|
|
Skill::Stun => 5,
|
|
Skill::Evasion => 3, // additional layer of dmg avoidance
|
|
|
|
// -----------------
|
|
// Technology
|
|
// -----------------
|
|
Skill::Replicate => 1,
|
|
Skill::Swarm => 3,
|
|
Skill::Orbit => 2,
|
|
Skill::Repair => 1,
|
|
Skill::Scan => 2, // track?
|
|
|
|
// -----------------
|
|
// Preservation
|
|
// -----------------
|
|
Skill::Heal => 1,
|
|
Skill::Triage => 1, // hot
|
|
Skill::TriageTick => 1, // hot
|
|
Skill::Throw => 2, // no dmg stun, adds vulnerable
|
|
Skill::Charm => 2,
|
|
Skill::Calm => 2,
|
|
Skill::Rez => 4,
|
|
|
|
// -----------------
|
|
// Destruction
|
|
// -----------------
|
|
Skill::Blast => 1,
|
|
Skill::Amplify => 2,
|
|
Skill::Decay => 1, // dot
|
|
Skill::DecayTick => 2, // hot
|
|
Skill::Drain => 2,
|
|
Skill::DrainTick => 2, // hot
|
|
Skill::Curse => 2,
|
|
Skill::Plague => 2, // aoe dot
|
|
Skill::Ruin => 3, // aoe
|
|
|
|
// -----------------
|
|
// Purity
|
|
// -----------------
|
|
// Skill::Precision => 1,
|
|
Skill::Empower => 2,
|
|
Skill::Slay => 1,
|
|
Skill::Shield => 1,
|
|
Skill::Silence => 2,
|
|
Skill::Inquiry => 2,
|
|
Skill::Purify => 1,
|
|
Skill::Purge => 1,
|
|
|
|
// -----------------
|
|
// Chaos
|
|
// -----------------
|
|
Skill::Banish => 2,
|
|
Skill::Hex => 1,
|
|
Skill::Fear => 1,
|
|
Skill::Taunt => 2,
|
|
Skill::Pause => 2, // extend durations
|
|
// Skill::Lag => 2, //
|
|
|
|
// -----------------
|
|
// Test
|
|
// -----------------
|
|
Skill::TestTouch => 10,
|
|
Skill::TestStun => 5,
|
|
Skill::TestBlock => 10,
|
|
Skill::TestDrain => 10,
|
|
}
|
|
}
|
|
|
|
pub fn resolve(&self, cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let mut rng = thread_rng();
|
|
let base: u64 = rng.gen();
|
|
|
|
// let res = Resolution { base, result: None };
|
|
|
|
// println!("{:?}'s stats", self.name);
|
|
// println!("{:064b} <- finalised", roll.result);
|
|
// roll.result = roll.result & stat();
|
|
|
|
// println!("{:064b} & <- attribute roll", stat());
|
|
// println!("{:064b} = {:?}", roll.result, roll.result);
|
|
// println!("");
|
|
|
|
// return Some(roll);
|
|
|
|
let (immune, reason) = target.immune(*self);
|
|
if immune {
|
|
log.push(format!("{:?} -> {:?} | {:?} immune: {:?}", cryp.name, target.name, self, reason));
|
|
return;
|
|
}
|
|
|
|
match self {
|
|
Skill::Attack => attack(cryp, target, log),
|
|
// -----------------
|
|
// Nature
|
|
// -----------------
|
|
Skill::Block => block(cryp, target, log),
|
|
Skill::Evade => panic!("nyi"), //
|
|
Skill::Parry => panic!("nyi"), // avoid all dmg
|
|
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, log),
|
|
Skill::Evasion => panic!("nyi"), // additional layer of dmg avoidance
|
|
|
|
// -----------------
|
|
// Technology
|
|
// -----------------
|
|
Skill::Replicate => panic!("nyi"),
|
|
Skill::Swarm => panic!("nyi"),
|
|
Skill::Orbit => panic!("nyi"),
|
|
Skill::Repair => panic!("nyi"),
|
|
Skill::Scan => panic!("nyi"), // track?
|
|
|
|
// -----------------
|
|
// Preservation
|
|
// -----------------
|
|
Skill::Heal => heal(cryp, target, log),
|
|
Skill::Triage => triage(cryp, target, log), // hot
|
|
Skill::TriageTick => triage_tick(cryp, target, log), // hot
|
|
Skill::Throw => throw(cryp, target, log), // no dmg stun, adds vulnerable
|
|
Skill::Charm => panic!("nyi"), // target casts random spell on teammate
|
|
Skill::Calm => panic!("nyi"), // physical fear, taunt removal
|
|
Skill::Rez => panic!("nyi"),
|
|
|
|
// -----------------
|
|
// Destruction
|
|
// -----------------
|
|
Skill::Blast => blast(cryp, target, log),
|
|
Skill::Amplify => amplify(cryp, target, log), // increase magic dmg
|
|
Skill::Decay => decay(cryp, target, log), // dot
|
|
Skill::DecayTick => decay_tick(cryp, target, log), // hot
|
|
Skill::Drain => drain(cryp, target, log),
|
|
Skill::DrainTick => drain_tick(cryp, target, log), // hot
|
|
Skill::Curse => curse(cryp, target, log),
|
|
Skill::Plague => panic!("nyi"), // dot that spreads every turn
|
|
Skill::Ruin => panic!("nyi"), // aoe version of blast
|
|
|
|
// -----------------
|
|
// Purity
|
|
// -----------------
|
|
// Skill::Precision => panic!("nyi"),
|
|
Skill::Empower => empower(cryp, target, log), // increased phys dmg
|
|
Skill::Slay => panic!("nyi"), // phys dmg mult by target magic dmg
|
|
Skill::Shield => shield(cryp, target, log), // target is immune to magic dmg and fx
|
|
Skill::Silence => silence(cryp, target, log), // target cannot cast spells
|
|
Skill::Inquiry => panic!("nyi"), //
|
|
Skill::Purify => purify(cryp, target, log), // dispel all debuffs
|
|
Skill::Purge => purge(cryp, target, log), // dispel all buffs
|
|
|
|
// -----------------
|
|
// Chaos
|
|
// -----------------
|
|
Skill::Banish => banish(cryp, target, log), // TODO prevent all actions
|
|
Skill::Hex => hex(cryp, target, log), // todo prevent casting
|
|
Skill::Fear => panic!("nyi"), // cast random spell on self
|
|
Skill::Taunt => panic!("nyi"), // target forced to attack
|
|
Skill::Pause => panic!("nyi"), // speed slow
|
|
|
|
// -----------------
|
|
// Test
|
|
// -----------------
|
|
Skill::TestTouch => (),
|
|
Skill::TestStun => stun(cryp, target, log),
|
|
Skill::TestBlock => block(cryp, target, log),
|
|
Skill::TestDrain => drain(cryp, target, log),
|
|
};
|
|
}
|
|
|
|
pub fn duration(&self) -> u8 {
|
|
match self {
|
|
Skill::Evade => 1,
|
|
Skill::Stun => 2,
|
|
Skill::Block => 1,
|
|
|
|
Skill::Empower => 2,
|
|
|
|
Skill::Decay => 3,
|
|
Skill::Drain => 3,
|
|
Skill::Triage => 3,
|
|
|
|
Skill::Amplify => 2,
|
|
Skill::Silence => 3,
|
|
|
|
Skill::TestBlock => 1,
|
|
Skill::TestStun => 2,
|
|
_ => panic!("{:?} does not have a duration", self),
|
|
}
|
|
}
|
|
|
|
pub fn self_targeting(&self) -> bool {
|
|
match self {
|
|
Skill::Block => true,
|
|
Skill::TestBlock => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn castable(&self, cryp: &Cryp) -> bool {
|
|
!cryp.effects.iter().any(|e| e.effect.prevents_casting(*self))
|
|
}
|
|
}
|
|
|
|
fn attack(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
target.deal_phys_dmg(cryp.phys_dmg());
|
|
log.push(format!("{:?} -> {:?} | Attack for {:?}", cryp.name, target.name, cryp.phys_dmg));
|
|
}
|
|
|
|
fn stun(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let stun = CrypEffect { effect: Effect::Stun, duration: Skill::Stun.duration(), tick: None };
|
|
target.effects.push(stun);
|
|
log.push(format!("{:?} -> {:?} | {:?} for {:?}T", cryp.name, target.name, stun.effect, stun.duration));
|
|
}
|
|
|
|
fn throw(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
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));
|
|
}
|
|
|
|
|
|
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!("{:?} < {:?} 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!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn empower(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect { effect: Effect::Empower, duration: Skill::Empower.duration(), tick: None };
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn heal(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let (healing, overhealing) = target.heal(cryp.phys_dmg());
|
|
log.push(format!("{:?} -> {:?} | Heal for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing));
|
|
}
|
|
|
|
fn triage(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect {
|
|
effect: Effect::Triage,
|
|
duration: Skill::Triage.duration(),
|
|
tick: Some(Cast::new_tick(cryp, target, Skill::TriageTick)),
|
|
};
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn triage_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let amount = cryp.spell_dmg().wrapping_div(2);
|
|
let (healing, overhealing) = target.heal(amount);
|
|
log.push(format!("{:?} -> {:?} | Triage for {:?} ({:?} OH)", cryp.name, target.name, healing, overhealing));
|
|
}
|
|
|
|
fn blast(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let amount = cryp.spell_dmg();
|
|
log.push(format!("{:?} -> {:?} | Blast for {:?}", cryp.name, target.name, amount));
|
|
target.deal_spell_dmg(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!("{:?} < {:?} 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(Cast::new_tick(cryp, target, Skill::DecayTick)),
|
|
};
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn decay_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let amount = cryp.spell_dmg();
|
|
log.push(format!("{:?} -> {:?} | Decay for {:?}", cryp.name, target.name, amount));
|
|
target.deal_spell_dmg(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!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn curse(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect { effect: Effect::Curse, duration: Skill::Curse.duration(), tick: None };
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn drain(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect {
|
|
effect: Effect::Drain,
|
|
duration: Skill::Drain.duration(),
|
|
tick: Some(Cast::new_tick(cryp, target, Skill::DrainTick)),
|
|
};
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn drain_tick(cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
// Damage part
|
|
let (damage, _) = target.deal_spell_dmg(cryp.spell_dmg().wrapping_div(2));
|
|
log.push(format!("{:?} | Drain Damage {:?}", target.name, damage));
|
|
|
|
let (healing, overhealing) = target.heal(damage);
|
|
log.push(format!("{:?} | Drain healing {:?} ({:?} OH)", cryp.name, healing, overhealing));
|
|
}
|
|
|
|
fn shield(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect { effect: Effect::Shield, duration: Skill::Shield.duration(), tick: None };
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn silence(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
let effect = CrypEffect { effect: Effect::Silence, duration: Skill::Silence.duration(), tick: None };
|
|
target.effects.push(effect);
|
|
log.push(format!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
fn purge(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
|
|
if ce.effect.source() == Source::Buff {
|
|
target.effects.remove(i);
|
|
log.push(format!("{:?} < {:?} purged", target.name, ce.effect));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn purify(_cryp: &mut Cryp, target: &mut Cryp, log: &mut Log) {
|
|
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
|
|
if ce.effect.source() == Source::Debuff {
|
|
target.effects.remove(i);
|
|
log.push(format!("{:?} < {:?} purified", target.name, ce.effect));
|
|
}
|
|
}
|
|
}
|
|
|
|
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!("{:?} < {:?} for {:?}T", target.name, effect.effect, effect.duration));
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use skill::*;
|
|
|
|
#[test]
|
|
fn heal_test() {
|
|
let mut x = Cryp::new()
|
|
.named(&"muji".to_string())
|
|
.level(8)
|
|
.learn(Skill::Heal)
|
|
.create();
|
|
|
|
let mut y = Cryp::new()
|
|
.named(&"camel".to_string())
|
|
.level(8)
|
|
.learn(Skill::Heal)
|
|
.create();
|
|
|
|
x.deal_phys_dmg(5);
|
|
|
|
let mut log = vec![];
|
|
heal(&mut y, &mut x, &mut log);
|
|
}
|
|
|
|
#[test]
|
|
fn decay_test() {
|
|
let mut x = Cryp::new()
|
|
.named(&"muji".to_string())
|
|
.level(8)
|
|
.create();
|
|
|
|
let mut y = Cryp::new()
|
|
.named(&"camel".to_string())
|
|
.level(8)
|
|
.create();
|
|
|
|
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(&mut log);
|
|
let decay = y.effects.iter().find(|e| e.effect == Effect::Decay);
|
|
// assert!(y.hp() == y.stamina().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.set(50);
|
|
y.deal_phys_dmg(5);
|
|
let prev_hp = y.hp();
|
|
|
|
triage(&mut x, &mut y, &mut log);
|
|
|
|
assert!(y.effects.iter().any(|e| e.effect == Effect::Triage));
|
|
|
|
triage_tick(&mut x, &mut y, &mut log);
|
|
assert!(y.hp() > prev_hp);
|
|
}
|
|
|
|
#[test]
|
|
fn silence_test() {
|
|
let mut x = Cryp::new()
|
|
.named(&"muji".to_string())
|
|
.level(8)
|
|
.create();
|
|
|
|
let mut log = vec![];
|
|
|
|
silence(&mut x.clone(), &mut x, &mut log);
|
|
assert!(x.effects.iter().any(|e| e.effect == Effect::Silence));
|
|
assert!(!Skill::Decay.castable(&x));
|
|
}
|
|
|
|
#[test]
|
|
fn amplify_test() {
|
|
let mut x = Cryp::new()
|
|
.named(&"muji".to_string())
|
|
.level(8)
|
|
.create();
|
|
|
|
x.spell_dmg.set(50);
|
|
|
|
let mut log = vec![];
|
|
amplify(&mut x.clone(), &mut x, &mut log);
|
|
assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify));
|
|
assert_eq!(x.spell_dmg(), 100);
|
|
}
|
|
|
|
#[test]
|
|
fn purify_test() {
|
|
let mut x = Cryp::new()
|
|
.named(&"muji".to_string())
|
|
.level(8)
|
|
.create();
|
|
|
|
let mut log = vec![];
|
|
decay(&mut x.clone(), &mut x, &mut log);
|
|
assert!(x.effects.iter().any(|e| e.effect == Effect::Decay));
|
|
|
|
purify(&mut x.clone(), &mut x, &mut log);
|
|
assert!(!x.effects.iter().any(|e| e.effect == Effect::Decay));
|
|
}
|
|
}
|
|
|
|
// #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
|
// pub enum Skill {
|
|
// Stoney,
|
|
// Evasive,
|
|
// }
|
|
|
|
// impl Skill {
|
|
// pub fn apply(&self, roll: Roll) -> Roll {
|
|
// match self {
|
|
// Skill::Stoney => stoney(self, roll),
|
|
// Skill::Evasive => evasive(self, roll),
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// fn stoney(_s: &Skill, mut roll: Roll) -> Roll {
|
|
// let effect = 0b11110000;
|
|
// match roll.kind {
|
|
// StatKind::Def => {
|
|
// // println!("{:064b} | <- {:?}", effect, s);
|
|
// roll.result = roll.result | effect;
|
|
// roll
|
|
// },
|
|
// _ => roll,
|
|
// }
|
|
// }
|
|
|
|
// fn evasive(_s: &Skill, mut roll: Roll) -> Roll {
|
|
// match roll.kind {
|
|
// StatKind::Def => {
|
|
// if roll.result.is_power_of_two() {
|
|
// roll.result = u64::max_value()
|
|
// }
|
|
// roll
|
|
// },
|
|
// _ => roll,
|
|
// }
|
|
// }
|