diff --git a/server/Cargo.toml b/server/Cargo.toml index 725929a2..e3edacc1 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["ntr "] [dependencies] -rand = "0.5" +rand = "0.6" uuid = { version = "0.5", features = ["serde", "v4"] } serde = "1" serde_derive = "1" diff --git a/server/WORKLOG.md b/server/WORKLOG.md index 5f5e5e6c..071d97c3 100644 --- a/server/WORKLOG.md +++ b/server/WORKLOG.md @@ -13,7 +13,6 @@ strangle ## NOW * pve granted stat reroll items - ## SOON * tutorial * aoe skills @@ -21,13 +20,10 @@ strangle * modifies skill base speed * skills - * handle setting account better maybe? - * calculate - * hp increase/decrease * private fields for opponents -* handle unserializable cryps ## LATER +* redis for game events * chat * notifications * rejoin in progress games diff --git a/server/src/account.rs b/server/src/account.rs index f0541c97..676a32fd 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -8,7 +8,6 @@ use serde_cbor::{from_slice}; use postgres::transaction::Transaction; use rpc::{AccountCreateParams, AccountLoginParams}; -use item::{Item, ItemAction, item_create}; use cryp::{Cryp, CrypRecover, cryp_write}; use game::Game; @@ -102,11 +101,6 @@ pub fn account_create(params: AccountCreateParams, tx: &mut Transaction) -> Resu println!("{:?} registered", entry.name); - // give them a revive - let revive = Item::new(ItemAction::Revive, &entry); - item_create(revive, tx, &entry)?; - - return Ok(entry); } diff --git a/server/src/cryp.rs b/server/src/cryp.rs index 81e2dfe7..4c77fbb5 100644 --- a/server/src/cryp.rs +++ b/server/src/cryp.rs @@ -558,51 +558,3 @@ mod tests { return; } } - - - // pub fn assign_str(&mut self, opp: &Cryp, plr_t: &mut Turn, opp_t: &Turn) -> &mut Cryp { - // // let final_str = opp_t.phys_dmg.result.saturating_sub(plr_t.agi.result); - // // let blocked = opp_t.phys_dmg.result.saturating_sub(final_str); - - // let final_str = opp_t.phys_dmg.result & !plr_t.agi.result; - // let blocked = opp_t.phys_dmg.result & plr_t.agi.result; - - // plr_t.log.push(format!("{:064b} <- attacking roll {:?}", opp_t.phys_dmg.result, opp_t.phys_dmg.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.base)); - - // plr_t.log.push(format!("")); - // 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.base; - - // log.push(format!("{:064b} & <- attribute roll", self.base)); - // log.push(format!("{:064b} = {:?}", roll.result, roll.result)); - // log.push(format!("")); - - // return roll; - // } diff --git a/server/src/game.rs b/server/src/game.rs index a658a90e..d259d062 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -14,6 +14,7 @@ use account::Account; use rpc::{GameStateParams, GameSkillParams, GamePveParams, GamePvpParams, GameTargetParams, GameJoinParams}; use cryp::{Cryp, cryp_get}; use skill::{Skill, Cast, ResolutionResult}; +use item::{item_drop}; pub type Log = Vec; @@ -514,7 +515,7 @@ impl Game { // handle cooldowns and statuses self.progress_durations(); - if self.is_finished() { + if self.finished() { return self.finish() } @@ -551,13 +552,18 @@ impl Game { self } - fn is_finished(&self) -> bool { + fn finished(&self) -> bool { self.teams.iter().any(|t| t.cryps.iter().all(|c| c.is_ko())) } + fn winner(&self) -> Option<&Team> { + self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko())) + } + fn finish(&mut self) -> &mut Game { self.phase = Phase::Finish; self.log.push(format!("Game finished.")); + self.stack.clear(); { let winner = self.teams.iter().find(|t| t.cryps.iter().any(|c| !c.is_ko())); @@ -567,8 +573,6 @@ impl Game { }; } - self.stack.clear(); - self } } @@ -717,7 +721,13 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> { result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?; - // println!("{:} wrote game", game.id); + if game.finished() { + if let Some(t) = game.winner() { + if !t.id.is_nil() { + item_drop(tx, t.id)?; + } + } + } return Ok(()); } diff --git a/server/src/item.rs b/server/src/item.rs index a86ac114..36046178 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -3,7 +3,11 @@ use uuid::Uuid; use postgres::transaction::Transaction; use failure::Error; -use failure::err_msg; + +// drops +use rand::prelude::*; +use rand::{thread_rng, Rng}; +use rand::distributions::{WeightedIndex}; use account::Account; use rpc::{ItemUseParams}; @@ -12,7 +16,9 @@ use cryp::{cryp_get, cryp_write}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum ItemAction { - Revive, + RerollPhysDamage, + RerollSpellDamage, + RerollStamina, } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -24,18 +30,20 @@ pub struct Item { } impl Item { - pub fn new(action: ItemAction, account: &Account) -> Item { + pub fn new(action: ItemAction, account_id: Uuid) -> Item { let id = Uuid::new_v4(); return Item { id, - account: account.id, + account: account_id, action, }; } fn apply(&mut self, tx: &mut Transaction, target: Uuid) -> Result<(), Error> { match self.action { - ItemAction::Revive => revive(self, tx, target), + ItemAction::RerollStamina => revive(self, tx, target), + ItemAction::RerollPhysDamage => revive(self, tx, target), + ItemAction::RerollSpellDamage => revive(self, tx, target), } } } @@ -47,7 +55,26 @@ fn revive(item: &mut Item, tx: &mut Transaction, target: Uuid) -> Result<(), Err return Ok(()); } -pub fn item_create(item: Item, tx: &mut Transaction, account: &Account) -> Result { +pub fn item_drop(tx: &mut Transaction, account_id: Uuid) -> Result { + let mut rng = thread_rng(); + + let actions = [ + (ItemAction::RerollStamina, 1), + (ItemAction::RerollPhysDamage, 1), + (ItemAction::RerollSpellDamage, 1) + ]; + + let dist = WeightedIndex::new(actions.iter().map(|item| item.1)).unwrap(); + let kind = actions[dist.sample(&mut rng)].0; + let item = Item::new(kind, account_id); + + println!("{:?} dropped {:?}", account_id, item); + + return item_create(item, tx, account_id); +} + + +pub fn item_create(item: Item, tx: &mut Transaction, account_id: Uuid) -> Result { let item_bytes = to_vec(&item)?; let query = " @@ -57,11 +84,11 @@ pub fn item_create(item: Item, tx: &mut Transaction, account: &Account) -> Resul "; let result = tx - .query(query, &[&item.id, &account.id, &item_bytes])?; + .query(query, &[&item.id, &account_id, &item_bytes])?; - let _returned = result.iter().next().expect("no row returned"); + result.iter().next().expect("no row returned"); - println!("{:?} wrote item {:}", account.id, item.id); + println!("{:?} wrote item {:}", account_id, item.id); return Ok(item); } @@ -84,13 +111,33 @@ pub fn item_use(params: ItemUseParams, tx: &mut Transaction, account: &Account) let mut item = from_slice::(&item_bytes)?; item.apply(tx, params.target)?; + item_delete(tx, params.item)?; + + return Ok(()); +} + +pub fn item_delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> { + let query = " + DELETE + FROM items + WHERE id = $1; + "; + + let result = tx + .execute(query, &[&id])?; + + if result != 1 { + return Err(format_err!("unable to delete item {:?}", id)); + } + + println!("invalid item deleted {:?}", id); return Ok(()); } pub fn items_list(tx: &mut Transaction, account: &Account) -> Result, Error> { let query = " - SELECT data + SELECT data, id FROM items WHERE account = $1; "; @@ -98,18 +145,21 @@ pub fn items_list(tx: &mut Transaction, account: &Account) -> Result, let result = tx .query(query, &[&account.id])?; - let items: Result, _> = result.iter().map(|row| { - let item_bytes: Vec = row.get(0); - from_slice::(&item_bytes) - }).collect(); + let mut items = vec![]; - // catch any errors - if items.is_err() { - return Err(err_msg("could not deserialize an item")); + for row in result.into_iter() { + let item_bytes: Vec = row.get(0); + let id = row.get(1); + + match from_slice::(&item_bytes) { + Ok(i) => items.push(i), + Err(_e) => { + item_delete(tx, id)?; + } + }; } - // now unwrap is safe - return Ok(items.unwrap()); + return Ok(items); } // # max damage potion diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 25c8e766..643a7d0b 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -7,7 +7,7 @@ use std::net::{TcpStream}; // demo use std::iter; use rand::{thread_rng, Rng}; -use rand::distributions::Alphanumeric; +use rand::distributions::{Alphanumeric}; use serde_cbor::{from_slice, to_vec}; use uuid::Uuid; @@ -164,11 +164,6 @@ impl Rpc { params: RpcResult::GameState(game_skill(msg.params, tx, &account)?) }; - // Rpc::send_msg(client, RpcResponse { - // method: "account_cryps".to_string(), - // params: RpcResult::CrypList(account_cryps(tx, &account)?) - // })?; - return Ok(game_response); } @@ -180,11 +175,6 @@ impl Rpc { params: RpcResult::GameState(game_target(msg.params, tx, &account)?) }; - // Rpc::send_msg(client, RpcResponse { - // method: "account_cryps".to_string(), - // params: RpcResult::CrypList(account_cryps(tx, &account)?) - // })?; - return Ok(game_response); } diff --git a/server/src/skill.rs b/server/src/skill.rs index b6993749..2e9eed89 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -355,6 +355,9 @@ pub enum Skill { Calm, Rez, + // Sleep, + // Nightmare, + // ------------------- // Destruction // -------------------