From a288f9ee438920348e2f6ee20134753cfd657bd4 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 11 Nov 2021 22:37:37 -0500 Subject: [PATCH] Addressed further review. --- common/net/src/msg/ecs_packet.rs | 12 ++-- common/src/comp/ability.rs | 91 ++++++++++++++---------- common/src/comp/inventory/item/mod.rs | 49 +++---------- common/src/comp/inventory/item/tool.rs | 43 ++++++----- common/src/comp/mod.rs | 8 ++- common/src/states/behavior.rs | 10 +-- common/src/states/utils.rs | 9 ++- common/state/src/state.rs | 2 +- common/systems/src/character_behavior.rs | 14 ++-- common/systems/src/controller.rs | 14 ++-- server/src/events/inventory_manip.rs | 6 +- server/src/lib.rs | 5 +- server/src/state_ext.rs | 9 ++- server/src/sys/agent.rs | 72 +++++++++++-------- server/src/sys/sentinel.rs | 29 +++++--- voxygen/src/hud/hotbar.rs | 11 +-- voxygen/src/hud/mod.rs | 8 +-- voxygen/src/hud/skillbar.rs | 24 +++---- voxygen/src/hud/slots.rs | 13 ++-- voxygen/src/hud/util.rs | 36 +++++----- 20 files changed, 250 insertions(+), 215 deletions(-) diff --git a/common/net/src/msg/ecs_packet.rs b/common/net/src/msg/ecs_packet.rs index 13a51ee6bd..cac265fce0 100644 --- a/common/net/src/msg/ecs_packet.rs +++ b/common/net/src/msg/ecs_packet.rs @@ -15,7 +15,7 @@ sum_type! { CanBuild(comp::CanBuild), Stats(comp::Stats), SkillSet(comp::SkillSet), - AbilityPool(comp::AbilityPool), + ActiveAbilities(comp::ActiveAbilities), Buffs(comp::Buffs), Auras(comp::Auras), Energy(comp::Energy), @@ -51,7 +51,7 @@ sum_type! { CanBuild(PhantomData), Stats(PhantomData), SkillSet(PhantomData), - AbilityPool(PhantomData), + ActiveAbilities(PhantomData), Buffs(PhantomData), Auras(PhantomData), Energy(PhantomData), @@ -87,7 +87,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Stats(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::SkillSet(comp) => sync::handle_insert(comp, entity, world), - EcsCompPacket::AbilityPool(comp) => sync::handle_insert(comp, entity, world), + EcsCompPacket::ActiveAbilities(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Buffs(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Auras(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world), @@ -127,7 +127,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::CanBuild(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Stats(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::SkillSet(comp) => sync::handle_modify(comp, entity, world), - EcsCompPacket::AbilityPool(comp) => sync::handle_modify(comp, entity, world), + EcsCompPacket::ActiveAbilities(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Buffs(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Auras(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world), @@ -167,8 +167,8 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPhantom::CanBuild(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Stats(_) => sync::handle_remove::(entity, world), EcsCompPhantom::SkillSet(_) => sync::handle_remove::(entity, world), - EcsCompPhantom::AbilityPool(_) => { - sync::handle_remove::(entity, world) + EcsCompPhantom::ActiveAbilities(_) => { + sync::handle_remove::(entity, world) }, EcsCompPhantom::Buffs(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Auras(_) => sync::handle_remove::(entity, world), diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 861add2252..f85620bfeb 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -5,7 +5,7 @@ use crate::{ self, aura, beam, buff, inventory::{ item::{ - tool::{Stats, ToolKind}, + tool::{AbilityItem, Stats, ToolKind}, ItemKind, }, slot::EquipSlot, @@ -34,18 +34,18 @@ pub const MAX_ABILITIES: usize = 5; // set of weapons. Consider after UI is set up and people weigh in on memory // considerations. #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct AbilityPool { +pub struct ActiveAbilities { pub primary: PrimaryAbility, pub secondary: SecondaryAbility, pub movement: MovementAbility, pub abilities: [AuxiliaryAbility; MAX_ABILITIES], } -impl Component for AbilityPool { +impl Component for ActiveAbilities { type Storage = DerefFlaggedStorage>; } -impl Default for AbilityPool { +impl Default for ActiveAbilities { fn default() -> Self { Self { primary: PrimaryAbility::Tool, @@ -56,7 +56,7 @@ impl Default for AbilityPool { } } -impl AbilityPool { +impl ActiveAbilities { pub fn new(inv: Option<&Inventory>, skill_set: Option<&SkillSet>) -> Self { let mut pool = Self::default(); pool.auto_update(inv, skill_set); @@ -90,7 +90,7 @@ impl AbilityPool { input: AbilityInput, inv: Option<&Inventory>, skill_set: &SkillSet, - body: &Body, + body: Option<&Body>, // bool is from_offhand ) -> Option<(CharacterAbility, bool)> { let ability = self.get_ability(input); @@ -110,6 +110,10 @@ impl AbilityPool { ability.adjusted_by_skills(skill_set, tool_kind) }; + let unwrap_ability = |(skill_req, ability): &(Option, AbilityItem)| { + (*skill_req, ability.ability.clone()) + }; + let unlocked = |(s, a): (Option, CharacterAbility)| { // If there is a skill requirement and the skillset does not contain the // required skill, return None @@ -118,25 +122,25 @@ impl AbilityPool { match ability { Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand) - .map(|abilities| abilities.primary.clone()) + .map(|abilities| abilities.primary.ability.clone()) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)), Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) - .map(|abilities| abilities.secondary.clone()) + .map(|abilities| abilities.secondary.ability.clone()) .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)) .or_else(|| { ability_set(EquipSlot::ActiveMainhand) - .map(|abilities| abilities.secondary.clone()) + .map(|abilities| abilities.secondary.ability.clone()) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)) }), - Ability::SpeciesMovement => matches!(body, Body::Humanoid(_)) - .then(|| CharacterAbility::default_roll) - .map(|ability| (ability().adjusted_by_skills(skill_set, None), false)), + Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_))) + .then(CharacterAbility::default_roll) + .map(|ability| (ability.adjusted_by_skills(skill_set, None), false)), Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand) - .and_then(|abilities| abilities.abilities.get(index).cloned()) + .and_then(|abilities| abilities.abilities.get(index).map(unwrap_ability)) .and_then(unlocked) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)), Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand) - .and_then(|abilities| abilities.abilities.get(index).cloned()) + .and_then(|abilities| abilities.abilities.get(index).map(unwrap_ability)) .and_then(unlocked) .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)), Ability::Empty => None, @@ -149,19 +153,13 @@ impl AbilityPool { inv: Option<&Inventory>, skill_set: Option<&SkillSet>, equip_slot: EquipSlot, - ) -> Vec { - let ability_from_slot = move |i| match equip_slot { - EquipSlot::ActiveMainhand => AuxiliaryAbility::MainWeapon(i), - EquipSlot::ActiveOffhand => AuxiliaryAbility::OffWeapon(i), - _ => AuxiliaryAbility::Empty, - }; - + ) -> Vec { inv .and_then(|inv| inv.equipped(equip_slot)) .iter() .flat_map(|i| &i.item_config_expect().abilities.abilities) .enumerate() - .filter_map(move |(i, (skill, _))| skill.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s))).then_some(ability_from_slot(i))) + .filter_map(move |(i, (skill, _))| skill.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s))).then_some(i)) // TODO: Let someone smarter than borrow checker remove collect .collect() } @@ -170,9 +168,18 @@ impl AbilityPool { let off_abilities = iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveOffhand); (0..MAX_ABILITIES) - .zip(main_abilities.iter().chain(off_abilities.iter())) + .zip( + main_abilities + .iter() + .map(|a| AuxiliaryAbility::MainWeapon(*a)) + .chain( + off_abilities + .iter() + .map(|a| AuxiliaryAbility::OffWeapon(*a)), + ), + ) .for_each(|(i, ability)| { - self.change_ability(i, *ability); + self.change_ability(i, ability); }) } } @@ -198,25 +205,37 @@ pub enum Ability { impl Ability { pub fn ability_id(self, inv: Option<&Inventory>) -> Option<&str> { - let ability_id_set = |equip_slot| { + let ability_set = |equip_slot| { inv.and_then(|inv| inv.equipped(equip_slot)) - .map(|i| &i.item_config_expect().ability_ids) + .map(|i| &i.item_config_expect().abilities) }; match self { - Ability::ToolPrimary => { - ability_id_set(EquipSlot::ActiveMainhand).map(|ids| ids.primary.as_str()) - }, - Ability::ToolSecondary => ability_id_set(EquipSlot::ActiveOffhand) - .map(|ids| ids.secondary.as_str()) + Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand) + .map(|abilities| abilities.primary.id.as_str()), + Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) + .map(|abilities| abilities.secondary.id.as_str()) .or_else(|| { - ability_id_set(EquipSlot::ActiveMainhand).map(|ids| ids.secondary.as_str()) + ability_set(EquipSlot::ActiveMainhand) + .map(|abilities| abilities.secondary.id.as_str()) }), Ability::SpeciesMovement => None, // TODO: Make not None - Ability::MainWeaponAux(index) => ability_id_set(EquipSlot::ActiveMainhand) - .and_then(|ids| ids.abilities.get(index).map(|(_, id)| id.as_str())), - Ability::OffWeaponAux(index) => ability_id_set(EquipSlot::ActiveOffhand) - .and_then(|ids| ids.abilities.get(index).map(|(_, id)| id.as_str())), + Ability::MainWeaponAux(index) => { + ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { + abilities + .abilities + .get(index) + .map(|(_, ability)| ability.id.as_str()) + }) + }, + Ability::OffWeaponAux(index) => { + ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| { + abilities + .abilities + .get(index) + .map(|(_, ability)| ability.id.as_str()) + }) + }, Ability::Empty => None, } } diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index 4269294741..a7fc768a8e 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -8,10 +8,7 @@ pub use tool::{AbilitySet, AbilitySpec, Hands, MaterialStatManifest, Tool, ToolK use crate::{ assets::{self, AssetExt, Error}, - comp::{ - inventory::{item::tool::AbilityMap, InvSlot}, - CharacterAbility, - }, + comp::inventory::{item::tool::AbilityMap, InvSlot}, effect::Effect, recipe::RecipeInput, terrain::Block, @@ -433,8 +430,7 @@ impl PartialEq for ItemDef { // TODO: Look into removing ItemConfig and just using AbilitySet #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ItemConfig { - pub abilities: AbilitySet, - pub ability_ids: AbilitySet, + pub abilities: AbilitySet, } #[derive(Debug)] @@ -449,56 +445,33 @@ impl TryFrom<(&Item, &AbilityMap, &MaterialStatManifest)> for ItemConfig { (item, ability_map, msm): (&Item, &AbilityMap, &MaterialStatManifest), ) -> Result { if let ItemKind::Tool(tool) = &item.kind { - // TODO: Maybe try to make an ecs resource? - let ability_ids_map = - AbilityMap::::load_expect("common.abilities.ability_set_manifest").read(); - // If no custom ability set is specified, fall back to abilityset of tool kind. let tool_default = |tool_kind| { let key = &AbilitySpec::Tool(tool_kind); - ( - ability_map.get_ability_set(key), - ability_ids_map.get_ability_set(key), - ) + ability_map.get_ability_set(key) }; - let (abilities, ability_ids) = if let Some(set_key) = item.ability_spec() { - if let (Some(set), Some(ids)) = ( - ability_map.get_ability_set(set_key), - ability_ids_map.get_ability_set(set_key), - ) { - ( - set.clone().modified_by_tool(tool, msm, &item.components), - ids.clone(), - ) + let abilities = if let Some(set_key) = item.ability_spec() { + if let Some(set) = ability_map.get_ability_set(set_key) { + set.clone().modified_by_tool(tool, msm, &item.components) } else { error!( "Custom ability set: {:?} references non-existent set, falling back to \ default ability set.", set_key ); - let (abilities, ids) = tool_default(tool.kind); - ( - abilities.cloned().unwrap_or_default(), - ids.cloned().unwrap_or_default(), - ) + tool_default(tool.kind).cloned().unwrap_or_default() } - } else if let (Some(set), Some(ids)) = tool_default(tool.kind) { - ( - set.clone().modified_by_tool(tool, msm, &item.components), - ids.clone(), - ) + } else if let Some(set) = tool_default(tool.kind) { + set.clone().modified_by_tool(tool, msm, &item.components) } else { error!( "No ability set defined for tool: {:?}, falling back to default ability set.", tool.kind ); - (Default::default(), Default::default()) + Default::default() }; - Ok(ItemConfig { - abilities, - ability_ids, - }) + Ok(ItemConfig { abilities }) } else { Err(ItemConfigError::BadItemKind) } diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index db7f23886e..d796ecddcd 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -345,7 +345,7 @@ pub struct AbilitySet { pub abilities: Vec<(Option, T)>, } -impl AbilitySet { +impl AbilitySet { pub fn modified_by_tool( self, tool: &Tool, @@ -353,7 +353,10 @@ impl AbilitySet { components: &[Item], ) -> Self { let stats = Stats::from((msm, components, tool)); - self.map(|a| a.adjusted_by_stats(stats)) + self.map(|a| AbilityItem { + id: a.id, + ability: a.ability.adjusted_by_stats(stats), + }) } } @@ -376,22 +379,17 @@ impl AbilitySet { } #[allow(clippy::derivable_impls)] -impl Default for AbilitySet { +impl Default for AbilitySet { fn default() -> Self { AbilitySet { - primary: CharacterAbility::default(), - secondary: CharacterAbility::default(), - abilities: Vec::new(), - } - } -} - -#[allow(clippy::derivable_impls)] -impl Default for AbilitySet { - fn default() -> Self { - AbilitySet { - primary: String::new(), - secondary: String::new(), + primary: AbilityItem { + id: String::new(), + ability: CharacterAbility::default(), + }, + secondary: AbilityItem { + id: String::new(), + ability: CharacterAbility::default(), + }, abilities: Vec::new(), } } @@ -404,7 +402,13 @@ pub enum AbilitySpec { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AbilityMap(HashMap>); +pub struct AbilityItem { + pub id: String, + pub ability: CharacterAbility, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AbilityMap(HashMap>); impl Default for AbilityMap { fn default() -> Self { @@ -445,7 +449,10 @@ impl assets::Compound for AbilityMap { kind.clone(), // expect cannot fail because CharacterAbility always // provides a default value in case of failure - set.map_ref(|s| cache.load_expect(s).cloned()), + set.map_ref(|s| AbilityItem { + id: s.clone(), + ability: cache.load_expect(s).cloned(), + }), ) }) .collect(), diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index efd5f32388..e3bbd9fd74 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -48,7 +48,7 @@ pub mod visual; // Reexports #[cfg(not(target_arch = "wasm32"))] pub use self::{ - ability::{Ability, AbilityPool, CharacterAbility, CharacterAbilityType}, + ability::{Ability, AbilityInput, ActiveAbilities, CharacterAbility, CharacterAbilityType}, admin::{Admin, AdminRole}, agent::{Agent, Alignment, Behavior, BehaviorCapability, BehaviorState, PidController}, anchor::Anchor, @@ -78,7 +78,11 @@ pub use self::{ group::Group, inputs::CanBuild, inventory::{ - item::{self, tool, Item, ItemConfig, ItemDrop}, + item::{ + self, + tool::{self, AbilityItem}, + Item, ItemConfig, ItemDrop, + }, slot, Inventory, InventoryUpdate, InventoryUpdateEvent, }, last::Last, diff --git a/common/src/states/behavior.rs b/common/src/states/behavior.rs index ea8dda5cf2..12875e95f3 100644 --- a/common/src/states/behavior.rs +++ b/common/src/states/behavior.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - self, character_state::OutputEvents, item::MaterialStatManifest, AbilityPool, Beam, Body, - CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy, + self, character_state::OutputEvents, item::MaterialStatManifest, ActiveAbilities, Beam, + Body, CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory, InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, StateUpdate, Stats, Vel, }, @@ -124,7 +124,7 @@ pub struct JoinData<'a> { pub updater: &'a LazyUpdate, pub stats: &'a Stats, pub skill_set: &'a SkillSet, - pub ability_pool: &'a AbilityPool, + pub active_abilities: &'a ActiveAbilities, pub msm: &'a MaterialStatManifest, pub combo: &'a Combo, pub alignment: Option<&'a comp::Alignment>, @@ -150,7 +150,7 @@ pub struct JoinStruct<'a> { pub beam: Option<&'a Beam>, pub stat: &'a Stats, pub skill_set: &'a SkillSet, - pub ability_pool: &'a AbilityPool, + pub active_abilities: &'a ActiveAbilities, pub combo: &'a Combo, pub alignment: Option<&'a comp::Alignment>, pub terrain: &'a TerrainGrid, @@ -188,7 +188,7 @@ impl<'a> JoinData<'a> { combo: j.combo, alignment: j.alignment, terrain: j.terrain, - ability_pool: j.ability_pool, + active_abilities: j.active_abilities, } } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 7299ffe243..cf47605a51 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -823,8 +823,13 @@ pub fn handle_jump( fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKind) { if let Some(ability_input) = input.into() { if let Some((ability, from_offhand)) = data - .ability_pool - .activate_ability(ability_input, data.inventory, data.skill_set, data.body) + .active_abilities + .activate_ability( + ability_input, + data.inventory, + data.skill_set, + Some(data.body), + ) .filter(|(ability, _)| ability.requirements_paid(data, update)) { update.character = CharacterState::from(( diff --git a/common/state/src/state.rs b/common/state/src/state.rs index 8a0c817148..a0ac7034e6 100644 --- a/common/state/src/state.rs +++ b/common/state/src/state.rs @@ -129,7 +129,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index 6adff0a268..6ff1ab4e55 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -5,9 +5,9 @@ use specs::{ use common::{ comp::{ - self, character_state::OutputEvents, inventory::item::MaterialStatManifest, AbilityPool, - Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health, Inventory, - InventoryManip, Mass, Melee, Mounting, Ori, PhysicsState, Poise, Pos, SkillSet, + self, character_state::OutputEvents, inventory::item::MaterialStatManifest, + ActiveAbilities, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health, + Inventory, InventoryManip, Mass, Melee, Mounting, Ori, PhysicsState, Poise, Pos, SkillSet, StateUpdate, Stats, Vel, }, event::{EventBus, LocalEvent, ServerEvent}, @@ -39,7 +39,7 @@ pub struct ReadData<'a> { mountings: ReadStorage<'a, Mounting>, stats: ReadStorage<'a, Stats>, skill_sets: ReadStorage<'a, SkillSet>, - ability_pools: ReadStorage<'a, AbilityPool>, + active_abilities: ReadStorage<'a, ActiveAbilities>, msm: Read<'a, MaterialStatManifest>, combos: ReadStorage<'a, Combo>, alignments: ReadStorage<'a, comp::Alignment>, @@ -109,7 +109,7 @@ impl<'a> System<'a> for Sys { health, body, physics, - (stat, skill_set, ability_pool), + (stat, skill_set, active_abilities), combo, ) in ( &read_data.entities, @@ -129,7 +129,7 @@ impl<'a> System<'a> for Sys { ( &read_data.stats, &read_data.skill_sets, - &read_data.ability_pools, + &read_data.active_abilities, ), &read_data.combos, ) @@ -187,7 +187,7 @@ impl<'a> System<'a> for Sys { beam: read_data.beams.get(entity), stat, skill_set, - ability_pool, + active_abilities, combo, alignment: read_data.alignments.get(entity), terrain: &read_data.terrain, diff --git a/common/systems/src/controller.rs b/common/systems/src/controller.rs index ed5f856eda..dcc403e15f 100644 --- a/common/systems/src/controller.rs +++ b/common/systems/src/controller.rs @@ -1,7 +1,7 @@ use common::{ comp::{ agent::{Sound, SoundKind}, - AbilityPool, Body, BuffChange, ControlEvent, Controller, Pos, + ActiveAbilities, Body, BuffChange, ControlEvent, Controller, Pos, }, event::{EventBus, ServerEvent}, uid::UidAllocator, @@ -30,7 +30,7 @@ impl<'a> System<'a> for Sys { type SystemData = ( ReadData<'a>, WriteStorage<'a, Controller>, - WriteStorage<'a, AbilityPool>, + WriteStorage<'a, ActiveAbilities>, ); const NAME: &'static str = "controller"; @@ -39,13 +39,11 @@ impl<'a> System<'a> for Sys { fn run( _job: &mut Job, - (read_data, mut controllers, mut ability_pools): Self::SystemData, + (read_data, mut controllers, mut active_abilities): Self::SystemData, ) { let mut server_emitter = read_data.server_bus.emitter(); - for (entity, controller, mut ability_pool) in - (&read_data.entities, &mut controllers, &mut ability_pools).join() - { + for (entity, controller) in (&read_data.entities, &mut controllers).join() { // Sanitize inputs to avoid clients sending bad data controller.inputs.sanitize(); @@ -113,7 +111,9 @@ impl<'a> System<'a> for Sys { } }, ControlEvent::ChangeAbility { slot, new_ability } => { - ability_pool.change_ability(slot, new_ability) + if let Some(mut active_abilities) = active_abilities.get_mut(entity) { + active_abilities.change_ability(slot, new_ability); + } }, } } diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index c9088eafb4..8208121a01 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -770,12 +770,12 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv // After any inventory manipulation, update the ability // TODO: Make less hacky, probably remove entirely but needs UI - if let Some(mut ability_pool) = state + if let Some(mut active_abilities) = state .ecs() - .write_storage::() + .write_storage::() .get_mut(entity) { - ability_pool.auto_update( + active_abilities.auto_update( state.ecs().read_storage::().get(entity), state.ecs().read_storage::().get(entity), ); diff --git a/server/src/lib.rs b/server/src/lib.rs index fb69658408..02feef4b9a 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -66,8 +66,7 @@ use common::{ assets::AssetExt, character::CharacterId, cmd::ChatCommand, - comp, - comp::{item::MaterialStatManifest, CharacterAbility}, + comp::{self, item::MaterialStatManifest}, event::{EventBus, ServerEvent}, recipe::default_recipe_book, resources::{BattleMode, Time, TimeOfDay}, @@ -287,7 +286,7 @@ impl Server { Arc::>::clone(&database_settings), )?); - let ability_map = comp::item::tool::AbilityMap::::load_expect_cloned( + let ability_map = comp::item::tool::AbilityMap::::load_expect_cloned( "common.abilities.ability_set_manifest", ); state.ecs_mut().insert(ability_map); diff --git a/server/src/state_ext.rs b/server/src/state_ext.rs index 04442a00cb..1b4dc8dd5f 100644 --- a/server/src/state_ext.rs +++ b/server/src/state_ext.rs @@ -215,7 +215,10 @@ impl StateExt for State { .unwrap_or(0), )) .with(stats) - .with(comp::AbilityPool::new(Some(&inventory), Some(&skill_set))) + .with(comp::ActiveAbilities::new( + Some(&inventory), + Some(&skill_set), + )) .with(skill_set) .maybe_with(health) .with(poise) @@ -268,7 +271,7 @@ impl StateExt for State { .with(comp::Energy::new(ship.into(), 0)) .with(comp::Stats::new("Airship".to_string())) .with(comp::SkillSet::default()) - .with(comp::AbilityPool::default()) + .with(comp::ActiveAbilities::default()) .with(comp::Combo::default()); if mountable { @@ -508,7 +511,7 @@ impl StateExt for State { self.write_component_ignore_entity_dead(entity, stats); self.write_component_ignore_entity_dead( entity, - comp::AbilityPool::new(Some(&inventory), Some(&skill_set)), + comp::ActiveAbilities::new(Some(&inventory), Some(&skill_set)), ); self.write_component_ignore_entity_dead(entity, skill_set); self.write_component_ignore_entity_dead(entity, inventory); diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index a7768d7187..0a53fab20d 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -19,9 +19,9 @@ use common::{ }, projectile::ProjectileConstructor, skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill}, - Agent, Alignment, BehaviorCapability, BehaviorState, Body, CharacterAbility, - CharacterState, Combo, ControlAction, ControlEvent, Controller, Energy, Health, - HealthChange, InputKind, Inventory, InventoryAction, LightEmitter, MountState, Ori, + AbilityInput, ActiveAbilities, Agent, Alignment, BehaviorCapability, BehaviorState, Body, + CharacterAbility, CharacterState, Combo, ControlAction, ControlEvent, Controller, Energy, + Health, HealthChange, InputKind, Inventory, InventoryAction, LightEmitter, MountState, Ori, PhysicsState, Pos, Scale, SkillSet, Stats, UnresolvedChatMsg, UtteranceKind, Vel, }, consts::GRAVITY, @@ -74,6 +74,7 @@ struct AgentData<'a> { is_gliding: bool, health: Option<&'a Health>, char_state: &'a CharacterState, + active_abilities: &'a ActiveAbilities, cached_spatial_grid: &'a common::CachedSpatialGrid, } @@ -160,6 +161,7 @@ pub struct ReadData<'a> { rtsim_entities: ReadStorage<'a, RtSimEntity>, buffs: ReadStorage<'a, Buffs>, combos: ReadStorage<'a, Combo>, + active_abilities: ReadStorage<'a, ActiveAbilities>, } const DAMAGE_MEMORY_DURATION: f64 = 0.25; @@ -212,7 +214,11 @@ impl<'a> System<'a> for Sys { ), read_data.bodies.maybe(), &read_data.inventories, - &read_data.skill_set, + ( + &read_data.char_states, + &read_data.skill_set, + &read_data.active_abilities, + ), &read_data.physics_states, &read_data.uids, &mut agents, @@ -220,10 +226,9 @@ impl<'a> System<'a> for Sys { read_data.light_emitter.maybe(), read_data.groups.maybe(), read_data.mount_states.maybe(), - &read_data.char_states, ) .par_join() - .filter(|(_, _, _, _, _, _, _, _, _, _, _, _, mount_state, _)| { + .filter(|(_, _, _, _, _, _, _, _, _, _, _, _, mount_state)| { // Skip mounted entities mount_state .map(|ms| *ms == MountState::Unmounted) @@ -241,7 +246,7 @@ impl<'a> System<'a> for Sys { (pos, vel, ori), body, inventory, - skill_set, + (char_state, skill_set, active_abilities), physics_state, uid, agent, @@ -249,7 +254,6 @@ impl<'a> System<'a> for Sys { light_emitter, group, _, - char_state, )| { // Hack, replace with better system when groups are more sophisticated // Override alignment if in a group unless entity is owned already @@ -359,6 +363,7 @@ impl<'a> System<'a> for Sys { is_gliding, health: read_data.healths.get(entity), char_state, + active_abilities, cached_spatial_grid: &read_data.cached_spatial_grid, }; /////////////////////////////////////////////////////////// @@ -2502,30 +2507,35 @@ impl<'a> AgentData<'a> { tgt_data: &TargetData, read_data: &ReadData, ) { - let extract_ability = |ability: &CharacterAbility| { - ability - .clone() - .adjusted_by_skills(self.skill_set, Some(ToolKind::Staff)) + let extract_ability = |input: AbilityInput| { + self.active_abilities + .activate_ability(input, Some(self.inventory), self.skill_set, self.body) + .unwrap_or_default() + .0 }; - let (flamethrower, shockwave) = self - .inventory - .equipped(EquipSlot::ActiveMainhand) - .map(|i| &i.item_config_expect().abilities) - .map(|a| { - ( - Some(a.secondary.clone()), - a.abilities.get(0).map(|(_, s)| s), - ) - }) - .map_or( - (CharacterAbility::default(), CharacterAbility::default()), - |(s, a)| { - ( - extract_ability(&s.unwrap_or_default()), - extract_ability(a.unwrap_or(&CharacterAbility::default())), - ) - }, - ); + let (flamethrower, shockwave) = ( + extract_ability(AbilityInput::Secondary), + extract_ability(AbilityInput::Auxiliary(0)), + ); + // self + // .inventory + // .equipped(EquipSlot::ActiveMainhand) + // .map(|i| &i.item_config_expect().abilities) + // .map(|a| { + // ( + // Some(a.secondary.clone()), + // a.abilities.get(0).map(|(_, s)| s), + // ) + // }) + // .map_or( + // (CharacterAbility::default(), CharacterAbility::default()), + // |(s, a)| { + // ( + // extract_ability(&s.unwrap_or_default()), + // extract_ability(a.unwrap_or(&CharacterAbility::default())), + // ) + // }, + // ); let flamethrower_range = match flamethrower { CharacterAbility::BasicBeam { range, .. } => range, _ => 20.0_f32, diff --git a/server/src/sys/sentinel.rs b/server/src/sys/sentinel.rs index 966ec59d45..0f45b9d978 100644 --- a/server/src/sys/sentinel.rs +++ b/server/src/sys/sentinel.rs @@ -1,9 +1,9 @@ use common::{ comp::{ item::{tool::AbilityMap, MaterialStatManifest}, - AbilityPool, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Combo, - Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, - Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, + ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, + Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, + Mounting, Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, }, uid::Uid, }; @@ -44,7 +44,7 @@ pub struct TrackedComps<'a> { pub player: ReadStorage<'a, Player>, pub stats: ReadStorage<'a, Stats>, pub skill_set: ReadStorage<'a, SkillSet>, - pub ability_pool: ReadStorage<'a, AbilityPool>, + pub active_abilities: ReadStorage<'a, ActiveAbilities>, pub buffs: ReadStorage<'a, Buffs>, pub auras: ReadStorage<'a, Auras>, pub energy: ReadStorage<'a, Energy>, @@ -92,7 +92,7 @@ impl<'a> TrackedComps<'a> { .get(entity) .cloned() .map(|c| comps.push(c.into())); - self.ability_pool + self.active_abilities .get(entity) .cloned() .map(|c| comps.push(c.into())); @@ -192,7 +192,7 @@ pub struct ReadTrackers<'a> { pub player: ReadExpect<'a, UpdateTracker>, pub stats: ReadExpect<'a, UpdateTracker>, pub skill_set: ReadExpect<'a, UpdateTracker>, - pub ability_pool: ReadExpect<'a, UpdateTracker>, + pub active_abilities: ReadExpect<'a, UpdateTracker>, pub buffs: ReadExpect<'a, UpdateTracker>, pub auras: ReadExpect<'a, UpdateTracker>, pub energy: ReadExpect<'a, UpdateTracker>, @@ -229,7 +229,12 @@ impl<'a> ReadTrackers<'a> { .with_component(&comps.uid, &*self.player, &comps.player, filter) .with_component(&comps.uid, &*self.stats, &comps.stats, filter) .with_component(&comps.uid, &*self.skill_set, &comps.skill_set, filter) - .with_component(&comps.uid, &*self.ability_pool, &comps.ability_pool, filter) + .with_component( + &comps.uid, + &*self.active_abilities, + &comps.active_abilities, + filter, + ) .with_component(&comps.uid, &*self.buffs, &comps.buffs, filter) .with_component(&comps.uid, &*self.auras, &comps.auras, filter) .with_component(&comps.uid, &*self.energy, &comps.energy, filter) @@ -273,7 +278,7 @@ pub struct WriteTrackers<'a> { player: WriteExpect<'a, UpdateTracker>, stats: WriteExpect<'a, UpdateTracker>, skill_set: WriteExpect<'a, UpdateTracker>, - ability_pool: WriteExpect<'a, UpdateTracker>, + active_abilities: WriteExpect<'a, UpdateTracker>, buffs: WriteExpect<'a, UpdateTracker>, auras: WriteExpect<'a, UpdateTracker>, energy: WriteExpect<'a, UpdateTracker>, @@ -304,7 +309,9 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) { trackers.player.record_changes(&comps.player); trackers.stats.record_changes(&comps.stats); trackers.skill_set.record_changes(&comps.skill_set); - trackers.ability_pool.record_changes(&comps.ability_pool); + trackers + .active_abilities + .record_changes(&comps.active_abilities); trackers.buffs.record_changes(&comps.buffs); trackers.auras.record_changes(&comps.auras); trackers.energy.record_changes(&comps.energy); @@ -350,7 +357,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) { log_counts!(player, "Players"); log_counts!(stats, "Stats"); log_counts!(skill_set, "SkillSet"); - log_counts!(ability_pool, "AbilityPool"); + log_counts!(active_abilities, "ActiveAbilities"); log_counts!(energy, "Energies"); log_counts!(combo, "Combos"); log_vounts!(health, "Healths"); @@ -377,7 +384,7 @@ pub fn register_trackers(world: &mut World) { world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); - world.register_tracker::(); + world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); diff --git a/voxygen/src/hud/hotbar.rs b/voxygen/src/hud/hotbar.rs index 51d4d1f547..c22e1b5b96 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -58,14 +58,14 @@ impl State { // Removes ability slots if not there and shouldn't be present pub fn maintain_abilities(&mut self, client: &client::Client) { use specs::WorldExt; - if let Some(ability_pool) = client + if let Some(active_abilities) = client .state() .ecs() - .read_storage::() + .read_storage::() .get(client.entity()) { use common::comp::ability::AuxiliaryAbility; - for ((i, ability), hotbar_slot) in ability_pool + for ((i, ability), hotbar_slot) in active_abilities .abilities .iter() .enumerate() @@ -82,7 +82,10 @@ impl State { } } } else { - self.slots.iter_mut().for_each(|slot| *slot = None) + self.slots + .iter_mut() + .filter(|slot| matches!(slot, Some(SlotContents::Ability(_)))) + .for_each(|slot| *slot = None) } } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 76d890bbee..f6653a6fcd 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -2640,7 +2640,7 @@ impl Hud { let inventories = ecs.read_storage::(); let energies = ecs.read_storage::(); let skillsets = ecs.read_storage::(); - let ability_pools = ecs.read_storage::(); + let active_abilities = ecs.read_storage::(); let character_states = ecs.read_storage::(); let controllers = ecs.read_storage::(); let bodies = ecs.read_storage::(); @@ -2666,7 +2666,7 @@ impl Hud { Some(inventory), Some(energy), Some(skillset), - Some(ability_pool), + Some(active_abilities), Some(body), Some(_character_state), Some(_controller), @@ -2675,7 +2675,7 @@ impl Hud { inventories.get(entity), energies.get(entity), skillsets.get(entity), - ability_pools.get(entity), + active_abilities.get(entity), bodies.get(entity), character_states.get(entity), controllers.get(entity).map(|c| &c.inputs), @@ -2691,7 +2691,7 @@ impl Hud { inventory, energy, skillset, - ability_pool, + active_abilities, body, //&character_state, self.pulse, diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index cd4500bcf9..b3001fac41 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -23,7 +23,7 @@ use common::comp::{ self, ability::AbilityInput, item::{ItemDesc, MaterialStatManifest}, - Ability, AbilityPool, Body, Energy, Health, Inventory, SkillSet, + Ability, ActiveAbilities, Body, Energy, Health, Inventory, SkillSet, }; use conrod_core::{ color, @@ -250,7 +250,7 @@ pub struct Skillbar<'a> { inventory: &'a Inventory, energy: &'a Energy, skillset: &'a SkillSet, - ability_pool: &'a AbilityPool, + active_abilities: &'a ActiveAbilities, body: &'a Body, // character_state: &'a CharacterState, // controller: &'a ControllerInputs, @@ -279,7 +279,7 @@ impl<'a> Skillbar<'a> { inventory: &'a Inventory, energy: &'a Energy, skillset: &'a SkillSet, - ability_pool: &'a AbilityPool, + active_abilities: &'a ActiveAbilities, body: &'a Body, // character_state: &'a CharacterState, pulse: f32, @@ -303,7 +303,7 @@ impl<'a> Skillbar<'a> { inventory, energy, skillset, - ability_pool, + active_abilities, body, common: widget::CommonBuilder::default(), // character_state, @@ -519,7 +519,7 @@ impl<'a> Skillbar<'a> { self.inventory, self.energy, self.skillset, - self.ability_pool, + self.active_abilities, self.body, ); @@ -601,16 +601,16 @@ impl<'a> Skillbar<'a> { // Helper let tooltip_text = |slot| { - let (hotbar, inventory, _, _, ability_pool, _) = content_source; + let (hotbar, inventory, _, _, active_abilities, _) = content_source; hotbar.get(slot).and_then(|content| match content { hotbar::SlotContents::Inventory(i) => inventory .get(i) .map(|item| (item.name(), item.description())), - hotbar::SlotContents::Ability(i) => ability_pool + hotbar::SlotContents::Ability(i) => active_abilities .abilities .get(i) .and_then(|a| Ability::from(*a).ability_id(Some(inventory))) - .and_then(|id| util::ability_description(id)), + .map(|id| util::ability_description(id)), }) }; @@ -680,7 +680,7 @@ impl<'a> Skillbar<'a> { .set(state.ids.m1_slot_bg, ui); let primary_ability_id = - Ability::from(self.ability_pool.primary).ability_id(Some(self.inventory)); + Ability::from(self.active_abilities.primary).ability_id(Some(self.inventory)); Button::image( primary_ability_id.map_or(self.imgs.nothing, |id| util::ability_image(self.imgs, id)), @@ -695,7 +695,7 @@ impl<'a> Skillbar<'a> { .set(state.ids.m2_slot_bg, ui); let secondary_ability_id = - Ability::from(self.ability_pool.secondary).ability_id(Some(self.inventory)); + Ability::from(self.active_abilities.secondary).ability_id(Some(self.inventory)); Button::image( secondary_ability_id.map_or(self.imgs.nothing, |id| util::ability_image(self.imgs, id)), @@ -705,12 +705,12 @@ impl<'a> Skillbar<'a> { .image_color( if self.energy.current() >= self - .ability_pool + .active_abilities .activate_ability( AbilityInput::Secondary, Some(self.inventory), self.skillset, - self.body, + Some(self.body), ) .map_or(0.0, |(a, _)| a.get_energy_cost()) { diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index b919ab74ac..5e83a48371 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -6,7 +6,8 @@ use super::{ }; use crate::ui::slot::{self, SlotKey, SumSlot}; use common::comp::{ - ability::AbilityInput, slot::InvSlotId, Ability, AbilityPool, Body, Energy, Inventory, SkillSet, + ability::AbilityInput, slot::InvSlotId, Ability, ActiveAbilities, Body, Energy, Inventory, + SkillSet, }; use conrod_core::{image, Color}; use specs::Entity as EcsEntity; @@ -117,7 +118,7 @@ type HotbarSource<'a> = ( &'a Inventory, &'a Energy, &'a SkillSet, - &'a AbilityPool, + &'a ActiveAbilities, &'a Body, ); type HotbarImageSource<'a> = (&'a ItemImgs, &'a img_ids::Imgs); @@ -127,7 +128,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { fn image_key( &self, - (hotbar, inventory, energy, skillset, ability_pool, body): &HotbarSource<'a>, + (hotbar, inventory, energy, skillset, active_abilities, body): &HotbarSource<'a>, ) -> Option<(Self::ImageKey, Option)> { hotbar.get(*self).and_then(|contents| match contents { hotbar::SlotContents::Inventory(idx) => inventory @@ -135,7 +136,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { .map(|item| HotbarImage::Item(item.into())) .map(|i| (i, None)), hotbar::SlotContents::Ability(i) => { - let ability_id = ability_pool + let ability_id = active_abilities .abilities .get(i) .and_then(|a| Ability::from(*a).ability_id(Some(inventory))); @@ -143,12 +144,12 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { ability_id .map(|id| HotbarImage::Ability(id.to_string())) .and_then(|image| { - ability_pool + active_abilities .activate_ability( AbilityInput::Auxiliary(i), Some(inventory), skillset, - body, + Some(body), ) .map(|(ability, _)| { ( diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index 4cff120767..b9aa00dcc9 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -326,53 +326,57 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id { } #[rustfmt::skip] -pub fn ability_description(ability_id: &str) -> Option<(&str, &str)> { +pub fn ability_description(ability_id: &str) -> (&str, &str) { match ability_id { // Debug stick - "common.abilities.debug.possess" => Some(( + "common.abilities.debug.possess" => ( "Possessing Arrow", "\n\ Shoots a poisonous arrow.\n\ Lets you control your target.", - )), + ), // Sword - "common.abilities.sword.spin" => Some(( + "common.abilities.sword.spin" => ( "Whirlwind", "\n\ Move forward while spinning with your sword.", - )), + ), // Axe - "common.abilities.axe.leap" => Some(( + "common.abilities.axe.leap" => ( "Axe Jump", "\n\ A jump with the slashing leap to position of cursor.", - )), + ), // Hammer - "common.abilities.hammer.leap" => Some(( + "common.abilities.hammer.leap" => ( "Smash of Doom", "\n\ An AOE attack with knockback.\n\ Leaps to position of cursor.", - )), + ), // Bow - "common.abilities.bow.shotgun" => Some(( + "common.abilities.bow.shotgun" => ( "Burst", "\n\ Launches a burst of arrows", - )), + ), // Staff - "common.abilities.staff.fireshockwave" => Some(( + "common.abilities.staff.fireshockwave" => ( "Ring of Fire", "\n\ Ignites the ground with fiery shockwave.", - )), + ), // Sceptre - "common.abilities.sceptre.wardingaura" => Some(( + "common.abilities.sceptre.wardingaura" => ( "Thorn Bulwark", "\n\ Protects you and your group with thorns\n\ for a short amount of time.", - )), - _ => None, + ), + _ => ( + "Ability as no title", + "\n\ + Ability has no description." + ), } }