diff --git a/server/WORKLOG.md b/server/WORKLOG.md index e73c203b..9b0db868 100644 --- a/server/WORKLOG.md +++ b/server/WORKLOG.md @@ -13,9 +13,15 @@ cost system for items design / implement specs combo specs randomise skill speed + round system for games + join instance + is pve? add cryps to player - find opponent or do pve + level bots every round + buy out vbox + find any combos + apply to random cryp ## SOON * clean up categories diff --git a/server/src/game.rs b/server/src/game.rs index 3583ef6d..34dabb13 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -11,8 +11,8 @@ use account::Account; use rpc::{GameStateParams, GameSkillParams, GamePveParams}; use cryp::{Cryp, cryp_get}; use skill::{Skill, Cast, ResolutionResult}; -// use zone::{node_finish}; use mob::{generate_mob_team}; +use player::{Player}; pub type Log = Vec; @@ -721,6 +721,45 @@ pub fn game_pve(params: GamePveParams, tx: &mut Transaction, account: &Account) Ok(game) } +pub fn game_instance_new(tx: &mut Transaction, player: Player, pve: bool) -> Result { + // create the game + let mut game = Game::new(); + let game_id = game.id; + + game + .set_pve(pve) + .set_team_num(2) + .set_team_size(3) + .set_mode(GameMode::Pvp); + + // create the initiators team + let mut team = Team::new(player.id); + team.set_cryps(player.cryps); + + game.team_add(team)?; + + // persist + game_write(&game, tx)?; + + Ok(game) +} + +pub fn game_instance_join(tx: &mut Transaction, player: Player, game_id: Uuid) -> Result { + let mut game = game_get(tx, game_id)?; + + let mut team = Team::new(player.id); + team.set_cryps(player.cryps); + game.team_add(team)?; + + if game.can_start() { + game.start(); + } + + game_update(&game, tx)?; + + Ok(game) +} + #[cfg(test)] mod tests { use game::*; diff --git a/server/src/instance.rs b/server/src/instance.rs index febbd87f..932b4ee6 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -7,10 +7,14 @@ use postgres::transaction::Transaction; use failure::Error; use failure::err_msg; -use rpc::{InstanceJoinParams}; +use std::iter; + +use rpc::{InstanceJoinParams, InstanceReadyParams}; use account::Account; -use player::{Player, player_create}; +use player::{Player, player_create, player_get}; use cryp::{Cryp, cryp_get}; +use mob::{generate_mob}; +use game::{Game, game_get, game_instance_new, game_instance_join}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] enum InstancePhase { @@ -20,12 +24,21 @@ enum InstancePhase { Finished, } +#[derive(Debug,Clone,Serialize,Deserialize)] +struct Round { + player_ids: Vec, + game_id: Option, + winner_id: Option, +} + #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Instance { id: Uuid, - players: Vec, + players: Vec, phase: InstancePhase, + rounds: Vec>, open: bool, + pve: bool, } impl Instance { @@ -33,15 +46,112 @@ impl Instance { Instance { id: Uuid::new_v4(), players: vec![], + rounds: vec![], phase: InstancePhase::Open, open: true, + pve: false, } } - fn add_player(&mut self, player: &Player) -> &mut Instance { - self.players.push(player.id); + fn add_bots(mut self) -> Instance { + self.pve = true; + self.players = iter::repeat_with(|| { + let bot_id = Uuid::new_v4(); + let cryps = iter::repeat_with(|| generate_mob(1).set_account(bot_id)).take(3).collect::>(); + Player::new(bot_id, self.id, cryps).set_bot(true) + }) + .take(15) + .collect::>(); self } + + fn add_player(&mut self, player: Player) -> &mut Instance { + self.players.push(player); + self + } + + fn update_player(mut self, player: Player) -> Result { + let i = self.players + .iter() + .position(|p| p.id == player.id) + .ok_or(err_msg("player_id not found"))?; + + self.players[i] = player; + + Ok(self) + } + + fn can_start(&self) -> bool { + match self.pve { + true => self.players.len() == 16, + false => self.players.len() == 2, + } + } + + fn start(&mut self) -> &mut Instance { + // self.players.sort_unstable_by_key(|p| p.id); + self.generate_rounds(); + self.phase = InstancePhase::Vbox; + + self + } + + fn progress(&mut self) -> &mut Instance { + if self.pve { + let r = self.rounds.len() - 1; + for mut round in self.rounds[r].iter_mut() { + if self.players + .iter() + .filter(|p| round.player_ids.contains(&p.id) && p.bot) + .count() == 2 { + // play bot game + } + } + } + + self + } + + fn generate_rounds(&mut self) -> &mut Instance { + let round_num = self.rounds.len(); + let mut matched_players = self.players + .iter() + .map(|p| p.id) + .collect::>(); + + if round_num > 0 { + matched_players.rotate_right(round_num); + matched_players.swap(0,1); + } + + // only set up for even player numbers atm + // no byes + let np = matched_players.len(); + let current_round = matched_players[0..(np / 2) - 1] + .iter() + .enumerate() + .map(|(i, id)| Round { + player_ids: vec![*id, matched_players[np - (i + 1)]], + game_id: None, + winner_id: None, + }) + .collect::>(); + + self.rounds.push(current_round); + + self + } + + fn next_game_id(&self, player: &Player) -> Option { + let current_round = self.rounds.len() - 1; + + let next_round = self.rounds[current_round] + .iter() + .find(|g| g.player_ids.contains(&player.id)) + .unwrap(); + + return next_round.game_id; + } } pub fn instance_create(instance: Instance, tx: &mut Transaction) -> Result { @@ -125,9 +235,12 @@ pub fn instance_get_open(tx: &mut Transaction) -> Result { pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account: &Account) -> Result { - let mut instance = match instance_get_open(tx) { - Ok(i) => i, - Err(_) => instance_create(Instance::new(), tx)?, + let mut instance = match params.pve { + true => instance_create(Instance::new().add_bots(), tx)?, + false => match instance_get_open(tx) { + Ok(i) => i, + Err(_) => instance_create(Instance::new(), tx)?, + }, }; let cryps = params.cryp_ids @@ -140,10 +253,32 @@ pub fn instance_join(params: InstanceJoinParams, tx: &mut Transaction, account: } let player = Player::new(account.id, instance.id, cryps); - instance.add_player(&player); - player_create(tx, &player, account)?; + + instance.add_player(player.clone()); instance_write(instance, tx)?; return Ok(player); } + +pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account: &Account) -> Result { + let player = player_get(tx, account.id, params.instance_id)?; + + let instance = instance_get(tx, params.instance_id)? + .update_player(player.clone())?; + + let game_id = instance.next_game_id(&player); + + let game = match game_id { + Some(id) => game_instance_join(tx, player, id)?, + None => { + let game = game_instance_new(tx, player, instance.pve)?; + // instance. + game + }, + }; + + instance_write(instance, tx)?; + + return Ok(game); +} diff --git a/server/src/mob.rs b/server/src/mob.rs index 969a3104..a90adab8 100644 --- a/server/src/mob.rs +++ b/server/src/mob.rs @@ -8,7 +8,7 @@ use cryp::{Cryp}; use game::{Team, GameMode}; use skill::{Skill}; -fn generate_mob(lvl: u8) -> Cryp { +pub fn generate_mob(lvl: u8) -> Cryp { let mut rng = thread_rng(); let name: String = iter::repeat(()) diff --git a/server/src/player.rs b/server/src/player.rs index 3009b447..2c50c0b1 100644 --- a/server/src/player.rs +++ b/server/src/player.rs @@ -27,6 +27,7 @@ pub struct Player { pub vbox: Vbox, pub score: Score, pub cryps: Vec, + pub bot: bool, } impl Player { @@ -38,8 +39,14 @@ impl Player { vbox: Vbox::new(account, instance), score: Score { wins: 0, losses: 0 }, cryps, + bot: false, } } + + pub fn set_bot(mut self, bot: bool) -> Player { + self.bot = bot; + self + } } pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) -> Result { diff --git a/server/src/rpc.rs b/server/src/rpc.rs index fc3ade17..ae8a8b84 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -15,14 +15,14 @@ use failure::Error; use failure::err_msg; use net::Db; -use cryp::{Cryp, cryp_spawn, cryp_learn}; +use cryp::{Cryp, cryp_spawn}; use game::{Game, game_state, game_pve, game_skill}; use account::{Account, account_create, account_login, account_from_token, account_cryps, account_players}; use skill::{Skill}; // use zone::{Zone, zone_create, zone_join, zone_close}; use spec::{Spec}; use player::{player_state, player_create, player_cryps_set, Player}; -use instance::{instance_join}; +use instance::{instance_join, instance_ready}; use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_drop}; pub struct Rpc; @@ -188,13 +188,13 @@ impl Rpc { let account = account_create(AccountCreateParams { name: acc_name, password: "grepgrepgrep".to_string() }, tx)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); - let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?; + cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); - let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?; + cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect(); - let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?; + cryp_spawn(CrypSpawnParams { name }, tx, &account)?; let player = Player::new(account.id, Uuid::nil(), vec![]); player_create(tx, &player, &account)?; @@ -273,6 +273,18 @@ impl Rpc { return Ok(response); } + fn instance_ready(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { + let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; + + let response = RpcResponse { + method: "instance_state".to_string(), + params: RpcResult::GameState(instance_ready(msg.params, tx, &account)?) + }; + + return Ok(response); + } + + fn player_state(data: Vec, tx: &mut Transaction, account: Account, _client: &mut WebSocket) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; @@ -538,6 +550,18 @@ struct InstanceJoinMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct InstanceJoinParams { pub cryp_ids: Vec, + pub pve: bool, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +struct InstanceReadyMsg { + method: String, + params: InstanceReadyParams, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct InstanceReadyParams { + pub instance_id: Uuid, } #[derive(Debug,Clone,Serialize,Deserialize)]