diff --git a/CHANGELOG.md b/CHANGELOG.md index f792f93994..d39623f0c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Loading-Screen tips - Feeding animation for some animals - Power stat to weapons which affects weapon damage -- Add IDs to abilities. ### Changed diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 357482ebce..79292b797e 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -43,63 +43,6 @@ impl From<&CharacterState> for CharacterAbilityType { } } -/// This enum is used for matching ability to image in GUI. -/// This is beacuse `CharacterAbility` can have more "meanings" -/// (like axe swing and sword swing, both are BasicMelee) -/// and different GUI can be done for each. -/// -/// TODO: Dehardcode this in case of modding. -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)] -pub enum AbilityId { - // Sword - SwordCut, - SwordThrust, - // Axe - AxeSwing, - AxeSpin, - // Hammer - HammerSmash, - HammerLeap, - // Bow - BowShot, - BowCharged, - // Staff - StaffSwing, - StaffShot, - StaffFireball, - StaffHeal, - // Dagger - DaggerStab, - DaggerDash, - // Shield - ShieldBash, - ShieldBlock, - // Farming - FarmingAttack, - // Debug - DebugFlyDirection, - DebugFlyUp, - DebugPossesArrow, - // Special - // TODO: Review usage - Roll, - Block, - Empty, -} - -/// Unique ability config. -/// It composes from an ID (currently used to inform Client's GUI) -/// and data, which is the actual ability behaviour/config. -#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct Ability { - pub id: AbilityId, - pub data: CharacterAbility, -} - -impl Ability { - pub fn new(id: AbilityId, data: CharacterAbility) -> Ability { Ability { id, data } } -} - #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub enum CharacterAbility { BasicMelee { @@ -215,11 +158,11 @@ impl CharacterAbility { #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct ItemConfig { pub item: Item, - pub ability1: Option, - pub ability2: Option, - pub ability3: Option, - pub block_ability: Option, - pub dodge_ability: Option, + pub ability1: Option, + pub ability2: Option, + pub ability3: Option, + pub block_ability: Option, + pub dodge_ability: Option, } #[derive(Arraygen, Clone, PartialEq, Default, Debug, Serialize, Deserialize)] @@ -417,10 +360,6 @@ impl From<&CharacterAbility> for CharacterState { } } -impl From<&Ability> for CharacterState { - fn from(ability: &Ability) -> Self { CharacterState::from(&ability.data) } -} - impl Component for Loadout { type Storage = FlaggedStorage>; } diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 79a9908c65..742709901e 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -2,8 +2,7 @@ // version in voxygen\src\meta.rs in order to reset save files to being empty use crate::comp::{ - body::object, projectile, Ability, AbilityId, Body, CharacterAbility, Gravity, LightEmitter, - Projectile, + body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile, }; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -107,62 +106,62 @@ impl Tool { Duration::from_millis(self.stats.equip_time_millis as u64) } - pub fn get_abilities(&self) -> Vec { + pub fn get_abilities(&self) -> Vec { use CharacterAbility::*; use ToolKind::*; match &self.kind { Sword(_) => vec![ - Ability::new(AbilityId::SwordCut, TripleStrike { + TripleStrike { base_damage: (60.0 * self.base_power()) as u32, needs_timing: false, - }), - Ability::new(AbilityId::SwordThrust, DashMelee { + }, + DashMelee { energy_cost: 700, buildup_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(500), base_damage: (120.0 * self.base_power()) as u32, - }), + }, ], Axe(_) => vec![ - Ability::new(AbilityId::AxeSwing, TripleStrike { + TripleStrike { base_damage: (80.0 * self.base_power()) as u32, needs_timing: true, - }), - Ability::new(AbilityId::AxeSpin, SpinMelee { + }, + SpinMelee { energy_cost: 100, buildup_duration: Duration::from_millis(125), recover_duration: Duration::from_millis(125), base_damage: (60.0 * self.base_power()) as u32, - }), + }, ], Hammer(_) => vec![ - Ability::new(AbilityId::HammerSmash, BasicMelee { + BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(700), recover_duration: Duration::from_millis(300), base_healthchange: (-120.0 * self.base_power()) as i32, range: 3.5, max_angle: 60.0, - }), - Ability::new(AbilityId::HammerLeap, LeapMelee { + }, + LeapMelee { energy_cost: 800, movement_duration: Duration::from_millis(500), buildup_duration: Duration::from_millis(1000), recover_duration: Duration::from_millis(100), base_damage: (240.0 * self.base_power()) as u32, - }), + }, ], - Farming(_) => vec![Ability::new(AbilityId::FarmingAttack, BasicMelee { + Farming(_) => vec![BasicMelee { energy_cost: 1, buildup_duration: Duration::from_millis(700), recover_duration: Duration::from_millis(150), base_healthchange: (-50.0 * self.base_power()) as i32, range: 3.0, max_angle: 60.0, - })], + }], Bow(_) => vec![ - Ability::new(AbilityId::BowShot, BasicRanged { + BasicRanged { energy_cost: 0, holdable: true, prepare_duration: Duration::from_millis(100), @@ -181,8 +180,8 @@ impl Tool { projectile_body: Body::Object(object::Body::Arrow), projectile_light: None, projectile_gravity: Some(Gravity(0.2)), - }), - Ability::new(AbilityId::BowCharged, ChargedRanged { + }, + ChargedRanged { energy_cost: 0, energy_drain: 300, initial_damage: (40.0 * self.base_power()) as u32, @@ -194,55 +193,55 @@ impl Tool { recover_duration: Duration::from_millis(500), projectile_body: Body::Object(object::Body::Arrow), projectile_light: None, - }), + }, ], Dagger(_) => vec![ - Ability::new(AbilityId::DaggerStab, BasicMelee { + BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(400), base_healthchange: (-50.0 * self.base_power()) as i32, range: 3.5, max_angle: 60.0, - }), - Ability::new(AbilityId::DaggerDash, DashMelee { + }, + DashMelee { energy_cost: 700, buildup_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(500), base_damage: (100.0 * self.base_power()) as u32, - }), + }, ], Staff(kind) => { if kind == "Sceptre" { vec![ - Ability::new(AbilityId::StaffSwing, BasicMelee { + BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(0), recover_duration: Duration::from_millis(300), base_healthchange: (-10.0 * self.base_power()) as i32, range: 10.0, max_angle: 45.0, - }), - Ability::new(AbilityId::StaffHeal, BasicMelee { + }, + BasicMelee { energy_cost: 350, buildup_duration: Duration::from_millis(0), recover_duration: Duration::from_millis(1000), base_healthchange: (150.0 * self.base_power()) as i32, range: 10.0, max_angle: 45.0, - }), + }, ] } else { vec![ - Ability::new(AbilityId::StaffSwing, BasicMelee { + BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(300), base_healthchange: (-40.0 * self.base_power()) as i32, range: 10.0, max_angle: 45.0, - }), - Ability::new(AbilityId::StaffShot, BasicRanged { + }, + BasicRanged { energy_cost: 0, holdable: false, prepare_duration: Duration::from_millis(250), @@ -264,8 +263,8 @@ impl Tool { }), projectile_gravity: None, - }), - Ability::new(AbilityId::StaffFireball, BasicRanged { + }, + BasicRanged { energy_cost: 400, holdable: true, prepare_duration: Duration::from_millis(800), @@ -293,33 +292,33 @@ impl Tool { }), projectile_gravity: None, - }), + }, ] } }, Shield(_) => vec![ - Ability::new(AbilityId::ShieldBash, BasicMelee { + BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(400), base_healthchange: (-40.0 * self.base_power()) as i32, range: 3.0, max_angle: 120.0, - }), - Ability::new(AbilityId::ShieldBlock, BasicBlock), + }, + BasicBlock, ], Debug(kind) => { if kind == "Boost" { vec![ - Ability::new(AbilityId::DebugFlyDirection, CharacterAbility::Boost { + CharacterAbility::Boost { duration: Duration::from_millis(50), only_up: false, - }), - Ability::new(AbilityId::DebugFlyUp, CharacterAbility::Boost { + }, + CharacterAbility::Boost { duration: Duration::from_millis(50), only_up: true, - }), - Ability::new(AbilityId::DebugPossesArrow, BasicRanged { + }, + BasicRanged { energy_cost: 0, holdable: false, prepare_duration: Duration::from_millis(0), @@ -339,20 +338,20 @@ impl Tool { ..Default::default() }), projectile_gravity: None, - }), + }, ] } else { vec![] } }, - Empty => vec![Ability::new(AbilityId::Empty, BasicMelee { + Empty => vec![BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(0), recover_duration: Duration::from_millis(1000), base_healthchange: -20, range: 5.0, max_angle: 60.0, - })], + }], } } diff --git a/common/src/comp/inventory/slot.rs b/common/src/comp/inventory/slot.rs index 4adf159768..db09354b25 100644 --- a/common/src/comp/inventory/slot.rs +++ b/common/src/comp/inventory/slot.rs @@ -2,7 +2,7 @@ use crate::{ comp, comp::{item, item::armor}, }; -use comp::{Ability, AbilityId, Inventory, Loadout}; +use comp::{Inventory, Loadout}; use serde::{Deserialize, Serialize}; use tracing::warn; @@ -100,11 +100,8 @@ fn item_config(item: item::Item) -> comp::ItemConfig { ability1: abilities.next(), ability2: abilities.next(), ability3: abilities.next(), - block_ability: Some(Ability::new( - AbilityId::Block, - comp::CharacterAbility::BasicBlock, - )), - dodge_ability: Some(Ability::new(AbilityId::Roll, comp::CharacterAbility::Roll)), + block_ability: Some(comp::CharacterAbility::BasicBlock), + dodge_ability: Some(comp::CharacterAbility::Roll), } } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 7b251b69d3..b99b575450 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -20,9 +20,7 @@ mod stats; mod visual; // Reexports -pub use ability::{ - Ability, AbilityId, CharacterAbility, CharacterAbilityType, ItemConfig, Loadout, -}; +pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout}; pub use admin::{Admin, AdminList}; pub use agent::{Agent, Alignment}; pub use body::{ diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 309fb746c6..0fc3983039 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -2,7 +2,7 @@ use crate::{ assets, comp::{ item::{Item, ItemKind}, - Ability, AbilityId, Body, CharacterAbility, ItemConfig, Loadout, + Body, CharacterAbility, ItemConfig, Loadout, }, }; use std::time::Duration; @@ -67,17 +67,14 @@ impl LoadoutBuilder { Self(Loadout { active_item: Some(ItemConfig { item: assets::load_expect_cloned("common.items.weapons.empty.empty"), - ability1: Some(Ability::new( - AbilityId::Empty, - CharacterAbility::BasicMelee { - energy_cost: 10, - buildup_duration: Duration::from_millis(600), - recover_duration: Duration::from_millis(100), - base_healthchange: -(body.base_dmg() as i32), - range: body.base_range(), - max_angle: 80.0, - }, - )), + ability1: Some(CharacterAbility::BasicMelee { + energy_cost: 10, + buildup_duration: Duration::from_millis(600), + recover_duration: Duration::from_millis(100), + base_healthchange: -(body.base_dmg() as i32), + range: body.base_range(), + max_angle: 80.0, + }), ability2: None, ability3: None, block_ability: None, @@ -116,11 +113,8 @@ impl LoadoutBuilder { ability1: ability_drain.next(), ability2: ability_drain.next(), ability3: ability_drain.next(), - block_ability: Some(Ability::new( - AbilityId::Block, - CharacterAbility::BasicBlock, - )), - dodge_ability: Some(Ability::new(AbilityId::Roll, CharacterAbility::Roll)), + block_ability: Some(CharacterAbility::BasicBlock), + dodge_ability: Some(CharacterAbility::Roll), }); } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index bc1e1b7d3e..ee20892e6c 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -203,7 +203,7 @@ pub fn handle_ability1_input(data: &JoinData, update: &mut StateUpdate) { .active_item .as_ref() .and_then(|i| i.ability1.as_ref()) - .filter(|ability| ability.data.requirements_paid(data, update)) + .filter(|ability| ability.requirements_paid(data, update)) { update.character = ability.into(); } @@ -233,7 +233,7 @@ pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) { .active_item .as_ref() .and_then(|i| i.ability2.as_ref()) - .filter(|ability| ability.data.requirements_paid(data, update)) + .filter(|ability| ability.requirements_paid(data, update)) { update.character = ability.into(); } @@ -244,7 +244,7 @@ pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) { .second_item .as_ref() .and_then(|i| i.ability2.as_ref()) - .filter(|ability| ability.data.requirements_paid(data, update)) + .filter(|ability| ability.requirements_paid(data, update)) { update.character = ability.into(); } @@ -262,7 +262,7 @@ pub fn handle_ability3_input(data: &JoinData, update: &mut StateUpdate) { .active_item .as_ref() .and_then(|i| i.ability3.as_ref()) - .filter(|ability| ability.data.requirements_paid(data, update)) + .filter(|ability| ability.requirements_paid(data, update)) { update.character = ability.into(); } @@ -278,7 +278,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { .active_item .as_ref() .and_then(|i| i.dodge_ability.as_ref()) - .filter(|ability| ability.data.requirements_paid(data, update)) + .filter(|ability| ability.requirements_paid(data, update)) { if data.character.is_wield() { update.character = ability.into(); diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index ccf2853a32..9d2775e194 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -127,26 +127,20 @@ impl<'a> System<'a> for Sys { ability2: ability_drain.next(), ability3: ability_drain.next(), block_ability: None, - dodge_ability: Some(comp::Ability::new( - comp::AbilityId::Roll, - comp::CharacterAbility::Roll, - )), + dodge_ability: Some(comp::CharacterAbility::Roll), }) } else { Some(ItemConfig { // We need the empty item so npcs can attack item: assets::load_expect_cloned("common.items.weapons.empty.empty"), - ability1: Some(comp::Ability::new( - comp::AbilityId::Empty, - CharacterAbility::BasicMelee { - energy_cost: 0, - buildup_duration: Duration::from_millis(0), - recover_duration: Duration::from_millis(400), - base_healthchange: -60, - range: 5.0, - max_angle: 80.0, - }, - )), + ability1: Some(CharacterAbility::BasicMelee { + energy_cost: 0, + buildup_duration: Duration::from_millis(0), + recover_duration: Duration::from_millis(400), + base_healthchange: -60, + range: 5.0, + max_angle: 80.0, + }), ability2: None, ability3: None, block_ability: None, @@ -260,17 +254,14 @@ impl<'a> System<'a> for Sys { item: assets::load_expect_cloned( "common.items.weapons.sword.zweihander_sword_0", ), - ability1: Some(comp::Ability::new( - comp::AbilityId::Empty, - CharacterAbility::BasicMelee { - energy_cost: 0, - buildup_duration: Duration::from_millis(800), - recover_duration: Duration::from_millis(200), - base_healthchange: -100, - range: 3.5, - max_angle: 60.0, - }, - )), + ability1: Some(CharacterAbility::BasicMelee { + energy_cost: 0, + buildup_duration: Duration::from_millis(800), + recover_duration: Duration::from_millis(200), + base_healthchange: -100, + range: 3.5, + max_angle: 60.0, + }), ability2: None, ability3: None, block_ability: None, diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index bba3bdcaf3..e5ce67075c 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -20,7 +20,7 @@ use common::comp::{ tool::{Tool, ToolKind}, Hands, ItemKind, }, - AbilityId, CharacterState, ControllerInputs, Energy, Inventory, Loadout, Stats, + CharacterState, ControllerInputs, Energy, Inventory, Loadout, Stats, }; use conrod_core::{ color, @@ -181,44 +181,6 @@ impl<'a> Skillbar<'a> { show, } } - - /// Pairs ability with image. - /// - /// TODO: Dehardcode this into a .ron file - fn get_ability_image(&self, ability: AbilityId) -> conrod_core::image::Id { - use AbilityId::*; - match ability { - // Sword - SwordCut => self.imgs.twohsword_m1, - SwordThrust => self.imgs.twohsword_m2, - // Axe - AxeSwing => self.imgs.twohaxe_m1, - AxeSpin => self.imgs.axespin, - // Hammer - HammerSmash => self.imgs.twohhammer_m1, - HammerLeap => self.imgs.hammerleap, - // Bow - BowShot => self.imgs.bow_m1, - BowCharged => self.imgs.bow_m2, - // Staff - StaffSwing => self.imgs.staff_m1, - StaffShot => self.imgs.staff_m2, - StaffFireball => self.imgs.fire_spell_1, - StaffHeal => self.imgs.heal_0, - // Dagger - DaggerStab => self.imgs.onehdagger_m1, - DaggerDash => self.imgs.onehdagger_m2, - // Shield - ShieldBash => self.imgs.onehshield_m1, - ShieldBlock => self.imgs.onehshield_m2, - // Debug - DebugFlyDirection => self.imgs.flyingrod_m1, - DebugFlyUp => self.imgs.flyingrod_m2, - DebugPossesArrow => self.imgs.snake_arrow_0, - - _ => self.imgs.nothing, - } - } } pub struct State { @@ -646,13 +608,20 @@ impl<'a> Widget for Skillbar<'a> { .middle_of(state.ids.m1_slot) .set(state.ids.m1_slot_bg, ui); Button::image( - match self.loadout.active_item.as_ref().map(|i| &i.ability1) { - Some(ability) => { - if let Some(ability) = ability { - self.get_ability_image(ability.id) - } else { - self.imgs.nothing - } + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(Tool { kind, .. })) => match kind { + ToolKind::Sword(_) => self.imgs.twohsword_m1, + ToolKind::Dagger(_) => self.imgs.onehdagger_m1, + ToolKind::Shield(_) => self.imgs.onehshield_m1, + ToolKind::Hammer(_) => self.imgs.twohhammer_m1, + ToolKind::Axe(_) => self.imgs.twohaxe_m1, + ToolKind::Bow(_) => self.imgs.bow_m1, + ToolKind::Staff(_) => self.imgs.staff_m1, + ToolKind::Debug(kind) => match kind.as_ref() { + "Boost" => self.imgs.flyingrod_m1, + _ => self.imgs.nothing, + }, + _ => self.imgs.nothing, }, _ => self.imgs.nothing, }, @@ -700,38 +669,63 @@ impl<'a> Widget for Skillbar<'a> { _ => None, }; - let active_tool_secondary_ability = - match self.loadout.active_item.as_ref().map(|i| &i.ability2) { - Some(Some(ability)) => Some(ability.id), - _ => None, - }; - - let second_tool_secondary_ability = - match self.loadout.second_item.as_ref().map(|i| &i.ability2) { - Some(Some(ability)) => Some(ability.id), - _ => None, - }; - - let used_secondary_ability = match ( + let tool_kind = match ( active_tool_kind.map(|tk| tk.hands()), second_tool_kind.map(|tk| tk.hands()), ) { - (Some(Hands::TwoHand), _) => active_tool_secondary_ability, - (Some(Hands::OneHand), Some(Hands::OneHand)) => second_tool_secondary_ability, + (Some(Hands::TwoHand), _) => active_tool_kind, + (_, Some(Hands::OneHand)) => second_tool_kind, (_, _) => None, }; Image::new(self.imgs.skillbar_slot_big_bg) .w_h(38.0 * scale, 38.0 * scale) - .color(Some(BG_COLOR_2)) + .color(match tool_kind { + Some(ToolKind::Bow(_)) => Some(BG_COLOR_2), + Some(ToolKind::Staff(_)) => Some(BG_COLOR_2), + _ => Some(BG_COLOR_2), + }) .middle_of(state.ids.m2_slot) .set(state.ids.m2_slot_bg, ui); - Button::image(match used_secondary_ability { - Some(ability) => self.get_ability_image(ability), + Button::image(match tool_kind { + Some(ToolKind::Sword(_)) => self.imgs.twohsword_m2, + Some(ToolKind::Dagger(_)) => self.imgs.onehdagger_m2, + Some(ToolKind::Shield(_)) => self.imgs.onehshield_m2, + Some(ToolKind::Hammer(_)) => self.imgs.hammerleap, + Some(ToolKind::Axe(_)) => self.imgs.axespin, + Some(ToolKind::Bow(_)) => self.imgs.bow_m2, + Some(ToolKind::Staff(kind)) => match kind.as_ref() { + "Sceptre" => self.imgs.heal_0, + _ => self.imgs.staff_m2, + }, + Some(ToolKind::Debug(kind)) => match kind.as_ref() { + "Boost" => self.imgs.flyingrod_m2, + _ => self.imgs.nothing, + }, _ => self.imgs.nothing, }) .w_h(32.0 * scale, 32.0 * scale) .middle_of(state.ids.m2_slot_bg) + .image_color(match tool_kind { + Some(ToolKind::Sword(_)) => { + if self.energy.current() as f64 >= 200.0 { + Color::Rgba(1.0, 1.0, 1.0, 1.0) + } else { + Color::Rgba(0.3, 0.3, 0.3, 0.8) + } + }, + Some(ToolKind::Staff(kind)) => match kind.as_ref() { + "Sceptre" => { + if self.energy.current() as f64 >= 400.0 { + Color::Rgba(1.0, 1.0, 1.0, 1.0) + } else { + Color::Rgba(0.3, 0.3, 0.3, 0.8) + } + }, + _ => Color::Rgba(1.0, 1.0, 1.0, 1.0), + }, + _ => Color::Rgba(1.0, 1.0, 1.0, 1.0), + }) .set(state.ids.m2_content, ui); // Slots let content_source = (self.hotbar, self.inventory, self.loadout, self.energy); // TODO: avoid this