veloren/common/src/states/utils.rs

238 lines
8.1 KiB
Rust
Raw Normal View History

2020-02-03 10:54:50 +00:00
use crate::{
2020-03-20 14:45:36 +00:00
comp::{CharacterState, ItemKind::Tool, StateUpdate, ToolData},
2020-02-03 10:54:50 +00:00
event::LocalEvent,
states::*,
2020-03-07 19:02:54 +00:00
sys::{character_behavior::JoinData, phys::GRAVITY},
2019-12-28 16:10:39 +00:00
};
2020-02-11 15:42:17 +00:00
use std::time::Duration;
use vek::vec::{Vec2, Vec3};
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-03-08 15:38:53 +00:00
const BASE_HUMANOID_ACCEL: f32 = 100.0;
const BASE_HUMANOID_SPEED: f32 = 150.0;
const BASE_HUMANOID_AIR_ACCEL: f32 = 15.0;
const BASE_HUMANOID_AIR_SPEED: f32 = 8.0;
const BASE_HUMANOID_WATER_ACCEL: f32 = 70.0;
const BASE_HUMANOID_WATER_SPEED: f32 = 120.0;
// 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-03-08 17:38:18 +00:00
/// Handles updating `Components` to move player based on state of `JoinData`
2020-03-07 18:15:02 +00:00
pub fn handle_move(data: &JoinData, update: &mut StateUpdate) {
if data.physics.in_fluid {
2020-03-07 23:45:10 +00:00
swim_move(data, update);
2020-03-07 18:15:02 +00:00
} else {
2020-03-08 17:38:18 +00:00
basic_move(data, update);
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
fn basic_move(data: &JoinData, update: &mut StateUpdate) {
2020-03-07 18:15:02 +00:00
let (accel, speed): (f32, f32) = if data.physics.on_ground {
2020-03-08 15:38:53 +00:00
(BASE_HUMANOID_ACCEL, BASE_HUMANOID_SPEED)
} else {
2020-03-08 15:38:53 +00:00
(BASE_HUMANOID_AIR_ACCEL, BASE_HUMANOID_AIR_SPEED)
};
// Move player according to move_dir
2020-02-03 19:43:36 +00:00
if update.vel.0.magnitude_squared() < speed.powf(2.0) {
2020-03-07 18:15:02 +00:00
update.vel.0 = update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel;
2020-02-03 19:43:36 +00:00
let mag2 = update.vel.0.magnitude_squared();
if mag2 > speed.powf(2.0) {
update.vel.0 = update.vel.0.normalized() * speed;
}
}
2020-03-20 22:03:29 +00:00
handle_orientation(data, update);
}
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate) {
// Set direction based on move direction
let ori_dir = if update.character.is_attack() || update.character.is_block() {
2020-03-07 18:15:02 +00:00
Vec2::from(data.inputs.look_dir).normalized()
} else {
Vec2::from(data.inputs.move_dir)
};
// Smooth orientation
if ori_dir.magnitude_squared() > 0.0001
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
> 0.001
{
2020-03-07 18:15:02 +00:00
update.ori.0 = vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 9.0 * data.dt.0);
}
}
2020-03-08 17:38:18 +00:00
/// Updates components to move player as if theyre swimming
2020-03-07 23:45:10 +00:00
fn swim_move(data: &JoinData, update: &mut StateUpdate) {
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
};
// Set direction based on move direction when on the ground
let ori_dir = if update.character.is_attack() || update.character.is_block() {
2020-03-07 18:15:02 +00:00
Vec2::from(data.inputs.look_dir).normalized()
} else {
Vec2::from(update.vel.0)
};
if ori_dir.magnitude_squared() > 0.0001
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
> 0.001
{
update.ori.0 = vek::ops::Slerp::slerp(
update.ori.0,
ori_dir.into(),
if data.physics.on_ground { 9.0 } else { 2.0 } * data.dt.0,
);
}
2020-03-07 18:15:02 +00:00
// Force players to pulse jump button to swim up
if data.inputs.jump.is_pressed() && !data.inputs.jump.is_long_press(Duration::from_millis(600))
{
2020-03-08 15:38:53 +00:00
update.vel.0.z =
(update.vel.0.z + data.dt.0 * GRAVITY * 1.25).min(BASE_HUMANOID_WATER_SPEED);
2020-03-07 18:15:02 +00:00
}
}
2020-03-08 17:04:26 +00:00
/// First checks whether `primary` input is pressed, then
/// attempts to go into Equipping state, otherwise Idle
2020-03-07 18:15:02 +00:00
pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
if data.inputs.primary.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) {
if let Some(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 {
update.character = CharacterState::Idle {};
};
}
2020-03-08 17:38:18 +00:00
/// Checks that player can `Sit` and updates `CharacterState` if so
2020-03-07 18:15:02 +00:00
pub fn handle_sit(data: &JoinData, update: &mut StateUpdate) {
if data.inputs.sit.is_pressed() && data.physics.on_ground && data.body.is_humanoid() {
update.character = CharacterState::Sit {};
}
}
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) {
if (data.inputs.climb.is_pressed() || data.inputs.climb_down.is_pressed())
&& 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()
&& update.energy.current() > 100
{
2020-03-07 18:15:02 +00:00
update.character = CharacterState::Climb {};
}
}
2020-03-08 17:38:18 +00:00
/// Checks that player can `Glide` and updates `CharacterState` if so
2020-03-07 18:15:02 +00:00
pub fn handle_unwield(data: &JoinData, update: &mut StateUpdate) {
if let CharacterState::Wielding { .. } = update.character {
if data.inputs.toggle_wield.is_pressed() {
update.character = CharacterState::Idle {};
}
}
}
2020-03-08 17:38:18 +00:00
/// Checks that player can glide and updates `CharacterState` if so
2020-03-07 18:15:02 +00:00
pub fn handle_glide(data: &JoinData, update: &mut StateUpdate) {
if let CharacterState::Idle { .. } | CharacterState::Wielding { .. } = update.character {
if data.inputs.glide.is_pressed()
&& !data.physics.on_ground
&& !data.physics.in_fluid
&& data.body.is_humanoid()
{
2020-03-07 18:15:02 +00:00
update.character = CharacterState::Glide {};
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) {
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-08 17:38:18 +00:00
/// If `inputs.primary` is pressed and in `Wielding` state,
2020-03-17 14:01:41 +00:00
/// will attempt to go into `loadout.active_item.primary_ability`
2020-03-08 17:38:18 +00:00
pub fn handle_primary_input(data: &JoinData, update: &mut StateUpdate) {
if data.inputs.primary.is_pressed() {
2020-03-17 14:01:41 +00:00
if let Some(ability) = data
.loadout
.active_item
.as_ref()
.and_then(|i| i.primary_ability.as_ref())
.filter(|ability| ability.test_requirements(data, update))
{
update.character = ability.into();
2020-02-03 10:54:50 +00:00
}
}
}
2020-03-08 17:38:18 +00:00
/// If `inputs.secondary` is pressed and in `Wielding` state,
2020-03-17 14:01:41 +00:00
/// will attempt to go into `loadout.active_item.secondary_ability`
2020-03-08 17:38:18 +00:00
pub fn handle_secondary_input(data: &JoinData, update: &mut StateUpdate) {
if data.inputs.secondary.is_pressed() {
2020-03-17 14:01:41 +00:00
if let Some(ability) = data
.loadout
.active_item
.as_ref()
.and_then(|i| i.secondary_ability.as_ref())
.filter(|ability| ability.test_requirements(data, update))
{
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-17 14:01:41 +00:00
if data.inputs.roll.is_pressed() {
if let Some(ability) = data
.loadout
.active_item
.as_ref()
.and_then(|i| i.dodge_ability.as_ref())
.filter(|ability| ability.test_requirements(data, update))
2020-03-08 17:38:18 +00:00
{
2020-03-17 14:01:41 +00:00
update.character = ability.into();
2020-02-03 10:54:50 +00:00
}
}
2019-12-28 16:10:39 +00:00
}
2020-03-07 18:15:02 +00:00
pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a ToolData> {
if let Some(Tool(tool)) = data.loadout.active_item.as_ref().map(|i| &i.item.kind) {
Some(tool)
} else {
None
}
}