1use crate::{
2 combat::GroupTarget,
3 comp::{
4 CharacterState, StateUpdate,
5 aura::{AuraBuffConstructor, AuraTarget, Auras},
6 character_state::OutputEvents,
7 },
8 event::CreateAuraEntityEvent,
9 resources::Secs,
10 states::{
11 behavior::{CharacterBehavior, JoinData},
12 sprite_summon::create_sprites,
13 utils::*,
14 },
15 terrain::SpriteKind,
16};
17use serde::{Deserialize, Serialize};
18use std::time::Duration;
19
20#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
22pub struct StaticData {
23 pub buildup_duration: Duration,
25 pub cast_duration: Duration,
27 pub recover_duration: Duration,
29 pub targets: GroupTarget,
31 pub auras: Vec<AuraBuffConstructor>,
33 pub aura_duration: Option<Secs>,
35 pub range: f32,
37 pub sprite_info: Option<SpriteInfo>,
39 pub ability_info: AbilityInfo,
41}
42
43#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
44pub struct Data {
45 pub static_data: StaticData,
48 pub timer: Duration,
50 pub stage_section: StageSection,
52 pub achieved_radius: Option<i32>,
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 match self.stage_section {
61 StageSection::Buildup => {
62 if self.timer < self.static_data.buildup_duration {
63 update.character = CharacterState::StaticAura(Data {
65 static_data: self.static_data.clone(),
66 timer: tick_attack_or_default(data, self.timer, None),
67 ..*self
68 });
69 } else {
70 update.character = CharacterState::StaticAura(Data {
72 static_data: self.static_data.clone(),
73 timer: Duration::default(),
74 stage_section: StageSection::Action,
75 achieved_radius: self.achieved_radius,
76 });
77 }
78 },
79 StageSection::Action => {
80 if self.timer < self.static_data.cast_duration {
81 let achieved_radius = if let Some(sprite_info) = self.static_data.sprite_info {
83 let timer_frac =
84 self.timer.as_secs_f32() / self.static_data.cast_duration.as_secs_f32();
85
86 let achieved_radius = create_sprites(
87 data,
88 output_events,
89 sprite_info.sprite,
90 timer_frac,
91 sprite_info.summon_distance,
92 self.achieved_radius.unwrap_or(0),
93 360.0,
94 sprite_info.sparseness,
95 data.pos.0,
96 false,
97 sprite_info.del_timeout,
98 );
99 Some(achieved_radius)
100 } else {
101 None
102 };
103 update.character = CharacterState::StaticAura(Data {
105 static_data: self.static_data.clone(),
106 timer: tick_attack_or_default(data, self.timer, None),
107 achieved_radius,
108 ..*self
109 });
110 } else {
111 let targets =
113 AuraTarget::from((Some(self.static_data.targets), Some(data.uid)));
114 let mut auras = Vec::new();
115 for aura_data in &self.static_data.auras {
116 let aura = aura_data.to_aura(
117 data.uid,
118 self.static_data.range,
119 self.static_data.aura_duration,
120 targets,
121 *data.time,
122 );
123 auras.push(aura);
124 }
125 output_events.emit_server(CreateAuraEntityEvent {
126 auras: Auras::new(auras),
127 pos: *data.pos,
128 creator_uid: *data.uid,
129 duration: self.static_data.aura_duration,
130 });
131 update.character = CharacterState::StaticAura(Data {
132 static_data: self.static_data.clone(),
133 timer: Duration::default(),
134 stage_section: StageSection::Recover,
135 achieved_radius: self.achieved_radius,
136 });
137 }
138 },
139 StageSection::Recover => {
140 if self.timer < self.static_data.recover_duration {
141 update.character = CharacterState::StaticAura(Data {
142 static_data: self.static_data.clone(),
143 timer: tick_attack_or_default(
144 data,
145 self.timer,
146 Some(data.stats.recovery_speed_modifier),
147 ),
148 ..*self
149 });
150 } else {
151 end_ability(data, &mut update);
153 }
154 },
155 _ => {
156 end_ability(data, &mut update);
158 },
159 }
160
161 handle_interrupts(data, &mut update, output_events);
163
164 update
165 }
166}
167
168#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
169pub struct SpriteInfo {
170 pub sprite: SpriteKind,
171 pub del_timeout: Option<(f32, f32)>,
172 pub summon_distance: (f32, f32),
173 pub sparseness: f64,
174}