veloren_common/states/
finisher_melee.rs

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/// Separated out to condense update portions of character state
13#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
14pub struct StaticData {
15    /// How long until state should deal damage
16    pub buildup_duration: Duration,
17    /// How long the state is swinging for
18    pub swing_duration: Duration,
19    /// How long the state has until exiting
20    pub recover_duration: Duration,
21    /// Used to construct the Melee attack
22    pub melee_constructor: MeleeConstructor,
23    /// Used to determine if and how scaling of the melee attack should happen
24    pub scaling: Option<Scaling>,
25    /// Minimum amount of combo needed to activate ability
26    pub minimum_combo: u32,
27    /// Amount of combo when ability was activated
28    pub combo_on_use: u32,
29    pub combo_consumption: ComboConsumption,
30    /// What key is used to press ability
31    pub ability_info: AbilityInfo,
32}
33
34#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
35pub struct Data {
36    /// Struct containing data that does not change over the course of the
37    /// character state
38    pub static_data: StaticData,
39    /// Timer for each stage
40    pub timer: Duration,
41    /// What section the character stage is in
42    pub stage_section: StageSection,
43    /// Whether the attack can deal more damage
44    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                    // Build up
60                    if let CharacterState::FinisherMelee(c) = &mut update.character {
61                        c.timer = tick_attack_or_default(data, self.timer, None);
62                    }
63                } else {
64                    // Transitions to swing section of stage
65                    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                    // Swings
116                    if let CharacterState::FinisherMelee(c) = &mut update.character {
117                        c.timer = tick_attack_or_default(data, self.timer, None);
118                    }
119                } else {
120                    // Transitions to recover section of stage
121                    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                    // Recovery
130                    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                    // Done
139                    end_melee_ability(data, &mut update);
140                }
141            },
142            _ => {
143                // If it somehow ends up in an incorrect stage section
144                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}