use crate::{
combat::{self, CombatBuff, CombatEffect},
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
pub buildup_duration: Duration,
pub swing_duration: Duration,
pub recover_duration: Duration,
pub melee_constructor: MeleeConstructor,
pub scaling: Option<Scaling>,
pub minimum_combo: u32,
pub combo_on_use: u32,
pub combo_consumption: ComboConsumption,
pub ability_info: AbilityInfo,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
pub static_data: StaticData,
pub timer: Duration,
pub stage_section: StageSection,
pub exhausted: bool,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(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);
handle_interrupts(data, &mut update, output_events);
match self.stage_section {
StageSection::Buildup => {
if self.timer < self.static_data.buildup_duration {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.timer = tick_attack_or_default(data, self.timer, None);
}
} else {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.timer = Duration::default();
c.stage_section = StageSection::Action;
}
}
},
StageSection::Action => {
if !self.exhausted {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.exhausted = true;
}
self.static_data.combo_consumption.consume(
data,
output_events,
self.static_data.minimum_combo,
);
let mut melee_constructor = self.static_data.melee_constructor;
if let Some(scaling) = self.static_data.scaling {
let scaling_factor = scaling
.kind
.factor(
self.static_data.combo_on_use as f32,
self.static_data.minimum_combo as f32,
)
.min(scaling.max_factor);
match scaling.target {
ScalingTarget::Attack => {
melee_constructor =
melee_constructor.handle_scaling(scaling_factor);
},
ScalingTarget::Buff => {
if let Some(CombatEffect::Buff(CombatBuff { strength, .. })) =
&mut melee_constructor.damage_effect
{
*strength *= scaling_factor;
}
},
}
}
let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
let tool_stats = get_tool_stats(data, self.static_data.ability_info);
data.updater.insert(
data.entity,
melee_constructor.create_melee(precision_mult, tool_stats),
);
} else if self.timer < self.static_data.swing_duration {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.timer = tick_attack_or_default(data, self.timer, None);
}
} else {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.timer = Duration::default();
c.stage_section = StageSection::Recover
}
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
if let CharacterState::FinisherMelee(c) = &mut update.character {
c.timer = tick_attack_or_default(
data,
self.timer,
Some(data.stats.recovery_speed_modifier),
);
}
} else {
end_melee_ability(data, &mut update);
}
},
_ => {
end_melee_ability(data, &mut update);
},
}
update
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ScalingTarget {
Attack,
Buff,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Scaling {
pub target: ScalingTarget,
pub kind: ScalingKind,
pub max_factor: f32,
}