Addressed further review.

This commit is contained in:
Sam 2021-11-11 22:37:37 -05:00
parent dfcb8c8519
commit a288f9ee43
20 changed files with 250 additions and 215 deletions

View File

@ -15,7 +15,7 @@ sum_type! {
CanBuild(comp::CanBuild), CanBuild(comp::CanBuild),
Stats(comp::Stats), Stats(comp::Stats),
SkillSet(comp::SkillSet), SkillSet(comp::SkillSet),
AbilityPool(comp::AbilityPool), ActiveAbilities(comp::ActiveAbilities),
Buffs(comp::Buffs), Buffs(comp::Buffs),
Auras(comp::Auras), Auras(comp::Auras),
Energy(comp::Energy), Energy(comp::Energy),
@ -51,7 +51,7 @@ sum_type! {
CanBuild(PhantomData<comp::CanBuild>), CanBuild(PhantomData<comp::CanBuild>),
Stats(PhantomData<comp::Stats>), Stats(PhantomData<comp::Stats>),
SkillSet(PhantomData<comp::SkillSet>), SkillSet(PhantomData<comp::SkillSet>),
AbilityPool(PhantomData<comp::AbilityPool>), ActiveAbilities(PhantomData<comp::ActiveAbilities>),
Buffs(PhantomData<comp::Buffs>), Buffs(PhantomData<comp::Buffs>),
Auras(PhantomData<comp::Auras>), Auras(PhantomData<comp::Auras>),
Energy(PhantomData<comp::Energy>), Energy(PhantomData<comp::Energy>),
@ -87,7 +87,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Stats(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::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::Buffs(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Auras(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), 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::CanBuild(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Stats(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::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::Buffs(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Auras(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), EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world),
@ -167,8 +167,8 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPhantom::CanBuild(_) => sync::handle_remove::<comp::CanBuild>(entity, world), EcsCompPhantom::CanBuild(_) => sync::handle_remove::<comp::CanBuild>(entity, world),
EcsCompPhantom::Stats(_) => sync::handle_remove::<comp::Stats>(entity, world), EcsCompPhantom::Stats(_) => sync::handle_remove::<comp::Stats>(entity, world),
EcsCompPhantom::SkillSet(_) => sync::handle_remove::<comp::SkillSet>(entity, world), EcsCompPhantom::SkillSet(_) => sync::handle_remove::<comp::SkillSet>(entity, world),
EcsCompPhantom::AbilityPool(_) => { EcsCompPhantom::ActiveAbilities(_) => {
sync::handle_remove::<comp::AbilityPool>(entity, world) sync::handle_remove::<comp::ActiveAbilities>(entity, world)
}, },
EcsCompPhantom::Buffs(_) => sync::handle_remove::<comp::Buffs>(entity, world), EcsCompPhantom::Buffs(_) => sync::handle_remove::<comp::Buffs>(entity, world),
EcsCompPhantom::Auras(_) => sync::handle_remove::<comp::Auras>(entity, world), EcsCompPhantom::Auras(_) => sync::handle_remove::<comp::Auras>(entity, world),

View File

@ -5,7 +5,7 @@ use crate::{
self, aura, beam, buff, self, aura, beam, buff,
inventory::{ inventory::{
item::{ item::{
tool::{Stats, ToolKind}, tool::{AbilityItem, Stats, ToolKind},
ItemKind, ItemKind,
}, },
slot::EquipSlot, 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 // set of weapons. Consider after UI is set up and people weigh in on memory
// considerations. // considerations.
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AbilityPool { pub struct ActiveAbilities {
pub primary: PrimaryAbility, pub primary: PrimaryAbility,
pub secondary: SecondaryAbility, pub secondary: SecondaryAbility,
pub movement: MovementAbility, pub movement: MovementAbility,
pub abilities: [AuxiliaryAbility; MAX_ABILITIES], pub abilities: [AuxiliaryAbility; MAX_ABILITIES],
} }
impl Component for AbilityPool { impl Component for ActiveAbilities {
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>; type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
} }
impl Default for AbilityPool { impl Default for ActiveAbilities {
fn default() -> Self { fn default() -> Self {
Self { Self {
primary: PrimaryAbility::Tool, 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 { pub fn new(inv: Option<&Inventory>, skill_set: Option<&SkillSet>) -> Self {
let mut pool = Self::default(); let mut pool = Self::default();
pool.auto_update(inv, skill_set); pool.auto_update(inv, skill_set);
@ -90,7 +90,7 @@ impl AbilityPool {
input: AbilityInput, input: AbilityInput,
inv: Option<&Inventory>, inv: Option<&Inventory>,
skill_set: &SkillSet, skill_set: &SkillSet,
body: &Body, body: Option<&Body>,
// bool is from_offhand // bool is from_offhand
) -> Option<(CharacterAbility, bool)> { ) -> Option<(CharacterAbility, bool)> {
let ability = self.get_ability(input); let ability = self.get_ability(input);
@ -110,6 +110,10 @@ impl AbilityPool {
ability.adjusted_by_skills(skill_set, tool_kind) ability.adjusted_by_skills(skill_set, tool_kind)
}; };
let unwrap_ability = |(skill_req, ability): &(Option<Skill>, AbilityItem)| {
(*skill_req, ability.ability.clone())
};
let unlocked = |(s, a): (Option<Skill>, CharacterAbility)| { let unlocked = |(s, a): (Option<Skill>, CharacterAbility)| {
// If there is a skill requirement and the skillset does not contain the // If there is a skill requirement and the skillset does not contain the
// required skill, return None // required skill, return None
@ -118,25 +122,25 @@ impl AbilityPool {
match ability { match ability {
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand) 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)), .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)),
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) 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)) .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true))
.or_else(|| { .or_else(|| {
ability_set(EquipSlot::ActiveMainhand) ability_set(EquipSlot::ActiveMainhand)
.map(|abilities| abilities.secondary.clone()) .map(|abilities| abilities.secondary.ability.clone())
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false))
}), }),
Ability::SpeciesMovement => matches!(body, Body::Humanoid(_)) Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_)))
.then(|| CharacterAbility::default_roll) .then(CharacterAbility::default_roll)
.map(|ability| (ability().adjusted_by_skills(skill_set, None), false)), .map(|ability| (ability.adjusted_by_skills(skill_set, None), false)),
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand) 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) .and_then(unlocked)
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)), .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)),
Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand) 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) .and_then(unlocked)
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)), .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)),
Ability::Empty => None, Ability::Empty => None,
@ -149,19 +153,13 @@ impl AbilityPool {
inv: Option<&Inventory>, inv: Option<&Inventory>,
skill_set: Option<&SkillSet>, skill_set: Option<&SkillSet>,
equip_slot: EquipSlot, equip_slot: EquipSlot,
) -> Vec<AuxiliaryAbility> { ) -> Vec<usize> {
let ability_from_slot = move |i| match equip_slot {
EquipSlot::ActiveMainhand => AuxiliaryAbility::MainWeapon(i),
EquipSlot::ActiveOffhand => AuxiliaryAbility::OffWeapon(i),
_ => AuxiliaryAbility::Empty,
};
inv inv
.and_then(|inv| inv.equipped(equip_slot)) .and_then(|inv| inv.equipped(equip_slot))
.iter() .iter()
.flat_map(|i| &i.item_config_expect().abilities.abilities) .flat_map(|i| &i.item_config_expect().abilities.abilities)
.enumerate() .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 // TODO: Let someone smarter than borrow checker remove collect
.collect() .collect()
} }
@ -170,9 +168,18 @@ impl AbilityPool {
let off_abilities = iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveOffhand); let off_abilities = iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveOffhand);
(0..MAX_ABILITIES) (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)| { .for_each(|(i, ability)| {
self.change_ability(i, *ability); self.change_ability(i, ability);
}) })
} }
} }
@ -198,25 +205,37 @@ pub enum Ability {
impl Ability { impl Ability {
pub fn ability_id(self, inv: Option<&Inventory>) -> Option<&str> { 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)) 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 { match self {
Ability::ToolPrimary => { Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
ability_id_set(EquipSlot::ActiveMainhand).map(|ids| ids.primary.as_str()) .map(|abilities| abilities.primary.id.as_str()),
}, Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
Ability::ToolSecondary => ability_id_set(EquipSlot::ActiveOffhand) .map(|abilities| abilities.secondary.id.as_str())
.map(|ids| ids.secondary.as_str())
.or_else(|| { .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::SpeciesMovement => None, // TODO: Make not None
Ability::MainWeaponAux(index) => ability_id_set(EquipSlot::ActiveMainhand) Ability::MainWeaponAux(index) => {
.and_then(|ids| ids.abilities.get(index).map(|(_, id)| id.as_str())), ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
Ability::OffWeaponAux(index) => ability_id_set(EquipSlot::ActiveOffhand) abilities
.and_then(|ids| ids.abilities.get(index).map(|(_, id)| id.as_str())), .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, Ability::Empty => None,
} }
} }

View File

@ -8,10 +8,7 @@ pub use tool::{AbilitySet, AbilitySpec, Hands, MaterialStatManifest, Tool, ToolK
use crate::{ use crate::{
assets::{self, AssetExt, Error}, assets::{self, AssetExt, Error},
comp::{ comp::inventory::{item::tool::AbilityMap, InvSlot},
inventory::{item::tool::AbilityMap, InvSlot},
CharacterAbility,
},
effect::Effect, effect::Effect,
recipe::RecipeInput, recipe::RecipeInput,
terrain::Block, terrain::Block,
@ -433,8 +430,7 @@ impl PartialEq for ItemDef {
// TODO: Look into removing ItemConfig and just using AbilitySet // TODO: Look into removing ItemConfig and just using AbilitySet
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ItemConfig { pub struct ItemConfig {
pub abilities: AbilitySet<CharacterAbility>, pub abilities: AbilitySet<tool::AbilityItem>,
pub ability_ids: AbilitySet<String>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -449,56 +445,33 @@ impl TryFrom<(&Item, &AbilityMap, &MaterialStatManifest)> for ItemConfig {
(item, ability_map, msm): (&Item, &AbilityMap, &MaterialStatManifest), (item, ability_map, msm): (&Item, &AbilityMap, &MaterialStatManifest),
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
if let ItemKind::Tool(tool) = &item.kind { if let ItemKind::Tool(tool) = &item.kind {
// TODO: Maybe try to make an ecs resource?
let ability_ids_map =
AbilityMap::<String>::load_expect("common.abilities.ability_set_manifest").read();
// If no custom ability set is specified, fall back to abilityset of tool kind. // If no custom ability set is specified, fall back to abilityset of tool kind.
let tool_default = |tool_kind| { let tool_default = |tool_kind| {
let key = &AbilitySpec::Tool(tool_kind); let key = &AbilitySpec::Tool(tool_kind);
( ability_map.get_ability_set(key)
ability_map.get_ability_set(key),
ability_ids_map.get_ability_set(key),
)
}; };
let (abilities, ability_ids) = if let Some(set_key) = item.ability_spec() { let abilities = if let Some(set_key) = item.ability_spec() {
if let (Some(set), Some(ids)) = ( if let Some(set) = ability_map.get_ability_set(set_key) {
ability_map.get_ability_set(set_key), set.clone().modified_by_tool(tool, msm, &item.components)
ability_ids_map.get_ability_set(set_key),
) {
(
set.clone().modified_by_tool(tool, msm, &item.components),
ids.clone(),
)
} else { } else {
error!( error!(
"Custom ability set: {:?} references non-existent set, falling back to \ "Custom ability set: {:?} references non-existent set, falling back to \
default ability set.", default ability set.",
set_key set_key
); );
let (abilities, ids) = tool_default(tool.kind); tool_default(tool.kind).cloned().unwrap_or_default()
(
abilities.cloned().unwrap_or_default(),
ids.cloned().unwrap_or_default(),
)
} }
} else if let (Some(set), Some(ids)) = tool_default(tool.kind) { } else if let Some(set) = tool_default(tool.kind) {
( set.clone().modified_by_tool(tool, msm, &item.components)
set.clone().modified_by_tool(tool, msm, &item.components),
ids.clone(),
)
} else { } else {
error!( error!(
"No ability set defined for tool: {:?}, falling back to default ability set.", "No ability set defined for tool: {:?}, falling back to default ability set.",
tool.kind tool.kind
); );
(Default::default(), Default::default()) Default::default()
}; };
Ok(ItemConfig { Ok(ItemConfig { abilities })
abilities,
ability_ids,
})
} else { } else {
Err(ItemConfigError::BadItemKind) Err(ItemConfigError::BadItemKind)
} }

View File

@ -345,7 +345,7 @@ pub struct AbilitySet<T> {
pub abilities: Vec<(Option<Skill>, T)>, pub abilities: Vec<(Option<Skill>, T)>,
} }
impl AbilitySet<CharacterAbility> { impl AbilitySet<AbilityItem> {
pub fn modified_by_tool( pub fn modified_by_tool(
self, self,
tool: &Tool, tool: &Tool,
@ -353,7 +353,10 @@ impl AbilitySet<CharacterAbility> {
components: &[Item], components: &[Item],
) -> Self { ) -> Self {
let stats = Stats::from((msm, components, tool)); 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<T> AbilitySet<T> {
} }
#[allow(clippy::derivable_impls)] #[allow(clippy::derivable_impls)]
impl Default for AbilitySet<CharacterAbility> { impl Default for AbilitySet<AbilityItem> {
fn default() -> Self { fn default() -> Self {
AbilitySet { AbilitySet {
primary: CharacterAbility::default(), primary: AbilityItem {
secondary: CharacterAbility::default(), id: String::new(),
abilities: Vec::new(), ability: CharacterAbility::default(),
} },
} secondary: AbilityItem {
} id: String::new(),
ability: CharacterAbility::default(),
#[allow(clippy::derivable_impls)] },
impl Default for AbilitySet<String> {
fn default() -> Self {
AbilitySet {
primary: String::new(),
secondary: String::new(),
abilities: Vec::new(), abilities: Vec::new(),
} }
} }
@ -404,7 +402,13 @@ pub enum AbilitySpec {
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbilityMap<T = CharacterAbility>(HashMap<AbilitySpec, AbilitySet<T>>); pub struct AbilityItem {
pub id: String,
pub ability: CharacterAbility,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbilityMap<T = AbilityItem>(HashMap<AbilitySpec, AbilitySet<T>>);
impl Default for AbilityMap { impl Default for AbilityMap {
fn default() -> Self { fn default() -> Self {
@ -445,7 +449,10 @@ impl assets::Compound for AbilityMap {
kind.clone(), kind.clone(),
// expect cannot fail because CharacterAbility always // expect cannot fail because CharacterAbility always
// provides a default value in case of failure // 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(), .collect(),

View File

@ -48,7 +48,7 @@ pub mod visual;
// Reexports // Reexports
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub use self::{ pub use self::{
ability::{Ability, AbilityPool, CharacterAbility, CharacterAbilityType}, ability::{Ability, AbilityInput, ActiveAbilities, CharacterAbility, CharacterAbilityType},
admin::{Admin, AdminRole}, admin::{Admin, AdminRole},
agent::{Agent, Alignment, Behavior, BehaviorCapability, BehaviorState, PidController}, agent::{Agent, Alignment, Behavior, BehaviorCapability, BehaviorState, PidController},
anchor::Anchor, anchor::Anchor,
@ -78,7 +78,11 @@ pub use self::{
group::Group, group::Group,
inputs::CanBuild, inputs::CanBuild,
inventory::{ inventory::{
item::{self, tool, Item, ItemConfig, ItemDrop}, item::{
self,
tool::{self, AbilityItem},
Item, ItemConfig, ItemDrop,
},
slot, Inventory, InventoryUpdate, InventoryUpdateEvent, slot, Inventory, InventoryUpdate, InventoryUpdateEvent,
}, },
last::Last, last::Last,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{ comp::{
self, character_state::OutputEvents, item::MaterialStatManifest, AbilityPool, Beam, Body, self, character_state::OutputEvents, item::MaterialStatManifest, ActiveAbilities, Beam,
CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy, Body, CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy,
Health, InputAttr, InputKind, Inventory, InventoryAction, Mass, Melee, Ori, PhysicsState, Health, InputAttr, InputKind, Inventory, InventoryAction, Mass, Melee, Ori, PhysicsState,
Pos, SkillSet, StateUpdate, Stats, Vel, Pos, SkillSet, StateUpdate, Stats, Vel,
}, },
@ -124,7 +124,7 @@ pub struct JoinData<'a> {
pub updater: &'a LazyUpdate, pub updater: &'a LazyUpdate,
pub stats: &'a Stats, pub stats: &'a Stats,
pub skill_set: &'a SkillSet, pub skill_set: &'a SkillSet,
pub ability_pool: &'a AbilityPool, pub active_abilities: &'a ActiveAbilities,
pub msm: &'a MaterialStatManifest, pub msm: &'a MaterialStatManifest,
pub combo: &'a Combo, pub combo: &'a Combo,
pub alignment: Option<&'a comp::Alignment>, pub alignment: Option<&'a comp::Alignment>,
@ -150,7 +150,7 @@ pub struct JoinStruct<'a> {
pub beam: Option<&'a Beam>, pub beam: Option<&'a Beam>,
pub stat: &'a Stats, pub stat: &'a Stats,
pub skill_set: &'a SkillSet, pub skill_set: &'a SkillSet,
pub ability_pool: &'a AbilityPool, pub active_abilities: &'a ActiveAbilities,
pub combo: &'a Combo, pub combo: &'a Combo,
pub alignment: Option<&'a comp::Alignment>, pub alignment: Option<&'a comp::Alignment>,
pub terrain: &'a TerrainGrid, pub terrain: &'a TerrainGrid,
@ -188,7 +188,7 @@ impl<'a> JoinData<'a> {
combo: j.combo, combo: j.combo,
alignment: j.alignment, alignment: j.alignment,
terrain: j.terrain, terrain: j.terrain,
ability_pool: j.ability_pool, active_abilities: j.active_abilities,
} }
} }
} }

View File

@ -823,8 +823,13 @@ pub fn handle_jump(
fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKind) { fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKind) {
if let Some(ability_input) = input.into() { if let Some(ability_input) = input.into() {
if let Some((ability, from_offhand)) = data if let Some((ability, from_offhand)) = data
.ability_pool .active_abilities
.activate_ability(ability_input, data.inventory, data.skill_set, data.body) .activate_ability(
ability_input,
data.inventory,
data.skill_set,
Some(data.body),
)
.filter(|(ability, _)| ability.requirements_paid(data, update)) .filter(|(ability, _)| ability.requirements_paid(data, update))
{ {
update.character = CharacterState::from(( update.character = CharacterState::from((

View File

@ -129,7 +129,7 @@ impl State {
ecs.register::<comp::Player>(); ecs.register::<comp::Player>();
ecs.register::<comp::Stats>(); ecs.register::<comp::Stats>();
ecs.register::<comp::SkillSet>(); ecs.register::<comp::SkillSet>();
ecs.register::<comp::AbilityPool>(); ecs.register::<comp::ActiveAbilities>();
ecs.register::<comp::Buffs>(); ecs.register::<comp::Buffs>();
ecs.register::<comp::Auras>(); ecs.register::<comp::Auras>();
ecs.register::<comp::Energy>(); ecs.register::<comp::Energy>();

View File

@ -5,9 +5,9 @@ use specs::{
use common::{ use common::{
comp::{ comp::{
self, character_state::OutputEvents, inventory::item::MaterialStatManifest, AbilityPool, self, character_state::OutputEvents, inventory::item::MaterialStatManifest,
Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health, Inventory, ActiveAbilities, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health,
InventoryManip, Mass, Melee, Mounting, Ori, PhysicsState, Poise, Pos, SkillSet, Inventory, InventoryManip, Mass, Melee, Mounting, Ori, PhysicsState, Poise, Pos, SkillSet,
StateUpdate, Stats, Vel, StateUpdate, Stats, Vel,
}, },
event::{EventBus, LocalEvent, ServerEvent}, event::{EventBus, LocalEvent, ServerEvent},
@ -39,7 +39,7 @@ pub struct ReadData<'a> {
mountings: ReadStorage<'a, Mounting>, mountings: ReadStorage<'a, Mounting>,
stats: ReadStorage<'a, Stats>, stats: ReadStorage<'a, Stats>,
skill_sets: ReadStorage<'a, SkillSet>, skill_sets: ReadStorage<'a, SkillSet>,
ability_pools: ReadStorage<'a, AbilityPool>, active_abilities: ReadStorage<'a, ActiveAbilities>,
msm: Read<'a, MaterialStatManifest>, msm: Read<'a, MaterialStatManifest>,
combos: ReadStorage<'a, Combo>, combos: ReadStorage<'a, Combo>,
alignments: ReadStorage<'a, comp::Alignment>, alignments: ReadStorage<'a, comp::Alignment>,
@ -109,7 +109,7 @@ impl<'a> System<'a> for Sys {
health, health,
body, body,
physics, physics,
(stat, skill_set, ability_pool), (stat, skill_set, active_abilities),
combo, combo,
) in ( ) in (
&read_data.entities, &read_data.entities,
@ -129,7 +129,7 @@ impl<'a> System<'a> for Sys {
( (
&read_data.stats, &read_data.stats,
&read_data.skill_sets, &read_data.skill_sets,
&read_data.ability_pools, &read_data.active_abilities,
), ),
&read_data.combos, &read_data.combos,
) )
@ -187,7 +187,7 @@ impl<'a> System<'a> for Sys {
beam: read_data.beams.get(entity), beam: read_data.beams.get(entity),
stat, stat,
skill_set, skill_set,
ability_pool, active_abilities,
combo, combo,
alignment: read_data.alignments.get(entity), alignment: read_data.alignments.get(entity),
terrain: &read_data.terrain, terrain: &read_data.terrain,

View File

@ -1,7 +1,7 @@
use common::{ use common::{
comp::{ comp::{
agent::{Sound, SoundKind}, agent::{Sound, SoundKind},
AbilityPool, Body, BuffChange, ControlEvent, Controller, Pos, ActiveAbilities, Body, BuffChange, ControlEvent, Controller, Pos,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
uid::UidAllocator, uid::UidAllocator,
@ -30,7 +30,7 @@ impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
ReadData<'a>, ReadData<'a>,
WriteStorage<'a, Controller>, WriteStorage<'a, Controller>,
WriteStorage<'a, AbilityPool>, WriteStorage<'a, ActiveAbilities>,
); );
const NAME: &'static str = "controller"; const NAME: &'static str = "controller";
@ -39,13 +39,11 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
_job: &mut Job<Self>, _job: &mut Job<Self>,
(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(); let mut server_emitter = read_data.server_bus.emitter();
for (entity, controller, mut ability_pool) in for (entity, controller) in (&read_data.entities, &mut controllers).join() {
(&read_data.entities, &mut controllers, &mut ability_pools).join()
{
// Sanitize inputs to avoid clients sending bad data // Sanitize inputs to avoid clients sending bad data
controller.inputs.sanitize(); controller.inputs.sanitize();
@ -113,7 +111,9 @@ impl<'a> System<'a> for Sys {
} }
}, },
ControlEvent::ChangeAbility { slot, new_ability } => { 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);
}
}, },
} }
} }

View File

@ -770,12 +770,12 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
// After any inventory manipulation, update the ability // After any inventory manipulation, update the ability
// TODO: Make less hacky, probably remove entirely but needs UI // 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() .ecs()
.write_storage::<comp::AbilityPool>() .write_storage::<comp::ActiveAbilities>()
.get_mut(entity) .get_mut(entity)
{ {
ability_pool.auto_update( active_abilities.auto_update(
state.ecs().read_storage::<comp::Inventory>().get(entity), state.ecs().read_storage::<comp::Inventory>().get(entity),
state.ecs().read_storage::<comp::SkillSet>().get(entity), state.ecs().read_storage::<comp::SkillSet>().get(entity),
); );

View File

@ -66,8 +66,7 @@ use common::{
assets::AssetExt, assets::AssetExt,
character::CharacterId, character::CharacterId,
cmd::ChatCommand, cmd::ChatCommand,
comp, comp::{self, item::MaterialStatManifest},
comp::{item::MaterialStatManifest, CharacterAbility},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
recipe::default_recipe_book, recipe::default_recipe_book,
resources::{BattleMode, Time, TimeOfDay}, resources::{BattleMode, Time, TimeOfDay},
@ -287,7 +286,7 @@ impl Server {
Arc::<RwLock<DatabaseSettings>>::clone(&database_settings), Arc::<RwLock<DatabaseSettings>>::clone(&database_settings),
)?); )?);
let ability_map = comp::item::tool::AbilityMap::<CharacterAbility>::load_expect_cloned( let ability_map = comp::item::tool::AbilityMap::<comp::AbilityItem>::load_expect_cloned(
"common.abilities.ability_set_manifest", "common.abilities.ability_set_manifest",
); );
state.ecs_mut().insert(ability_map); state.ecs_mut().insert(ability_map);

View File

@ -215,7 +215,10 @@ impl StateExt for State {
.unwrap_or(0), .unwrap_or(0),
)) ))
.with(stats) .with(stats)
.with(comp::AbilityPool::new(Some(&inventory), Some(&skill_set))) .with(comp::ActiveAbilities::new(
Some(&inventory),
Some(&skill_set),
))
.with(skill_set) .with(skill_set)
.maybe_with(health) .maybe_with(health)
.with(poise) .with(poise)
@ -268,7 +271,7 @@ impl StateExt for State {
.with(comp::Energy::new(ship.into(), 0)) .with(comp::Energy::new(ship.into(), 0))
.with(comp::Stats::new("Airship".to_string())) .with(comp::Stats::new("Airship".to_string()))
.with(comp::SkillSet::default()) .with(comp::SkillSet::default())
.with(comp::AbilityPool::default()) .with(comp::ActiveAbilities::default())
.with(comp::Combo::default()); .with(comp::Combo::default());
if mountable { 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, stats);
self.write_component_ignore_entity_dead( self.write_component_ignore_entity_dead(
entity, 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, skill_set);
self.write_component_ignore_entity_dead(entity, inventory); self.write_component_ignore_entity_dead(entity, inventory);

View File

@ -19,9 +19,9 @@ use common::{
}, },
projectile::ProjectileConstructor, projectile::ProjectileConstructor,
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill}, skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
Agent, Alignment, BehaviorCapability, BehaviorState, Body, CharacterAbility, AbilityInput, ActiveAbilities, Agent, Alignment, BehaviorCapability, BehaviorState, Body,
CharacterState, Combo, ControlAction, ControlEvent, Controller, Energy, Health, CharacterAbility, CharacterState, Combo, ControlAction, ControlEvent, Controller, Energy,
HealthChange, InputKind, Inventory, InventoryAction, LightEmitter, MountState, Ori, Health, HealthChange, InputKind, Inventory, InventoryAction, LightEmitter, MountState, Ori,
PhysicsState, Pos, Scale, SkillSet, Stats, UnresolvedChatMsg, UtteranceKind, Vel, PhysicsState, Pos, Scale, SkillSet, Stats, UnresolvedChatMsg, UtteranceKind, Vel,
}, },
consts::GRAVITY, consts::GRAVITY,
@ -74,6 +74,7 @@ struct AgentData<'a> {
is_gliding: bool, is_gliding: bool,
health: Option<&'a Health>, health: Option<&'a Health>,
char_state: &'a CharacterState, char_state: &'a CharacterState,
active_abilities: &'a ActiveAbilities,
cached_spatial_grid: &'a common::CachedSpatialGrid, cached_spatial_grid: &'a common::CachedSpatialGrid,
} }
@ -160,6 +161,7 @@ pub struct ReadData<'a> {
rtsim_entities: ReadStorage<'a, RtSimEntity>, rtsim_entities: ReadStorage<'a, RtSimEntity>,
buffs: ReadStorage<'a, Buffs>, buffs: ReadStorage<'a, Buffs>,
combos: ReadStorage<'a, Combo>, combos: ReadStorage<'a, Combo>,
active_abilities: ReadStorage<'a, ActiveAbilities>,
} }
const DAMAGE_MEMORY_DURATION: f64 = 0.25; const DAMAGE_MEMORY_DURATION: f64 = 0.25;
@ -212,7 +214,11 @@ impl<'a> System<'a> for Sys {
), ),
read_data.bodies.maybe(), read_data.bodies.maybe(),
&read_data.inventories, &read_data.inventories,
(
&read_data.char_states,
&read_data.skill_set, &read_data.skill_set,
&read_data.active_abilities,
),
&read_data.physics_states, &read_data.physics_states,
&read_data.uids, &read_data.uids,
&mut agents, &mut agents,
@ -220,10 +226,9 @@ impl<'a> System<'a> for Sys {
read_data.light_emitter.maybe(), read_data.light_emitter.maybe(),
read_data.groups.maybe(), read_data.groups.maybe(),
read_data.mount_states.maybe(), read_data.mount_states.maybe(),
&read_data.char_states,
) )
.par_join() .par_join()
.filter(|(_, _, _, _, _, _, _, _, _, _, _, _, mount_state, _)| { .filter(|(_, _, _, _, _, _, _, _, _, _, _, _, mount_state)| {
// Skip mounted entities // Skip mounted entities
mount_state mount_state
.map(|ms| *ms == MountState::Unmounted) .map(|ms| *ms == MountState::Unmounted)
@ -241,7 +246,7 @@ impl<'a> System<'a> for Sys {
(pos, vel, ori), (pos, vel, ori),
body, body,
inventory, inventory,
skill_set, (char_state, skill_set, active_abilities),
physics_state, physics_state,
uid, uid,
agent, agent,
@ -249,7 +254,6 @@ impl<'a> System<'a> for Sys {
light_emitter, light_emitter,
group, group,
_, _,
char_state,
)| { )| {
// Hack, replace with better system when groups are more sophisticated // Hack, replace with better system when groups are more sophisticated
// Override alignment if in a group unless entity is owned already // Override alignment if in a group unless entity is owned already
@ -359,6 +363,7 @@ impl<'a> System<'a> for Sys {
is_gliding, is_gliding,
health: read_data.healths.get(entity), health: read_data.healths.get(entity),
char_state, char_state,
active_abilities,
cached_spatial_grid: &read_data.cached_spatial_grid, cached_spatial_grid: &read_data.cached_spatial_grid,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -2502,30 +2507,35 @@ impl<'a> AgentData<'a> {
tgt_data: &TargetData, tgt_data: &TargetData,
read_data: &ReadData, read_data: &ReadData,
) { ) {
let extract_ability = |ability: &CharacterAbility| { let extract_ability = |input: AbilityInput| {
ability self.active_abilities
.clone() .activate_ability(input, Some(self.inventory), self.skill_set, self.body)
.adjusted_by_skills(self.skill_set, Some(ToolKind::Staff)) .unwrap_or_default()
.0
}; };
let (flamethrower, shockwave) = self let (flamethrower, shockwave) = (
.inventory extract_ability(AbilityInput::Secondary),
.equipped(EquipSlot::ActiveMainhand) extract_ability(AbilityInput::Auxiliary(0)),
.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())),
)
},
); );
// 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 { let flamethrower_range = match flamethrower {
CharacterAbility::BasicBeam { range, .. } => range, CharacterAbility::BasicBeam { range, .. } => range,
_ => 20.0_f32, _ => 20.0_f32,

View File

@ -1,9 +1,9 @@
use common::{ use common::{
comp::{ comp::{
item::{tool::AbilityMap, MaterialStatManifest}, item::{tool::AbilityMap, MaterialStatManifest},
AbilityPool, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Combo, ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider,
Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, MountState,
Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, Mounting, Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel,
}, },
uid::Uid, uid::Uid,
}; };
@ -44,7 +44,7 @@ pub struct TrackedComps<'a> {
pub player: ReadStorage<'a, Player>, pub player: ReadStorage<'a, Player>,
pub stats: ReadStorage<'a, Stats>, pub stats: ReadStorage<'a, Stats>,
pub skill_set: ReadStorage<'a, SkillSet>, pub skill_set: ReadStorage<'a, SkillSet>,
pub ability_pool: ReadStorage<'a, AbilityPool>, pub active_abilities: ReadStorage<'a, ActiveAbilities>,
pub buffs: ReadStorage<'a, Buffs>, pub buffs: ReadStorage<'a, Buffs>,
pub auras: ReadStorage<'a, Auras>, pub auras: ReadStorage<'a, Auras>,
pub energy: ReadStorage<'a, Energy>, pub energy: ReadStorage<'a, Energy>,
@ -92,7 +92,7 @@ impl<'a> TrackedComps<'a> {
.get(entity) .get(entity)
.cloned() .cloned()
.map(|c| comps.push(c.into())); .map(|c| comps.push(c.into()));
self.ability_pool self.active_abilities
.get(entity) .get(entity)
.cloned() .cloned()
.map(|c| comps.push(c.into())); .map(|c| comps.push(c.into()));
@ -192,7 +192,7 @@ pub struct ReadTrackers<'a> {
pub player: ReadExpect<'a, UpdateTracker<Player>>, pub player: ReadExpect<'a, UpdateTracker<Player>>,
pub stats: ReadExpect<'a, UpdateTracker<Stats>>, pub stats: ReadExpect<'a, UpdateTracker<Stats>>,
pub skill_set: ReadExpect<'a, UpdateTracker<SkillSet>>, pub skill_set: ReadExpect<'a, UpdateTracker<SkillSet>>,
pub ability_pool: ReadExpect<'a, UpdateTracker<AbilityPool>>, pub active_abilities: ReadExpect<'a, UpdateTracker<ActiveAbilities>>,
pub buffs: ReadExpect<'a, UpdateTracker<Buffs>>, pub buffs: ReadExpect<'a, UpdateTracker<Buffs>>,
pub auras: ReadExpect<'a, UpdateTracker<Auras>>, pub auras: ReadExpect<'a, UpdateTracker<Auras>>,
pub energy: ReadExpect<'a, UpdateTracker<Energy>>, pub energy: ReadExpect<'a, UpdateTracker<Energy>>,
@ -229,7 +229,12 @@ impl<'a> ReadTrackers<'a> {
.with_component(&comps.uid, &*self.player, &comps.player, filter) .with_component(&comps.uid, &*self.player, &comps.player, filter)
.with_component(&comps.uid, &*self.stats, &comps.stats, 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.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.buffs, &comps.buffs, filter)
.with_component(&comps.uid, &*self.auras, &comps.auras, filter) .with_component(&comps.uid, &*self.auras, &comps.auras, filter)
.with_component(&comps.uid, &*self.energy, &comps.energy, filter) .with_component(&comps.uid, &*self.energy, &comps.energy, filter)
@ -273,7 +278,7 @@ pub struct WriteTrackers<'a> {
player: WriteExpect<'a, UpdateTracker<Player>>, player: WriteExpect<'a, UpdateTracker<Player>>,
stats: WriteExpect<'a, UpdateTracker<Stats>>, stats: WriteExpect<'a, UpdateTracker<Stats>>,
skill_set: WriteExpect<'a, UpdateTracker<SkillSet>>, skill_set: WriteExpect<'a, UpdateTracker<SkillSet>>,
ability_pool: WriteExpect<'a, UpdateTracker<AbilityPool>>, active_abilities: WriteExpect<'a, UpdateTracker<ActiveAbilities>>,
buffs: WriteExpect<'a, UpdateTracker<Buffs>>, buffs: WriteExpect<'a, UpdateTracker<Buffs>>,
auras: WriteExpect<'a, UpdateTracker<Auras>>, auras: WriteExpect<'a, UpdateTracker<Auras>>,
energy: WriteExpect<'a, UpdateTracker<Energy>>, energy: WriteExpect<'a, UpdateTracker<Energy>>,
@ -304,7 +309,9 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
trackers.player.record_changes(&comps.player); trackers.player.record_changes(&comps.player);
trackers.stats.record_changes(&comps.stats); trackers.stats.record_changes(&comps.stats);
trackers.skill_set.record_changes(&comps.skill_set); 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.buffs.record_changes(&comps.buffs);
trackers.auras.record_changes(&comps.auras); trackers.auras.record_changes(&comps.auras);
trackers.energy.record_changes(&comps.energy); trackers.energy.record_changes(&comps.energy);
@ -350,7 +357,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
log_counts!(player, "Players"); log_counts!(player, "Players");
log_counts!(stats, "Stats"); log_counts!(stats, "Stats");
log_counts!(skill_set, "SkillSet"); log_counts!(skill_set, "SkillSet");
log_counts!(ability_pool, "AbilityPool"); log_counts!(active_abilities, "ActiveAbilities");
log_counts!(energy, "Energies"); log_counts!(energy, "Energies");
log_counts!(combo, "Combos"); log_counts!(combo, "Combos");
log_vounts!(health, "Healths"); log_vounts!(health, "Healths");
@ -377,7 +384,7 @@ pub fn register_trackers(world: &mut World) {
world.register_tracker::<Player>(); world.register_tracker::<Player>();
world.register_tracker::<Stats>(); world.register_tracker::<Stats>();
world.register_tracker::<SkillSet>(); world.register_tracker::<SkillSet>();
world.register_tracker::<AbilityPool>(); world.register_tracker::<ActiveAbilities>();
world.register_tracker::<Buffs>(); world.register_tracker::<Buffs>();
world.register_tracker::<Auras>(); world.register_tracker::<Auras>();
world.register_tracker::<Energy>(); world.register_tracker::<Energy>();

View File

@ -58,14 +58,14 @@ impl State {
// Removes ability slots if not there and shouldn't be present // Removes ability slots if not there and shouldn't be present
pub fn maintain_abilities(&mut self, client: &client::Client) { pub fn maintain_abilities(&mut self, client: &client::Client) {
use specs::WorldExt; use specs::WorldExt;
if let Some(ability_pool) = client if let Some(active_abilities) = client
.state() .state()
.ecs() .ecs()
.read_storage::<common::comp::AbilityPool>() .read_storage::<common::comp::ActiveAbilities>()
.get(client.entity()) .get(client.entity())
{ {
use common::comp::ability::AuxiliaryAbility; use common::comp::ability::AuxiliaryAbility;
for ((i, ability), hotbar_slot) in ability_pool for ((i, ability), hotbar_slot) in active_abilities
.abilities .abilities
.iter() .iter()
.enumerate() .enumerate()
@ -82,7 +82,10 @@ impl State {
} }
} }
} else { } 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)
} }
} }
} }

View File

@ -2640,7 +2640,7 @@ impl Hud {
let inventories = ecs.read_storage::<comp::Inventory>(); let inventories = ecs.read_storage::<comp::Inventory>();
let energies = ecs.read_storage::<comp::Energy>(); let energies = ecs.read_storage::<comp::Energy>();
let skillsets = ecs.read_storage::<comp::SkillSet>(); let skillsets = ecs.read_storage::<comp::SkillSet>();
let ability_pools = ecs.read_storage::<comp::AbilityPool>(); let active_abilities = ecs.read_storage::<comp::ActiveAbilities>();
let character_states = ecs.read_storage::<comp::CharacterState>(); let character_states = ecs.read_storage::<comp::CharacterState>();
let controllers = ecs.read_storage::<comp::Controller>(); let controllers = ecs.read_storage::<comp::Controller>();
let bodies = ecs.read_storage::<comp::Body>(); let bodies = ecs.read_storage::<comp::Body>();
@ -2666,7 +2666,7 @@ impl Hud {
Some(inventory), Some(inventory),
Some(energy), Some(energy),
Some(skillset), Some(skillset),
Some(ability_pool), Some(active_abilities),
Some(body), Some(body),
Some(_character_state), Some(_character_state),
Some(_controller), Some(_controller),
@ -2675,7 +2675,7 @@ impl Hud {
inventories.get(entity), inventories.get(entity),
energies.get(entity), energies.get(entity),
skillsets.get(entity), skillsets.get(entity),
ability_pools.get(entity), active_abilities.get(entity),
bodies.get(entity), bodies.get(entity),
character_states.get(entity), character_states.get(entity),
controllers.get(entity).map(|c| &c.inputs), controllers.get(entity).map(|c| &c.inputs),
@ -2691,7 +2691,7 @@ impl Hud {
inventory, inventory,
energy, energy,
skillset, skillset,
ability_pool, active_abilities,
body, body,
//&character_state, //&character_state,
self.pulse, self.pulse,

View File

@ -23,7 +23,7 @@ use common::comp::{
self, self,
ability::AbilityInput, ability::AbilityInput,
item::{ItemDesc, MaterialStatManifest}, item::{ItemDesc, MaterialStatManifest},
Ability, AbilityPool, Body, Energy, Health, Inventory, SkillSet, Ability, ActiveAbilities, Body, Energy, Health, Inventory, SkillSet,
}; };
use conrod_core::{ use conrod_core::{
color, color,
@ -250,7 +250,7 @@ pub struct Skillbar<'a> {
inventory: &'a Inventory, inventory: &'a Inventory,
energy: &'a Energy, energy: &'a Energy,
skillset: &'a SkillSet, skillset: &'a SkillSet,
ability_pool: &'a AbilityPool, active_abilities: &'a ActiveAbilities,
body: &'a Body, body: &'a Body,
// character_state: &'a CharacterState, // character_state: &'a CharacterState,
// controller: &'a ControllerInputs, // controller: &'a ControllerInputs,
@ -279,7 +279,7 @@ impl<'a> Skillbar<'a> {
inventory: &'a Inventory, inventory: &'a Inventory,
energy: &'a Energy, energy: &'a Energy,
skillset: &'a SkillSet, skillset: &'a SkillSet,
ability_pool: &'a AbilityPool, active_abilities: &'a ActiveAbilities,
body: &'a Body, body: &'a Body,
// character_state: &'a CharacterState, // character_state: &'a CharacterState,
pulse: f32, pulse: f32,
@ -303,7 +303,7 @@ impl<'a> Skillbar<'a> {
inventory, inventory,
energy, energy,
skillset, skillset,
ability_pool, active_abilities,
body, body,
common: widget::CommonBuilder::default(), common: widget::CommonBuilder::default(),
// character_state, // character_state,
@ -519,7 +519,7 @@ impl<'a> Skillbar<'a> {
self.inventory, self.inventory,
self.energy, self.energy,
self.skillset, self.skillset,
self.ability_pool, self.active_abilities,
self.body, self.body,
); );
@ -601,16 +601,16 @@ impl<'a> Skillbar<'a> {
// Helper // Helper
let tooltip_text = |slot| { 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.get(slot).and_then(|content| match content {
hotbar::SlotContents::Inventory(i) => inventory hotbar::SlotContents::Inventory(i) => inventory
.get(i) .get(i)
.map(|item| (item.name(), item.description())), .map(|item| (item.name(), item.description())),
hotbar::SlotContents::Ability(i) => ability_pool hotbar::SlotContents::Ability(i) => active_abilities
.abilities .abilities
.get(i) .get(i)
.and_then(|a| Ability::from(*a).ability_id(Some(inventory))) .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); .set(state.ids.m1_slot_bg, ui);
let primary_ability_id = 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( Button::image(
primary_ability_id.map_or(self.imgs.nothing, |id| util::ability_image(self.imgs, id)), 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); .set(state.ids.m2_slot_bg, ui);
let secondary_ability_id = 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( Button::image(
secondary_ability_id.map_or(self.imgs.nothing, |id| util::ability_image(self.imgs, id)), 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( .image_color(
if self.energy.current() if self.energy.current()
>= self >= self
.ability_pool .active_abilities
.activate_ability( .activate_ability(
AbilityInput::Secondary, AbilityInput::Secondary,
Some(self.inventory), Some(self.inventory),
self.skillset, self.skillset,
self.body, Some(self.body),
) )
.map_or(0.0, |(a, _)| a.get_energy_cost()) .map_or(0.0, |(a, _)| a.get_energy_cost())
{ {

View File

@ -6,7 +6,8 @@ use super::{
}; };
use crate::ui::slot::{self, SlotKey, SumSlot}; use crate::ui::slot::{self, SlotKey, SumSlot};
use common::comp::{ 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 conrod_core::{image, Color};
use specs::Entity as EcsEntity; use specs::Entity as EcsEntity;
@ -117,7 +118,7 @@ type HotbarSource<'a> = (
&'a Inventory, &'a Inventory,
&'a Energy, &'a Energy,
&'a SkillSet, &'a SkillSet,
&'a AbilityPool, &'a ActiveAbilities,
&'a Body, &'a Body,
); );
type HotbarImageSource<'a> = (&'a ItemImgs, &'a img_ids::Imgs); type HotbarImageSource<'a> = (&'a ItemImgs, &'a img_ids::Imgs);
@ -127,7 +128,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
fn image_key( fn image_key(
&self, &self,
(hotbar, inventory, energy, skillset, ability_pool, body): &HotbarSource<'a>, (hotbar, inventory, energy, skillset, active_abilities, body): &HotbarSource<'a>,
) -> Option<(Self::ImageKey, Option<Color>)> { ) -> Option<(Self::ImageKey, Option<Color>)> {
hotbar.get(*self).and_then(|contents| match contents { hotbar.get(*self).and_then(|contents| match contents {
hotbar::SlotContents::Inventory(idx) => inventory hotbar::SlotContents::Inventory(idx) => inventory
@ -135,7 +136,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
.map(|item| HotbarImage::Item(item.into())) .map(|item| HotbarImage::Item(item.into()))
.map(|i| (i, None)), .map(|i| (i, None)),
hotbar::SlotContents::Ability(i) => { hotbar::SlotContents::Ability(i) => {
let ability_id = ability_pool let ability_id = active_abilities
.abilities .abilities
.get(i) .get(i)
.and_then(|a| Ability::from(*a).ability_id(Some(inventory))); .and_then(|a| Ability::from(*a).ability_id(Some(inventory)));
@ -143,12 +144,12 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
ability_id ability_id
.map(|id| HotbarImage::Ability(id.to_string())) .map(|id| HotbarImage::Ability(id.to_string()))
.and_then(|image| { .and_then(|image| {
ability_pool active_abilities
.activate_ability( .activate_ability(
AbilityInput::Auxiliary(i), AbilityInput::Auxiliary(i),
Some(inventory), Some(inventory),
skillset, skillset,
body, Some(body),
) )
.map(|(ability, _)| { .map(|(ability, _)| {
( (

View File

@ -326,53 +326,57 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
} }
#[rustfmt::skip] #[rustfmt::skip]
pub fn ability_description(ability_id: &str) -> Option<(&str, &str)> { pub fn ability_description(ability_id: &str) -> (&str, &str) {
match ability_id { match ability_id {
// Debug stick // Debug stick
"common.abilities.debug.possess" => Some(( "common.abilities.debug.possess" => (
"Possessing Arrow", "Possessing Arrow",
"\n\ "\n\
Shoots a poisonous arrow.\n\ Shoots a poisonous arrow.\n\
Lets you control your target.", Lets you control your target.",
)), ),
// Sword // Sword
"common.abilities.sword.spin" => Some(( "common.abilities.sword.spin" => (
"Whirlwind", "Whirlwind",
"\n\ "\n\
Move forward while spinning with your sword.", Move forward while spinning with your sword.",
)), ),
// Axe // Axe
"common.abilities.axe.leap" => Some(( "common.abilities.axe.leap" => (
"Axe Jump", "Axe Jump",
"\n\ "\n\
A jump with the slashing leap to position of cursor.", A jump with the slashing leap to position of cursor.",
)), ),
// Hammer // Hammer
"common.abilities.hammer.leap" => Some(( "common.abilities.hammer.leap" => (
"Smash of Doom", "Smash of Doom",
"\n\ "\n\
An AOE attack with knockback.\n\ An AOE attack with knockback.\n\
Leaps to position of cursor.", Leaps to position of cursor.",
)), ),
// Bow // Bow
"common.abilities.bow.shotgun" => Some(( "common.abilities.bow.shotgun" => (
"Burst", "Burst",
"\n\ "\n\
Launches a burst of arrows", Launches a burst of arrows",
)), ),
// Staff // Staff
"common.abilities.staff.fireshockwave" => Some(( "common.abilities.staff.fireshockwave" => (
"Ring of Fire", "Ring of Fire",
"\n\ "\n\
Ignites the ground with fiery shockwave.", Ignites the ground with fiery shockwave.",
)), ),
// Sceptre // Sceptre
"common.abilities.sceptre.wardingaura" => Some(( "common.abilities.sceptre.wardingaura" => (
"Thorn Bulwark", "Thorn Bulwark",
"\n\ "\n\
Protects you and your group with thorns\n\ Protects you and your group with thorns\n\
for a short amount of time.", for a short amount of time.",
)), ),
_ => None, _ => (
"Ability as no title",
"\n\
Ability has no description."
),
} }
} }