use super::utils::*;
use crate::{
comp::{
character_state::OutputEvents, controller::InputKind, slot::EquipSlot, CharacterState,
InventoryAction, Ori, StateUpdate,
},
event::LocalEvent,
outcome::Outcome,
states::{
behavior::{CharacterBehavior, JoinData},
glide, idle,
},
};
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
pub ori: Ori,
span_length: f32,
chord_length: f32,
}
impl From<&JoinData<'_>> for Data {
fn from(data: &JoinData) -> Self {
let scale = data.body.dimensions().z.sqrt();
Self {
span_length: scale * 4.5,
chord_length: scale,
ori: *data.ori,
}
}
}
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);
handle_move(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
if input_is_pressed(data, InputKind::Roll) {
handle_input(data, output_events, &mut update, InputKind::Roll);
}
handle_glider_input_or(data, &mut update, output_events, handle_wield);
if matches!(update.character, CharacterState::GlideWield(_)) {
update.character = if data.physics.on_ground.is_none() {
CharacterState::Glide(glide::Data::new(
self.span_length,
self.chord_length,
self.ori,
))
} else if data
.inventory
.and_then(|inv| inv.equipped(EquipSlot::Glider))
.is_some()
&& data.physics.in_liquid().map_or(true, |depth| depth < 0.5)
{
CharacterState::GlideWield(Self {
ori: self.ori.slerped_towards(
data.ori.slerped_towards(
Ori::from(data.inputs.look_dir).pitched_up(0.6),
(1.0 + data.inputs.look_dir.dot(*data.ori.look_dir()).max(0.0)) / 3.0,
),
5.0 * data.dt.0,
),
..*self
})
} else {
CharacterState::Idle(idle::Data::default())
};
}
update
}
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn unwield(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Glider {
pos: data.pos.0,
wielded: false,
}));
update.character = CharacterState::Idle(idle::Data::default());
update
}
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sneak(data, &mut update);
update
}
}