1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::{
comp::{
buff::{BuffChange, BuffKind},
character_state::{AttackFilters, OutputEvents},
CharacterState, StateUpdate,
},
event::BuffEvent,
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
},
util::Dir,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// How long until state should roll
pub buildup_duration: Duration,
/// How long state is rolling for
pub movement_duration: Duration,
/// How long it takes to recover from roll
pub recover_duration: Duration,
/// Affects the speed and distance of the roll
pub roll_strength: f32,
/// Affects whether you are immune to various attacks while rolling
pub attack_immunities: AttackFilters,
/// Information about the ability
pub ability_info: AbilityInfo,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Had weapon
pub was_wielded: bool,
/// What direction were we previously aiming in?
pub prev_aimed_dir: Option<Dir>,
/// Is sneaking, true if previous state was also considered sneaking
pub is_sneaking: bool,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// You should not be able to strafe while rolling
update.should_strafe = false;
// Smooth orientation
handle_orientation(data, &mut update, 2.5, None);
match self.stage_section {
StageSection::Buildup => {
handle_move(data, &mut update, 0.3);
if self.timer < self.static_data.buildup_duration {
// Build up
update.character = CharacterState::Roll(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
} else {
// Remove burning effect if active
output_events.emit_server(BuffEvent {
entity: data.entity,
buff_change: BuffChange::RemoveByKind(BuffKind::Burning),
});
// Transitions to movement section of stage
update.character = CharacterState::Roll(Data {
timer: Duration::default(),
stage_section: StageSection::Movement,
..*self
});
}
},
StageSection::Movement => {
// Update velocity
handle_forced_movement(
data,
&mut update,
ForcedMovement::Forward(
self.static_data.roll_strength
* ((1.0
- self.timer.as_secs_f32()
/ self.static_data.movement_duration.as_secs_f32())
/ 2.0
+ 0.25),
),
);
if self.timer < self.static_data.movement_duration {
// Movement
update.character = CharacterState::Roll(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
} else {
// Transition to recover section of stage
update.character = CharacterState::Roll(Data {
timer: Duration::default(),
stage_section: StageSection::Recover,
..*self
});
}
},
StageSection::Recover => {
handle_move(data, &mut update, 1.0);
// Allows for jumps to interrupt recovery in roll
if self.timer < self.static_data.recover_duration
&& !handle_jump(data, output_events, &mut update, 1.5)
{
// Recover
update.character = CharacterState::Roll(Data {
timer: tick_attack_or_default(
data,
self.timer,
Some(data.stats.recovery_speed_modifier),
),
..*self
});
} else {
// Done
end_ability(data, &mut update);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
end_ability(data, &mut update);
},
}
update
}
}