1use crate::{
2 combat::{self, CombatBuff, CombatEffect},
3 comp::{CharacterState, MeleeConstructor, StateUpdate, character_state::OutputEvents},
4 states::{
5 behavior::{CharacterBehavior, JoinData},
6 utils::*,
7 },
8};
9use serde::{Deserialize, Serialize};
10use std::time::Duration;
11
12#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
14pub struct StaticData {
15 pub buildup_duration: Duration,
17 pub swing_duration: Duration,
19 pub recover_duration: Duration,
21 pub melee_constructor: MeleeConstructor,
23 pub scaling: Option<Scaling>,
25 pub minimum_combo: u32,
27 pub combo_on_use: u32,
29 pub combo_consumption: ComboConsumption,
30 pub ability_info: AbilityInfo,
32}
33
34#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
35pub struct Data {
36 pub static_data: StaticData,
39 pub timer: Duration,
41 pub stage_section: StageSection,
43 pub exhausted: bool,
45}
46
47impl CharacterBehavior for Data {
48 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
49 let mut update = StateUpdate::from(data);
50
51 handle_orientation(data, &mut update, 1.0, None);
52 handle_move(data, &mut update, 0.7);
53 handle_jump(data, output_events, &mut update, 1.0);
54 handle_interrupts(data, &mut update, output_events);
55
56 match self.stage_section {
57 StageSection::Buildup => {
58 if self.timer < self.static_data.buildup_duration {
59 if let CharacterState::FinisherMelee(c) = &mut update.character {
61 c.timer = tick_attack_or_default(data, self.timer, None);
62 }
63 } else {
64 if let CharacterState::FinisherMelee(c) = &mut update.character {
66 c.timer = Duration::default();
67 c.stage_section = StageSection::Action;
68 }
69 }
70 },
71 StageSection::Action => {
72 if !self.exhausted {
73 if let CharacterState::FinisherMelee(c) = &mut update.character {
74 c.exhausted = true;
75 }
76
77 self.static_data.combo_consumption.consume(
78 data,
79 output_events,
80 self.static_data.minimum_combo,
81 );
82 let mut melee_constructor = self.static_data.melee_constructor;
83
84 if let Some(scaling) = self.static_data.scaling {
85 let scaling_factor = scaling
86 .kind
87 .factor(
88 self.static_data.combo_on_use as f32,
89 self.static_data.minimum_combo as f32,
90 )
91 .min(scaling.max_factor);
92 match scaling.target {
93 ScalingTarget::Attack => {
94 melee_constructor =
95 melee_constructor.handle_scaling(scaling_factor);
96 },
97 ScalingTarget::Buff => {
98 if let Some(CombatEffect::Buff(CombatBuff { strength, .. })) =
99 &mut melee_constructor.damage_effect
100 {
101 *strength *= scaling_factor;
102 }
103 },
104 }
105 }
106
107 let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
108 let tool_stats = get_tool_stats(data, self.static_data.ability_info);
109
110 data.updater.insert(
111 data.entity,
112 melee_constructor.create_melee(precision_mult, tool_stats),
113 );
114 } else if self.timer < self.static_data.swing_duration {
115 if let CharacterState::FinisherMelee(c) = &mut update.character {
117 c.timer = tick_attack_or_default(data, self.timer, None);
118 }
119 } else {
120 if let CharacterState::FinisherMelee(c) = &mut update.character {
122 c.timer = Duration::default();
123 c.stage_section = StageSection::Recover
124 }
125 }
126 },
127 StageSection::Recover => {
128 if self.timer < self.static_data.recover_duration {
129 if let CharacterState::FinisherMelee(c) = &mut update.character {
131 c.timer = tick_attack_or_default(
132 data,
133 self.timer,
134 Some(data.stats.recovery_speed_modifier),
135 );
136 }
137 } else {
138 end_melee_ability(data, &mut update);
140 }
141 },
142 _ => {
143 end_melee_ability(data, &mut update);
145 },
146 }
147
148 update
149 }
150}
151
152#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
153pub enum ScalingTarget {
154 Attack,
155 Buff,
156}
157
158#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
159pub struct Scaling {
160 pub target: ScalingTarget,
161 pub kind: ScalingKind,
162 pub max_factor: f32,
163}