veloren/common/src/sys/controller.rs

387 lines
16 KiB
Rust
Raw Normal View History

2019-08-26 18:05:30 +00:00
use super::{
combat::{ATTACK_DURATION, WIELD_DURATION},
movement::ROLL_DURATION,
};
use crate::{
comp::{
2019-10-11 04:30:34 +00:00
self, item, projectile, ActionState::*, Body, CharacterState, ControlEvent, Controller,
HealthChange, HealthSource, Item, MovementState::*, PhysicsState, Projectile, Stats, Vel,
},
2019-08-25 16:48:12 +00:00
event::{EventBus, LocalEvent, ServerEvent},
2019-06-09 14:20:20 +00:00
};
use specs::{
saveload::{Marker, MarkerAllocator},
Entities, Join, Read, ReadStorage, System, WriteStorage,
};
2019-10-11 04:30:34 +00:00
use sphynx::{Uid, UidAllocator};
use std::time::Duration;
2019-08-29 17:39:34 +00:00
use vek::*;
2019-06-09 14:20:20 +00:00
2019-06-09 19:33:20 +00:00
/// This system is responsible for validating controller inputs
2019-06-09 14:20:20 +00:00
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Read<'a, UidAllocator>,
2019-06-09 14:20:20 +00:00
Entities<'a>,
Read<'a, EventBus<ServerEvent>>,
Read<'a, EventBus<LocalEvent>>,
2019-07-21 16:50:13 +00:00
WriteStorage<'a, Controller>,
2019-06-09 14:20:20 +00:00
ReadStorage<'a, Stats>,
2019-08-04 08:21:29 +00:00
ReadStorage<'a, Body>,
2019-06-13 18:09:50 +00:00
ReadStorage<'a, Vel>,
ReadStorage<'a, PhysicsState>,
2019-10-11 04:30:34 +00:00
ReadStorage<'a, Uid>,
WriteStorage<'a, CharacterState>,
2019-06-09 14:20:20 +00:00
);
fn run(
&mut self,
(
uid_allocator,
2019-06-09 14:20:20 +00:00
entities,
server_bus,
local_bus,
2019-07-21 16:50:13 +00:00
mut controllers,
2019-06-09 14:20:20 +00:00
stats,
2019-08-04 08:21:29 +00:00
bodies,
2019-06-13 18:09:50 +00:00
velocities,
physics_states,
uids,
mut character_states,
2019-06-09 14:20:20 +00:00
): Self::SystemData,
) {
let mut server_emitter = server_bus.emitter();
let mut local_emitter = local_bus.emitter();
for (entity, uid, controller, stats, body, vel, physics, mut character) in (
2019-06-09 14:20:20 +00:00
&entities,
&uids,
2019-07-21 16:50:13 +00:00
&mut controllers,
2019-06-09 14:20:20 +00:00
&stats,
2019-08-04 08:21:29 +00:00
&bodies,
2019-06-13 18:09:50 +00:00
&velocities,
&physics_states,
&mut character_states,
2019-06-09 14:20:20 +00:00
)
.join()
{
let mut inputs = &mut controller.inputs;
2019-06-09 14:20:20 +00:00
if stats.is_dead {
2019-06-09 19:33:20 +00:00
// Respawn
if inputs.respawn {
server_emitter.emit(ServerEvent::Respawn(entity));
2019-06-09 19:33:20 +00:00
}
2019-06-09 14:20:20 +00:00
continue;
}
// Move
inputs.move_dir = if inputs.move_dir.magnitude_squared() > 1.0 {
inputs.move_dir.normalized()
} else {
inputs.move_dir
};
if character.movement == Stand && inputs.move_dir.magnitude_squared() > 0.0 {
character.movement = Run;
} else if character.movement == Run && inputs.move_dir.magnitude_squared() == 0.0 {
character.movement = Stand;
2019-06-16 15:40:47 +00:00
}
2019-08-24 19:12:54 +00:00
// Look
inputs.look_dir = inputs
2019-08-24 19:12:54 +00:00
.look_dir
2019-08-25 16:08:00 +00:00
.try_normalized()
.unwrap_or(inputs.move_dir.into());
2019-08-24 19:12:54 +00:00
2019-06-09 19:33:20 +00:00
// Glide
2019-08-25 19:14:10 +00:00
// TODO: Check for glide ability/item
if inputs.glide
&& !physics.on_ground
&& (character.action == Idle || character.action.is_wield())
&& character.movement == Jump
&& body.is_humanoid()
2019-08-04 08:21:29 +00:00
{
character.movement = Glide;
} else if !inputs.glide && character.movement == Glide {
character.movement = Jump;
2019-06-09 14:20:20 +00:00
}
// Sit
if inputs.sit
&& physics.on_ground
&& character.action == Idle
&& character.movement != Sit
&& body.is_humanoid()
{
character.movement = Sit;
} else if character.movement == Sit
&& (inputs.move_dir.magnitude_squared() > 0.0 || !physics.on_ground)
{
character.movement = Run;
}
// Wield
if inputs.primary
&& character.action == Idle
&& (character.movement == Stand || character.movement == Run)
{
character.action = Wield {
2019-08-26 18:05:30 +00:00
time_left: WIELD_DURATION,
};
}
match stats.equipment.main {
2019-09-16 15:58:40 +00:00
Some(Item::Tool {
kind: item::Tool::Bow,
power,
2019-09-16 15:58:40 +00:00
..
}) => {
if inputs.primary
2019-09-16 15:58:40 +00:00
&& (character.movement == Stand
|| character.movement == Run
|| character.movement == Jump)
{
if let Wield { time_left } = character.action {
if time_left == Duration::default() {
// Immediately end the wield
character.action = Idle;
2019-09-28 19:35:28 +00:00
server_emitter.emit(ServerEvent::Shoot {
entity,
dir: inputs.look_dir,
2019-10-11 04:30:34 +00:00
body: comp::Body::Object(comp::object::Body::Arrow),
light: None,
gravity: Some(comp::Gravity(0.3)),
2019-09-28 19:35:28 +00:00
projectile: Projectile {
owner: *uid,
2019-09-28 19:35:28 +00:00
hit_ground: vec![projectile::Effect::Stick],
2019-09-29 08:37:07 +00:00
hit_wall: vec![projectile::Effect::Stick],
2019-09-28 19:35:28 +00:00
hit_entity: vec![
projectile::Effect::Damage(HealthChange {
amount: -(power as i32),
cause: HealthSource::Attack { by: *uid },
}),
2019-09-28 19:35:28 +00:00
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(30),
},
});
}
}
}
}
Some(Item::Tool {
kind: item::Tool::Staff,
power,
..
}) => {
// Melee Attack
if inputs.primary
&& (character.movement == Stand
|| character.movement == Run
|| character.movement == Jump)
{
if let Wield { time_left } = character.action {
if time_left == Duration::default() {
character.action = Attack {
time_left: ATTACK_DURATION,
applied: false,
};
}
}
}
// Magical Bolt
if inputs.secondary
&& (
character.movement == Stand
//|| character.movement == Run
//|| character.movement == Jump
)
{
if let Wield { time_left } = character.action {
if time_left == Duration::default() {
character.action = Attack {
time_left: ATTACK_DURATION,
applied: false,
};
server_emitter.emit(ServerEvent::Shoot {
entity,
dir: inputs.look_dir,
body: comp::Body::Object(comp::object::Body::BoltFire),
gravity: Some(comp::Gravity(0.0)),
light: Some(comp::LightEmitter {
col: (0.72, 0.11, 0.11).into(),
strength: 10.0,
offset: Vec3::new(0.0, -5.0, 2.0),
}),
projectile: Projectile {
owner: *uid,
hit_ground: vec![projectile::Effect::Vanish],
hit_wall: vec![projectile::Effect::Vanish],
hit_entity: vec![
projectile::Effect::Damage(HealthChange {
amount: -(power as i32),
cause: HealthSource::Attack { by: *uid },
}),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(5),
2019-09-28 19:35:28 +00:00
},
});
2019-09-16 15:58:40 +00:00
}
}
}
}
Some(Item::Tool { .. }) => {
// Melee Attack
if inputs.primary
&& (character.movement == Stand
|| character.movement == Run
|| character.movement == Jump)
{
if let Wield { time_left } = character.action {
if time_left == Duration::default() {
character.action = Attack {
time_left: ATTACK_DURATION,
applied: false,
};
}
}
}
// Block
if inputs.secondary
&& (character.movement == Stand || character.movement == Run)
&& character.action.is_wield()
{
character.action = Block {
time_left: Duration::from_secs(5),
};
} else if !inputs.secondary && character.action.is_block() {
character.action = Wield {
time_left: Duration::default(),
};
}
}
2019-08-29 17:42:25 +00:00
Some(Item::Debug(item::Debug::Boost)) => {
if inputs.primary {
local_emitter.emit(LocalEvent::Boost {
entity,
vel: inputs.look_dir * 7.0,
2019-08-29 17:39:34 +00:00
});
}
if inputs.secondary {
2019-08-29 17:39:34 +00:00
// Go upward
local_emitter.emit(LocalEvent::Boost {
entity,
2019-08-30 22:08:44 +00:00
vel: Vec3::new(0.0, 0.0, 7.0),
});
}
}
2019-10-11 04:30:34 +00:00
Some(Item::Debug(item::Debug::Possess)) => {
if inputs.primary
2019-10-11 04:30:34 +00:00
&& (character.movement == Stand
|| character.movement == Run
|| character.movement == Jump)
{
if let Wield { time_left } = character.action {
if time_left == Duration::default() {
// Immediately end the wield
character.action = Idle;
server_emitter.emit(ServerEvent::Shoot {
entity,
gravity: Some(comp::Gravity(0.1)),
dir: inputs.look_dir,
body: comp::Body::Object(comp::object::Body::ArrowSnake),
2019-10-11 04:30:34 +00:00
light: Some(comp::LightEmitter {
col: (0.0, 1.0, 0.3).into(),
..Default::default()
}),
projectile: Projectile {
owner: *uid,
hit_ground: vec![projectile::Effect::Stick],
hit_wall: vec![projectile::Effect::Stick],
hit_entity: vec![
projectile::Effect::Stick,
projectile::Effect::Possess,
],
time_left: Duration::from_secs(10),
2019-10-11 04:30:34 +00:00
},
});
}
}
}
// Block
if inputs.secondary
&& (character.movement == Stand || character.movement == Run)
&& character.action.is_wield()
{
character.action = Block {
time_left: Duration::from_secs(5),
};
} else if !inputs.secondary && character.action.is_block() {
character.action = Wield {
time_left: Duration::default(),
};
}
2019-10-11 04:30:34 +00:00
}
2019-09-07 09:46:30 +00:00
None => {
// Attack
if inputs.primary
2019-09-07 09:46:30 +00:00
&& (character.movement == Stand
|| character.movement == Run
|| character.movement == Jump)
&& !character.action.is_attack()
{
character.action = Attack {
time_left: ATTACK_DURATION,
applied: false,
};
}
}
_ => {}
}
2019-06-11 04:08:55 +00:00
// Roll
if inputs.roll
&& (character.action == Idle || character.action.is_wield())
&& character.movement == Run
&& physics.on_ground
2019-06-29 20:40:40 +00:00
{
character.movement = Roll {
2019-08-26 18:05:30 +00:00
time_left: ROLL_DURATION,
};
2019-06-30 17:48:38 +00:00
}
2019-08-25 16:48:12 +00:00
2019-06-30 17:48:38 +00:00
// Jump
if inputs.jump && physics.on_ground && vel.0.z <= 0.0 && !character.movement.is_roll() {
local_emitter.emit(LocalEvent::Jump(entity));
2019-06-11 04:08:55 +00:00
}
// Wall leap
if inputs.wall_leap {
if let (Some(_wall_dir), Climb) = (physics.on_wall, character.movement) {
//local_emitter.emit(LocalEvent::WallLeap { entity, wall_dir });
}
}
// Process controller events
for event in std::mem::replace(&mut controller.events, Vec::new()) {
match event {
ControlEvent::Mount(mountee_uid) => {
if let Some(mountee_entity) =
uid_allocator.retrieve_entity_internal(mountee_uid.id())
{
server_emitter.emit(ServerEvent::Mount(entity, mountee_entity));
}
}
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
ControlEvent::InventoryManip(manip) => {
server_emitter.emit(ServerEvent::InventoryManip(entity, manip))
} //ControlEvent::Respawn => server_emitter.emit(ServerEvent::Unmount(entity)),
}
}
2019-06-09 14:20:20 +00:00
}
}
}