2020-02-03 10:54:50 +00:00
|
|
|
use crate::{
|
2020-03-28 05:51:52 +00:00
|
|
|
comp::{
|
2020-07-01 09:51:06 +00:00
|
|
|
item::{Hands, ItemKind, Tool},
|
2020-07-04 00:17:51 +00:00
|
|
|
Body, CharacterState, StateUpdate,
|
2020-03-28 05:51:52 +00:00
|
|
|
},
|
2020-02-03 10:54:50 +00:00
|
|
|
event::LocalEvent,
|
2020-03-14 18:50:07 +00:00
|
|
|
states::*,
|
2020-03-07 19:02:54 +00:00
|
|
|
sys::{character_behavior::JoinData, phys::GRAVITY},
|
2020-03-28 01:31:22 +00:00
|
|
|
util::Dir,
|
2019-12-28 16:10:39 +00:00
|
|
|
};
|
2020-03-21 03:23:46 +00:00
|
|
|
use vek::vec::Vec2;
|
2019-12-28 16:10:39 +00:00
|
|
|
|
2020-03-08 19:37:17 +00:00
|
|
|
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
2020-07-06 19:51:57 +00:00
|
|
|
const BASE_HUMANOID_AIR_ACCEL: f32 = 8.0;
|
2020-04-26 01:09:03 +00:00
|
|
|
const BASE_HUMANOID_WATER_ACCEL: f32 = 150.0;
|
|
|
|
const BASE_HUMANOID_WATER_SPEED: f32 = 180.0;
|
2020-03-08 15:38:53 +00:00
|
|
|
// const BASE_HUMANOID_CLIMB_ACCEL: f32 = 10.0;
|
|
|
|
// const ROLL_SPEED: f32 = 17.0;
|
|
|
|
// const CHARGE_SPEED: f32 = 20.0;
|
|
|
|
// const GLIDE_ACCEL: f32 = 15.0;
|
|
|
|
// const GLIDE_SPEED: f32 = 45.0;
|
|
|
|
// const BLOCK_ACCEL: f32 = 30.0;
|
|
|
|
// const BLOCK_SPEED: f32 = 75.0;
|
2020-03-10 18:12:16 +00:00
|
|
|
// Gravity is 9.81 * 4, so this makes gravity equal to .15 //TODO: <- is wrong
|
|
|
|
//
|
2020-03-08 15:38:53 +00:00
|
|
|
// const GLIDE_ANTIGRAV: f32 = GRAVITY * 0.96;
|
|
|
|
// const CLIMB_SPEED: f32 = 5.0;
|
|
|
|
// const CLIMB_COST: i32 = 5;
|
|
|
|
|
2020-07-03 18:30:41 +00:00
|
|
|
impl Body {
|
|
|
|
pub fn base_accel(&self) -> f32 {
|
|
|
|
match self {
|
|
|
|
Body::Humanoid(_) => 100.0,
|
|
|
|
Body::QuadrupedSmall(_) => 80.0,
|
|
|
|
Body::QuadrupedMedium(_) => 180.0,
|
|
|
|
Body::BirdMedium(_) => 70.0,
|
|
|
|
Body::FishMedium(_) => 50.0,
|
|
|
|
Body::Dragon(_) => 250.0,
|
|
|
|
Body::BirdSmall(_) => 75.0,
|
|
|
|
Body::FishSmall(_) => 40.0,
|
|
|
|
Body::BipedLarge(_) => 120.0,
|
|
|
|
Body::Object(_) => 40.0,
|
|
|
|
Body::Golem(_) => 130.0,
|
|
|
|
Body::Critter(_) => 65.0,
|
|
|
|
Body::QuadrupedLow(_) => 120.0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Handles updating `Components` to move player based on state of `JoinData`
|
2020-03-26 19:02:01 +00:00
|
|
|
pub fn handle_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
2020-03-07 18:15:02 +00:00
|
|
|
if data.physics.in_fluid {
|
2020-03-26 19:02:01 +00:00
|
|
|
swim_move(data, update, efficiency);
|
2020-03-07 18:15:02 +00:00
|
|
|
} else {
|
2020-03-26 19:02:01 +00:00
|
|
|
basic_move(data, update, efficiency);
|
2020-03-07 18:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Updates components to move player as if theyre on ground or in air
|
2020-06-10 19:47:36 +00:00
|
|
|
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
|
2020-03-26 19:02:01 +00:00
|
|
|
fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
2020-07-03 18:30:41 +00:00
|
|
|
let accel = if data.physics.on_ground {
|
|
|
|
data.body.base_accel()
|
2020-01-21 22:54:32 +00:00
|
|
|
} else {
|
2020-07-03 18:30:41 +00:00
|
|
|
BASE_HUMANOID_AIR_ACCEL
|
2020-01-21 22:54:32 +00:00
|
|
|
};
|
|
|
|
|
2020-07-03 18:30:41 +00:00
|
|
|
update.vel.0 =
|
2020-07-03 19:30:21 +00:00
|
|
|
update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel * efficiency;
|
2020-01-21 22:54:32 +00:00
|
|
|
|
2020-03-26 13:46:08 +00:00
|
|
|
handle_orientation(data, update, 20.0);
|
2020-03-20 22:03:29 +00:00
|
|
|
}
|
|
|
|
|
2020-03-21 14:06:35 +00:00
|
|
|
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f32) {
|
2020-01-21 22:54:32 +00:00
|
|
|
// Set direction based on move direction
|
2020-03-19 21:03:17 +00:00
|
|
|
let ori_dir = if update.character.is_attack() || update.character.is_block() {
|
2020-04-25 01:23:49 +00:00
|
|
|
data.inputs.look_dir.xy()
|
|
|
|
} else if !data.inputs.move_dir.is_approx_zero() {
|
|
|
|
data.inputs.move_dir
|
2020-01-21 22:54:32 +00:00
|
|
|
} else {
|
2020-04-25 01:23:49 +00:00
|
|
|
update.ori.0.xy()
|
2020-01-21 22:54:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Smooth orientation
|
2020-03-28 01:31:22 +00:00
|
|
|
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), strength * data.dt.0);
|
2020-01-21 22:54:32 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Updates components to move player as if theyre swimming
|
2020-03-26 19:02:01 +00:00
|
|
|
fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
2020-03-07 18:15:02 +00:00
|
|
|
// Update velocity
|
|
|
|
update.vel.0 += Vec2::broadcast(data.dt.0)
|
|
|
|
* data.inputs.move_dir
|
2020-03-08 15:38:53 +00:00
|
|
|
* if update.vel.0.magnitude_squared() < BASE_HUMANOID_WATER_SPEED.powf(2.0) {
|
|
|
|
BASE_HUMANOID_WATER_ACCEL
|
2020-03-07 18:15:02 +00:00
|
|
|
} else {
|
|
|
|
0.0
|
2020-03-26 19:02:01 +00:00
|
|
|
}
|
|
|
|
* efficiency;
|
2020-03-07 18:15:02 +00:00
|
|
|
|
2020-03-21 14:06:35 +00:00
|
|
|
handle_orientation(data, update, if data.physics.on_ground { 9.0 } else { 2.0 });
|
2020-01-21 22:54:32 +00:00
|
|
|
|
2020-03-23 11:50:08 +00:00
|
|
|
// Swim
|
2020-07-04 19:22:55 +00:00
|
|
|
if data.inputs.swim.is_pressed() {
|
2020-03-08 15:38:53 +00:00
|
|
|
update.vel.0.z =
|
2020-03-21 16:45:26 +00:00
|
|
|
(update.vel.0.z + data.dt.0 * GRAVITY * 2.25).min(BASE_HUMANOID_WATER_SPEED);
|
2020-03-07 18:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-12 16:07:38 +00:00
|
|
|
/// First checks whether `primary`, `secondary` or `ability3` input is pressed,
|
|
|
|
/// then attempts to go into Equipping state, otherwise Idle
|
|
|
|
pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
|
|
|
|
if data.inputs.primary.is_pressed()
|
|
|
|
|| data.inputs.secondary.is_pressed()
|
|
|
|
|| data.inputs.ability3.is_pressed()
|
|
|
|
{
|
2020-03-08 17:04:26 +00:00
|
|
|
attempt_wield(data, update);
|
2020-03-07 18:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:04:26 +00:00
|
|
|
/// If a tool is equipped, goes into Equipping state, otherwise goes to Idle
|
|
|
|
pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-28 05:51:52 +00:00
|
|
|
if let Some(ItemKind::Tool(tool)) = data.loadout.active_item.as_ref().map(|i| &i.item.kind) {
|
2020-03-14 21:17:27 +00:00
|
|
|
update.character = CharacterState::Equipping(equipping::Data {
|
2020-03-08 17:04:26 +00:00
|
|
|
time_left: tool.equip_time(),
|
2020-03-14 21:17:27 +00:00
|
|
|
});
|
2020-03-08 17:04:26 +00:00
|
|
|
} else {
|
2020-03-21 22:55:20 +00:00
|
|
|
update.character = CharacterState::Idle;
|
2020-03-08 17:04:26 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Checks that player can `Sit` and updates `CharacterState` if so
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn attempt_sit(data: &JoinData, update: &mut StateUpdate) {
|
|
|
|
if data.physics.on_ground && data.body.is_humanoid() {
|
2020-03-21 22:55:20 +00:00
|
|
|
update.character = CharacterState::Sit;
|
2020-01-21 22:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 06:41:55 +00:00
|
|
|
pub fn attempt_dance(data: &JoinData, update: &mut StateUpdate) {
|
|
|
|
if data.physics.on_ground && data.body.is_humanoid() {
|
|
|
|
update.character = CharacterState::Dance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Checks that player can `Climb` and updates `CharacterState` if so
|
2020-03-07 18:15:02 +00:00
|
|
|
pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-24 07:38:16 +00:00
|
|
|
if data.inputs.climb.is_some()
|
2020-03-07 18:15:02 +00:00
|
|
|
&& data.physics.on_wall.is_some()
|
|
|
|
&& !data.physics.on_ground
|
2020-02-03 19:43:36 +00:00
|
|
|
//&& update.vel.0.z < 0.0
|
2020-03-07 18:15:02 +00:00
|
|
|
&& data.body.is_humanoid()
|
2020-03-10 16:33:36 +00:00
|
|
|
&& update.energy.current() > 100
|
2020-01-21 22:54:32 +00:00
|
|
|
{
|
2020-03-21 22:55:20 +00:00
|
|
|
update.character = CharacterState::Climb;
|
2020-01-21 22:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 21:16:26 +00:00
|
|
|
/// Checks that player can Swap Weapons and updates `Loadout` if so
|
2020-07-06 05:56:02 +00:00
|
|
|
pub fn attempt_swap_loadout(data: &JoinData, update: &mut StateUpdate) {
|
|
|
|
if data.loadout.second_item.is_some() {
|
|
|
|
update.swap_loadout = true;
|
2020-03-25 14:58:26 +00:00
|
|
|
}
|
2020-03-21 21:16:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 21:32:39 +00:00
|
|
|
/// Checks that player can wield the glider and updates `CharacterState` if so
|
|
|
|
pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) {
|
|
|
|
if data.physics.on_ground && !data.physics.in_fluid && data.body.is_humanoid() {
|
|
|
|
update.character = CharacterState::GlideWield;
|
2020-02-03 10:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Checks that player can jump and sends jump event if so
|
2020-03-07 18:15:02 +00:00
|
|
|
pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-10 18:00:49 +00:00
|
|
|
if data.inputs.jump.is_pressed() && data.physics.on_ground && !data.physics.in_fluid {
|
2020-02-03 10:54:50 +00:00
|
|
|
update
|
|
|
|
.local_events
|
2020-03-07 18:15:02 +00:00
|
|
|
.push_front(LocalEvent::Jump(data.entity));
|
2020-02-03 10:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 12:59:53 +00:00
|
|
|
/// Will attempt to go into `loadout.active_item.ability1`
|
|
|
|
pub fn handle_ability1_input(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-25 22:10:50 +00:00
|
|
|
if data.inputs.primary.is_pressed() {
|
2020-03-17 14:01:41 +00:00
|
|
|
if let Some(ability) = data
|
|
|
|
.loadout
|
|
|
|
.active_item
|
|
|
|
.as_ref()
|
2020-03-24 12:59:53 +00:00
|
|
|
.and_then(|i| i.ability1.as_ref())
|
2020-03-21 22:55:20 +00:00
|
|
|
.filter(|ability| ability.requirements_paid(data, update))
|
2020-03-17 14:01:41 +00:00
|
|
|
{
|
|
|
|
update.character = ability.into();
|
2020-02-03 10:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 12:59:53 +00:00
|
|
|
/// Will attempt to go into `loadout.active_item.ability2`
|
|
|
|
pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-25 22:10:50 +00:00
|
|
|
if data.inputs.secondary.is_pressed() {
|
2020-07-01 09:51:06 +00:00
|
|
|
let active_tool_kind = match data.loadout.active_item.as_ref().map(|i| &i.item.kind) {
|
|
|
|
Some(ItemKind::Tool(Tool { kind, .. })) => Some(kind),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let second_tool_kind = match data.loadout.second_item.as_ref().map(|i| &i.item.kind) {
|
|
|
|
Some(ItemKind::Tool(Tool { kind, .. })) => Some(kind),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
match (
|
|
|
|
active_tool_kind.map(|tk| tk.into_hands()),
|
|
|
|
second_tool_kind.map(|tk| tk.into_hands()),
|
|
|
|
) {
|
|
|
|
(Some(Hands::TwoHand), _) => {
|
|
|
|
if let Some(ability) = data
|
|
|
|
.loadout
|
|
|
|
.active_item
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|i| i.ability2.as_ref())
|
|
|
|
.filter(|ability| ability.requirements_paid(data, update))
|
|
|
|
{
|
|
|
|
update.character = ability.into();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(_, Some(Hands::OneHand)) => {
|
|
|
|
if let Some(ability) = data
|
|
|
|
.loadout
|
|
|
|
.second_item
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|i| i.ability2.as_ref())
|
|
|
|
.filter(|ability| ability.requirements_paid(data, update))
|
|
|
|
{
|
|
|
|
update.character = ability.into();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(_, _) => {},
|
|
|
|
};
|
2020-03-24 12:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Will attempt to go into `loadout.active_item.ability3`
|
|
|
|
pub fn handle_ability3_input(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-25 22:10:50 +00:00
|
|
|
if data.inputs.ability3.is_pressed() {
|
2020-03-24 12:59:53 +00:00
|
|
|
if let Some(ability) = data
|
|
|
|
.loadout
|
|
|
|
.active_item
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|i| i.ability3.as_ref())
|
2020-03-21 22:55:20 +00:00
|
|
|
.filter(|ability| ability.requirements_paid(data, update))
|
2020-03-17 14:01:41 +00:00
|
|
|
{
|
|
|
|
update.character = ability.into();
|
2020-02-24 14:35:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 17:38:18 +00:00
|
|
|
/// Checks that player can perform a dodge, then
|
2020-03-17 14:01:41 +00:00
|
|
|
/// attempts to go into `loadout.active_item.dodge_ability`
|
2020-03-08 17:38:18 +00:00
|
|
|
pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
2020-03-25 22:10:50 +00:00
|
|
|
if data.inputs.roll.is_pressed() {
|
2020-03-17 14:01:41 +00:00
|
|
|
if let Some(ability) = data
|
|
|
|
.loadout
|
|
|
|
.active_item
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|i| i.dodge_ability.as_ref())
|
2020-03-21 22:55:20 +00:00
|
|
|
.filter(|ability| ability.requirements_paid(data, update))
|
2020-03-08 17:38:18 +00:00
|
|
|
{
|
2020-03-26 13:46:08 +00:00
|
|
|
if data.character.is_wield() {
|
|
|
|
update.character = ability.into();
|
|
|
|
if let CharacterState::Roll(roll) = &mut update.character {
|
|
|
|
roll.was_wielded = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
update.character = ability.into();
|
|
|
|
}
|
2020-02-03 10:54:50 +00:00
|
|
|
}
|
2020-01-21 22:54:32 +00:00
|
|
|
}
|
2019-12-28 16:10:39 +00:00
|
|
|
}
|
2020-03-07 18:15:02 +00:00
|
|
|
|
2020-03-28 05:51:52 +00:00
|
|
|
pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> {
|
|
|
|
if let Some(ItemKind::Tool(tool)) = data.loadout.active_item.as_ref().map(|i| &i.item.kind) {
|
2020-03-14 18:50:07 +00:00
|
|
|
Some(tool)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|