use crate::{ comp::{character_state::OutputEvents, CharacterState, StateUpdate}, event::ServerEvent, states::{ behavior::{CharacterBehavior, JoinData}, utils::*, wielding, }, }; 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 the state builds up for pub buildup_duration: Duration, /// How long the state recovers for pub recover_duration: Duration, /// What the max range of the teleport is pub max_range: f32, /// Miscellaneous 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, } impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate { let mut update = StateUpdate::from(data); handle_orientation(data, &mut update, 1.0, None); match self.stage_section { StageSection::Buildup => { if self.timer < self.static_data.buildup_duration { // Build up update.character = CharacterState::Blink(Data { timer: tick_attack_or_default(data, self.timer, None), ..*self }); } else { // Blinks to target location, defaults to 25 meters in front if no target // provided if let Some(input_attr) = self.static_data.ability_info.input_attr { if let Some(target) = input_attr.target_entity { output_events.emit_server(ServerEvent::TeleportTo { entity: data.entity, target, max_range: Some(self.static_data.max_range), }); } else if let Some(pos) = input_attr.select_pos { update.pos.0 = pos; } else { update.pos.0 += *data.inputs.look_dir * 25.0; } } // Transitions to recover section of stage update.character = CharacterState::Blink(Data { timer: Duration::default(), stage_section: StageSection::Recover, ..*self }); } }, StageSection::Recover => { if self.timer < self.static_data.recover_duration { // Recovery update.character = CharacterState::Blink(Data { timer: tick_attack_or_default(data, self.timer, None), ..*self }); } else { // Done update.character = CharacterState::Wielding(wielding::Data { is_sneaking: false }); } }, _ => { // If it somehow ends up in an incorrect stage section update.character = CharacterState::Wielding(wielding::Data { is_sneaking: false }); }, } update } }