use uuid::Uuid; use rand::prelude::*; use serde_cbor::{from_slice, to_vec}; use postgres::transaction::Transaction; use failure::Error; use failure::err_msg; use account::Account; use rpc::{CrypSpawnParams}; use game::Skill; // use skill::{Skill}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Stat { Str, Agi, Int, Hp, Stam, } #[derive(Debug,Clone)] pub struct Roll { pub base: u64, pub result: u64, pub kind: Stat, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct CrypStat { pub value: u64, pub stat: Stat, } impl CrypStat { fn set(&mut self, v: u64) -> &CrypStat { self.value = v; self } // fn roll(&self, c: &Cryp, log: &mut Vec) -> Roll { // let mut rng = thread_rng(); // let base: u64 = rng.gen(); // let mut roll = Roll { kind: self.kind, base, result: base }; // log.push(format!("{:?}", self.kind)); // log.push(format!("{:064b} <- base roll", base)); // // apply skills // roll = c.skills.iter().fold(roll, |roll, s| s.apply(roll)); // // finally combine with CrypStat // log.push(format!("{:064b} <- finalised", roll.result)); // roll.result = roll.result & self.value; // log.push(format!("{:064b} & <- attribute roll", self.value)); // log.push(format!("{:064b} = {:?}", roll.result, roll.result)); // log.push(format!("")); // return roll; // } pub fn reduce(&mut self, dmg: u64) -> &mut CrypStat { self.value = self.value.saturating_sub(dmg); self } } pub struct Turn { pub str: Roll, pub agi: Roll, pub log: Vec, } #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Cryp { pub id: Uuid, pub account: Uuid, pub str: CrypStat, pub agi: CrypStat, pub int: CrypStat, pub stam: CrypStat, pub hp: CrypStat, 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, account: id, str: CrypStat { value: 0, stat: Stat::Str }, agi: CrypStat { value: 0, stat: Stat::Agi }, int: CrypStat { value: 0, stat: Stat::Int }, stam: CrypStat { value: 0, stat: Stat::Stam }, hp: CrypStat { value: 0, stat: Stat::Hp }, lvl: 0, xp: 0, skills: vec![Skill::Attack], name: String::new() }; } pub fn named(mut self, name: &String) -> Cryp { self.name = name.clone(); self } pub fn set_account(mut self, account: Uuid) -> Cryp { self.account = account; 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 { // let mut log = vec![format!("{:?}'s turn:", self.name)]; // let str = self.str.roll(self, &mut log); // let agi = self.agi.roll(self, &mut log); // return Turn { str, agi, log } // } 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.str.set(rng.gen_range(1, max)); self.agi.set(rng.gen_range(1, max)); self.int.set(rng.gen_range(1, max)); self.stam.set(rng.gen_range(1, max)); self.hp.set(self.stam.value); self } // pub fn assign_str(&mut self, opp: &Cryp, plr_t: &mut Turn, opp_t: &Turn) -> &mut Cryp { // // let final_str = opp_t.str.result.saturating_sub(plr_t.agi.result); // // let blocked = opp_t.str.result.saturating_sub(final_str); // let final_str = opp_t.str.result & !plr_t.agi.result; // let blocked = opp_t.str.result & plr_t.agi.result; // plr_t.log.push(format!("{:064b} <- attacking roll {:?}", opp_t.str.result, opp_t.str.result)); // // plr_t.log.push(format!("{:064b} <- blocking roll {:?}", plr_t.agi.result, plr_t.agi.result)); // plr_t.log.push(format!("{:064b} <- final str {:?} ({:?} blocked)", final_str, final_str, blocked)); // self.hp.reduce(final_str); // plr_t.log.push(format!("{:?} deals {:?} str to {:?} ({:?} blocked / {:?} hp remaining)" // ,opp.name // ,final_str // ,self.name // ,blocked // ,self.hp.value)); // plr_t.log.push(format!("")); // self // } pub fn is_ko(&self) -> bool { self.hp.value == 0 } pub fn rez(&mut self) -> &mut Cryp { self.hp.set(self.stam.value); self } } pub fn cryp_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result { let query = " SELECT data FROM cryps WHERE id = $1 AND account = $2; "; let result = tx .query(query, &[&id, &account_id])?; let result = result.iter().next().ok_or(format_err!("cryp {:} not found", id))?; let cryp_bytes: Vec = result.get(0); let cryp = from_slice::(&cryp_bytes)?; return Ok(cryp); } pub fn cryp_spawn(params: CrypSpawnParams, tx: &mut Transaction, account: &Account) -> Result { let cryp = Cryp::new() .named(¶ms.name) .level(10) .set_account(account.id) .create(); let cryp_bytes = to_vec(&cryp)?; let query = " INSERT INTO cryps (id, account, data) VALUES ($1, $2, $3) RETURNING id, account; "; let result = tx .query(query, &[&cryp.id, &account.id, &cryp_bytes])?; let _returned = result.iter().next().ok_or(err_msg("no row returned"))?; println!("{:?} spawned cryp {:}", account.id, cryp.id); return Ok(cryp); } pub fn cryp_write(cryp: Cryp, tx: &mut Transaction) -> Result { let cryp_bytes = to_vec(&cryp)?; let query = " UPDATE cryps SET data = $1 WHERE id = $2 RETURNING id, account, data; "; let result = tx .query(query, &[&cryp_bytes, &cryp.id])?; let _returned = result.iter().next().expect("no row returned"); println!("{:?} wrote cryp", cryp.id); return Ok(cryp); } #[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; } }