mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Primary input now activated from control actions.
Moved a lot of key_state to a HashSet so that it is handled automatically.
This commit is contained in:
parent
b0a41704da
commit
c6d8daaae3
@ -26,7 +26,7 @@ use common::{
|
||||
invite::{InviteKind, InviteResponse},
|
||||
skills::Skill,
|
||||
slot::Slot,
|
||||
ChatMode, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip,
|
||||
ChatMode, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputKind,
|
||||
InventoryAction, InventoryEvent, InventoryUpdateEvent,
|
||||
},
|
||||
event::{EventBus, LocalEvent},
|
||||
@ -60,7 +60,7 @@ use num::traits::FloatConst;
|
||||
use rayon::prelude::*;
|
||||
use specs::Component;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
collections::{BTreeSet, VecDeque},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
@ -991,6 +991,17 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(&mut self, input: InputKind, pressed: bool) {
|
||||
if pressed {
|
||||
self.control_action(ControlAction::StartInput {
|
||||
ability: input,
|
||||
target: None,
|
||||
});
|
||||
} else {
|
||||
self.control_action(ControlAction::CancelInput);
|
||||
}
|
||||
}
|
||||
|
||||
fn control_action(&mut self, control_action: ControlAction) {
|
||||
if let Some(controller) = self
|
||||
.state
|
||||
@ -1133,6 +1144,7 @@ impl Client {
|
||||
entry
|
||||
.or_insert_with(|| Controller {
|
||||
inputs: inputs.clone(),
|
||||
queued_inputs: BTreeSet::new(),
|
||||
events: Vec::new(),
|
||||
actions: Vec::new(),
|
||||
})
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::{
|
||||
combat::Attack,
|
||||
comp::{Energy, Ori, Pos, Vel},
|
||||
comp::{Energy, InputKind, Ori, Pos, Vel},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
states::{behavior::JoinData, *},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage, VecStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
|
||||
/// Data returned from character behavior fn's to Character Behavior System.
|
||||
pub struct StateUpdate {
|
||||
@ -17,6 +17,7 @@ pub struct StateUpdate {
|
||||
pub ori: Ori,
|
||||
pub energy: Energy,
|
||||
pub swap_equipped_weapons: bool,
|
||||
pub queued_inputs: BTreeSet<InputKind>,
|
||||
pub local_events: VecDeque<LocalEvent>,
|
||||
pub server_events: VecDeque<ServerEvent>,
|
||||
}
|
||||
@ -30,6 +31,7 @@ impl From<&JoinData<'_>> for StateUpdate {
|
||||
energy: *data.energy,
|
||||
swap_equipped_weapons: false,
|
||||
character: data.character.clone(),
|
||||
queued_inputs: BTreeSet::new(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::time::Duration;
|
||||
use std::{collections::BTreeSet, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
/// Default duration before an input is considered 'held'.
|
||||
@ -111,6 +111,24 @@ pub enum ControlAction {
|
||||
Sneak,
|
||||
Stand,
|
||||
Talk,
|
||||
StartInput {
|
||||
ability: InputKind,
|
||||
target: Option<Uid>,
|
||||
},
|
||||
CancelInput,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Ord, PartialOrd)]
|
||||
#[repr(u32)]
|
||||
pub enum InputKind {
|
||||
Primary = 0,
|
||||
/* Secondary = 1,
|
||||
* Ability(usize) = 2,
|
||||
* Jump = 3,
|
||||
* Roll = 4,
|
||||
* Glide = 5,
|
||||
* Fly = 6,
|
||||
* WallLeap = 7, */
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -225,7 +243,7 @@ pub enum Climb {
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ControllerInputs {
|
||||
pub primary: Input,
|
||||
//pub primary: Input,
|
||||
pub secondary: Input,
|
||||
pub ability3: Input,
|
||||
pub ability4: Input,
|
||||
@ -245,6 +263,7 @@ pub struct ControllerInputs {
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Controller {
|
||||
pub inputs: ControllerInputs,
|
||||
pub queued_inputs: BTreeSet<InputKind>,
|
||||
// TODO: consider SmallVec
|
||||
pub events: Vec<ControlEvent>,
|
||||
pub actions: Vec<ControlAction>,
|
||||
@ -253,7 +272,7 @@ pub struct Controller {
|
||||
impl ControllerInputs {
|
||||
/// Updates all inputs, accounting for delta time
|
||||
pub fn tick(&mut self, dt: Duration) {
|
||||
self.primary.tick(dt);
|
||||
//self.primary.tick(dt);
|
||||
self.secondary.tick(dt);
|
||||
self.ability3.tick(dt);
|
||||
self.ability4.tick(dt);
|
||||
@ -266,7 +285,7 @@ impl ControllerInputs {
|
||||
}
|
||||
|
||||
pub fn tick_freshness(&mut self) {
|
||||
self.primary.tick_freshness();
|
||||
//self.primary.tick_freshness();
|
||||
self.secondary.tick_freshness();
|
||||
self.ability3.tick_freshness();
|
||||
self.ability4.tick_freshness();
|
||||
@ -280,7 +299,7 @@ impl ControllerInputs {
|
||||
|
||||
/// Updates Controller inputs with new version received from the client
|
||||
pub fn update_with_new(&mut self, new: Self) {
|
||||
self.primary.update_with_new(new.primary);
|
||||
//self.primary.update_with_new(new.primary);
|
||||
self.secondary.update_with_new(new.secondary);
|
||||
self.ability3.update_with_new(new.ability3);
|
||||
self.ability4.update_with_new(new.ability4);
|
||||
@ -297,10 +316,8 @@ impl ControllerInputs {
|
||||
}
|
||||
|
||||
pub fn holding_ability_key(&self) -> bool {
|
||||
self.primary.is_pressed()
|
||||
|| self.secondary.is_pressed()
|
||||
|| self.ability3.is_pressed()
|
||||
|| self.ability4.is_pressed()
|
||||
//self.primary.is_pressed() ||
|
||||
self.secondary.is_pressed() || self.ability3.is_pressed() || self.ability4.is_pressed()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub use self::{
|
||||
combo::Combo,
|
||||
controller::{
|
||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, Input,
|
||||
InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
||||
InputKind, InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
||||
},
|
||||
energy::{Energy, EnergyChange, EnergySource},
|
||||
group::Group,
|
||||
|
@ -17,9 +17,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
handle_move(&data, &mut update, 0.4);
|
||||
|
||||
if !data.physics.on_ground
|
||||
|| !(data.inputs.secondary.is_pressed() || data.inputs.primary.is_pressed())
|
||||
{
|
||||
if !data.physics.on_ground || !data.inputs.secondary.is_pressed() {
|
||||
attempt_wield(data, &mut update);
|
||||
}
|
||||
update
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
item::MaterialStatManifest, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
||||
ControllerInputs, Energy, Health, Inventory, InventoryAction, Melee, Ori, PhysicsState,
|
||||
Pos, StateUpdate, Stats, Vel,
|
||||
ControllerInputs, Energy, Health, InputKind, Inventory, InventoryAction, Melee, Ori,
|
||||
PhysicsState, Pos, StateUpdate, Stats, Vel,
|
||||
},
|
||||
resources::DeltaTime,
|
||||
uid::Uid,
|
||||
@ -29,6 +29,12 @@ pub trait CharacterBehavior {
|
||||
fn sneak(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn stand(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn talk(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn handle_input(&self, data: &JoinData, input: InputKind, _target: Option<Uid>) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.queued_inputs.insert(input);
|
||||
update
|
||||
}
|
||||
fn cancel_input(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
|
||||
fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate {
|
||||
match event {
|
||||
ControlAction::SwapEquippedWeapons => self.swap_equipped_weapons(data),
|
||||
@ -41,6 +47,10 @@ pub trait CharacterBehavior {
|
||||
ControlAction::Sneak => self.sneak(data),
|
||||
ControlAction::Stand => self.stand(data),
|
||||
ControlAction::Talk => self.talk(data),
|
||||
ControlAction::StartInput { ability, target } => {
|
||||
self.handle_input(data, ability, target)
|
||||
},
|
||||
ControlAction::CancelInput => self.cancel_input(data),
|
||||
}
|
||||
}
|
||||
// fn init(data: &JoinData) -> CharacterState;
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
item::{Hands, ItemKind, Tool, ToolKind},
|
||||
quadruped_low, quadruped_medium, quadruped_small,
|
||||
skills::Skill,
|
||||
theropod, Body, CharacterAbility, CharacterState, InventoryAction, StateUpdate,
|
||||
theropod, Body, CharacterAbility, CharacterState, InputKind, InventoryAction, StateUpdate,
|
||||
},
|
||||
consts::{FRIC_GROUND, GRAVITY},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
@ -314,8 +314,10 @@ fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
||||
/// First checks whether `primary`, `secondary`, `ability3`, or `ability4` 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()
|
||||
if
|
||||
/*data.inputs.primary.is_pressed()
|
||||
|| */
|
||||
data.inputs.secondary.is_pressed()
|
||||
|| data.inputs.ability3.is_pressed()
|
||||
|| data.inputs.ability4.is_pressed()
|
||||
{
|
||||
@ -489,11 +491,17 @@ fn handle_ability_pressed(data: &JoinData, update: &mut StateUpdate, ability_key
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_ability1_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
match input {
|
||||
InputKind::Primary => handle_ability_pressed(data, update, AbilityKey::Mouse1),
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn handle_ability1_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.inputs.primary.is_pressed() {
|
||||
handle_ability_pressed(data, update, AbilityKey::Mouse1);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.inputs.secondary.is_pressed() {
|
||||
@ -595,7 +603,7 @@ pub fn get_crit_data(data: &JoinData, ai: AbilityInfo) -> (f32, f32) {
|
||||
|
||||
pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate, attacks_interrupt: bool) {
|
||||
if attacks_interrupt {
|
||||
handle_ability1_input(data, update);
|
||||
//handle_ability1_input(data, update);
|
||||
handle_ability2_input(data, update);
|
||||
handle_ability3_input(data, update);
|
||||
handle_ability4_input(data, update);
|
||||
@ -605,7 +613,11 @@ pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate, attacks_inter
|
||||
|
||||
pub fn ability_key_is_pressed(data: &JoinData, ability_key: AbilityKey) -> bool {
|
||||
match ability_key {
|
||||
AbilityKey::Mouse1 => data.inputs.primary.is_pressed(),
|
||||
AbilityKey::Mouse1 =>
|
||||
/* data.inputs.primary.is_pressed() */
|
||||
{
|
||||
false
|
||||
},
|
||||
AbilityKey::Mouse2 => data.inputs.secondary.is_pressed(),
|
||||
AbilityKey::Skill1 => data.inputs.ability3.is_pressed(),
|
||||
AbilityKey::Skill2 => data.inputs.ability4.is_pressed(),
|
||||
|
@ -2,9 +2,10 @@ use super::utils::*;
|
||||
use crate::{
|
||||
comp::{
|
||||
slot::{EquipSlot, Slot},
|
||||
CharacterState, InventoryAction, StateUpdate,
|
||||
CharacterState, InputKind, InventoryAction, StateUpdate,
|
||||
},
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
uid::Uid,
|
||||
};
|
||||
|
||||
pub struct Data;
|
||||
@ -16,7 +17,7 @@ impl CharacterBehavior for Data {
|
||||
handle_move(&data, &mut update, 1.0);
|
||||
handle_jump(&data, &mut update);
|
||||
handle_climb(&data, &mut update);
|
||||
handle_ability1_input(&data, &mut update);
|
||||
//handle_ability1_input(&data, &mut update);
|
||||
handle_ability2_input(&data, &mut update);
|
||||
handle_ability3_input(&data, &mut update);
|
||||
handle_ability4_input(&data, &mut update);
|
||||
@ -25,6 +26,18 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
}
|
||||
|
||||
fn handle_input(
|
||||
&self,
|
||||
data: &JoinData,
|
||||
ability: InputKind,
|
||||
_target: Option<Uid>,
|
||||
) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
handle_input(&data, &mut update, ability);
|
||||
|
||||
update
|
||||
}
|
||||
|
||||
fn sit(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_sit(data, &mut update);
|
||||
|
@ -350,6 +350,10 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
local_emitter.append(&mut state_update.local_events);
|
||||
server_emitter.append(&mut state_update.server_events);
|
||||
join_struct
|
||||
.controller
|
||||
.queued_inputs
|
||||
.append(&mut state_update.queued_inputs);
|
||||
incorporate_update(&mut join_struct, state_update);
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ use common::{
|
||||
},
|
||||
skills::{AxeSkill, BowSkill, HammerSkill, Skill, StaffSkill, SwordSkill},
|
||||
Agent, Alignment, Body, CharacterState, ControlAction, ControlEvent, Controller, Energy,
|
||||
Health, Inventory, LightEmitter, MountState, Ori, PhysicsState, Pos, Scale, Stats,
|
||||
UnresolvedChatMsg, Vel,
|
||||
Health, InputKind, Inventory, LightEmitter, MountState, Ori, PhysicsState, Pos, Scale,
|
||||
Stats, UnresolvedChatMsg, Vel,
|
||||
},
|
||||
event::{Emitter, EventBus, ServerEvent},
|
||||
path::TraversalConfig,
|
||||
@ -1081,7 +1081,11 @@ impl<'a> AgentData<'a> {
|
||||
match tactic {
|
||||
Tactic::Melee => {
|
||||
if dist_sqrd < (min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1129,7 +1133,11 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.ability3.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1177,7 +1185,11 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.ability3.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1237,7 +1249,11 @@ impl<'a> AgentData<'a> {
|
||||
} else if agent.action_timer > 2.0 {
|
||||
agent.action_timer = 0.0;
|
||||
} else {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1318,7 +1334,11 @@ impl<'a> AgentData<'a> {
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.inputs.secondary.set_state(false);
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else {
|
||||
@ -1388,7 +1408,11 @@ impl<'a> AgentData<'a> {
|
||||
} else if self.energy.current() > 10 {
|
||||
controller.inputs.secondary.set_state(true);
|
||||
} else {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1408,7 +1432,11 @@ impl<'a> AgentData<'a> {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* speed;
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
@ -1447,7 +1475,11 @@ impl<'a> AgentData<'a> {
|
||||
// 2.0 is temporary correction factor to allow them to melee with their
|
||||
// large hitbox
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if self.vel.0.is_approx_zero() {
|
||||
controller.inputs.ability3.set_state(true);
|
||||
@ -1489,7 +1521,11 @@ impl<'a> AgentData<'a> {
|
||||
if dist_sqrd < (min_attack_dist * self.scale).powi(2) && thread_rng().gen_bool(0.5)
|
||||
{
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < (radius as f32 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = (self.pos.0 - tgt_pos.0)
|
||||
.xy()
|
||||
@ -1547,7 +1583,11 @@ impl<'a> AgentData<'a> {
|
||||
.xy()
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -1598,10 +1638,15 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::TailSlap => {
|
||||
if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) {
|
||||
if agent.action_timer > 4.0 {
|
||||
controller.inputs.primary.set_state(false);
|
||||
controller.actions.push(ControlAction::CancelInput);
|
||||
//controller.inputs.primary.set_state(false);
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 1.0 {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.inputs.secondary.set_state(true);
|
||||
@ -1639,7 +1684,11 @@ impl<'a> AgentData<'a> {
|
||||
} else if dist_sqrd < (3.0 * min_attack_dist * self.scale).powi(2)
|
||||
&& dist_sqrd > (2.0 * min_attack_dist * self.scale).powi(2)
|
||||
{
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
.xy()
|
||||
.rotated_z(-0.47 * PI)
|
||||
@ -1674,7 +1723,11 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.secondary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1715,7 +1768,11 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
) {
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
} else {
|
||||
@ -1736,7 +1793,11 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.secondary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 3.0 {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
@ -1772,7 +1833,11 @@ impl<'a> AgentData<'a> {
|
||||
.rotated_z(0.47 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 4.0 {
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -1780,7 +1845,11 @@ impl<'a> AgentData<'a> {
|
||||
.rotated_z(-0.47 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 6.0 {
|
||||
controller.inputs.ability3.set_state(true);
|
||||
@ -1811,7 +1880,11 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::Theropod => {
|
||||
if dist_sqrd < (2.0 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -1834,7 +1907,11 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
Tactic::Turret => {
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
@ -1842,7 +1919,11 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::FixedTurret => {
|
||||
controller.inputs.look_dir = self.ori.look_dir();
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
@ -1856,7 +1937,11 @@ impl<'a> AgentData<'a> {
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
ability: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
|
@ -10,16 +10,7 @@ pub struct KeyState {
|
||||
pub swim_up: bool,
|
||||
pub swim_down: bool,
|
||||
pub fly: bool,
|
||||
pub toggle_wield: bool,
|
||||
pub toggle_glide: bool,
|
||||
pub toggle_lantern: bool,
|
||||
pub toggle_sit: bool,
|
||||
pub toggle_sneak: bool,
|
||||
pub toggle_dance: bool,
|
||||
pub auto_walk: bool,
|
||||
pub swap_loadout: bool,
|
||||
pub respawn: bool,
|
||||
pub interact: bool,
|
||||
pub trade: bool,
|
||||
pub analog_matrix: Vec2<f32>,
|
||||
}
|
||||
@ -36,16 +27,7 @@ impl Default for KeyState {
|
||||
swim_up: false,
|
||||
swim_down: false,
|
||||
fly: false,
|
||||
toggle_wield: false,
|
||||
toggle_glide: false,
|
||||
toggle_lantern: false,
|
||||
toggle_sit: false,
|
||||
toggle_sneak: false,
|
||||
toggle_dance: false,
|
||||
auto_walk: false,
|
||||
swap_loadout: false,
|
||||
respawn: false,
|
||||
interact: false,
|
||||
trade: false,
|
||||
analog_matrix: Vec2::zero(),
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use std::{cell::RefCell, collections::HashSet, rc::Rc, time::Duration};
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
use specs::{Join, WorldExt};
|
||||
@ -10,8 +10,8 @@ use common::{
|
||||
assets::AssetExt,
|
||||
comp,
|
||||
comp::{
|
||||
inventory::slot::Slot, invite::InviteKind, ChatMsg, ChatType, InventoryUpdateEvent, Pos,
|
||||
Vel,
|
||||
inventory::slot::Slot, invite::InviteKind, ChatMsg, ChatType, InputKind,
|
||||
InventoryUpdateEvent, Pos, Vel,
|
||||
},
|
||||
consts::{MAX_MOUNT_RANGE, MAX_PICKUP_RANGE},
|
||||
outcome::Outcome,
|
||||
@ -61,6 +61,7 @@ pub struct SessionState {
|
||||
hud: Hud,
|
||||
key_state: KeyState,
|
||||
inputs: comp::ControllerInputs,
|
||||
inputs_state: HashSet<GameInput>,
|
||||
selected_block: Block,
|
||||
walk_forward_dir: Vec2<f32>,
|
||||
walk_right_dir: Vec2<f32>,
|
||||
@ -96,6 +97,7 @@ impl SessionState {
|
||||
client,
|
||||
key_state: KeyState::default(),
|
||||
inputs: comp::ControllerInputs::default(),
|
||||
inputs_state: HashSet::new(),
|
||||
hud,
|
||||
selected_block: Block::new(BlockKind::Misc, Rgb::broadcast(255)),
|
||||
walk_forward_dir,
|
||||
@ -349,313 +351,297 @@ impl PlayState for SessionState {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
Event::InputUpdate(GameInput::Primary, state) => {
|
||||
// If we can build, use LMB to break blocks, if not, use it to attack
|
||||
let mut client = self.client.borrow_mut();
|
||||
if state && can_build {
|
||||
if let Some(select_pos) = select_pos {
|
||||
client.remove_block(select_pos);
|
||||
}
|
||||
} else {
|
||||
self.inputs.primary.set_state(state);
|
||||
}
|
||||
},
|
||||
|
||||
Event::InputUpdate(GameInput::Secondary, state) => {
|
||||
self.inputs.secondary.set_state(false); // To be changed later on
|
||||
|
||||
let mut client = self.client.borrow_mut();
|
||||
|
||||
if state && can_build {
|
||||
if let Some(build_pos) = build_pos {
|
||||
client.place_block(build_pos, self.selected_block);
|
||||
}
|
||||
} else {
|
||||
self.inputs.secondary.set_state(state);
|
||||
}
|
||||
},
|
||||
|
||||
Event::InputUpdate(GameInput::Roll, state) => {
|
||||
let client = self.client.borrow();
|
||||
if can_build {
|
||||
if state {
|
||||
if let Some(block) = select_pos
|
||||
.and_then(|sp| client.state().terrain().get(sp).ok().copied())
|
||||
{
|
||||
self.selected_block = block;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.inputs.roll.set_state(state);
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::Respawn, state)
|
||||
if state != self.key_state.respawn =>
|
||||
Event::InputUpdate(input, state)
|
||||
if state != self.inputs_state.contains(&input) =>
|
||||
{
|
||||
self.stop_auto_walk();
|
||||
self.key_state.respawn = state;
|
||||
if state {
|
||||
self.client.borrow_mut().respawn();
|
||||
if !self.inputs_state.insert(input) {
|
||||
self.inputs_state.remove(&input);
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Jump, state) => {
|
||||
self.inputs.jump.set_state(state);
|
||||
},
|
||||
Event::InputUpdate(GameInput::SwimUp, state) => {
|
||||
self.key_state.swim_up = state;
|
||||
},
|
||||
Event::InputUpdate(GameInput::SwimDown, state) => {
|
||||
self.key_state.swim_down = state;
|
||||
},
|
||||
Event::InputUpdate(GameInput::Sit, state)
|
||||
if state != self.key_state.toggle_sit =>
|
||||
{
|
||||
self.key_state.toggle_sit = state;
|
||||
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_sit();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Dance, state)
|
||||
if state != self.key_state.toggle_dance =>
|
||||
{
|
||||
self.key_state.toggle_dance = state;
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_dance();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Sneak, state)
|
||||
if state != self.key_state.toggle_sneak =>
|
||||
{
|
||||
self.key_state.toggle_sneak = state;
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_sneak();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::MoveForward, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.up = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveBack, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.down = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveLeft, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.left = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveRight, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.right = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::Glide, state)
|
||||
if state != self.key_state.toggle_glide =>
|
||||
{
|
||||
self.key_state.toggle_glide = state;
|
||||
if state {
|
||||
self.client.borrow_mut().toggle_glide();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Fly, state) => {
|
||||
self.key_state.fly ^= state;
|
||||
},
|
||||
Event::InputUpdate(GameInput::Climb, state) => {
|
||||
self.key_state.climb_up = state;
|
||||
},
|
||||
Event::InputUpdate(GameInput::ClimbDown, state) => {
|
||||
self.key_state.climb_down = state;
|
||||
},
|
||||
/*Event::InputUpdate(GameInput::WallLeap, state) => {
|
||||
self.inputs.wall_leap.set_state(state)
|
||||
},*/
|
||||
Event::InputUpdate(GameInput::ToggleWield, state)
|
||||
if state != self.key_state.toggle_wield =>
|
||||
{
|
||||
self.key_state.toggle_wield = state;
|
||||
if state {
|
||||
self.client.borrow_mut().toggle_wield();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::SwapLoadout, state)
|
||||
if state != self.key_state.swap_loadout =>
|
||||
{
|
||||
self.key_state.swap_loadout = state;
|
||||
if state {
|
||||
self.client.borrow_mut().swap_loadout();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::ToggleLantern, true) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.is_lantern_enabled() {
|
||||
client.disable_lantern();
|
||||
} else {
|
||||
client.enable_lantern();
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::Mount, true) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.is_mounted() {
|
||||
client.unmount();
|
||||
} else {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.copied();
|
||||
if let Some(player_pos) = player_pos {
|
||||
// Find closest mountable entity
|
||||
let closest_mountable_entity = (
|
||||
&client.state().ecs().entities(),
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
&client.state().ecs().read_storage::<comp::MountState>(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(entity, _, mount_state)| {
|
||||
*entity != client.entity()
|
||||
&& **mount_state == comp::MountState::Unmounted
|
||||
})
|
||||
.map(|(entity, pos, _)| {
|
||||
(entity, player_pos.0.distance_squared(pos.0))
|
||||
})
|
||||
.filter(|(_, dist_sqr)| *dist_sqr < MAX_MOUNT_RANGE.powi(2))
|
||||
.min_by_key(|(_, dist_sqr)| OrderedFloat(*dist_sqr));
|
||||
if let Some((mountee_entity, _)) = closest_mountable_entity {
|
||||
client.mount(mountee_entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::Interact, state)
|
||||
if state != self.key_state.interact =>
|
||||
{
|
||||
self.key_state.interact = state;
|
||||
|
||||
if state {
|
||||
if let Some(interactable) = self.interactable {
|
||||
match input {
|
||||
GameInput::Primary => {
|
||||
// If we can build, use LMB to break blocks, if not, use it to
|
||||
// attack
|
||||
let mut client = self.client.borrow_mut();
|
||||
match interactable {
|
||||
Interactable::Block(block, pos) => {
|
||||
if block.is_collectible() {
|
||||
client.collect_block(pos);
|
||||
}
|
||||
},
|
||||
Interactable::Entity(entity) => {
|
||||
if client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::Item>()
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
client.pick_up(entity);
|
||||
} else {
|
||||
client.npc_interact(entity);
|
||||
}
|
||||
},
|
||||
if state && can_build {
|
||||
if let Some(select_pos) = select_pos {
|
||||
client.remove_block(select_pos);
|
||||
}
|
||||
} else {
|
||||
client.handle_input(InputKind::Primary, state);
|
||||
//self.inputs.primary.set_state(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Trade, state)
|
||||
if state != self.key_state.trade =>
|
||||
{
|
||||
self.key_state.trade = state;
|
||||
},
|
||||
GameInput::Secondary => {
|
||||
self.inputs.secondary.set_state(false); // To be changed later on
|
||||
|
||||
if state {
|
||||
if let Some(interactable) = self.interactable {
|
||||
let mut client = self.client.borrow_mut();
|
||||
match interactable {
|
||||
Interactable::Block(_, _) => {},
|
||||
Interactable::Entity(entity) => {
|
||||
if let Some(uid) =
|
||||
client.state().ecs().uid_from_entity(entity)
|
||||
{
|
||||
let name = client
|
||||
.player_list()
|
||||
.get(&uid)
|
||||
.map(|info| info.player_alias.clone())
|
||||
.unwrap_or_else(|| format!("<entity {:?}>", uid));
|
||||
let msg = global_state
|
||||
.i18n
|
||||
.read()
|
||||
.get("hud.trade.invite_sent")
|
||||
.replace("{playername}", &name);
|
||||
self.hud.new_message(ChatType::Meta.chat_msg(msg));
|
||||
client.send_invite(uid, InviteKind::Trade)
|
||||
};
|
||||
},
|
||||
|
||||
if state && can_build {
|
||||
if let Some(build_pos) = build_pos {
|
||||
client.place_block(build_pos, self.selected_block);
|
||||
}
|
||||
} else {
|
||||
self.inputs.secondary.set_state(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Event::InputUpdate(GameInput::Charge, state) => {
|
||||
self.inputs.charge.set_state(state);
|
||||
},*/
|
||||
Event::InputUpdate(GameInput::FreeLook, state) => {
|
||||
match (global_state.settings.gameplay.free_look_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
self.free_look = !self.free_look;
|
||||
self.hud.free_look(self.free_look);
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
self.free_look = state;
|
||||
self.hud.free_look(self.free_look);
|
||||
GameInput::Roll => {
|
||||
let client = self.client.borrow();
|
||||
if can_build {
|
||||
if state {
|
||||
if let Some(block) = select_pos.and_then(|sp| {
|
||||
client.state().terrain().get(sp).ok().copied()
|
||||
}) {
|
||||
self.selected_block = block;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.inputs.roll.set_state(state);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
Event::InputUpdate(GameInput::AutoWalk, state) => {
|
||||
match (global_state.settings.gameplay.auto_walk_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
self.auto_walk = !self.auto_walk;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
GameInput::Respawn => {
|
||||
self.stop_auto_walk();
|
||||
if state {
|
||||
self.client.borrow_mut().respawn();
|
||||
}
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
self.auto_walk = state;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
GameInput::Jump => {
|
||||
self.inputs.jump.set_state(state);
|
||||
},
|
||||
GameInput::SwimUp => {
|
||||
self.key_state.swim_up = state;
|
||||
},
|
||||
GameInput::SwimDown => {
|
||||
self.key_state.swim_down = state;
|
||||
},
|
||||
GameInput::Sit => {
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_sit();
|
||||
}
|
||||
},
|
||||
GameInput::Dance => {
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_dance();
|
||||
}
|
||||
},
|
||||
GameInput::Sneak => {
|
||||
if state {
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_sneak();
|
||||
}
|
||||
},
|
||||
GameInput::MoveForward => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.up = state
|
||||
},
|
||||
GameInput::MoveBack => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.down = state
|
||||
},
|
||||
GameInput::MoveLeft => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.left = state
|
||||
},
|
||||
GameInput::MoveRight => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.right = state
|
||||
},
|
||||
GameInput::Glide => {
|
||||
if state {
|
||||
self.client.borrow_mut().toggle_glide();
|
||||
}
|
||||
},
|
||||
GameInput::Fly => {
|
||||
self.key_state.fly ^= state;
|
||||
},
|
||||
GameInput::Climb => {
|
||||
self.key_state.climb_up = state;
|
||||
},
|
||||
GameInput::ClimbDown => {
|
||||
self.key_state.climb_down = state;
|
||||
},
|
||||
GameInput::ToggleWield => {
|
||||
if state {
|
||||
self.client.borrow_mut().toggle_wield();
|
||||
}
|
||||
},
|
||||
GameInput::SwapLoadout => {
|
||||
if state {
|
||||
self.client.borrow_mut().swap_loadout();
|
||||
}
|
||||
},
|
||||
GameInput::ToggleLantern if state => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.is_lantern_enabled() {
|
||||
client.disable_lantern();
|
||||
} else {
|
||||
client.enable_lantern();
|
||||
}
|
||||
},
|
||||
GameInput::Mount if state => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.is_mounted() {
|
||||
client.unmount();
|
||||
} else {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.copied();
|
||||
if let Some(player_pos) = player_pos {
|
||||
// Find closest mountable entity
|
||||
let closest_mountable_entity = (
|
||||
&client.state().ecs().entities(),
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
&client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::MountState>(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(entity, _, mount_state)| {
|
||||
*entity != client.entity()
|
||||
&& **mount_state == comp::MountState::Unmounted
|
||||
})
|
||||
.map(|(entity, pos, _)| {
|
||||
(entity, player_pos.0.distance_squared(pos.0))
|
||||
})
|
||||
.filter(|(_, dist_sqr)| {
|
||||
*dist_sqr < MAX_MOUNT_RANGE.powi(2)
|
||||
})
|
||||
.min_by_key(|(_, dist_sqr)| OrderedFloat(*dist_sqr));
|
||||
if let Some((mountee_entity, _)) = closest_mountable_entity
|
||||
{
|
||||
client.mount(mountee_entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
GameInput::Interact => {
|
||||
if state {
|
||||
if let Some(interactable) = self.interactable {
|
||||
let mut client = self.client.borrow_mut();
|
||||
match interactable {
|
||||
Interactable::Block(block, pos) => {
|
||||
if block.is_collectible() {
|
||||
client.collect_block(pos);
|
||||
}
|
||||
},
|
||||
Interactable::Entity(entity) => {
|
||||
if client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::Item>()
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
client.pick_up(entity);
|
||||
} else {
|
||||
client.npc_interact(entity);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
GameInput::Trade => {
|
||||
if state {
|
||||
if let Some(interactable) = self.interactable {
|
||||
let mut client = self.client.borrow_mut();
|
||||
match interactable {
|
||||
Interactable::Block(_, _) => {},
|
||||
Interactable::Entity(entity) => {
|
||||
if let Some(uid) =
|
||||
client.state().ecs().uid_from_entity(entity)
|
||||
{
|
||||
let name = client
|
||||
.player_list()
|
||||
.get(&uid)
|
||||
.map(|info| info.player_alias.clone())
|
||||
.unwrap_or_else(|| {
|
||||
format!("<entity {:?}>", uid)
|
||||
});
|
||||
let msg = global_state
|
||||
.i18n
|
||||
.read()
|
||||
.get("hud.trade.invite_sent")
|
||||
.replace("{playername}", &name);
|
||||
self.hud
|
||||
.new_message(ChatType::Meta.chat_msg(msg));
|
||||
client.send_invite(uid, InviteKind::Trade)
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
GameInput::FreeLook => {
|
||||
match (global_state.settings.gameplay.free_look_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
self.free_look = !self.free_look;
|
||||
self.hud.free_look(self.free_look);
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
self.free_look = state;
|
||||
self.hud.free_look(self.free_look);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
GameInput::AutoWalk => {
|
||||
match (global_state.settings.gameplay.auto_walk_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
self.auto_walk = !self.auto_walk;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
self.auto_walk = state;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
GameInput::CycleCamera if state => {
|
||||
// Prevent accessing camera modes which aren't available in
|
||||
// multiplayer unless you are an
|
||||
// admin. This is an easily bypassed clientside check.
|
||||
// The server should do its own filtering of which entities are sent
|
||||
// to clients to prevent abuse.
|
||||
let camera = self.scene.camera_mut();
|
||||
camera.next_mode(self.client.borrow().is_admin());
|
||||
},
|
||||
GameInput::Select => {
|
||||
if !state {
|
||||
self.selected_entity =
|
||||
self.target_entity.map(|e| (e, std::time::Instant::now()));
|
||||
}
|
||||
},
|
||||
GameInput::AcceptGroupInvite if state => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.invite().is_some() {
|
||||
client.accept_invite();
|
||||
}
|
||||
},
|
||||
GameInput::DeclineGroupInvite if state => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.invite().is_some() {
|
||||
client.decline_invite();
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::CycleCamera, true) => {
|
||||
// Prevent accessing camera modes which aren't available in multiplayer
|
||||
// unless you are an admin. This is an easily bypassed clientside check.
|
||||
// The server should do its own filtering of which entities are sent to
|
||||
// clients to prevent abuse.
|
||||
let camera = self.scene.camera_mut();
|
||||
camera.next_mode(self.client.borrow().is_admin());
|
||||
},
|
||||
Event::InputUpdate(GameInput::Select, state) => {
|
||||
if !state {
|
||||
self.selected_entity =
|
||||
self.target_entity.map(|e| (e, std::time::Instant::now()));
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::AcceptGroupInvite, true) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.invite().is_some() {
|
||||
client.accept_invite();
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::DeclineGroupInvite, true) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.invite().is_some() {
|
||||
client.decline_invite();
|
||||
}
|
||||
},
|
||||
}
|
||||
Event::AnalogGameInput(input) => match input {
|
||||
AnalogGameInput::MovementX(v) => {
|
||||
self.key_state.analog_matrix.x = v;
|
||||
|
Loading…
Reference in New Issue
Block a user