mob modes
This commit is contained in:
parent
aaf2991a13
commit
9fa2a94ade
@ -17,6 +17,10 @@ strangle
|
|||||||
## SOON
|
## SOON
|
||||||
* aoe skills
|
* aoe skills
|
||||||
|
|
||||||
|
* hash cryp name for avatar
|
||||||
|
|
||||||
|
* order cryps based on id
|
||||||
|
|
||||||
* keep track of games joined
|
* keep track of games joined
|
||||||
* concede game on leave
|
* concede game on leave
|
||||||
* ko all cryps on team, check status
|
* ko all cryps on team, check status
|
||||||
@ -28,6 +32,8 @@ strangle
|
|||||||
* skills
|
* skills
|
||||||
* private fields for opponents
|
* private fields for opponents
|
||||||
|
|
||||||
|
* flavour text
|
||||||
|
|
||||||
## LATER
|
## LATER
|
||||||
* redis for game events
|
* redis for game events
|
||||||
* chat
|
* chat
|
||||||
|
|||||||
@ -117,7 +117,7 @@ impl Cryp {
|
|||||||
hp: CrypStat { base: 0, stat: Stat::Hp },
|
hp: CrypStat { base: 0, stat: Stat::Hp },
|
||||||
lvl: 0,
|
lvl: 0,
|
||||||
xp: 0,
|
xp: 0,
|
||||||
skills: vec![CrypSkill::new(Skill::Attack)],
|
skills: vec![],
|
||||||
effects: vec![],
|
effects: vec![],
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
ko_logged: false,
|
ko_logged: false,
|
||||||
@ -268,6 +268,23 @@ impl Cryp {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mob_select_skill(&self) -> Option<Skill> {
|
||||||
|
let available = self.available_skills();
|
||||||
|
|
||||||
|
if available.len() == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let highest_cd = available.iter()
|
||||||
|
.filter(|s| s.skill.base_cd().is_some())
|
||||||
|
.max_by_key(|s| s.skill.base_cd().unwrap());
|
||||||
|
|
||||||
|
return match highest_cd {
|
||||||
|
Some(s) => Some(s.skill),
|
||||||
|
None => Some(available[0].skill),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn knows(&self, skill: Skill) -> bool {
|
pub fn knows(&self, skill: Skill) -> bool {
|
||||||
self.skills.iter().any(|s| s.skill == skill)
|
self.skills.iter().any(|s| s.skill == skill)
|
||||||
}
|
}
|
||||||
@ -499,6 +516,7 @@ pub fn cryp_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<Cryp
|
|||||||
pub fn cryp_spawn(params: CrypSpawnParams, tx: &mut Transaction, account: &Account) -> Result<Cryp, Error> {
|
pub fn cryp_spawn(params: CrypSpawnParams, tx: &mut Transaction, account: &Account) -> Result<Cryp, Error> {
|
||||||
let cryp = Cryp::new()
|
let cryp = Cryp::new()
|
||||||
.named(¶ms.name)
|
.named(¶ms.name)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.level(10)
|
.level(10)
|
||||||
.set_account(account.id)
|
.set_account(account.id)
|
||||||
.create();
|
.create();
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use uuid::Uuid;
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand::distributions::Alphanumeric;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
// Db Commons
|
// Db Commons
|
||||||
use serde_cbor::{from_slice, to_vec};
|
use serde_cbor::{from_slice, to_vec};
|
||||||
@ -16,15 +13,10 @@ use cryp::{Cryp, cryp_get};
|
|||||||
use skill::{Skill, Cast, ResolutionResult};
|
use skill::{Skill, Cast, ResolutionResult};
|
||||||
use item::{item_drop};
|
use item::{item_drop};
|
||||||
use zone::{node_finish};
|
use zone::{node_finish};
|
||||||
|
use mob::{PveMode, generate_mob_team};
|
||||||
|
|
||||||
pub type Log = Vec<String>;
|
pub type Log = Vec<String>;
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
|
||||||
pub enum PveMode {
|
|
||||||
Boss,
|
|
||||||
Normal,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct Team {
|
pub struct Team {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
@ -214,13 +206,27 @@ impl Game {
|
|||||||
let mob_team_id = Uuid::nil();
|
let mob_team_id = Uuid::nil();
|
||||||
let mobs = self.team_by_id(mob_team_id).clone();
|
let mobs = self.team_by_id(mob_team_id).clone();
|
||||||
|
|
||||||
// TODO attack multiple players based on some criteria
|
|
||||||
let player_team = self.teams.iter().find(|t| t.id != mob_team_id).unwrap().clone();
|
let player_team = self.teams.iter().find(|t| t.id != mob_team_id).unwrap().clone();
|
||||||
let player_len = player_team.cryps.len();
|
let player_len = player_team.cryps.len();
|
||||||
|
|
||||||
for (i, mob) in mobs.cryps.iter().enumerate() {
|
for mob in mobs.cryps.iter() {
|
||||||
// doesn't matter if the cryp can't cast
|
let skill = mob.mob_select_skill();
|
||||||
self.add_skill(mob_team_id, mob.id, Some(player_team.cryps[player_len % (i + 1)].id), Skill::Attack).ok();
|
// println!("{:?} {:?}", mob.name, skill);
|
||||||
|
match skill {
|
||||||
|
Some(s) => {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let mut target = &player_team.cryps[rng.gen_range(0, player_len)];
|
||||||
|
while target.is_ko() {
|
||||||
|
target = &player_team.cryps[rng.gen_range(0, player_len)];
|
||||||
|
}
|
||||||
|
match self.add_skill(mob_team_id, mob.id, Some(target.id), s) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => println!("{:?} could not add pve skill", e),
|
||||||
|
}
|
||||||
|
// println!("{:?}", cast);
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,10 +248,15 @@ impl Game {
|
|||||||
|
|
||||||
// target checks
|
// target checks
|
||||||
{
|
{
|
||||||
let _target = match self.cryp_by_id(final_target_id) {
|
let target = match self.cryp_by_id(final_target_id) {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
None => return Err(err_msg("target cryp not in game")),
|
None => return Err(err_msg("target cryp not in game")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// fixme for rez
|
||||||
|
if target.is_ko() {
|
||||||
|
return Err(err_msg("target cryp is ko"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cryp checks
|
// cryp checks
|
||||||
@ -275,12 +286,6 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
|
||||||
// let (target_cryp_id, target_team_id) = match skill.self_targeting() {
|
|
||||||
// true => (Some(source_cryp_id), source_team_id),
|
|
||||||
// false => (None, target_team_id.unwrap())
|
|
||||||
// };
|
|
||||||
|
|
||||||
// replace cryp skill
|
// replace cryp skill
|
||||||
if let Some(s) = self.stack.iter_mut().position(|s| s.source_cryp_id == source_cryp_id) {
|
if let Some(s) = self.stack.iter_mut().position(|s| s.source_cryp_id == source_cryp_id) {
|
||||||
self.stack.remove(s);
|
self.stack.remove(s);
|
||||||
@ -304,129 +309,6 @@ impl Game {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn target_phase_start(&mut self) -> &mut Game {
|
|
||||||
// assert!(self.skill_phase_finished());
|
|
||||||
// self.log.push("<Target Phase>".to_string());
|
|
||||||
|
|
||||||
// if self.phase != Phase::Skill {
|
|
||||||
// panic!("game not in skill phase");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self.phase = Phase::Target;
|
|
||||||
|
|
||||||
// if self.is_pve {
|
|
||||||
// self.pve_add_targets();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // all cryps are stunned or otherwise inactive
|
|
||||||
// if self.target_phase_finished() {
|
|
||||||
// self.resolve_phase_start();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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 (i, incoming_skill_id) in self.stack.clone().iter()
|
|
||||||
// .filter(|s| s.target_cryp_id.is_none() && s.target_team_id == mob_team_id)
|
|
||||||
// .enumerate()
|
|
||||||
// .map(|(i, s)| (i, s.id)) {
|
|
||||||
// let targets = mobs.cryps
|
|
||||||
// .iter()
|
|
||||||
// .filter(|c| self.cryp_targetable(mob_team_id, c.id).is_ok())
|
|
||||||
// .collect::<Vec<&Cryp>>();
|
|
||||||
|
|
||||||
// if targets.len() == 0 {
|
|
||||||
// panic!("could not find a targetable pve cryp");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let target_id = targets[i % targets.len()].id;
|
|
||||||
// self.add_target(mob_team_id, target_id, incoming_skill_id).unwrap();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self
|
|
||||||
// }
|
|
||||||
|
|
||||||
// each cryp can be the target of
|
|
||||||
// incomingSkills / activeCryps rounded up
|
|
||||||
// maybe a problem with friendly / self targeting skills
|
|
||||||
fn cryp_targetable(&mut self, team_id: Uuid, cryp_id: Uuid) -> Result<(), Error> {
|
|
||||||
// whose team is this?
|
|
||||||
let team = self.teams.iter()
|
|
||||||
.find(|t| t.id == team_id)
|
|
||||||
.ok_or(err_msg("team not found"))?;
|
|
||||||
|
|
||||||
// is the target in the team?
|
|
||||||
let cryp = team.cryps.iter()
|
|
||||||
.find(|c| c.id == cryp_id)
|
|
||||||
.ok_or(err_msg("cryp not in team"))?;
|
|
||||||
|
|
||||||
if cryp.is_ko() {
|
|
||||||
return Err(err_msg("you cannot target ko cryps"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// let incoming = self.stack.iter()
|
|
||||||
// .filter(|i| i.target_team_id == team.id)
|
|
||||||
// .count();
|
|
||||||
|
|
||||||
// let incoming = incoming as u32 as f64;
|
|
||||||
|
|
||||||
// let active_cryps = team.cryps.iter()
|
|
||||||
// .filter(|c| !c.is_ko())
|
|
||||||
// .count();
|
|
||||||
|
|
||||||
// let active_cryps = active_cryps as u32 as f64;
|
|
||||||
// let max_targets = (incoming / active_cryps).ceil();
|
|
||||||
|
|
||||||
// // println!("targets {:} / {:} = {:}", incoming, active_cryps, max_targets);
|
|
||||||
|
|
||||||
// let targeted = self.stack.iter()
|
|
||||||
// .filter(|s| s.target_cryp_id.is_some())
|
|
||||||
// .filter(|s| s.target_cryp_id.unwrap() == cryp_id)
|
|
||||||
// .count();
|
|
||||||
|
|
||||||
// if targeted >= max_targets as usize {
|
|
||||||
// return Err(format_err!("cryp target of maximum number of skills ({:})", max_targets));
|
|
||||||
// }
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// targets can only be added by the owner of the team
|
|
||||||
// fn add_target(&mut self, team_id: Uuid, cryp_id: Uuid, skill_id: Uuid) -> Result<&mut Cast, Error> {
|
|
||||||
// if self.phase != Phase::Target {
|
|
||||||
// return Err(err_msg("game not in target phase"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self.cryp_targetable(team_id, cryp_id)?;
|
|
||||||
|
|
||||||
// // set the target
|
|
||||||
// let cast = match self.stack.iter_mut().find(|s| s.id == skill_id) {
|
|
||||||
// Some(c) => c,
|
|
||||||
// None => return Err(err_msg("skill_id not found")),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if cast.skill.self_targeting() {
|
|
||||||
// return Err(err_msg("skill is self targeting"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if cast.target_team_id != team_id {
|
|
||||||
// return Err(err_msg("you cannot target that skill"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ok(cast.set_target(cryp_id))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn target_phase_finished(&self) -> bool {
|
|
||||||
// self.stack.iter().all(|s| s.target_cryp_id.is_some())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// requires no input
|
// requires no input
|
||||||
// just do it
|
// just do it
|
||||||
fn resolve_phase_start(&mut self) -> &mut Game {
|
fn resolve_phase_start(&mut self) -> &mut Game {
|
||||||
@ -760,52 +642,6 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mob(lvl: u8) -> Cryp {
|
|
||||||
let mut rng = thread_rng();
|
|
||||||
|
|
||||||
let name: String = iter::repeat(())
|
|
||||||
.map(|()| rng.sample(Alphanumeric))
|
|
||||||
.take(8)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// rng panics on min == max
|
|
||||||
// let mob_lvl: u8 = match lvl {
|
|
||||||
// 1 => 1,
|
|
||||||
// _ => rng.gen_range(lvl.saturating_sub(2), lvl)
|
|
||||||
// };
|
|
||||||
|
|
||||||
return Cryp::new()
|
|
||||||
.named(&name)
|
|
||||||
.level(lvl)
|
|
||||||
.create();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_mob_team(mode: PveMode, cryps: &Vec<Cryp>) -> Team {
|
|
||||||
let mut mob_team = Team::new(Uuid::nil());
|
|
||||||
|
|
||||||
// Default settings
|
|
||||||
let mut team_size = 1;
|
|
||||||
|
|
||||||
// Modify the NPC cryps for game mode settings
|
|
||||||
let mob_lvl = match mode {
|
|
||||||
PveMode::Normal => {
|
|
||||||
team_size = cryps.len();
|
|
||||||
cryps.iter().max_by_key(|c| c.lvl).unwrap().lvl
|
|
||||||
},
|
|
||||||
PveMode::Boss => cryps.iter().max_by_key(|c| c.lvl).unwrap().lvl + 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate and return the NPC team based on settings
|
|
||||||
let mobs = iter::repeat_with(|| generate_mob(mob_lvl).set_account(Uuid::nil()))
|
|
||||||
.take(team_size)
|
|
||||||
.collect::<Vec<Cryp>>();
|
|
||||||
mob_team.set_cryps(mobs);
|
|
||||||
|
|
||||||
return mob_team;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn game_pve_new(cryp_ids: Vec<Uuid>, mode: PveMode, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
pub fn game_pve_new(cryp_ids: Vec<Uuid>, mode: PveMode, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
||||||
let cryps = cryp_ids
|
let cryps = cryp_ids
|
||||||
.iter()
|
.iter()
|
||||||
@ -948,6 +784,7 @@ mod tests {
|
|||||||
let x = Cryp::new()
|
let x = Cryp::new()
|
||||||
.named(&"pronounced \"creeep\"".to_string())
|
.named(&"pronounced \"creeep\"".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestStun)
|
.learn(Skill::TestStun)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.learn(Skill::TestBlock)
|
.learn(Skill::TestBlock)
|
||||||
@ -960,6 +797,7 @@ mod tests {
|
|||||||
let y = Cryp::new()
|
let y = Cryp::new()
|
||||||
.named(&"lemongrass tea".to_string())
|
.named(&"lemongrass tea".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestStun)
|
.learn(Skill::TestStun)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.learn(Skill::TestBlock)
|
.learn(Skill::TestBlock)
|
||||||
@ -1001,24 +839,28 @@ mod tests {
|
|||||||
let i = Cryp::new()
|
let i = Cryp::new()
|
||||||
.named(&"pretaliate".to_string())
|
.named(&"pretaliate".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let j = Cryp::new()
|
let j = Cryp::new()
|
||||||
.named(&"poy sian".to_string())
|
.named(&"poy sian".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let x = Cryp::new()
|
let x = Cryp::new()
|
||||||
.named(&"pronounced \"creeep\"".to_string())
|
.named(&"pronounced \"creeep\"".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let y = Cryp::new()
|
let y = Cryp::new()
|
||||||
.named(&"lemongrass tea".to_string())
|
.named(&"lemongrass tea".to_string())
|
||||||
.level(8)
|
.level(8)
|
||||||
|
.learn(Skill::Attack)
|
||||||
.learn(Skill::TestTouch)
|
.learn(Skill::TestTouch)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
@ -1113,8 +955,6 @@ mod tests {
|
|||||||
assert!(game.skill_phase_finished());
|
assert!(game.skill_phase_finished());
|
||||||
game.resolve_phase_start();
|
game.resolve_phase_start();
|
||||||
|
|
||||||
// resolution should have been prevented by KO
|
|
||||||
// println!("{:#?}", game);
|
|
||||||
assert!(!game.team_by_id(y_team.id).cryps[0].is_stunned());
|
assert!(!game.team_by_id(y_team.id).cryps[0].is_stunned());
|
||||||
assert!(game.phase == Phase::Finish);
|
assert!(game.phase == Phase::Finish);
|
||||||
}
|
}
|
||||||
@ -1220,18 +1060,20 @@ mod tests {
|
|||||||
// kill a cryp
|
// kill a cryp
|
||||||
game.team_by_id(i_team.id).cryp_by_id(i_cryp.id).unwrap().hp.reduce(u64::max_value());
|
game.team_by_id(i_team.id).cryp_by_id(i_cryp.id).unwrap().hp.reduce(u64::max_value());
|
||||||
|
|
||||||
|
assert!(game.team_by_id(i_team.id).skills_required() == 1);
|
||||||
|
assert!(game.team_by_id(x_team.id).skills_required() == 2);
|
||||||
|
|
||||||
// add some more skills
|
// add some more skills
|
||||||
game.add_skill(i_team.id, j_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
|
game.add_skill(i_team.id, j_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
|
||||||
game.add_skill(x_team.id, x_cryp.id, Some(i_cryp.id), Skill::TestTouch).unwrap();
|
game.add_skill(x_team.id, x_cryp.id, Some(j_cryp.id), Skill::TestTouch).unwrap();
|
||||||
game.add_skill(x_team.id, y_cryp.id, Some(i_cryp.id), Skill::TestTouch).unwrap();
|
game.add_skill(x_team.id, y_cryp.id, Some(j_cryp.id), Skill::TestTouch).unwrap();
|
||||||
|
assert!(game.add_skill(x_team.id, x_cryp.id, Some(i_cryp.id), Skill::TestTouch).is_err());
|
||||||
|
|
||||||
assert!(game.skill_phase_finished());
|
assert!(game.skill_phase_finished());
|
||||||
game.resolve_phase_start();
|
game.resolve_phase_start();
|
||||||
|
|
||||||
assert!(game.team_by_id(i_team.id).skills_required() == 1);
|
assert!(game.team_by_id(i_team.id).skills_required() == 1);
|
||||||
assert!(game.cryp_targetable(i_team.id, i_cryp.id).is_err());
|
assert!(game.team_by_id(x_team.id).skills_required() == 2);
|
||||||
assert!(game.cryp_targetable(i_team.id, j_cryp.id).is_ok());
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ mod rpc;
|
|||||||
mod account;
|
mod account;
|
||||||
mod item;
|
mod item;
|
||||||
mod zone;
|
mod zone;
|
||||||
|
mod mob;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use net::{start};
|
use net::{start};
|
||||||
|
|||||||
152
server/src/mob.rs
Normal file
152
server/src/mob.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use rand::prelude::*;
|
||||||
|
use rand::distributions::Alphanumeric;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
use cryp::{Cryp};
|
||||||
|
use game::{Team};
|
||||||
|
use skill::{Skill};
|
||||||
|
|
||||||
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
|
pub enum PveMode {
|
||||||
|
Boss,
|
||||||
|
Normal,
|
||||||
|
Zone3v2Attack,
|
||||||
|
Zone2v2Caster,
|
||||||
|
Zone3v3MeleeMiniboss,
|
||||||
|
Zone3v3HealerBoss,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_mob(lvl: u8) -> Cryp {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let name: String = iter::repeat(())
|
||||||
|
.map(|()| rng.sample(Alphanumeric))
|
||||||
|
.take(8)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// rng panics on min == max
|
||||||
|
// let mob_lvl: u8 = match lvl {
|
||||||
|
// 1 => 1,
|
||||||
|
// _ => rng.gen_range(lvl.saturating_sub(2), lvl)
|
||||||
|
// };
|
||||||
|
|
||||||
|
return Cryp::new()
|
||||||
|
.named(&name)
|
||||||
|
.level(lvl)
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quick_game(mob_lvl: u8, team_size: usize) -> Vec<Cryp> {
|
||||||
|
iter::repeat_with(||
|
||||||
|
generate_mob(mob_lvl)
|
||||||
|
.set_account(Uuid::nil())
|
||||||
|
.learn(Skill::Attack))
|
||||||
|
.take(team_size)
|
||||||
|
.collect::<Vec<Cryp>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zone_3v2_attack(player_lvl: u8) -> Vec<Cryp> {
|
||||||
|
let x = Cryp::new()
|
||||||
|
.named(&"hench".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let y = Cryp::new()
|
||||||
|
.named(&"bench".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
return vec![x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zone_2v2_caster(player_lvl: u8) -> Vec<Cryp> {
|
||||||
|
let x = Cryp::new()
|
||||||
|
.named(&"robe".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Blast)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let y = Cryp::new()
|
||||||
|
.named(&"wizard hat".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Blast)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
return vec![x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zone_3v3_melee_miniboss(player_lvl: u8) -> Vec<Cryp> {
|
||||||
|
let x = Cryp::new()
|
||||||
|
.named(&"jungle juice".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let y = Cryp::new()
|
||||||
|
.named(&"bamboo basher".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.learn(Skill::Stun)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let z = Cryp::new()
|
||||||
|
.named(&"lemongrass tea".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
return vec![x, y, z];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zone_3v3_healer_boss(player_lvl: u8) -> Vec<Cryp> {
|
||||||
|
let x = Cryp::new()
|
||||||
|
.named(&"coinage".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.learn(Skill::Block)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let y = Cryp::new()
|
||||||
|
.named(&"wololo".to_string())
|
||||||
|
.level(player_lvl + 1)
|
||||||
|
// big strong
|
||||||
|
// .learn(Skill::Blast)
|
||||||
|
.learn(Skill::Heal)
|
||||||
|
.learn(Skill::Triage)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
let z = Cryp::new()
|
||||||
|
.named(&"quarry".to_string())
|
||||||
|
.level(player_lvl)
|
||||||
|
.learn(Skill::Attack)
|
||||||
|
.learn(Skill::Stun)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
return vec![x, y, z];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn generate_mob_team(mode: PveMode, cryps: &Vec<Cryp>) -> Team {
|
||||||
|
let mut mob_team = Team::new(Uuid::nil());
|
||||||
|
|
||||||
|
let cryp_lvl = cryps.iter().max_by_key(|c| c.lvl).unwrap().lvl;
|
||||||
|
let team_size = cryps.len();
|
||||||
|
|
||||||
|
let mobs = match mode {
|
||||||
|
PveMode::Normal => quick_game(cryp_lvl, team_size),
|
||||||
|
PveMode::Boss => quick_game(cryp_lvl + 2, 1),
|
||||||
|
PveMode::Zone3v2Attack => zone_3v2_attack(cryp_lvl),
|
||||||
|
PveMode::Zone2v2Caster => zone_2v2_caster(cryp_lvl),
|
||||||
|
PveMode::Zone3v3MeleeMiniboss => zone_3v3_melee_miniboss(cryp_lvl),
|
||||||
|
PveMode::Zone3v3HealerBoss => zone_3v3_healer_boss(cryp_lvl),
|
||||||
|
};
|
||||||
|
|
||||||
|
mob_team.set_cryps(mobs);
|
||||||
|
|
||||||
|
return mob_team;
|
||||||
|
|
||||||
|
}
|
||||||
@ -16,11 +16,12 @@ use failure::err_msg;
|
|||||||
|
|
||||||
use net::Db;
|
use net::Db;
|
||||||
use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget};
|
use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget};
|
||||||
use game::{Game, PveMode, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill};
|
use game::{Game, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill};
|
||||||
use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone};
|
use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone};
|
||||||
use item::{Item, items_list, item_use};
|
use item::{Item, items_list, item_use};
|
||||||
use skill::{Skill};
|
use skill::{Skill};
|
||||||
use zone::{Zone, zone_create, zone_join, zone_close};
|
use zone::{Zone, zone_create, zone_join, zone_close};
|
||||||
|
use mob::{PveMode};
|
||||||
|
|
||||||
pub struct Rpc;
|
pub struct Rpc;
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,9 @@ use postgres::transaction::Transaction;
|
|||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
|
||||||
use game::{Game, PveMode, game_pve_new, game_write};
|
use game::{Game, game_pve_new, game_write};
|
||||||
use rpc::{ZoneJoinParams, ZoneCloseParams};
|
use rpc::{ZoneJoinParams, ZoneCloseParams};
|
||||||
|
use mob::{PveMode};
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct Zone {
|
pub struct Zone {
|
||||||
@ -140,20 +141,28 @@ pub fn zone_update(zone: &Zone, tx: &mut Transaction) -> Result<(), Error> {
|
|||||||
|
|
||||||
pub fn zone_join(params: ZoneJoinParams, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
pub fn zone_join(params: ZoneJoinParams, tx: &mut Transaction, account: &Account) -> Result<Game, Error> {
|
||||||
let mut zone = zone_get(tx, params.zone_id)?;
|
let mut zone = zone_get(tx, params.zone_id)?;
|
||||||
|
let mut game;
|
||||||
|
|
||||||
// check node joinable
|
// check node joinable
|
||||||
node_joinable(&zone.graph, NodeIndex::from(params.node_id))?;
|
node_joinable(&zone.graph, NodeIndex::from(params.node_id))?;
|
||||||
|
|
||||||
let mut game = game_pve_new(params.cryp_ids, PveMode::Normal, tx, account)?;
|
// borrow zone.graph to make the game
|
||||||
game.set_zone(zone.id, params.node_id);
|
|
||||||
|
|
||||||
// borrow zone to update the encounter
|
|
||||||
{
|
{
|
||||||
let node_index = NodeIndex::from(params.node_id);
|
let node_index = NodeIndex::from(params.node_id);
|
||||||
let encounter = zone.graph
|
let encounter = zone.graph
|
||||||
.node_weight_mut(node_index)
|
.node_weight_mut(node_index)
|
||||||
.ok_or(err_msg("invalid encounter id"))?;
|
.ok_or(err_msg("invalid encounter id"))?;
|
||||||
|
|
||||||
|
let mode = match encounter.tag.as_ref() {
|
||||||
|
"ZONE0" => PveMode::Zone3v2Attack,
|
||||||
|
"ZONE1" => PveMode::Zone2v2Caster,
|
||||||
|
"ZONE2" => PveMode::Zone3v3MeleeMiniboss,
|
||||||
|
"BOSS" => PveMode::Zone3v3HealerBoss,
|
||||||
|
_ => return Err(err_msg("unknown zone tag")),
|
||||||
|
};
|
||||||
|
game = game_pve_new(params.cryp_ids, mode, tx, account)?;
|
||||||
|
game.set_zone(zone.id, params.node_id);
|
||||||
|
|
||||||
encounter.game_id = Some(game.id);
|
encounter.game_id = Some(game.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user