veloren_common/states/
static_aura.rs

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/// Separated out to condense update portions of character state
21#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
22pub struct StaticData {
23    /// How long until state should create the aura
24    pub buildup_duration: Duration,
25    /// How long the state is creating an aura
26    pub cast_duration: Duration,
27    /// How long the state has until exiting
28    pub recover_duration: Duration,
29    /// Determines how the aura selects its targets
30    pub targets: GroupTarget,
31    /// Has information used to construct the auras
32    pub auras: Vec<AuraBuffConstructor>,
33    /// How long aura lasts
34    pub aura_duration: Option<Secs>,
35    /// Radius of aura
36    pub range: f32,
37    /// Information about sprites if the state should create sprites
38    pub sprite_info: Option<SpriteInfo>,
39    /// What key is used to press ability
40    pub ability_info: AbilityInfo,
41}
42
43#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
44pub struct Data {
45    /// Struct containing data that does not change over the course of the
46    /// character state
47    pub static_data: StaticData,
48    /// Timer for each stage
49    pub timer: Duration,
50    /// What section the character stage is in
51    pub stage_section: StageSection,
52    /// If creates sprites, what radius has been achieved so far
53    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                    // Build up
64                    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                    // Build up
71                    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                    // If creates sprites, create sprites
82                    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                    // Cast
104                    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                    // Creates aura
112                    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                    // Done
152                    end_ability(data, &mut update);
153                }
154            },
155            _ => {
156                // If it somehow ends up in an incorrect stage section
157                end_ability(data, &mut update);
158            },
159        }
160
161        // At end of state logic so an interrupt isn't overwritten
162        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}