pvp init
This commit is contained in:
@@ -30,8 +30,6 @@
|
||||
* teach cyps skills
|
||||
* can you attack yourself?
|
||||
* fetch existing battles
|
||||
* check for cryp skill already used
|
||||
* check for cryp skill ownership
|
||||
* check for game participation
|
||||
* write players row for every team+cryp added
|
||||
* return results<>
|
||||
|
||||
+1
-1
@@ -219,7 +219,7 @@ pub fn cryp_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<Cryp
|
||||
let result = tx
|
||||
.query(query, &[&id, &account_id])?;
|
||||
|
||||
let result = result.iter().next().ok_or(err_msg("cryp not found"))?;
|
||||
let result = result.iter().next().ok_or(format_err!("cryp {:} not found", id))?;
|
||||
let cryp_bytes: Vec<u8> = result.get(0);
|
||||
let cryp = from_slice::<Cryp>(&cryp_bytes)?;
|
||||
|
||||
|
||||
+124
-43
@@ -8,8 +8,8 @@ use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use account::Account;
|
||||
use rpc::{GameSkillParams, GamePveParams, GameTargetParams};
|
||||
use cryp::{Cryp, CrypStat, Stat};
|
||||
use rpc::{GameSkillParams, GamePveParams, GamePvpParams, GameTargetParams, GameJoinParams};
|
||||
use cryp::{Cryp, cryp_get};
|
||||
|
||||
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
|
||||
pub struct Roll {
|
||||
@@ -142,7 +142,7 @@ pub struct Game {
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn new() -> Game {
|
||||
fn new() -> Game {
|
||||
return Game {
|
||||
id: Uuid::new_v4(),
|
||||
team_size: 0,
|
||||
@@ -154,38 +154,40 @@ impl Game {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_team_num(&mut self, size: usize) -> &mut Game {
|
||||
fn set_team_num(&mut self, size: usize) -> &mut Game {
|
||||
self.team_num = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_team_size(&mut self, size: usize) -> &mut Game {
|
||||
fn set_team_size(&mut self, size: usize) -> &mut Game {
|
||||
self.team_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_pve(&mut self, pve: bool) -> &mut Game {
|
||||
fn set_pve(&mut self, pve: bool) -> &mut Game {
|
||||
self.is_pve = pve;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_team(&mut self, team: Team) -> &mut Game {
|
||||
// check team not already in
|
||||
fn add_team(&mut self, team: Team) -> Result<&mut Game, Error> {
|
||||
if self.teams.len() == self.team_num {
|
||||
panic!("maximum number of teams");
|
||||
return Err(err_msg("maximum number of teams"));
|
||||
}
|
||||
self.teams.push(team);
|
||||
self
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
// handle missing team properly
|
||||
pub fn team_by_id(&mut self, id: Uuid) -> &mut Team {
|
||||
fn team_by_id(&mut self, id: Uuid) -> &mut Team {
|
||||
match self.teams.iter_mut().find(|t| t.id == id) {
|
||||
Some(t) => t,
|
||||
None => panic!("id not in game {:?}", id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cryp_by_id(&mut self, id: Uuid) -> &mut Cryp {
|
||||
fn cryp_by_id(&mut self, id: Uuid) -> &mut Cryp {
|
||||
for team in self.teams.iter_mut() {
|
||||
let in_team = team.cryp_by_id(id);
|
||||
if in_team.is_some() {
|
||||
@@ -195,16 +197,16 @@ impl Game {
|
||||
panic!("cryp not in game");
|
||||
}
|
||||
|
||||
fn update_team(&mut self, updated: Team) -> &mut Game {
|
||||
match self.teams.iter().position(|t| t.id == updated.id) {
|
||||
Some(index) => {
|
||||
self.teams.remove(index);
|
||||
self.teams.push(updated);
|
||||
self
|
||||
}
|
||||
None => panic!("team not in game"),
|
||||
}
|
||||
}
|
||||
// fn update_team(&mut self, updated: Team) -> &mut Game {
|
||||
// match self.teams.iter().position(|t| t.id == updated.id) {
|
||||
// Some(index) => {
|
||||
// self.teams.remove(index);
|
||||
// self.teams.push(updated);
|
||||
// self
|
||||
// }
|
||||
// None => panic!("team not in game"),
|
||||
// }
|
||||
// }
|
||||
|
||||
fn update_cryp(&mut self, updated: Cryp) -> &mut Game {
|
||||
for team in self.teams.iter_mut() {
|
||||
@@ -217,16 +219,16 @@ impl Game {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_start(&self) -> bool {
|
||||
fn can_start(&self) -> bool {
|
||||
self.teams.len() == self.team_num
|
||||
}
|
||||
|
||||
pub fn start(&mut self) -> &mut Game {
|
||||
fn start(&mut self) -> &mut Game {
|
||||
self.skill_phase_start();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn skill_phase_start(&mut self) -> &mut Game {
|
||||
fn skill_phase_start(&mut self) -> &mut Game {
|
||||
if ![Phase::Start, Phase::Damage].contains(&self.phase) {
|
||||
panic!("game not in damage or start phase");
|
||||
}
|
||||
@@ -261,7 +263,7 @@ impl Game {
|
||||
|
||||
// skills can target any team, but we have to check if the caller is the owner of the cryp
|
||||
// and that the cryp has the skill they are trying to add
|
||||
pub fn add_skill(&mut self, team_id: Uuid, cryp_id: Uuid, target_team_id: Uuid, skill: Skill) -> Result<Uuid, Error> {
|
||||
fn add_skill(&mut self, team_id: Uuid, cryp_id: Uuid, target_team_id: Uuid, skill: Skill) -> Result<Uuid, Error> {
|
||||
if self.phase != Phase::Skill {
|
||||
return Err(err_msg("game not in skill phase"));
|
||||
}
|
||||
@@ -291,12 +293,12 @@ impl Game {
|
||||
return Ok(skill.id);
|
||||
}
|
||||
|
||||
pub fn skill_phase_finished(&self) -> bool {
|
||||
fn skill_phase_finished(&self) -> bool {
|
||||
self.teams.iter().all(|t| t.skills.len() == self.team_size)
|
||||
}
|
||||
|
||||
// move all skills into their target team's targets list
|
||||
pub fn target_phase_start(&mut self) -> &mut Game {
|
||||
fn target_phase_start(&mut self) -> &mut Game {
|
||||
if self.phase != Phase::Skill {
|
||||
panic!("game not in skill phase");
|
||||
}
|
||||
@@ -335,7 +337,7 @@ impl Game {
|
||||
|
||||
|
||||
// targets can only be added by the owner of the team
|
||||
pub fn add_target(&mut self, team_id: Uuid, cryp_id: Uuid, skill_id: Uuid) -> Result<&mut GameSkill, Error> {
|
||||
fn add_target(&mut self, team_id: Uuid, cryp_id: Uuid, skill_id: Uuid) -> Result<&mut GameSkill, Error> {
|
||||
// whose team is this?
|
||||
let team = self.team_by_id(team_id);
|
||||
|
||||
@@ -350,13 +352,13 @@ impl Game {
|
||||
Ok(skill.set_target(cryp_id))
|
||||
}
|
||||
|
||||
pub fn target_phase_finished(&self) -> bool {
|
||||
fn target_phase_finished(&self) -> bool {
|
||||
self.teams.iter().all(|t| t.incoming.iter().all(|i| i.target_cryp_id.is_some()))
|
||||
}
|
||||
|
||||
// requires no input
|
||||
// just do it
|
||||
pub fn damage_phase_start(&mut self) -> &mut Game {
|
||||
fn damage_phase_start(&mut self) -> &mut Game {
|
||||
if self.phase != Phase::Target {
|
||||
panic!("game not in target phase");
|
||||
}
|
||||
@@ -392,7 +394,7 @@ impl Game {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_finished(&self) -> bool {
|
||||
fn is_finished(&self) -> bool {
|
||||
self.teams.iter().any(|t| t.cryps.iter().all(|c| c.is_ko()))
|
||||
}
|
||||
|
||||
@@ -433,7 +435,9 @@ pub fn game_skill(params: GameSkillParams, tx: &mut Transaction, account: &Accou
|
||||
game.target_phase_start();
|
||||
}
|
||||
|
||||
return game_write(game, tx);
|
||||
game_update(&game, tx)?;
|
||||
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
pub fn game_target(params: GameTargetParams, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
||||
@@ -461,7 +465,9 @@ pub fn game_target(params: GameTargetParams, tx: &mut Transaction, account: &Acc
|
||||
game.damage_phase_start();
|
||||
}
|
||||
|
||||
return game_write(game, tx);
|
||||
game_update(&game, tx)?;
|
||||
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
pub fn game_new(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
|
||||
@@ -476,13 +482,35 @@ pub fn game_new(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
|
||||
let result = tx
|
||||
.query(query, &[&game.id, &game_bytes])?;
|
||||
|
||||
let _returned = result.iter().next().expect("no row returned");
|
||||
result.iter().next().ok_or(format_err!("no game written"))?;
|
||||
|
||||
println!("{:?} wrote game", game.id);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn game_get(tx: &mut Transaction, id: Uuid) -> Result<Game, Error> {
|
||||
let query = "
|
||||
SELECT *
|
||||
FROM games
|
||||
WHERE id = $1
|
||||
";
|
||||
|
||||
let result = tx
|
||||
.query(query, &[&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<u8> = returned.get("data");
|
||||
let game = from_slice::<Game>(&game_bytes)?;
|
||||
|
||||
return Ok(game);
|
||||
}
|
||||
|
||||
/// write a row for every cryp in a team when added to a battle
|
||||
pub fn players_write(team: &Team, game_id: Uuid, tx: &mut Transaction) -> Result<(), Error> {
|
||||
// pve
|
||||
@@ -508,7 +536,7 @@ pub fn players_write(team: &Team, game_id: Uuid, tx: &mut Transaction) -> Result
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn game_write(game: Game, tx: &mut Transaction) -> Result<Game, Error> {
|
||||
pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
|
||||
let game_bytes = to_vec(&game)?;
|
||||
|
||||
let query = "
|
||||
@@ -521,11 +549,11 @@ pub fn game_write(game: Game, tx: &mut Transaction) -> Result<Game, Error> {
|
||||
let result = tx
|
||||
.query(query, &[&game_bytes, &game.id])?;
|
||||
|
||||
let returned = result.iter().next().expect("no row returned");
|
||||
result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?;
|
||||
|
||||
println!("{:?} wrote game", game.id);
|
||||
|
||||
return Ok(game);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn generate_mob(plr: &Cryp) -> Cryp {
|
||||
@@ -589,8 +617,8 @@ pub fn game_pve(params: GamePveParams, tx: &mut Transaction, account: &Account)
|
||||
.set_cryps(vec![mob]);
|
||||
|
||||
game
|
||||
.add_team(plr_team)
|
||||
.add_team(mob_team);
|
||||
.add_team(plr_team)?
|
||||
.add_team(mob_team)?;
|
||||
|
||||
game.start();
|
||||
|
||||
@@ -601,6 +629,59 @@ pub fn game_pve(params: GamePveParams, tx: &mut Transaction, account: &Account)
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
pub fn game_pvp(params: GamePvpParams, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
||||
let cryps = params.cryp_ids
|
||||
.iter()
|
||||
.map(|id| cryp_get(tx, *id, account.id))
|
||||
.collect::<Result<Vec<Cryp>, Error>>()?;
|
||||
|
||||
// create the game
|
||||
let mut game = Game::new();
|
||||
let game_id = game.id;
|
||||
|
||||
game
|
||||
.set_pve(false)
|
||||
.set_team_num(2)
|
||||
.set_team_size(1);
|
||||
|
||||
// create the initiators team
|
||||
let mut team = Team::new(account.id);
|
||||
team.set_cryps(cryps);
|
||||
|
||||
game.add_team(team)?;
|
||||
|
||||
// persist
|
||||
game_new(&game, tx)?;
|
||||
players_write(&game.team_by_id(account.id), game_id, tx)?;
|
||||
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
pub fn game_join(params: GameJoinParams, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
||||
let mut game = game_get(tx, params.game_id)?;
|
||||
let game_id = game.id;
|
||||
|
||||
let cryps = params.cryp_ids
|
||||
.iter()
|
||||
.map(|id| cryp_get(tx, *id, account.id))
|
||||
.collect::<Result<Vec<Cryp>, Error>>()?;
|
||||
|
||||
let mut team = Team::new(account.id);
|
||||
team.set_cryps(cryps);
|
||||
|
||||
game.add_team(team)?;
|
||||
|
||||
if game.can_start() {
|
||||
game.start();
|
||||
}
|
||||
|
||||
game_update(&game, tx)?;
|
||||
players_write(&game.team_by_id(account.id), game_id, tx)?;
|
||||
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use game::*;
|
||||
@@ -640,8 +721,8 @@ mod tests {
|
||||
.set_cryps(vec![y]);
|
||||
|
||||
game
|
||||
.add_team(x_team)
|
||||
.add_team(y_team);
|
||||
.add_team(x_team).unwrap()
|
||||
.add_team(y_team).unwrap();
|
||||
|
||||
assert!(game.can_start());
|
||||
|
||||
@@ -656,8 +737,8 @@ mod tests {
|
||||
|
||||
println!("{:?}", game);
|
||||
|
||||
game.add_target(x_team_id, x_id, y_attack_id.unwrap());
|
||||
game.add_target(y_team_id, y_id, x_attack_id.unwrap());
|
||||
game.add_target(x_team_id, x_id, y_attack_id.unwrap()).unwrap();
|
||||
game.add_target(y_team_id, y_id, x_attack_id.unwrap()).unwrap();
|
||||
|
||||
assert!(game.target_phase_finished());
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ extern crate serde_cbor;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate failure;
|
||||
#[macro_use] extern crate failure;
|
||||
// #[macro_use] extern crate failure_derive;
|
||||
|
||||
mod cryp;
|
||||
|
||||
+60
-1
@@ -11,7 +11,7 @@ use failure::err_msg;
|
||||
|
||||
use net::Db;
|
||||
use cryp::{Cryp, cryp_spawn};
|
||||
use game::{Game, Skill, game_pve, game_skill, game_target};
|
||||
use game::{Game, Skill, game_pve, game_pvp, game_join, game_skill, game_target};
|
||||
use account::{Account, account_create, account_login, account_from_token, account_cryps};
|
||||
use item::{Item, items_list, item_use};
|
||||
|
||||
@@ -39,6 +39,8 @@ impl Rpc {
|
||||
let response = match v.method.as_ref() {
|
||||
"cryp_spawn" => Rpc::cryp_spawn(data, &mut tx, account, client),
|
||||
"game_pve" => Rpc::game_pve(data, &mut tx, account, client),
|
||||
"game_pvp" => Rpc::game_pvp(data, &mut tx, account, client),
|
||||
"game_join" => Rpc::game_join(data, &mut tx, account, client),
|
||||
"game_skill" => Rpc::game_skill(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),
|
||||
@@ -87,6 +89,40 @@ impl Rpc {
|
||||
return Ok(game_response);
|
||||
}
|
||||
|
||||
fn game_pvp(data: Vec<u8>, tx: &mut Transaction, account: Option<Account>, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
|
||||
let a = match account {
|
||||
Some(a) => a,
|
||||
None => return Err(err_msg("auth required")),
|
||||
};
|
||||
|
||||
let msg = from_slice::<GamePvpMsg>(&data).or(Err(err_msg("invalid params")))?;
|
||||
|
||||
let game_response = RpcResponse {
|
||||
method: "game_state".to_string(),
|
||||
params: RpcResult::GameState(game_pvp(msg.params, tx, &a)?)
|
||||
};
|
||||
|
||||
return Ok(game_response);
|
||||
}
|
||||
|
||||
|
||||
fn game_join(data: Vec<u8>, tx: &mut Transaction, account: Option<Account>, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
|
||||
let a = match account {
|
||||
Some(a) => a,
|
||||
None => return Err(err_msg("auth required")),
|
||||
};
|
||||
|
||||
let msg = from_slice::<GameJoinMsg>(&data).or(Err(err_msg("invalid params")))?;
|
||||
|
||||
let game_response = RpcResponse {
|
||||
method: "game_state".to_string(),
|
||||
params: RpcResult::GameState(game_join(msg.params, tx, &a)?)
|
||||
};
|
||||
|
||||
return Ok(game_response);
|
||||
}
|
||||
|
||||
|
||||
fn game_skill(data: Vec<u8>, tx: &mut Transaction, account: Option<Account>, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
|
||||
let a = match account {
|
||||
Some(a) => a,
|
||||
@@ -250,6 +286,29 @@ pub struct GamePveParams {
|
||||
pub id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
struct GamePvpMsg {
|
||||
method: String,
|
||||
params: GamePvpParams,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
pub struct GamePvpParams {
|
||||
pub cryp_ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
struct GameJoinMsg {
|
||||
method: String,
|
||||
params: GameJoinParams,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
pub struct GameJoinParams {
|
||||
pub game_id: Uuid,
|
||||
pub cryp_ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||
struct GameTargetMsg {
|
||||
method: String,
|
||||
|
||||
Reference in New Issue
Block a user