diff --git a/client/src/components/game.container.js b/client/src/components/game.container.js index 7f5fd849..3f504ff0 100644 --- a/client/src/components/game.container.js +++ b/client/src/components/game.container.js @@ -9,7 +9,11 @@ const addState = connect( return ws.sendGameAbility(game.id, crypId, targetTeamId, ability); } - return { game, account, sendGameAbility }; + function sendGameTarget(crypId, abilityId) { + return ws.sendGameTarget(game.id, crypId, abilityId); + } + + return { game, account, sendGameAbility, sendGameTarget }; } ); diff --git a/client/src/components/game.jsx b/client/src/components/game.jsx index 966643cb..96a3b10d 100644 --- a/client/src/components/game.jsx +++ b/client/src/components/game.jsx @@ -1,11 +1,22 @@ const preact = require('preact'); -function GamePanel({ game, sendGameAbility, account }) { +function GamePanel({ game, sendGameAbility, sendGameTarget, account }) { if (!game) return
...
; const otherTeams = game.teams.filter(t => t.id !== account.id); const playerTeam = game.teams.find(t => t.id === account.id); + + const targetBtn = playerTeam.incoming.map(i => ( + + )); + const playerCryps = playerTeam.cryps.map(c => (
{c.name}
@@ -21,6 +32,7 @@ function GamePanel({ game, sendGameAbility, account }) { return (
+

{game.phase}

them

{JSON.stringify(otherTeams)}
@@ -28,6 +40,7 @@ function GamePanel({ game, sendGameAbility, account }) {

us

{playerCryps} + {targetBtn}
) diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 357fd547..b6e6d03e 100755 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -117,6 +117,9 @@ function createSocket(store) { send({ method: 'game_ability', params: { game_id: gameId, cryp_id: crypId, target_team_id: targetTeamId, ability } }); } + function sendGameTarget(gameId, crypId, abilityId) { + send({ method: 'game_target', params: { game_id: gameId, cryp_id: crypId, ability_id: abilityId } }); + } function sendItemUse(item, target) { console.log(item, target); @@ -160,6 +163,7 @@ function createSocket(store) { sendAccountRegister, sendGamePve, sendGameAbility, + sendGameTarget, sendCrypSpawn, sendItemUse, connect, diff --git a/server/WORKLOG.md b/server/WORKLOG.md index 3e3effc5..361bb12e 100755 --- a/server/WORKLOG.md +++ b/server/WORKLOG.md @@ -26,6 +26,7 @@ * skills * offensive -> choose target ✔ + * check for cryp ability already used * check for cryp ability ownership * check for game participation * write players row for every team+cryp added diff --git a/server/src/game.rs b/server/src/game.rs index f14c54f0..97f9f659 100755 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -8,7 +8,7 @@ use failure::Error; use failure::err_msg; use account::Account; -use rpc::{GameAbilityParams, GamePveParams}; +use rpc::{GameAbilityParams, GamePveParams, GameTargetParams}; use cryp::{Cryp, CrypStat, Stat}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -86,15 +86,6 @@ impl GameAbility { } } -#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] -pub enum Phase { - Start, - GameAbility, - Target, - Damage, - Finish, -} - #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Team { id: Uuid, @@ -130,6 +121,15 @@ impl Team { } } +#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] +pub enum Phase { + Start, + Ability, + Target, + Damage, + Finish, +} + #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Game { pub id: Uuid, @@ -216,11 +216,31 @@ impl Game { panic!("game not in damage or start phase"); } - self.phase = Phase::GameAbility; + self.phase = Phase::Ability; for team in self.teams.iter_mut() { team.abilities.clear(); team.incoming.clear(); } + + if self.is_pve { + self.pve_add_abilities(); + } + + self + } + + fn pve_add_abilities(&mut self) -> &mut Game { + { + let mob_team_id = Uuid::nil(); + let teams = self.teams.clone(); + let mobs = self.team_by_id(mob_team_id).clone(); + // TODO attack multiple players based on some criteria + let player_team = teams.iter().find(|t| t.id != mob_team_id).unwrap(); + for mob in &mobs.cryps { + self.add_ability(mob_team_id, mob.id, player_team.id, Ability::Attack); + } + } + self } @@ -233,6 +253,8 @@ impl Game { None => panic!("cryp not in team"), }; + // TODO check cryp ownership + // TODO check cryp ability already used // TODO check cryp has ability let ability = GameAbility::new(cryp_id, target_team_id, ability); team.abilities.push(ability); @@ -245,8 +267,8 @@ impl Game { } // move all abilities into their target team's targets list - pub fn targets_phase_start(&mut self) -> &mut Game { - if self.phase != Phase::GameAbility { + pub fn target_phase_start(&mut self) -> &mut Game { + if self.phase != Phase::Ability { panic!("game not in ability phase"); } @@ -262,9 +284,27 @@ impl Game { } } + if self.is_pve { + self.pve_add_targets(); + } + self } + fn pve_add_targets(&mut self) -> &mut Game { + { + let mob_team_id = Uuid::nil(); + let mobs = self.team_by_id(mob_team_id).clone(); + // TODO attack multiple players based on some criteria + for incoming in &mobs.incoming { + self.add_target(mob_team_id, mobs.cryps[0].id, incoming.id); + } + } + + self + } + + // targets can only be added by the owner of the team pub fn add_target(&mut self, team_id: Uuid, cryp_id: Uuid, ability_id: Uuid) -> &mut GameAbility { // whose team is this? @@ -297,8 +337,7 @@ impl Game { self.resolve_abilities(); if self.is_finished() { - self.phase = Phase::Finish; - return self; + return self.finish() } self.ability_phase_start(); @@ -327,6 +366,17 @@ impl Game { pub fn is_finished(&self) -> bool { self.teams.iter().any(|t| t.cryps.iter().all(|c| c.is_ko())) } + + fn finish(&mut self) -> &mut Game { + self.phase = Phase::Finish; + + for team in self.teams.iter_mut() { + team.abilities.clear(); + team.incoming.clear(); + } + + self + } } pub fn game_ability(params: GameAbilityParams, tx: &mut Transaction, account: &Account) -> Result { @@ -350,6 +400,38 @@ pub fn game_ability(params: GameAbilityParams, tx: &mut Transaction, account: &A game.add_ability(account.id, params.cryp_id, params.target_team_id, params.ability); + if game.ability_phase_finished() { + game.target_phase_start(); + } + + return game_write(game, tx); +} + +pub fn game_target(params: GameTargetParams, tx: &mut Transaction, account: &Account) -> Result { + let query = " + SELECT * + FROM games + WHERE id = $1 + "; + + let result = tx + .query(query, &[¶ms.game_id])?; + + let returned = match result.iter().next() { + Some(row) => row, + None => return Err(err_msg("game not found")), + }; + + // tells from_slice to cast into a cryp + let game_bytes: Vec = returned.get("data"); + let mut game = from_slice::(&game_bytes)?; + + game.add_target(account.id, params.cryp_id, params.ability_id); + + if game.target_phase_finished() { + game.damage_phase_start(); + } + return game_write(game, tx); } @@ -540,7 +622,7 @@ mod tests { assert!(game.ability_phase_finished()); - game.targets_phase_start(); + game.target_phase_start(); println!("{:?}", game); @@ -551,7 +633,7 @@ mod tests { game.damage_phase_start(); - assert!([Phase::GameAbility, Phase::Finish].contains(&game.phase)); + assert!([Phase::Ability, Phase::Finish].contains(&game.phase)); println!("{:?}", game); diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 65fa4dbe..4b1be3fe 100755 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -11,7 +11,7 @@ use failure::err_msg; use net::Db; use cryp::{Cryp, cryp_spawn}; -use game::{Game, Ability, game_pve, game_ability}; +use game::{Game, Ability, game_pve, game_ability, game_target}; use account::{Account, account_create, account_login, account_from_token, account_cryps}; use item::{Item, items_list, item_use}; @@ -40,6 +40,7 @@ impl Rpc { "cryp_spawn" => Rpc::cryp_spawn(data, &mut tx, account, client), "game_pve" => Rpc::game_pve(data, &mut tx, account, client), "game_ability" => Rpc::game_ability(data, &mut tx, account, client), + "game_target" => Rpc::game_target(data, &mut tx, account, client), "account_create" => Rpc::account_create(data, &mut tx, account, client), "account_login" => Rpc::account_login(data, &mut tx, account, client), "account_cryps" => Rpc::account_cryps(data, &mut tx, account, client), @@ -75,7 +76,7 @@ impl Rpc { let game_response = RpcResponse { method: "game_state".to_string(), - params: RpcResult::Pve(game_pve(msg.params, tx, &a)?) + params: RpcResult::GameState(game_pve(msg.params, tx, &a)?) }; Rpc::send_msg(client, RpcResponse { @@ -96,7 +97,7 @@ impl Rpc { let game_response = RpcResponse { method: "game_state".to_string(), - params: RpcResult::Pve(game_ability(msg.params, tx, &a)?) + params: RpcResult::GameState(game_ability(msg.params, tx, &a)?) }; // Rpc::send_msg(client, RpcResponse { @@ -107,6 +108,28 @@ impl Rpc { return Ok(game_response); } + fn game_target(data: Vec, tx: &mut Transaction, account: Option, _client: &mut WebSocket) -> Result { + let a = match account { + Some(a) => a, + None => return Err(err_msg("auth required")), + }; + + let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; + + let game_response = RpcResponse { + method: "game_state".to_string(), + params: RpcResult::GameState(game_target(msg.params, tx, &a)?) + }; + + // Rpc::send_msg(client, RpcResponse { + // method: "account_cryps".to_string(), + // params: RpcResult::CrypList(account_cryps(tx, &a)?) + // })?; + + return Ok(game_response); + } + + fn cryp_spawn(data: Vec, tx: &mut Transaction, account: Option, _client: &mut WebSocket) -> Result { match from_slice::(&data) { Ok(v) => { @@ -194,7 +217,7 @@ pub enum RpcResult { SpawnCryp(Cryp), Account(Account), CrypList(Vec), - Pve(Game), + GameState(Game), ItemList(Vec), ItemUse(()), } @@ -227,6 +250,19 @@ pub struct GamePveParams { pub id: Uuid, } +#[derive(Debug,Clone,Serialize,Deserialize)] +struct GameTargetMsg { + method: String, + params: GameTargetParams, +} + +#[derive(Debug,Clone,Serialize,Deserialize)] +pub struct GameTargetParams { + pub game_id: Uuid, + pub cryp_id: Uuid, + pub ability_id: Uuid, +} + #[derive(Debug,Clone,Serialize,Deserialize)] struct GameAbilityMsg { method: String,