1use crate::{
2 combat::GroupTarget,
3 comp::{
4 CharacterState, StateUpdate,
5 aura::{AuraBuffConstructor, AuraChange, AuraKind, AuraTarget, Specifier},
6 character_state::OutputEvents,
7 },
8 event::{AuraEvent, ComboChangeEvent},
9 resources::Secs,
10 states::{
11 behavior::{CharacterBehavior, JoinData},
12 utils::*,
13 },
14};
15use serde::{Deserialize, Serialize};
16use std::time::Duration;
17
18#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
20pub struct StaticData {
21 pub buildup_duration: Duration,
23 pub cast_duration: Duration,
25 pub recover_duration: Duration,
27 pub targets: GroupTarget,
29 pub auras: Vec<AuraBuffConstructor>,
31 pub aura_duration: Option<Secs>,
33 pub range: f32,
35 pub ability_info: AbilityInfo,
37 pub scales_with_combo: bool,
39 pub combo_at_cast: u32,
41 pub specifier: Option<Specifier>,
43}
44
45#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
46pub struct Data {
47 pub static_data: StaticData,
50 pub timer: Duration,
52 pub stage_section: StageSection,
54}
55
56impl CharacterBehavior for Data {
57 fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
58 let mut update = StateUpdate::from(data);
59
60 handle_orientation(data, &mut update, 1.0, None);
61 handle_move(data, &mut update, 0.8);
62 handle_jump(data, output_events, &mut update, 1.0);
63
64 match self.stage_section {
65 StageSection::Buildup => {
66 if self.timer < self.static_data.buildup_duration {
67 update.character = CharacterState::BasicAura(Data {
69 static_data: self.static_data.clone(),
70 timer: tick_attack_or_default(data, self.timer, None),
71 ..*self
72 });
73 } else {
74 let targets =
76 AuraTarget::from((Some(self.static_data.targets), Some(data.uid)));
77 for aura_data in &self.static_data.auras {
78 let mut aura = aura_data.to_aura(
79 (data.uid, self.static_data.ability_info.tool),
80 self.static_data.range,
81 self.static_data.aura_duration,
83 targets,
84 *data.time,
85 self.static_data.specifier,
86 );
87 if self.static_data.scales_with_combo {
88 match aura.aura_kind {
89 AuraKind::Buff {
90 kind: _,
91 ref mut data,
92 category: _,
93 source: _,
94 } => {
95 data.strength *=
96 (self.static_data.combo_at_cast.max(1) as f32).sqrt();
97 },
98 AuraKind::FriendlyFire | AuraKind::ForcePvP => {},
99 }
100 output_events.emit_server(ComboChangeEvent {
101 entity: data.entity,
102 change: -(self.static_data.combo_at_cast as i32),
103 });
104 }
105 output_events.emit_server(AuraEvent {
106 entity: data.entity,
107 aura_change: AuraChange::Add(aura),
108 });
109 }
110 update.character = CharacterState::BasicAura(Data {
112 static_data: self.static_data.clone(),
113 timer: Duration::default(),
114 stage_section: StageSection::Action,
115 });
116 }
117 },
118 StageSection::Action => {
119 if self.timer < self.static_data.cast_duration {
120 update.character = CharacterState::BasicAura(Data {
122 static_data: self.static_data.clone(),
123 timer: tick_attack_or_default(data, self.timer, None),
124 ..*self
125 });
126 } else {
127 update.character = CharacterState::BasicAura(Data {
128 static_data: self.static_data.clone(),
129 timer: Duration::default(),
130 stage_section: StageSection::Recover,
131 });
132 }
133 },
134 StageSection::Recover => {
135 if self.timer < self.static_data.recover_duration {
136 update.character = CharacterState::BasicAura(Data {
137 static_data: self.static_data.clone(),
138 timer: tick_attack_or_default(
139 data,
140 self.timer,
141 Some(data.stats.recovery_speed_modifier),
142 ),
143 ..*self
144 });
145 } else {
146 end_ability(data, &mut update);
148 }
149 },
150 _ => {
151 end_ability(data, &mut update);
153 },
154 }
155
156 handle_interrupts(data, &mut update, output_events);
158
159 update
160 }
161}