diff --git a/client/src/scenes/menu.navigation.js b/client/src/scenes/menu.navigation.js index 6ffcc4e6..cac3edea 100644 --- a/client/src/scenes/menu.navigation.js +++ b/client/src/scenes/menu.navigation.js @@ -114,7 +114,7 @@ class MenuNavigation extends Phaser.Scene { .setOrigin(0) .on('pointerdown', () => { const team = this.registry.get('cryps').filter(c => c.active).map(c => c.id); - ws.sendGamePve(team, 'Normal'); + ws.sendGamePve(team); return this.scene.restart(); }); this.add diff --git a/server/WORKLOG.md b/server/WORKLOG.md index e9ff2e96..0ae6331f 100644 --- a/server/WORKLOG.md +++ b/server/WORKLOG.md @@ -25,7 +25,7 @@ strangle ## NOW * rolls as a drop item -* evasion is a % function of the hp value +* check zone completion ## SOON * clean up categories diff --git a/server/src/cryp.rs b/server/src/cryp.rs index f4407fc8..b710983a 100644 --- a/server/src/cryp.rs +++ b/server/src/cryp.rs @@ -188,6 +188,9 @@ impl Cryp { let stat_min = 128u64.saturating_mul(self.lvl.into()); let stat_max = 256u64.saturating_mul(self.lvl.into()); + let evasion_min = 1u64; + let evasion_max = 25; + match stat { Stat::PhysicalDamage => self.phys_dmg.set(rng.gen_range(stat_min, stat_max)), Stat::SpellDamage => self.spell_dmg.set(rng.gen_range(stat_min, stat_max)), @@ -196,6 +199,9 @@ impl Cryp { self.stamina.set(rng.gen_range(stam_min, stam_max)); self.hp.set(self.stamina.base) }, + Stat::SpellShield => self.spell_shield.set(rng.gen_range(stat_min, stat_max)), + Stat::Armour => self.armour.set(rng.gen_range(stat_min, stat_max)), + Stat::Evasion => self.evasion.set(rng.gen_range(evasion_min, evasion_max)), _ => panic!("{:?} not a rollable stat", stat), }; @@ -525,15 +531,14 @@ impl Cryp { } pub fn evade(&self, skill: Skill) -> Option { - let mut rng = thread_rng(); - let hp_pct = (self.hp.base * 100) / self.stamina.base; - let evasion_rating = (self.evasion.base * hp_pct) / 100; - - println!("{:?}", evasion_rating); - if evasion_rating == 0 { + if self.evasion.base == 0 { return None; } + let mut rng = thread_rng(); + let hp_pct = (self.hp.base * 100) / self.stamina.base; + let evasion_rating = (self.evasion.base * hp_pct) / 100; + // println!("{:?}", evasion_rating); let roll = rng.gen_range(0, 100); match roll > evasion_rating { diff --git a/server/src/game.rs b/server/src/game.rs index 7eb593e3..67587f30 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -13,7 +13,7 @@ use cryp::{Cryp, cryp_get}; use skill::{Skill, Cast, ResolutionResult}; use item::{item_drop}; use zone::{node_finish}; -use mob::{PveMode, generate_mob_team}; +use mob::{generate_mob_team}; pub type Log = Vec; @@ -60,6 +60,16 @@ pub enum Phase { Finish, } +#[derive(Debug,Clone,Copy,Serialize,Deserialize)] +pub enum GameMode { + Normal, + Pvp, + Zone3v2Attack, + Zone2v2Caster, + Zone3v3MeleeMiniboss, + Zone3v3HealerBoss, +} + #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Game { pub id: Uuid, @@ -72,6 +82,7 @@ pub struct Game { pub resolved: Vec, pub log: Vec, pub zone: Option<(Uuid, u32)>, + pub mode: GameMode, } impl Game { @@ -87,6 +98,7 @@ impl Game { resolved: vec![], log: vec![], zone: None, + mode: GameMode::Normal, }; } @@ -110,6 +122,11 @@ impl Game { self } + pub fn set_mode(&mut self, mode: GameMode) -> &mut Game { + self.mode = mode; + self + } + fn already_joined(&self, team_id: Uuid) -> bool { self.teams.iter().any(|t| t.id == team_id) } @@ -670,7 +687,7 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> { if game.finished() { if let Some(t) = game.winner() { if !t.id.is_nil() { - item_drop(tx, t.id)?; + item_drop(tx, t.id, game.mode)?; } } @@ -684,7 +701,7 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> { return Ok(()); } -pub fn game_pve_new(cryp_ids: Vec, mode: PveMode, tx: &mut Transaction, account: &Account) -> Result { +pub fn game_pve_new(cryp_ids: Vec, mode: GameMode, tx: &mut Transaction, account: &Account) -> Result { if cryp_ids.len() == 0 { return Err(err_msg("no cryps selected")); } @@ -705,7 +722,8 @@ pub fn game_pve_new(cryp_ids: Vec, mode: PveMode, tx: &mut Transaction, ac game .set_pve(true) .set_team_num(2) - .set_team_size(cryps.len()); + .set_team_size(cryps.len()) + .set_mode(mode); // create the mob team let mob_team = generate_mob_team(mode, &cryps); @@ -726,7 +744,7 @@ pub fn game_pve_new(cryp_ids: Vec, mode: PveMode, tx: &mut Transaction, ac } pub fn game_pve(params: GamePveParams, tx: &mut Transaction, account: &Account) -> Result { - let game = game_pve_new(params.cryp_ids, params.mode, tx, account)?; + let game = game_pve_new(params.cryp_ids, GameMode::Normal, tx, account)?; // persist game_write(&game, tx)?; @@ -747,7 +765,8 @@ pub fn game_pvp(params: GamePvpParams, tx: &mut Transaction, account: &Account) game .set_pve(false) .set_team_num(2) - .set_team_size(cryps.len()); + .set_team_size(cryps.len()) + .set_mode(GameMode::Pvp); // create the initiators team let mut team = Team::new(account.id); diff --git a/server/src/game_target_phase.rs b/server/src/game_target_phase.rs index 7e61ae8a..c7dc27f7 100644 --- a/server/src/game_target_phase.rs +++ b/server/src/game_target_phase.rs @@ -20,7 +20,7 @@ use zone::{node_finish}; pub type Log = Vec; #[derive(Debug,Clone,Serialize,Deserialize)] -pub enum PveMode { +pub enum GameMode { Boss, Normal, } @@ -767,7 +767,7 @@ fn generate_mob(lvl: u8) -> Cryp { } -fn generate_mob_team(mode: PveMode, cryps: &Vec) -> Team { +fn generate_mob_team(mode: GameMode, cryps: &Vec) -> Team { let mut mob_team = Team::new(Uuid::nil()); // Default settings @@ -775,11 +775,11 @@ fn generate_mob_team(mode: PveMode, cryps: &Vec) -> Team { // Modify the NPC cryps for game mode settings let mob_lvl = match mode { - PveMode::Normal => { + GameMode::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, + GameMode::Boss => cryps.iter().max_by_key(|c| c.lvl).unwrap().lvl + 2, }; // Generate and return the NPC team based on settings @@ -792,7 +792,7 @@ fn generate_mob_team(mode: PveMode, cryps: &Vec) -> Team { } -pub fn game_pve_new(cryp_ids: Vec, mode: PveMode, tx: &mut Transaction, account: &Account) -> Result { +pub fn game_pve_new(cryp_ids: Vec, mode: GameMode, tx: &mut Transaction, account: &Account) -> Result { let cryps = cryp_ids .iter() .map(|id| cryp_get(tx, *id, account.id)) diff --git a/server/src/item.rs b/server/src/item.rs index 8301118a..1309d479 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -12,6 +12,7 @@ use rand::distributions::{WeightedIndex}; use account::Account; use rpc::{ItemUseParams}; use cryp::{Stat, cryp_get, cryp_write}; +use game::{GameMode}; #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum ItemAction { @@ -19,6 +20,9 @@ pub enum ItemAction { RerollSpellDamage, RerollSpeed, RerollStamina, + RerollArmour, + RerollSpellShield, + RerollEvasion, } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -45,6 +49,9 @@ impl Item { ItemAction::RerollPhysDamage => reroll(self, tx, target, Stat::PhysicalDamage), ItemAction::RerollSpellDamage => reroll(self, tx, target, Stat::SpellDamage), ItemAction::RerollSpeed => reroll(self, tx, target, Stat::Speed), + ItemAction::RerollArmour => reroll(self, tx, target, Stat::Armour), + ItemAction::RerollSpellShield => reroll(self, tx, target, Stat::SpellShield), + ItemAction::RerollEvasion => reroll(self, tx, target, Stat::Evasion), } } } @@ -63,15 +70,42 @@ fn reroll(item: &mut Item, tx: &mut Transaction, target: Uuid, stat: Stat) -> Re return Ok(()); } -pub fn item_drop(tx: &mut Transaction, account_id: Uuid) -> Result { +fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> { + match mode { + GameMode::Normal => vec![ + (ItemAction::RerollStamina, 1), + (ItemAction::RerollPhysDamage, 1), + (ItemAction::RerollSpellDamage, 1), + ], + GameMode::Pvp => vec![ + (ItemAction::RerollSpeed, 1), + ], + GameMode::Zone3v2Attack | + GameMode::Zone2v2Caster | + GameMode::Zone3v3MeleeMiniboss => vec![ + (ItemAction::RerollSpeed, 1), + (ItemAction::RerollArmour, 1), + (ItemAction::RerollSpellShield, 1), + ], + GameMode::Zone3v3HealerBoss => vec![ + (ItemAction::RerollSpeed, 1), + ], + _ => vec![ + (ItemAction::RerollStamina, 1), + (ItemAction::RerollPhysDamage, 1), + (ItemAction::RerollSpellDamage, 1), + (ItemAction::RerollSpeed, 1), + (ItemAction::RerollArmour, 1), + (ItemAction::RerollSpellShield, 1), + (ItemAction::RerollEvasion, 1), + ], + } +} + +pub fn item_drop(tx: &mut Transaction, account_id: Uuid, mode: GameMode) -> Result { let mut rng = thread_rng(); - let actions = [ - (ItemAction::RerollStamina, 1), - (ItemAction::RerollPhysDamage, 1), - (ItemAction::RerollSpellDamage, 1), - (ItemAction::RerollSpeed, 1), - ]; + let actions = mode_drops(mode); let dist = WeightedIndex::new(actions.iter().map(|item| item.1)).unwrap(); let kind = actions[dist.sample(&mut rng)].0; diff --git a/server/src/mob.rs b/server/src/mob.rs index 4ccfe356..969a3104 100644 --- a/server/src/mob.rs +++ b/server/src/mob.rs @@ -5,19 +5,9 @@ use rand::distributions::Alphanumeric; use std::iter; use cryp::{Cryp}; -use game::{Team}; +use game::{Team, GameMode}; 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(); @@ -134,19 +124,19 @@ fn zone_3v3_healer_boss(player_lvl: u8) -> Vec { } -pub fn generate_mob_team(mode: PveMode, cryps: &Vec) -> Team { +pub fn generate_mob_team(mode: GameMode, cryps: &Vec) -> 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), + GameMode::Normal => quick_game(cryp_lvl, team_size), + GameMode::Zone3v2Attack => zone_3v2_attack(cryp_lvl), + GameMode::Zone2v2Caster => zone_2v2_caster(cryp_lvl), + GameMode::Zone3v3MeleeMiniboss => zone_3v3_melee_miniboss(cryp_lvl), + GameMode::Zone3v3HealerBoss => zone_3v3_healer_boss(cryp_lvl), + _ => panic!("{:?} not handled for pve mobs", mode), }; mob_team.set_cryps(mobs); diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 5fca1655..a1f9cc30 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -21,7 +21,6 @@ use account::{Account, account_create, account_login, account_from_token, accoun use item::{Item, items_list, item_use}; use skill::{Skill}; use zone::{Zone, zone_create, zone_join, zone_close}; -use mob::{PveMode}; pub struct Rpc; @@ -443,7 +442,6 @@ struct GamePveMsg { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct GamePveParams { pub cryp_ids: Vec, - pub mode: PveMode, } #[derive(Debug,Clone,Serialize,Deserialize)] diff --git a/server/src/skill.rs b/server/src/skill.rs index cc2b46c5..bc35c846 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -260,26 +260,30 @@ impl Effect { pub fn duration(&self) -> u8 { match self { + Effect::Stun => 1, Effect::Block => 1, Effect::Parry => 1, - Effect::Stun => 2, Effect::Vulnerable => 2, - Effect::Snare => 1, + Effect::Snare => 2, Effect::Empower => 2, - Effect::Shield => 2, + Effect::Hex => 2, + Effect::Curse => 2, + Effect::Banish => 1, - Effect::Decay => 2, - Effect::Drain => 2, - Effect::Triage => 2, + Effect::Slow => 2, + Effect::Haste => 2, Effect::Amplify => 2, Effect::Silence => 2, - Effect::Haste => 2, - Effect::Slow => 2, + Effect::Shield => 2, + + Effect::Triage => 3, + Effect::Decay => 3, + Effect::Drain => 2, _ => { println!("{:?} does not have a duration", self); diff --git a/server/src/zone.rs b/server/src/zone.rs index 4754ca74..ad08fc86 100644 --- a/server/src/zone.rs +++ b/server/src/zone.rs @@ -9,9 +9,8 @@ use postgres::transaction::Transaction; use failure::Error; use failure::err_msg; -use game::{Game, game_pve_new, game_write}; +use game::{Game, GameMode, game_pve_new, game_write}; use rpc::{ZoneJoinParams, ZoneCloseParams}; -use mob::{PveMode}; #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Zone { @@ -154,10 +153,10 @@ pub fn zone_join(params: ZoneJoinParams, tx: &mut Transaction, account: &Account .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, + "ZONE0" => GameMode::Zone3v2Attack, + "ZONE1" => GameMode::Zone2v2Caster, + "ZONE2" => GameMode::Zone3v3MeleeMiniboss, + "BOSS" => GameMode::Zone3v3HealerBoss, _ => return Err(err_msg("unknown zone tag")), }; game = game_pve_new(params.cryp_ids, mode, tx, account)?;