1use crate::{
2 combat::{self, CombatBuff, CombatEffect, ScalingKind},
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(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(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.clone();
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(
113 precision_mult,
114 tool_stats,
115 self.static_data.ability_info,
116 ),
117 );
118 } else if self.timer < self.static_data.swing_duration {
119 if let CharacterState::FinisherMelee(c) = &mut update.character {
121 c.timer = tick_attack_or_default(data, self.timer, None);
122 }
123 } else {
124 if let CharacterState::FinisherMelee(c) = &mut update.character {
126 c.timer = Duration::default();
127 c.stage_section = StageSection::Recover
128 }
129 }
130 },
131 StageSection::Recover => {
132 if self.timer < self.static_data.recover_duration {
133 if let CharacterState::FinisherMelee(c) = &mut update.character {
135 c.timer = tick_attack_or_default(
136 data,
137 self.timer,
138 Some(data.stats.recovery_speed_modifier),
139 );
140 }
141 } else {
142 end_melee_ability(data, &mut update);
144 }
145 },
146 _ => {
147 end_melee_ability(data, &mut update);
149 },
150 }
151
152 update
153 }
154}
155
156#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
157pub enum ScalingTarget {
158 Attack,
159 Buff,
160}
161
162#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
163pub struct Scaling {
164 pub target: ScalingTarget,
165 pub kind: ScalingKind,
166 pub max_factor: f32,
167}