diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index e3d53f1949..7f7dad517b 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -3,7 +3,7 @@ ({ Tool(Sword): ( primary: "common.abilities.sword.balancedstance", - secondary: "common.abilities.sword.balancedstance", + secondary: "common.abilities.sword.lunge", abilities: [], ), Tool(Axe): ( diff --git a/assets/common/abilities/sword/balancedstance.ron b/assets/common/abilities/sword/balancedstance.ron index 79e7cd3473..260b69601f 100644 --- a/assets/common/abilities/sword/balancedstance.ron +++ b/assets/common/abilities/sword/balancedstance.ron @@ -54,5 +54,6 @@ ComboMelee2( forward_movement: 0.0, ori_modifier: 0.6, ), - ] + ], + meta: Some(Sword(Balanced)), ) \ No newline at end of file diff --git a/assets/common/abilities/sword/lunge.ron b/assets/common/abilities/sword/lunge.ron new file mode 100644 index 0000000000..71815e8a5f --- /dev/null +++ b/assets/common/abilities/sword/lunge.ron @@ -0,0 +1,18 @@ +// TODO: Make actual ability, just for testing right now +BasicMelee( + energy_cost: 50, + buildup_duration: 0.3, + swing_duration: 0.1, + recover_duration: 0.2, + melee_constructor: ( + kind: Stab( + damage: 10, + poise: 0, + knockback: 0, + energy_regen: 0, + ), + range: 5.0, + angle: 10.0, + ), + meta: Some(Sword(Balanced)), +) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index a0f3237b13..037da0458e 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -419,6 +419,7 @@ pub enum CharacterAbility { recover_duration: f32, melee_constructor: MeleeConstructor, ori_modifier: f32, + meta: Option, }, BasicRanged { energy_cost: f32, @@ -430,6 +431,7 @@ pub enum CharacterAbility { projectile_speed: f32, num_projectiles: u32, projectile_spread: f32, + meta: Option, }, RepeaterRanged { energy_cost: f32, @@ -442,12 +444,14 @@ pub enum CharacterAbility { projectile_body: Body, projectile_light: Option, projectile_speed: f32, + meta: Option, }, Boost { movement_duration: f32, only_up: bool, speed: f32, max_exit_velocity: f32, + meta: Option, }, DashMelee { energy_cost: f32, @@ -461,6 +465,7 @@ pub enum CharacterAbility { ori_modifier: f32, charge_through: bool, is_interruptible: bool, + meta: Option, }, BasicBlock { buildup_duration: f32, @@ -468,6 +473,7 @@ pub enum CharacterAbility { max_angle: f32, block_strength: f32, energy_cost: f32, + meta: Option, }, Roll { energy_cost: f32, @@ -476,6 +482,7 @@ pub enum CharacterAbility { recover_duration: f32, roll_strength: f32, immune_melee: bool, + meta: Option, }, ComboMelee { stage_data: Vec>, @@ -487,9 +494,11 @@ pub enum CharacterAbility { scales_from_combo: u32, is_interruptible: bool, ori_modifier: f32, + meta: Option, }, ComboMelee2 { strikes: Vec>, + meta: Option, }, LeapMelee { energy_cost: f32, @@ -500,6 +509,7 @@ pub enum CharacterAbility { melee_constructor: MeleeConstructor, forward_leap_strength: f32, vertical_leap_strength: f32, + meta: Option, }, SpinMelee { buildup_duration: f32, @@ -513,6 +523,7 @@ pub enum CharacterAbility { num_spins: u32, specifier: Option, melee_constructor: MeleeConstructor, + meta: Option, }, ChargedMelee { energy_cost: f32, @@ -523,6 +534,7 @@ pub enum CharacterAbility { recover_duration: f32, melee_constructor: MeleeConstructor, specifier: Option, + meta: Option, }, ChargedRanged { energy_cost: f32, @@ -541,6 +553,7 @@ pub enum CharacterAbility { initial_projectile_speed: f32, scaled_projectile_speed: f32, move_speed: f32, + meta: Option, }, Shockwave { energy_cost: f32, @@ -559,6 +572,7 @@ pub enum CharacterAbility { damage_kind: DamageKind, specifier: comp::shockwave::FrontendSpecifier, damage_effect: Option, + meta: Option, }, BasicBeam { buildup_duration: f32, @@ -573,6 +587,7 @@ pub enum CharacterAbility { energy_drain: f32, ori_rate: f32, specifier: beam::FrontendSpecifier, + meta: Option, }, BasicAura { buildup_duration: f32, @@ -585,11 +600,13 @@ pub enum CharacterAbility { energy_cost: f32, scales_with_combo: bool, specifier: Option, + meta: Option, }, Blink { buildup_duration: f32, recover_duration: f32, max_range: f32, + meta: Option, }, BasicSummon { buildup_duration: f32, @@ -599,6 +616,7 @@ pub enum CharacterAbility { summon_distance: (f32, f32), summon_info: basic_summon::SummonInfo, duration: Option, + meta: Option, }, SelfBuff { buildup_duration: f32, @@ -608,6 +626,7 @@ pub enum CharacterAbility { buff_strength: f32, buff_duration: Option, energy_cost: f32, + meta: Option, }, SpriteSummon { buildup_duration: f32, @@ -616,6 +635,7 @@ pub enum CharacterAbility { sprite: SpriteKind, summon_distance: (f32, f32), sparseness: f64, + meta: Option, }, Music { play_duration: f32, @@ -643,6 +663,7 @@ impl Default for CharacterAbility { damage_effect: None, }, ori_modifier: 1.0, + meta: None, } } } @@ -709,6 +730,7 @@ impl CharacterAbility { recover_duration: 0.125, roll_strength: 2.0, immune_melee: true, + meta: None, } } @@ -719,6 +741,7 @@ impl CharacterAbility { max_angle: 60.0, block_strength: 0.5, energy_cost: 2.5, + meta: None, } } @@ -733,6 +756,7 @@ impl CharacterAbility { ref mut recover_duration, ref mut melee_constructor, ori_modifier: _, + meta: _, } => { *buildup_duration /= stats.speed; *swing_duration /= stats.speed; @@ -750,6 +774,7 @@ impl CharacterAbility { ref mut projectile_speed, num_projectiles: _, projectile_spread: _, + meta: _, } => { *buildup_duration /= stats.speed; *recover_duration /= stats.speed; @@ -768,6 +793,7 @@ impl CharacterAbility { projectile_body: _, projectile_light: _, ref mut projectile_speed, + meta: _, } => { *buildup_duration /= stats.speed; *shoot_duration /= stats.speed; @@ -781,6 +807,7 @@ impl CharacterAbility { only_up: _, speed: ref mut boost_speed, max_exit_velocity: _, + meta: _, } => { *movement_duration /= stats.speed; *boost_speed *= stats.power; @@ -797,6 +824,7 @@ impl CharacterAbility { ori_modifier: _, charge_through: _, is_interruptible: _, + meta: _, } => { *buildup_duration /= stats.speed; *swing_duration /= stats.speed; @@ -813,6 +841,7 @@ impl CharacterAbility { // Block strength explicitly not modified by power, that will be a separate stat block_strength: _, ref mut energy_cost, + meta: _, } => { *buildup_duration /= stats.speed; *recover_duration /= stats.speed; @@ -825,6 +854,7 @@ impl CharacterAbility { ref mut recover_duration, roll_strength: _, immune_melee: _, + meta: _, } => { *buildup_duration /= stats.speed; *movement_duration /= stats.speed; @@ -841,13 +871,17 @@ impl CharacterAbility { scales_from_combo: _, is_interruptible: _, ori_modifier: _, + meta: _, } => { *stage_data = stage_data .iter_mut() .map(|s| s.adjusted_by_stats(stats)) .collect(); }, - ComboMelee2 { ref mut strikes } => { + ComboMelee2 { + ref mut strikes, + meta: _, + } => { *strikes = strikes .iter_mut() .map(|s| s.adjusted_by_stats(stats)) @@ -862,6 +896,7 @@ impl CharacterAbility { ref mut melee_constructor, forward_leap_strength: _, vertical_leap_strength: _, + meta: _, } => { *buildup_duration /= stats.speed; *swing_duration /= stats.speed; @@ -881,6 +916,7 @@ impl CharacterAbility { forward_speed: _, num_spins: _, specifier: _, + meta: _, } => { *buildup_duration /= stats.speed; *swing_duration /= stats.speed; @@ -897,6 +933,7 @@ impl CharacterAbility { ref mut recover_duration, ref mut melee_constructor, specifier: _, + meta: _, } => { *swing_duration /= stats.speed; *recover_duration /= stats.speed; @@ -921,6 +958,7 @@ impl CharacterAbility { ref mut initial_projectile_speed, ref mut scaled_projectile_speed, move_speed: _, + meta: _, } => { *initial_damage *= stats.power; *scaled_damage *= stats.power; @@ -948,6 +986,7 @@ impl CharacterAbility { damage_kind: _, specifier: _, ref mut damage_effect, + meta: _, } => { *buildup_duration /= stats.speed; *swing_duration /= stats.speed; @@ -979,6 +1018,7 @@ impl CharacterAbility { ref mut energy_drain, ori_rate: _, specifier: _, + meta: _, } => { *buildup_duration /= stats.speed; *recover_duration /= stats.speed; @@ -1009,6 +1049,7 @@ impl CharacterAbility { ref mut energy_cost, scales_with_combo: _, specifier: _, + meta: _, } => { *buildup_duration /= stats.speed; *cast_duration /= stats.speed; @@ -1030,6 +1071,7 @@ impl CharacterAbility { ref mut buildup_duration, ref mut recover_duration, ref mut max_range, + meta: _, } => { *buildup_duration /= stats.speed; *recover_duration /= stats.speed; @@ -1043,6 +1085,7 @@ impl CharacterAbility { summon_distance: (ref mut inner_dist, ref mut outer_dist), summon_info: _, duration: _, + meta: _, } => { // TODO: Figure out how/if power should affect this *buildup_duration /= stats.speed; @@ -1059,6 +1102,7 @@ impl CharacterAbility { ref mut buff_strength, buff_duration: _, ref mut energy_cost, + meta: _, } => { *buff_strength *= stats.diminished_buff_strength(); *buildup_duration /= stats.speed; @@ -1073,6 +1117,7 @@ impl CharacterAbility { sprite: _, summon_distance: (ref mut inner_dist, ref mut outer_dist), sparseness: _, + meta: _, } => { // TODO: Figure out how/if power should affect this *buildup_duration /= stats.speed; @@ -1124,6 +1169,53 @@ impl CharacterAbility { } } + // TODO: Maybe consider making CharacterAbility a struct at some point? + pub fn ability_meta(&self) -> Option { + use CharacterAbility::*; + match self { + BasicMelee { meta, .. } + | BasicRanged { meta, .. } + | RepeaterRanged { meta, .. } + | DashMelee { meta, .. } + | Roll { meta, .. } + | LeapMelee { meta, .. } + | SpinMelee { meta, .. } + | ChargedMelee { meta, .. } + | ChargedRanged { meta, .. } + | Shockwave { meta, .. } + | BasicAura { meta, .. } + | BasicBlock { meta, .. } + | SelfBuff { meta, .. } + | BasicBeam { meta, .. } + | Boost { meta, .. } + | ComboMelee { meta, .. } + | ComboMelee2 { meta, .. } + | Blink { meta, .. } + | BasicSummon { meta, .. } + | SpriteSummon { meta, .. } => *meta, + } + } + + #[must_use] + pub fn contextualize(mut self, data: &JoinData) -> Self { + if let Some(ability_info) = data.character.ability_info() { + if let Some(AbilityMeta::Sword(old_stance)) = ability_info.ability_meta { + if matches!(self.ability_meta(), Some(AbilityMeta::Sword(new_stance)) if old_stance == new_stance) + { + const ENERGY_REDUCTION: f32 = 0.75; + use CharacterAbility::*; + match &mut self { + BasicMelee { energy_cost, .. } => { + *energy_cost *= ENERGY_REDUCTION; + }, + _ => {}, + } + } + } + } + self + } + #[must_use = "method returns new ability and doesn't mutate the original value"] pub fn adjusted_by_skills(mut self, skillset: &SkillSet, tool: Option) -> Self { match tool { @@ -1649,6 +1741,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { melee_constructor, ori_modifier, energy_cost: _, + meta: _, } => CharacterState::BasicMelee(basic_melee::Data { static_data: basic_melee::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1672,6 +1765,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { energy_cost: _, num_projectiles, projectile_spread, + meta: _, } => CharacterState::BasicRanged(basic_ranged::Data { static_data: basic_ranged::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1693,6 +1787,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { only_up, speed, max_exit_velocity, + meta: _, } => CharacterState::Boost(boost::Data { static_data: boost::StaticData { movement_duration: Duration::from_secs_f32(*movement_duration), @@ -1715,6 +1810,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { ori_modifier, charge_through, is_interruptible, + meta: _, } => CharacterState::DashMelee(dash_melee::Data { static_data: dash_melee::StaticData { energy_drain: *energy_drain, @@ -1741,6 +1837,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { max_angle, block_strength, energy_cost, + meta: _, } => CharacterState::BasicBlock(basic_block::Data { static_data: basic_block::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1760,6 +1857,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { recover_duration, roll_strength, immune_melee, + meta: _, } => CharacterState::Roll(roll::Data { static_data: roll::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1785,6 +1883,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { scales_from_combo, is_interruptible, ori_modifier, + meta: _, } => CharacterState::ComboMelee(combo_melee::Data { static_data: combo_melee::StaticData { num_stages: stage_data.len() as u32, @@ -1804,7 +1903,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { timer: Duration::default(), stage_section: StageSection::Buildup, }), - CharacterAbility::ComboMelee2 { strikes } => { + CharacterAbility::ComboMelee2 { strikes, meta: _ } => { CharacterState::ComboMelee2(combo_melee2::Data { static_data: combo_melee2::StaticData { strikes: strikes.iter().map(|s| s.to_duration()).collect(), @@ -1813,7 +1912,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { exhausted: false, skip_recover: false, timer: Duration::default(), - stage_section: None, + stage_section: Some(StageSection::Buildup), completed_strikes: 0, }) }, @@ -1826,6 +1925,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { melee_constructor, forward_leap_strength, vertical_leap_strength, + meta: _, } => CharacterState::LeapMelee(leap_melee::Data { static_data: leap_melee::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1853,6 +1953,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { forward_speed, num_spins, specifier, + meta: _, } => CharacterState::SpinMelee(spin_melee::Data { static_data: spin_melee::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1882,6 +1983,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { recover_duration, melee_constructor, specifier, + meta: _, } => CharacterState::ChargedMelee(charged_melee::Data { static_data: charged_melee::StaticData { energy_cost: *energy_cost, @@ -1916,6 +2018,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { initial_projectile_speed, scaled_projectile_speed, move_speed, + meta: _, } => CharacterState::ChargedRanged(charged_ranged::Data { static_data: charged_ranged::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1950,6 +2053,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { projectile_body, projectile_light, projectile_speed, + meta: _, } => CharacterState::RepeaterRanged(repeater_ranged::Data { static_data: repeater_ranged::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -1987,6 +2091,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { damage_kind, specifier, damage_effect, + meta: _, } => CharacterState::Shockwave(shockwave::Data { static_data: shockwave::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2022,6 +2127,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { energy_drain, ori_rate, specifier, + meta: _, } => CharacterState::BasicBeam(basic_beam::Data { static_data: basic_beam::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2052,6 +2158,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { energy_cost: _, scales_with_combo, specifier, + meta: _, } => CharacterState::BasicAura(basic_aura::Data { static_data: basic_aura::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2073,6 +2180,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { buildup_duration, recover_duration, max_range, + meta: _, } => CharacterState::Blink(blink::Data { static_data: blink::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2091,6 +2199,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { summon_distance, summon_info, duration, + meta: _, } => CharacterState::BasicSummon(basic_summon::Data { static_data: basic_summon::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2114,6 +2223,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { buff_strength, buff_duration, energy_cost: _, + meta: _, } => CharacterState::SelfBuff(self_buff::Data { static_data: self_buff::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2134,6 +2244,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { sprite, summon_distance, sparseness, + meta: _, } => CharacterState::SpriteSummon(sprite_summon::Data { static_data: sprite_summon::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), @@ -2164,3 +2275,22 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { } } } + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum AbilityMeta { + Sword(SwordStance), +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum SwordStance { + Balanced, + Offensive, + Crippling, + Cleaving, + Defensive, + Parrying, + Heavy, + Mobility, + Reaching, + AirSlash, +} diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 7a082e1359..cbd100697c 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -7,7 +7,7 @@ use crate::{ states::{ self, behavior::{CharacterBehavior, JoinData}, - utils::StageSection, + utils::{AbilityInfo, StageSection}, *, }, }; @@ -413,6 +413,44 @@ impl CharacterState { _ => None, } } + + pub fn ability_info(&self) -> Option { + match &self { + CharacterState::Idle(_) => None, + CharacterState::Talk => None, + CharacterState::Climb(_) => None, + CharacterState::Wallrun(_) => None, + CharacterState::Glide(_) => None, + CharacterState::GlideWield(_) => None, + CharacterState::Stunned(_) => None, + CharacterState::Sit => None, + CharacterState::Dance => None, + CharacterState::BasicBlock(data) => Some(data.static_data.ability_info), + CharacterState::Roll(data) => Some(data.static_data.ability_info), + CharacterState::Wielding(_) => None, + CharacterState::Equipping(_) => None, + CharacterState::ComboMelee(data) => Some(data.static_data.ability_info), + CharacterState::ComboMelee2(data) => Some(data.static_data.ability_info), + CharacterState::BasicMelee(data) => Some(data.static_data.ability_info), + CharacterState::BasicRanged(data) => Some(data.static_data.ability_info), + CharacterState::Boost(data) => Some(data.static_data.ability_info), + CharacterState::DashMelee(data) => Some(data.static_data.ability_info), + CharacterState::LeapMelee(data) => Some(data.static_data.ability_info), + CharacterState::SpinMelee(data) => Some(data.static_data.ability_info), + CharacterState::ChargedMelee(data) => Some(data.static_data.ability_info), + CharacterState::ChargedRanged(data) => Some(data.static_data.ability_info), + CharacterState::RepeaterRanged(data) => Some(data.static_data.ability_info), + CharacterState::Shockwave(data) => Some(data.static_data.ability_info), + CharacterState::BasicBeam(data) => Some(data.static_data.ability_info), + CharacterState::BasicAura(data) => Some(data.static_data.ability_info), + CharacterState::Blink(data) => Some(data.static_data.ability_info), + CharacterState::BasicSummon(data) => Some(data.static_data.ability_info), + CharacterState::SelfBuff(data) => Some(data.static_data.ability_info), + CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info), + CharacterState::UseItem(_) => None, + CharacterState::SpriteInteract(_) => None, + } + } } impl Default for CharacterState { diff --git a/common/src/states/combo_melee2.rs b/common/src/states/combo_melee2.rs index 273cac46a7..8a62e3526d 100644 --- a/common/src/states/combo_melee2.rs +++ b/common/src/states/combo_melee2.rs @@ -97,7 +97,9 @@ impl CharacterBehavior for Data { handle_orientation(data, &mut update, 1.0, None); handle_move(data, &mut update, 0.7); - handle_jump(data, output_events, &mut update, 1.0); + if !input_is_pressed(data, InputKind::Primary) { + handle_dodge_input(data, &mut update); + } let strike_data = self.static_data.strikes[self.completed_strikes % self.static_data.strikes.len()]; @@ -106,41 +108,31 @@ impl CharacterBehavior for Data { Some(StageSection::Buildup) => { if self.timer < strike_data.buildup_duration { // Build up - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: tick_attack_or_default(data, self.timer, None), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + } } else { // Transitions to swing section of stage - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: Duration::default(), - stage_section: Some(StageSection::Action), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = Duration::default(); + c.stage_section = Some(StageSection::Action); + } } }, Some(StageSection::Action) => { if input_is_pressed(data, InputKind::Primary) { - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - skip_recover: true, - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.skip_recover = true; + } } if self.timer.as_secs_f32() > strike_data.hit_timing * strike_data.swing_duration.as_secs_f32() && !self.exhausted { - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: tick_attack_or_default(data, self.timer, None), - exhausted: true, - skip_recover: self.skip_recover - || input_is_pressed(data, InputKind::Primary), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + c.exhausted = true; + } let crit_data = get_crit_data(data, self.static_data.ability_info); let buff_strength = get_buff_strength(data, self.static_data.ability_info); @@ -153,41 +145,31 @@ impl CharacterBehavior for Data { ); } else if self.timer < strike_data.swing_duration { // Swings - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: tick_attack_or_default(data, self.timer, None), - skip_recover: self.skip_recover - || input_is_pressed(data, InputKind::Primary), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + } } else if self.skip_recover { next_strike(&mut update) } else { // Transitions to recover section of stage - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: Duration::default(), - stage_section: Some(StageSection::Recover), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = Duration::default(); + c.stage_section = Some(StageSection::Recover); + } } }, Some(StageSection::Recover) => { if self.timer < strike_data.recover_duration { // Recovery - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: tick_attack_or_default(data, self.timer, None), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + } } else { // Done - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: Duration::default(), - stage_section: None, - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = Duration::default(); + c.stage_section = None; + } } }, Some(_) => { @@ -198,11 +180,9 @@ impl CharacterBehavior for Data { }, None => { if self.timer < STANCE_TIME { - update.character = CharacterState::ComboMelee2(Data { - static_data: self.static_data.clone(), - timer: tick_attack_or_default(data, self.timer, None), - ..*self - }); + if let CharacterState::ComboMelee2(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + } } else { // Done update.character = @@ -210,17 +190,18 @@ impl CharacterBehavior for Data { // Make sure melee component is removed data.updater.remove::(data.entity); } + + handle_climb(data, &mut update); + handle_jump(data, output_events, &mut update, 1.0); + if input_is_pressed(data, InputKind::Primary) { next_strike(&mut update) + } else { + attempt_input(data, output_events, &mut update); } }, } - // At end of state logic so an interrupt isn't overwritten - if !input_is_pressed(data, InputKind::Primary) { - handle_dodge_input(data, &mut update); - } - update } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 8aa88f80f1..02f9567ad6 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -2,6 +2,7 @@ use crate::{ astar::Astar, combat, comp::{ + ability::AbilityMeta, arthropod, biped_large, biped_small, character_state::OutputEvents, inventory::slot::{ArmorSlot, EquipSlot, Slot}, @@ -952,28 +953,18 @@ fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKin Some(data.body), ) }) + .map(|(ability, from_offhand)| (ability.contextualize(data), from_offhand)) .filter(|(ability, _)| ability.requirements_paid(data, update)) { update.character = CharacterState::from(( &ability, - AbilityInfo::from_input(data, from_offhand, input), + AbilityInfo::from_input(data, from_offhand, input, ability.ability_meta()), data, )); } } } -pub fn handle_ability_input(data: &JoinData<'_>, update: &mut StateUpdate) { - if let Some(input) = data - .controller - .queued_inputs - .keys() - .find(|i| i.is_ability()) - { - handle_ability(data, update, *input); - } -} - pub fn handle_input( data: &JoinData<'_>, output_events: &mut OutputEvents, @@ -1016,7 +1007,7 @@ pub fn handle_block_input(data: &JoinData<'_>, update: &mut StateUpdate) { if ability.requirements_paid(data, update) { update.character = CharacterState::from(( &ability, - AbilityInfo::from_input(data, false, InputKind::Roll), + AbilityInfo::from_input(data, false, InputKind::Block, None), data, )); } @@ -1031,7 +1022,7 @@ pub fn handle_dodge_input(data: &JoinData<'_>, update: &mut StateUpdate) { if ability.requirements_paid(data, update) { update.character = CharacterState::from(( &ability, - AbilityInfo::from_input(data, false, InputKind::Roll), + AbilityInfo::from_input(data, false, InputKind::Roll, None), data, )); if let CharacterState::Roll(roll) = &mut update.character { @@ -1218,10 +1209,16 @@ pub struct AbilityInfo { pub hand: Option, pub input: InputKind, pub input_attr: Option, + pub ability_meta: Option, } impl AbilityInfo { - pub fn from_input(data: &JoinData<'_>, from_offhand: bool, input: InputKind) -> Self { + pub fn from_input( + data: &JoinData<'_>, + from_offhand: bool, + input: InputKind, + ability_meta: Option, + ) -> Self { let tool_data = if from_offhand { unwrap_tool_data(data, EquipSlot::ActiveOffhand) } else { @@ -1239,6 +1236,7 @@ impl AbilityInfo { hand, input, input_attr: data.controller.queued_inputs.get(&input).copied(), + ability_meta, } } } diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index b3b0b0eac8..791ea1835d 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -241,5 +241,6 @@ fn empty_ability_info() -> states::utils::AbilityInfo { hand: None, input: InputKind::Primary, input_attr: None, + ability_meta: None, } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs index d6cf1cff35..aaccfe5e1d 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs @@ -293,5 +293,6 @@ fn empty_ability_info() -> states::utils::AbilityInfo { hand: None, input: InputKind::Primary, input_attr: None, + ability_meta: None, } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 451a393438..5fce375573 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -1626,8 +1626,9 @@ impl FigureMgr { CharacterState::ComboMelee2(s) => { if let Some(stage_section) = s.stage_section { let timer = s.timer.as_secs_f32(); - let strike_data = s.static_data.strikes - [s.completed_strikes % s.static_data.strikes.len()]; + let current_strike = + s.completed_strikes % s.static_data.strikes.len(); + let strike_data = s.static_data.strikes[current_strike]; let progress = match stage_section { StageSection::Buildup => { timer / strike_data.buildup_duration.as_secs_f32() @@ -1640,8 +1641,6 @@ impl FigureMgr { }, _ => 0.0, }; - let current_strike = - s.completed_strikes % s.static_data.strikes.len(); anim::character::ComboAnimation::update_skeleton( &target_base,