From 41effe61d00deb9ba186ad49ddb8bf5379391bcc Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 29 Oct 2021 19:24:40 -0400 Subject: [PATCH 1/3] Being knocked out of item use or sprite interact states forces a poise state. --- common/src/comp/poise.rs | 73 ++++++++++++++++- common/systems/src/character_behavior.rs | 100 ++++------------------- server/src/events/entity_manipulation.rs | 25 +++++- 3 files changed, 108 insertions(+), 90 deletions(-) diff --git a/common/src/comp/poise.rs b/common/src/comp/poise.rs index b7dfe5e81d..e1ae93e98e 100644 --- a/common/src/comp/poise.rs +++ b/common/src/comp/poise.rs @@ -2,14 +2,15 @@ use crate::{ comp::{ self, inventory::item::{armor::Protection, ItemKind}, - Inventory, + CharacterState, Inventory, }, + states, util::Dir, }; use serde::{Deserialize, Serialize}; use specs::{Component, DerefFlaggedStorage}; use specs_idvs::IdvStorage; -use std::ops::Mul; +use std::{ops::Mul, time::Duration}; use vek::*; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] @@ -52,6 +53,74 @@ pub enum PoiseState { KnockedDown, } +impl PoiseState { + pub fn poise_effect(&self, was_wielded: bool) -> (Option, Option) { + use states::{ + stunned::{Data, StaticData}, + utils::StageSection, + }; + match self { + PoiseState::Normal => (None, None), + PoiseState::Interrupted => ( + Some(CharacterState::Stunned(Data { + static_data: StaticData { + buildup_duration: Duration::from_millis(125), + recover_duration: Duration::from_millis(125), + movement_speed: 0.80, + poise_state: *self, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + was_wielded, + })), + None, + ), + PoiseState::Stunned => ( + Some(CharacterState::Stunned(Data { + static_data: StaticData { + buildup_duration: Duration::from_millis(300), + recover_duration: Duration::from_millis(300), + movement_speed: 0.65, + poise_state: *self, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + was_wielded, + })), + Some(5.0), + ), + PoiseState::Dazed => ( + Some(CharacterState::Stunned(Data { + static_data: StaticData { + buildup_duration: Duration::from_millis(600), + recover_duration: Duration::from_millis(250), + movement_speed: 0.45, + poise_state: *self, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + was_wielded, + })), + Some(10.0), + ), + PoiseState::KnockedDown => ( + Some(CharacterState::Stunned(Data { + static_data: StaticData { + buildup_duration: Duration::from_millis(750), + recover_duration: Duration::from_millis(500), + movement_speed: 0.4, + poise_state: *self, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + was_wielded, + })), + Some(10.0), + ), + } + } +} + impl Poise { /// Maximum value allowed for poise before scaling const MAX_POISE: u16 = u16::MAX - 1; diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index 282523b561..e9ec5fb443 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -7,8 +7,7 @@ use common::{ comp::{ self, character_state::OutputEvents, inventory::item::MaterialStatManifest, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health, Inventory, InventoryManip, - Mass, Melee, Mounting, Ori, PhysicsState, Poise, PoiseState, Pos, SkillSet, StateUpdate, - Stats, Vel, + Mass, Melee, Mounting, Ori, PhysicsState, Poise, Pos, SkillSet, StateUpdate, Stats, Vel, }, event::{EventBus, LocalEvent, ServerEvent}, outcome::Outcome, @@ -21,7 +20,6 @@ use common::{ uid::Uid, }; use common_ecs::{Job, Origin, Phase, System}; -use std::time::Duration; #[derive(SystemData)] pub struct ReadData<'a> { @@ -142,92 +140,22 @@ impl<'a> System<'a> for Sys { let was_wielded = char_state.is_wield(); let poise_state = poise.poise_state(); let pos = pos.0; - match poise_state { - PoiseState::Normal => {}, - PoiseState::Interrupted => { - poise.reset(); - *char_state = CharacterState::Stunned(common::states::stunned::Data { - static_data: common::states::stunned::StaticData { - buildup_duration: Duration::from_millis(125), - recover_duration: Duration::from_millis(125), - movement_speed: 0.80, - poise_state, - }, - timer: Duration::default(), - stage_section: common::states::utils::StageSection::Buildup, - was_wielded, - }); - outcomes.push(Outcome::PoiseChange { - pos, - state: PoiseState::Interrupted, - }); - }, - PoiseState::Stunned => { - poise.reset(); - *char_state = CharacterState::Stunned(common::states::stunned::Data { - static_data: common::states::stunned::StaticData { - buildup_duration: Duration::from_millis(300), - recover_duration: Duration::from_millis(300), - movement_speed: 0.65, - poise_state, - }, - timer: Duration::default(), - stage_section: common::states::utils::StageSection::Buildup, - was_wielded, - }); - outcomes.push(Outcome::PoiseChange { - pos, - state: PoiseState::Stunned, - }); + if let (Some(stunned_state), impulse_strength) = + poise_state.poise_effect(was_wielded) + { + // Reset poise if there is some stunned state to apply + poise.reset(); + *char_state = stunned_state; + outcomes.push(Outcome::PoiseChange { + pos, + state: poise_state, + }); + if let Some(impulse_strength) = impulse_strength { server_emitter.emit(ServerEvent::Knockback { entity, - impulse: 5.0 * *poise.knockback(), + impulse: impulse_strength * *poise.knockback(), }); - }, - PoiseState::Dazed => { - poise.reset(); - *char_state = CharacterState::Stunned(common::states::stunned::Data { - static_data: common::states::stunned::StaticData { - buildup_duration: Duration::from_millis(600), - recover_duration: Duration::from_millis(250), - movement_speed: 0.45, - poise_state, - }, - timer: Duration::default(), - stage_section: common::states::utils::StageSection::Buildup, - was_wielded, - }); - outcomes.push(Outcome::PoiseChange { - pos, - state: PoiseState::Dazed, - }); - server_emitter.emit(ServerEvent::Knockback { - entity, - impulse: 10.0 * *poise.knockback(), - }); - }, - PoiseState::KnockedDown => { - poise.reset(); - *char_state = CharacterState::Stunned(common::states::stunned::Data { - static_data: common::states::stunned::StaticData { - buildup_duration: Duration::from_millis(750), - recover_duration: Duration::from_millis(500), - movement_speed: 0.4, - poise_state, - }, - timer: Duration::default(), - stage_section: common::states::utils::StageSection::Buildup, - was_wielded, - }); - outcomes.push(Outcome::PoiseChange { - pos, - state: PoiseState::KnockedDown, - }); - server_emitter.emit(ServerEvent::Knockback { - entity, - impulse: 10.0 * *poise.knockback(), - }); - }, + } } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 8b98efce3e..4c90ae483d 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -1095,14 +1095,35 @@ pub fn handle_teleport_to(server: &Server, entity: EcsEntity, target: Uid, max_r pub fn handle_entity_attacked_hook(server: &Server, entity: EcsEntity) { let ecs = &server.state.ecs(); let server_eventbus = ecs.read_resource::>(); + let mut outcomes = ecs.write_resource::>(); - if let Some(mut char_state) = ecs.write_storage::().get_mut(entity) { + if let (Some(mut char_state), Some(mut poise), Some(pos)) = ( + ecs.write_storage::().get_mut(entity), + ecs.write_storage::().get_mut(entity), + ecs.read_storage::().get(entity), + ) { // Interrupt sprite interaction and item use if any attack is applied to entity if matches!( *char_state, CharacterState::SpriteInteract(_) | CharacterState::UseItem(_) ) { - *char_state = CharacterState::Idle(common::states::idle::Data { is_sneaking: false }); + let poise_state = comp::poise::PoiseState::Dazed; + let was_wielded = char_state.is_wield(); + if let (Some(stunned_state), impulse_strength) = poise_state.poise_effect(was_wielded) { + // Reset poise if there is some stunned state to apply + poise.reset(); + *char_state = stunned_state; + outcomes.push(Outcome::PoiseChange { + pos: pos.0, + state: poise_state, + }); + if let Some(impulse_strength) = impulse_strength { + server_eventbus.emit_now(ServerEvent::Knockback { + entity, + impulse: impulse_strength * *poise.knockback(), + }); + } + } } } From ad257410e9adbc12ff0a7f5f580b65615296d632 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 29 Oct 2021 19:58:38 -0400 Subject: [PATCH 2/3] Merchants now have less potion stock. --- world/src/site/settlement/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 605de5e531..6a421a9730 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -1173,9 +1173,12 @@ fn consumable_bags(economy: Option<&trade::SiteInformation>, rng: &mut impl Rng) .and_then(|e| e.unconsumed_stock.get(&Good::Food)) .copied() .map_or(Some(10_000.0), |food| Some(food.max(10_000.0))); + // Reduce amount of potions so merchants do not oversupply potions. + // TODO: Maybe remove when merchants and their inventories are rtsim? let mut potions = economy .and_then(|e| e.unconsumed_stock.get(&Good::Potions)) - .copied(); + .copied() + .map(|potions| potions.powf(0.25)); let goods = [ (Good::Food, &mut food, &mut bag3), From 560f73d296e5688f851edee07e7326132713bc6e Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 31 Oct 2021 16:39:47 -0400 Subject: [PATCH 3/3] Addressed review feedback. --- common/src/comp/poise.rs | 62 +++++++++++++--------------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/common/src/comp/poise.rs b/common/src/comp/poise.rs index e1ae93e98e..c0192b227a 100644 --- a/common/src/comp/poise.rs +++ b/common/src/comp/poise.rs @@ -59,65 +59,43 @@ impl PoiseState { stunned::{Data, StaticData}, utils::StageSection, }; - match self { + // charstate_parameters is Option<(buildup_duration, recover_duration, + // movement_speed)> + let (charstate_parameters, impulse) = match self { PoiseState::Normal => (None, None), PoiseState::Interrupted => ( - Some(CharacterState::Stunned(Data { - static_data: StaticData { - buildup_duration: Duration::from_millis(125), - recover_duration: Duration::from_millis(125), - movement_speed: 0.80, - poise_state: *self, - }, - timer: Duration::default(), - stage_section: StageSection::Buildup, - was_wielded, - })), + Some((Duration::from_millis(125), Duration::from_millis(125), 0.80)), None, ), PoiseState::Stunned => ( - Some(CharacterState::Stunned(Data { - static_data: StaticData { - buildup_duration: Duration::from_millis(300), - recover_duration: Duration::from_millis(300), - movement_speed: 0.65, - poise_state: *self, - }, - timer: Duration::default(), - stage_section: StageSection::Buildup, - was_wielded, - })), + Some((Duration::from_millis(300), Duration::from_millis(300), 0.65)), Some(5.0), ), PoiseState::Dazed => ( - Some(CharacterState::Stunned(Data { - static_data: StaticData { - buildup_duration: Duration::from_millis(600), - recover_duration: Duration::from_millis(250), - movement_speed: 0.45, - poise_state: *self, - }, - timer: Duration::default(), - stage_section: StageSection::Buildup, - was_wielded, - })), + Some((Duration::from_millis(600), Duration::from_millis(250), 0.45)), Some(10.0), ), PoiseState::KnockedDown => ( - Some(CharacterState::Stunned(Data { + Some((Duration::from_millis(750), Duration::from_millis(500), 0.4)), + Some(10.0), + ), + }; + ( + charstate_parameters.map(|(buildup_duration, recover_duration, movement_speed)| { + CharacterState::Stunned(Data { static_data: StaticData { - buildup_duration: Duration::from_millis(750), - recover_duration: Duration::from_millis(500), - movement_speed: 0.4, + buildup_duration, + recover_duration, + movement_speed, poise_state: *self, }, timer: Duration::default(), stage_section: StageSection::Buildup, was_wielded, - })), - Some(10.0), - ), - } + }) + }), + impulse, + ) } }