use uuid::Uuid; use rand::prelude::*; use serde_cbor::*; use rpc::{GenerateParams}; use skill::{Skill}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum StatKind { Dmg, Def, Hp, Stam, } #[derive(Debug,Clone)] pub struct Roll { pub base: u64, pub result: u64, pub kind: StatKind, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Stat { pub value: u64, pub kind: StatKind, } impl Stat { fn set(&mut self, v: u64) -> &Stat { self.value = v; self } fn roll(&self, c: &Cryp) -> Roll { let mut rng = thread_rng(); let base: u64 = rng.gen(); let mut roll = Roll { kind: self.kind, base, result: base }; println!("{:?}", self.kind); println!("{:064b} <- base roll", base); // apply skills roll = c.skills.iter().fold(roll, |roll, s| s.apply(roll)); // finally combine with stat println!("{:064b} <- finalised", roll.result); roll.result = roll.result & self.value; println!("{:064b} & <- attribute roll", self.value); println!("{:064b} = {:?}", roll.result, roll.result); println!(""); return roll; } fn reduce(&mut self, dmg: u64) -> &mut Stat { self.value = self.value.saturating_sub(dmg); self } } pub struct Turn { pub dmg: Roll, pub def: Roll, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Cryp { pub id: Uuid, // todo // make attributes hold this value pub dmg: Stat, pub def: Stat, pub stam: Stat, pub hp: Stat, pub xp: u64, pub lvl: u8, pub skills: Vec, pub name: String, } fn check_lvl(lvl: u8) -> u8 { if lvl > 64 { return 64; } return lvl; } impl Cryp { pub fn new() -> Cryp { let id = Uuid::new_v4(); return Cryp { id, dmg: Stat { value: 0, kind: StatKind::Dmg }, def: Stat { value: 0, kind: StatKind::Def }, stam: Stat { value: 0, kind: StatKind::Stam }, hp: Stat { value: 0, kind: StatKind::Hp }, lvl: 0, xp: 0, skills: vec![], name: String::new() }; } pub fn named(mut self, name: String) -> Cryp { self.name = name.clone(); self } pub fn level(mut self, lvl: u8) -> Cryp { self.lvl = check_lvl(lvl); self } pub fn learn(mut self, s: Skill) -> Cryp { self.skills.push(s); self } pub fn add_xp(mut self) -> Cryp { self.xp = self.xp.saturating_add(1); if self.xp.is_power_of_two() { return self.level_up(); } self } pub fn level_up(mut self) -> Cryp { self.lvl = self.lvl.saturating_add(1); self.create() } pub fn turn(&self) -> Turn { // println!("{:?}'s turn:", c.name); let dmg = self.dmg.roll(self); let def = self.def.roll(self); return Turn { dmg, def } } pub fn create(mut self) -> Cryp { let mut rng = thread_rng(); let max = match self.lvl == 64 { true => u64::max_value(), false => 2_u64.pow(self.lvl.into()), }; self.xp = max; self.dmg.set(rng.gen_range(1, max)); self.def.set(rng.gen_range(1, max)); self.stam.set(rng.gen_range(1, max)); self.hp.set(self.stam.value); self } pub fn assign_dmg(&mut self, opp: &Cryp, plr_t: &Turn, opp_t: &Turn) -> &mut Cryp { let final_dmg = opp_t.dmg.result.saturating_sub(plr_t.def.result); let blocked = opp_t.dmg.result.saturating_sub(final_dmg); self.hp.reduce(final_dmg); println!("{:?} deals {:?} dmg to {:?} ({:?} blocked / {:?} hp remaining)" ,opp.name ,final_dmg ,self.name ,blocked ,self.hp.value); self } pub fn is_ko(&self) -> bool { self.hp.value == 0 } } pub fn generate(params: GenerateParams) -> Cryp { Cryp::new() .named("hatchling".to_string()) .level(params.level) .learn(Skill::Stoney) .create() } #[cfg(test)] mod tests { use cryp::*; use skill::*; #[test] fn create_cryp_test() { let max_level = Cryp::new() .named("hatchling".to_string()) .level(64) .learn(Skill::Stoney) .create(); assert_eq!(max_level.lvl, 64); return; } }