mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial implementation of pickaxe
This commit is contained in:
parent
1afe3b7de5
commit
347e1022a0
23
assets/common/abilities/pick/swing.ron
Normal file
23
assets/common/abilities/pick/swing.ron
Normal file
@ -0,0 +1,23 @@
|
||||
ComboMelee(
|
||||
stage_data: [(
|
||||
stage: 1,
|
||||
base_damage: 150,
|
||||
damage_increase: 10,
|
||||
base_poise_damage: 40,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 10.0,
|
||||
range: 4.5,
|
||||
angle: 50.0,
|
||||
base_buildup_duration: 0.4,
|
||||
base_swing_duration: 0.1,
|
||||
base_recover_duration: 0.25,
|
||||
forward_movement: 0.0,
|
||||
)],
|
||||
initial_energy_gain: 50,
|
||||
max_energy_gain: 150,
|
||||
energy_increase: 50,
|
||||
speed_increase: 0.1,
|
||||
max_speed_increase: 0.4,
|
||||
scales_from_combo: 2,
|
||||
is_interruptible: false,
|
||||
)
|
@ -206,6 +206,11 @@
|
||||
secondary: "common.abilities.farming.basic",
|
||||
abilities: [],
|
||||
),
|
||||
Pick: (
|
||||
primary: "common.abilities.pick.swing",
|
||||
secondary: "common.abilities.pick.swing",
|
||||
abilities: [],
|
||||
),
|
||||
Empty: (
|
||||
primary: "common.abilities.empty.basic",
|
||||
secondary: "common.abilities.empty.basic",
|
||||
|
18
assets/common/items/tool/pick.ron
Normal file
18
assets/common/items/tool/pick.ron
Normal file
@ -0,0 +1,18 @@
|
||||
ItemDef(
|
||||
name: "Stone Pickaxe",
|
||||
description: "Strike the earth!",
|
||||
kind: Tool((
|
||||
kind: Pick,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.25,
|
||||
power: 0.25,
|
||||
poise_strength: 0.25,
|
||||
speed: 0.5,
|
||||
crit_chance: 0.09375,
|
||||
crit_mult: 2.2190475,
|
||||
)),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
)
|
@ -1013,7 +1013,11 @@
|
||||
"voxel.weapon.tool.shovel_gold",
|
||||
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.2,
|
||||
),
|
||||
|
||||
// Picks
|
||||
Tool("common.items.tool.pick"): VoxTrans(
|
||||
"voxel.weapon.tool.pickaxe_green-0",
|
||||
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.0,
|
||||
),
|
||||
// Other
|
||||
Utility(Coins): VoxTrans(
|
||||
"voxel.object.coins",
|
||||
@ -1709,7 +1713,7 @@
|
||||
"voxel.armor.misc.head.assa_mask-0",
|
||||
(0.0, 0.0, 0.0), (-90.0, 180.0, 0.0), 1.0,
|
||||
),
|
||||
// Bags
|
||||
// Bags
|
||||
Armor(Bag("RedFace")): Png (
|
||||
"element.icons.item_bag_red_face",
|
||||
),
|
||||
|
@ -168,7 +168,7 @@ void main() {
|
||||
// reflectivity that accounts for physical surroundings like the ground
|
||||
if ((material & (1u << 1u)) > 0u) {
|
||||
vec3 reflect_ray_dir = reflect(cam_to_frag, f_norm);
|
||||
surf_color *= dot(vec3(1.0) - abs(fract(reflect_ray_dir * 3.5) * 2.0 - 1.0) * 0.85, vec3(1));
|
||||
surf_color *= dot(vec3(1.0) - abs(fract(reflect_ray_dir * 1.5) * 2.0 - 1.0) * 0.85, vec3(1));
|
||||
}
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
@ -228,7 +228,7 @@ void main() {
|
||||
// f_light = 1.0;
|
||||
// if (select_pos.w > 0) */{
|
||||
vec3 sprite_pos = /*round*/floor(((inst_mat * vec4(-offs.xyz, 1)).xyz) * SCALE/* - vec3(0.5, 0.5, 0.0)*/) + inst_offs;
|
||||
f_light = (select_pos.w > 0 && select_pos.xyz == sprite_pos/* - vec3(0.5, 0.5, 0.0) * SCALE*/) ? 5.0 : 1.0;
|
||||
f_light = (select_pos.w > 0 && select_pos.xyz == sprite_pos/* - vec3(0.5, 0.5, 0.0) * SCALE*/) ? 10.0 : 1.0;
|
||||
// }
|
||||
|
||||
gl_Position =
|
||||
|
@ -255,8 +255,7 @@ void main() {
|
||||
|
||||
emitted_light = vec3(1.0);
|
||||
reflected_light = vec3(1.0);
|
||||
float f_select = (select_pos.w > 0 && select_pos.xyz == floor(f_pos - f_norm * 0.5)) ? 1.0 / PERSISTENT_AMBIANCE : 1.0;
|
||||
max_light += get_sun_diffuse2(/*time_of_day.x, */sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a * f_select/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
max_light += get_sun_diffuse2(/*time_of_day.x, */sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
|
||||
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// reflected_light *= f_light * point_shadow * shade_frac;
|
||||
@ -269,6 +268,9 @@ void main() {
|
||||
vec3 glow = glow_light(f_pos) * (pow(f_glow, 6) * 5 + pow(f_glow, 1.5) * 2);
|
||||
reflected_light += glow;
|
||||
|
||||
float f_select = (select_pos.w > 0 && select_pos.xyz == floor(f_pos - f_norm * 0.5)) ? 0.5 / PERSISTENT_AMBIANCE : 0.0;
|
||||
reflected_light += f_select;
|
||||
|
||||
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
|
||||
// float f_ao = 1.0;
|
||||
|
@ -600,7 +600,7 @@
|
||||
color: None
|
||||
),
|
||||
"common.items.weapons.hammer.cultist_purp_2h-0": (
|
||||
vox_spec: ("weapon.hammer.cult_purp-0", (-3.5, -4.5, -5.0)),
|
||||
vox_spec: ("weapon.hammer.cult_purp-0", (-3.5, -4.5, -5.0)),
|
||||
color: None
|
||||
),
|
||||
/*"Craftsman": ( //TODO This should be a 1h hammer!
|
||||
@ -839,7 +839,7 @@
|
||||
"common.items.weapons.tool.rake": (
|
||||
vox_spec: ("weapon.tool.rake-0", (-1.0, -5.5, -4.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.tool.pickaxe": (
|
||||
vox_spec: ("weapon.tool.pickaxe_green-0", (-1.5, -7.5, -4.0)),
|
||||
color: None
|
||||
@ -876,43 +876,43 @@
|
||||
"common.items.weapons.staff.phoenix": (
|
||||
vox_spec: ("weapon.staff.phoenix", (-2.5, -3.5, -5.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.heated_arm": (
|
||||
vox_spec: ("weapon.staff.heated_arm", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.aurora": (
|
||||
vox_spec: ("weapon.staff.aurora", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.infused_tower": (
|
||||
vox_spec: ("weapon.staff.infused_tower", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.flamethrower_0": (
|
||||
vox_spec: ("weapon.staff.unstable_thrower", (-1.5, -2.5, -5.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.ley_seeker": (
|
||||
vox_spec: ("weapon.staff.ley_seeker", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.lava_rod": (
|
||||
vox_spec: ("weapon.staff.lava_rod", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.fiery_wishing_rod": (
|
||||
vox_spec: ("weapon.staff.fiery_wishing_rod", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.orc_iron": (
|
||||
vox_spec: ("weapon.staff.orcish_branding_iron", (-2.5, -2.5, -3.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.staff.bent_fuse": (
|
||||
vox_spec: ("weapon.staff.bent_fuse", (-2.0, -2.5, -5.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
// Healing sceptre
|
||||
"common.items.weapons.sceptre.starter_sceptre": (
|
||||
vox_spec: ("weapon.sceptre.wood-simple", (-1.5, -2.5, -6.0)),
|
||||
@ -945,10 +945,15 @@
|
||||
"common.items.weapons.sceptre.root_evil": (
|
||||
vox_spec: ("weapon.sceptre.root_evil", (-1.5, -2.5, -6.0)),
|
||||
color: None
|
||||
),
|
||||
),
|
||||
"common.items.weapons.sceptre.sceptre_velorite_0": (
|
||||
vox_spec: ("weapon.sceptre.ore-nature", (-2.0, -6.0, -5.0)),
|
||||
color: None
|
||||
),
|
||||
// Picks
|
||||
"common.items.tool.pick": (
|
||||
vox_spec: ("weapon.tool.pickaxe_green-0", (-1.5, -7.5, -4.0)),
|
||||
color: None
|
||||
),
|
||||
// Misc
|
||||
"common.items.debug.admin_stick": (
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -61,7 +61,7 @@ use num::traits::FloatConst;
|
||||
use rayon::prelude::*;
|
||||
use specs::Component;
|
||||
use std::{
|
||||
collections::{BTreeSet, VecDeque},
|
||||
collections::{BTreeMap, VecDeque},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
@ -915,15 +915,18 @@ impl Client {
|
||||
/// and sends the `ControlAction` event that signals to do the swap.
|
||||
pub fn swap_loadout(&mut self) { self.control_action(ControlAction::SwapEquippedWeapons) }
|
||||
|
||||
pub fn toggle_wield(&mut self) {
|
||||
let is_wielding = self
|
||||
.state
|
||||
/// Determine whether the player is wielding, if they're even capable of
|
||||
/// being in a wield state.
|
||||
pub fn is_wielding(&self) -> Option<bool> {
|
||||
self.state
|
||||
.ecs()
|
||||
.read_storage::<comp::CharacterState>()
|
||||
.get(self.entity())
|
||||
.map(|cs| cs.is_wield());
|
||||
.map(|cs| cs.is_wield())
|
||||
}
|
||||
|
||||
match is_wielding {
|
||||
pub fn toggle_wield(&mut self) {
|
||||
match self.is_wielding() {
|
||||
Some(true) => self.control_action(ControlAction::Unwield),
|
||||
Some(false) => self.control_action(ControlAction::Wield),
|
||||
None => warn!("Can't toggle wield, client entity doesn't have a `CharacterState`"),
|
||||
@ -995,11 +998,12 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(&mut self, input: InputKind, pressed: bool) {
|
||||
pub fn handle_input(&mut self, input: InputKind, pressed: bool, select_pos: Option<Vec3<f32>>) {
|
||||
if pressed {
|
||||
self.control_action(ControlAction::StartInput {
|
||||
input,
|
||||
target: None,
|
||||
select_pos,
|
||||
});
|
||||
} else {
|
||||
self.control_action(ControlAction::CancelInput(input));
|
||||
@ -1148,7 +1152,7 @@ impl Client {
|
||||
entry
|
||||
.or_insert_with(|| Controller {
|
||||
inputs: inputs.clone(),
|
||||
queued_inputs: BTreeSet::new(),
|
||||
queued_inputs: BTreeMap::new(),
|
||||
events: Vec::new(),
|
||||
actions: Vec::new(),
|
||||
})
|
||||
|
@ -7,7 +7,13 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage, VecStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct InputAttr {
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
/// Data returned from character behavior fn's to Character Behavior System.
|
||||
pub struct StateUpdate {
|
||||
@ -17,10 +23,11 @@ pub struct StateUpdate {
|
||||
pub ori: Ori,
|
||||
pub energy: Energy,
|
||||
pub swap_equipped_weapons: bool,
|
||||
pub queued_inputs: BTreeSet<InputKind>,
|
||||
pub queued_inputs: BTreeMap<InputKind, InputAttr>,
|
||||
pub removed_inputs: Vec<InputKind>,
|
||||
pub local_events: VecDeque<LocalEvent>,
|
||||
pub server_events: VecDeque<ServerEvent>,
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
impl From<&JoinData<'_>> for StateUpdate {
|
||||
@ -32,10 +39,11 @@ impl From<&JoinData<'_>> for StateUpdate {
|
||||
energy: *data.energy,
|
||||
swap_equipped_weapons: false,
|
||||
character: data.character.clone(),
|
||||
queued_inputs: BTreeSet::new(),
|
||||
queued_inputs: BTreeMap::new(),
|
||||
removed_inputs: Vec::new(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
select_pos: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,6 +200,7 @@ pub struct Melee {
|
||||
pub max_angle: f32,
|
||||
pub applied: bool,
|
||||
pub hit_count: u32,
|
||||
pub break_block: Option<Vec3<i32>>,
|
||||
}
|
||||
|
||||
impl Component for Melee {
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{
|
||||
inventory::slot::{EquipSlot, InvSlotId, Slot},
|
||||
invite::{InviteKind, InviteResponse},
|
||||
BuffKind,
|
||||
BuffKind, InputAttr,
|
||||
},
|
||||
trade::{TradeAction, TradeId},
|
||||
uid::Uid,
|
||||
@ -11,7 +11,7 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::BTreeMap;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -111,10 +111,22 @@ pub enum ControlAction {
|
||||
StartInput {
|
||||
input: InputKind,
|
||||
target: Option<Uid>,
|
||||
// Some inputs need a selected position, such as mining
|
||||
select_pos: Option<Vec3<f32>>,
|
||||
},
|
||||
CancelInput(InputKind),
|
||||
}
|
||||
|
||||
impl ControlAction {
|
||||
pub fn basic_start(input: InputKind) -> Self {
|
||||
ControlAction::StartInput {
|
||||
input,
|
||||
target: None,
|
||||
select_pos: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Ord, PartialOrd)]
|
||||
#[repr(u32)]
|
||||
pub enum InputKind {
|
||||
@ -151,7 +163,7 @@ pub struct ControllerInputs {
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Controller {
|
||||
pub inputs: ControllerInputs,
|
||||
pub queued_inputs: BTreeSet<InputKind>,
|
||||
pub queued_inputs: BTreeMap<InputKind, InputAttr>,
|
||||
// TODO: consider SmallVec
|
||||
pub events: Vec<ControlEvent>,
|
||||
pub actions: Vec<ControlAction>,
|
||||
|
@ -25,6 +25,7 @@ use specs::{Component, DerefFlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::{
|
||||
num::{NonZeroU32, NonZeroU64},
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
};
|
||||
use vek::Rgb;
|
||||
@ -298,6 +299,12 @@ impl PartialEq for Item {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Item {
|
||||
type Target = ItemDef;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.item_def }
|
||||
}
|
||||
|
||||
impl assets::Compound for ItemDef {
|
||||
fn load<S: assets_manager::source::Source>(
|
||||
cache: &assets_manager::AssetCache<S>,
|
||||
@ -536,10 +543,6 @@ impl Item {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_stackable(&self) -> bool { self.item_def.is_stackable() }
|
||||
|
||||
pub fn is_modular(&self) -> bool { self.item_def.is_modular() }
|
||||
|
||||
pub fn name(&self) -> &str { &self.item_def.name }
|
||||
|
||||
pub fn description(&self) -> &str { &self.item_def.description }
|
||||
@ -666,6 +669,14 @@ pub trait ItemDesc {
|
||||
fn item_definition_id(&self) -> &str;
|
||||
fn components(&self) -> &[Item];
|
||||
fn tags(&self) -> &[ItemTag];
|
||||
|
||||
fn tool(&self) -> Option<&Tool> {
|
||||
if let ItemKind::Tool(tool) = self.kind() {
|
||||
Some(tool)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemDesc for Item {
|
||||
|
@ -49,6 +49,7 @@ impl TagExampleInfo for ModularComponentTag {
|
||||
ToolKind::Unique(_) => "unique damage component",
|
||||
ToolKind::Debug => "debug damage component",
|
||||
ToolKind::Farming => "farming damage component",
|
||||
ToolKind::Pick => "pickaxe head",
|
||||
ToolKind::Empty => "empty damage component",
|
||||
},
|
||||
ModularComponentKind::Held => match self.toolkind {
|
||||
@ -65,6 +66,7 @@ impl TagExampleInfo for ModularComponentTag {
|
||||
ToolKind::Unique(_) => "unique held component",
|
||||
ToolKind::Debug => "debug held component",
|
||||
ToolKind::Farming => "farming held component",
|
||||
ToolKind::Pick => "pickaxe handle",
|
||||
ToolKind::Empty => "empty held component",
|
||||
},
|
||||
}
|
||||
@ -95,6 +97,7 @@ impl TagExampleInfo for ModularComponentTag {
|
||||
ToolKind::Unique(_) => "common.items.tag_examples.modular.damage.unique",
|
||||
ToolKind::Debug => "common.items.tag_examples.modular.damage.debug",
|
||||
ToolKind::Farming => "common.items.tag_examples.modular.damage.farming",
|
||||
ToolKind::Pick => "common.items.tag_examples.modular.damage.pick",
|
||||
ToolKind::Empty => "common.items.tag_examples.modular.damage.empty",
|
||||
},
|
||||
ModularComponentKind::Held => match self.toolkind {
|
||||
@ -116,6 +119,7 @@ impl TagExampleInfo for ModularComponentTag {
|
||||
ToolKind::Unique(_) => "common.items.tag_examples.modular.held.unique",
|
||||
ToolKind::Debug => "common.items.tag_examples.modular.held.debug",
|
||||
ToolKind::Farming => "common.items.tag_examples.modular.held.farming",
|
||||
ToolKind::Pick => "common.items.tag_examples.modular.held.pick",
|
||||
ToolKind::Empty => "common.items.tag_examples.modular.held.empty",
|
||||
},
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ pub enum ToolKind {
|
||||
Unique(UniqueKind),
|
||||
Debug,
|
||||
Farming,
|
||||
Pick,
|
||||
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
||||
Empty,
|
||||
}
|
||||
@ -56,6 +57,7 @@ impl ToolKind {
|
||||
ToolKind::Unique(_) => "unique",
|
||||
ToolKind::Debug => "debug",
|
||||
ToolKind::Farming => "farming",
|
||||
ToolKind::Pick => "pickaxe",
|
||||
ToolKind::Empty => "empty",
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ pub use self::{
|
||||
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs,
|
||||
ModifierKind,
|
||||
},
|
||||
character_state::{CharacterState, Melee, StateUpdate},
|
||||
character_state::{CharacterState, InputAttr, Melee, StateUpdate},
|
||||
chat::{
|
||||
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
||||
},
|
||||
@ -69,8 +69,7 @@ pub use self::{
|
||||
home_chunk::HomeChunk,
|
||||
inputs::CanBuild,
|
||||
inventory::{
|
||||
item,
|
||||
item::{Item, ItemConfig, ItemDrop},
|
||||
item::{self, tool, Item, ItemConfig, ItemDrop},
|
||||
slot, Inventory, InventoryUpdate, InventoryUpdateEvent,
|
||||
},
|
||||
last::Last,
|
||||
|
@ -149,6 +149,10 @@ pub enum ServerEvent {
|
||||
entity: EcsEntity,
|
||||
id: SiteId,
|
||||
},
|
||||
// Attempt to mine a block, turning it into an item
|
||||
MineBlock {
|
||||
pos: Vec3<i32>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, InputAttr, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -122,6 +122,10 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle,
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: update
|
||||
.select_pos
|
||||
.filter(|_| self.static_data.ability_info.tool == Some(ToolKind::Pick))
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
// Swings
|
||||
@ -178,5 +182,10 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
|
||||
handle_input(join, update, data.static_data.ability_info.input);
|
||||
handle_input(
|
||||
join,
|
||||
update,
|
||||
data.static_data.ability_info.input,
|
||||
InputAttr::default(),
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, ProjectileConstructor, StateUpdate},
|
||||
comp::{
|
||||
Body, CharacterState, Gravity, InputAttr, LightEmitter, ProjectileConstructor, StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -125,5 +127,10 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
|
||||
handle_input(join, update, data.static_data.ability_info.input);
|
||||
handle_input(
|
||||
join,
|
||||
update,
|
||||
data.static_data.ability_info.input,
|
||||
InputAttr::default(),
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
item::MaterialStatManifest, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
||||
ControllerInputs, Energy, Health, InputKind, Inventory, InventoryAction, Melee, Ori,
|
||||
PhysicsState, Pos, StateUpdate, Stats, Vel,
|
||||
ControllerInputs, Energy, Health, InputAttr, InputKind, Inventory, InventoryAction, Melee,
|
||||
Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
|
||||
},
|
||||
resources::DeltaTime,
|
||||
uid::Uid,
|
||||
@ -13,6 +13,7 @@ use specs::{
|
||||
DerefFlaggedStorage, Entity, LazyUpdate,
|
||||
};
|
||||
use specs_idvs::IdvStorage;
|
||||
use vek::*;
|
||||
|
||||
pub trait CharacterBehavior {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate;
|
||||
@ -29,9 +30,16 @@ 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 start_input(&self, data: &JoinData, input: InputKind, _target: Option<Uid>) -> StateUpdate {
|
||||
fn start_input(
|
||||
&self,
|
||||
data: &JoinData,
|
||||
input: InputKind,
|
||||
_target: Option<Uid>,
|
||||
select_pos: Option<Vec3<f32>>,
|
||||
) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.queued_inputs.insert(input);
|
||||
update.select_pos = select_pos;
|
||||
update.queued_inputs.insert(input, InputAttr { select_pos });
|
||||
update
|
||||
}
|
||||
fn cancel_input(&self, data: &JoinData, input: InputKind) -> StateUpdate {
|
||||
@ -51,7 +59,11 @@ pub trait CharacterBehavior {
|
||||
ControlAction::Sneak => self.sneak(data),
|
||||
ControlAction::Stand => self.stand(data),
|
||||
ControlAction::Talk => self.talk(data),
|
||||
ControlAction::StartInput { input, target } => self.start_input(data, input, target),
|
||||
ControlAction::StartInput {
|
||||
input,
|
||||
target,
|
||||
select_pos,
|
||||
} => self.start_input(data, input, target, select_pos),
|
||||
ControlAction::CancelInput(input) => self.cancel_input(data, input),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, StateUpdate},
|
||||
comp::{CharacterState, InputAttr, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -59,5 +59,10 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
|
||||
handle_input(join, update, data.static_data.ability_info.input);
|
||||
handle_input(
|
||||
join,
|
||||
update,
|
||||
data.static_data.ability_info.input,
|
||||
InputAttr::default(),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::{StageSection, *},
|
||||
@ -187,6 +187,10 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: update
|
||||
.select_pos
|
||||
.filter(|_| self.static_data.ability_info.tool == Some(ToolKind::Pick))
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
// Swings
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, InputAttr, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -213,6 +213,12 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: self
|
||||
.static_data
|
||||
.ability_info
|
||||
.select_pos
|
||||
.filter(|_| self.static_data.ability_info.tool == Some(ToolKind::Pick))
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -285,7 +291,12 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
|
||||
handle_input(join, update, data.static_data.ability_info.input);
|
||||
handle_input(
|
||||
join,
|
||||
update,
|
||||
data.static_data.ability_info.input,
|
||||
InputAttr::default(),
|
||||
);
|
||||
|
||||
if let CharacterState::ComboMelee(c) = &mut update.character {
|
||||
c.stage = (data.stage % data.static_data.num_stages) + 1;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -164,6 +164,12 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: update
|
||||
.select_pos
|
||||
.filter(|_| {
|
||||
self.static_data.ability_info.tool == Some(ToolKind::Pick)
|
||||
})
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
}
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::{StageSection, *},
|
||||
@ -177,6 +177,10 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: update
|
||||
.select_pos
|
||||
.filter(|_| self.static_data.ability_info.tool == Some(ToolKind::Pick))
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
|
||||
update.character = CharacterState::LeapMelee(Data {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, InputKind, StateUpdate},
|
||||
comp::{CharacterState, InputAttr, InputKind, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -116,7 +116,7 @@ impl CharacterBehavior for Data {
|
||||
// Done
|
||||
if let Some((input, stage)) = self.was_combo {
|
||||
if input_is_pressed(data, input) {
|
||||
handle_input(data, &mut update, input);
|
||||
handle_input(data, &mut update, input, InputAttr::default());
|
||||
// If other states are introduced that progress through stages, add them
|
||||
// here
|
||||
if let CharacterState::ComboMelee(c) = &mut update.character {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
comp::{tool::ToolKind, CharacterState, EnergyChange, EnergySource, Melee, StateUpdate},
|
||||
consts::GRAVITY,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -141,6 +141,10 @@ impl CharacterBehavior for Data {
|
||||
max_angle: 180_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: update
|
||||
.select_pos
|
||||
.filter(|_| self.static_data.ability_info.tool == Some(ToolKind::Pick))
|
||||
.map(|p| p.map(|e| e.floor() as i32)),
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
if matches!(
|
||||
|
@ -5,7 +5,8 @@ use crate::{
|
||||
item::{Hands, ItemKind, Tool, ToolKind},
|
||||
quadruped_low, quadruped_medium, quadruped_small, ship,
|
||||
skills::Skill,
|
||||
theropod, Body, CharacterAbility, CharacterState, InputKind, InventoryAction, StateUpdate,
|
||||
theropod, Body, CharacterAbility, CharacterState, InputAttr, InputKind, InventoryAction,
|
||||
StateUpdate,
|
||||
},
|
||||
consts::{FRIC_GROUND, GRAVITY},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
@ -345,7 +346,7 @@ fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
|
||||
/// Checks if an input related to an attack is held. If one is, moves entity
|
||||
/// into wielding state
|
||||
pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) {
|
||||
if data.controller.queued_inputs.iter().any(|i| i.is_ability()) {
|
||||
if data.controller.queued_inputs.keys().any(|i| i.is_ability()) {
|
||||
attempt_wield(data, update);
|
||||
}
|
||||
}
|
||||
@ -461,7 +462,12 @@ pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
fn handle_ability(
|
||||
data: &JoinData,
|
||||
update: &mut StateUpdate,
|
||||
input: InputKind,
|
||||
input_attr: InputAttr,
|
||||
) {
|
||||
let hands = |equip_slot| match data.inventory.equipped(equip_slot).map(|i| i.kind()) {
|
||||
Some(ItemKind::Tool(tool)) => Some(tool.hands),
|
||||
_ => None,
|
||||
@ -511,7 +517,12 @@ fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
{
|
||||
update.character = (
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, matches!(equip_slot, EquipSlot::Offhand), input),
|
||||
AbilityInfo::from_input(
|
||||
data,
|
||||
matches!(equip_slot, EquipSlot::Offhand),
|
||||
input,
|
||||
input_attr,
|
||||
),
|
||||
)
|
||||
.into();
|
||||
}
|
||||
@ -519,20 +530,25 @@ fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
}
|
||||
|
||||
pub fn handle_ability_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Some(input) = data
|
||||
if let Some((input, input_attr)) = data
|
||||
.controller
|
||||
.queued_inputs
|
||||
.iter()
|
||||
.find(|i| i.is_ability())
|
||||
.find(|(i, _)| i.is_ability())
|
||||
{
|
||||
handle_ability(data, update, *input);
|
||||
handle_ability(data, update, *input, input_attr.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
pub fn handle_input(
|
||||
data: &JoinData,
|
||||
update: &mut StateUpdate,
|
||||
input: InputKind,
|
||||
input_attr: InputAttr,
|
||||
) {
|
||||
match input {
|
||||
InputKind::Primary | InputKind::Secondary | InputKind::Ability(_) => {
|
||||
handle_ability(data, update, input)
|
||||
handle_ability(data, update, input, input_attr)
|
||||
},
|
||||
InputKind::Roll => handle_dodge_input(data, update),
|
||||
InputKind::Jump => handle_jump(data, update),
|
||||
@ -542,8 +558,8 @@ pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind)
|
||||
|
||||
pub fn attempt_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
// TODO: look into using first() when it becomes stable
|
||||
if let Some(input) = data.controller.queued_inputs.iter().next() {
|
||||
handle_input(data, update, *input);
|
||||
if let Some((input, input_attr)) = data.controller.queued_inputs.iter().next() {
|
||||
handle_input(data, update, *input, input_attr.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,7 +581,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let CharacterState::ComboMelee(c) = data.character {
|
||||
update.character = (
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll),
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, InputAttr::default()),
|
||||
)
|
||||
.into();
|
||||
if let CharacterState::Roll(roll) = &mut update.character {
|
||||
@ -575,7 +591,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
} else if data.character.is_wield() {
|
||||
update.character = (
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll),
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, InputAttr::default()),
|
||||
)
|
||||
.into();
|
||||
if let CharacterState::Roll(roll) = &mut update.character {
|
||||
@ -584,7 +600,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
} else if data.character.is_stealthy() {
|
||||
update.character = (
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll),
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, InputAttr::default()),
|
||||
)
|
||||
.into();
|
||||
if let CharacterState::Roll(roll) = &mut update.character {
|
||||
@ -593,7 +609,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
} else {
|
||||
update.character = (
|
||||
&ability,
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll),
|
||||
AbilityInfo::from_input(data, false, InputKind::Roll, InputAttr::default()),
|
||||
)
|
||||
.into();
|
||||
}
|
||||
@ -635,7 +651,7 @@ pub fn handle_state_interrupt(data: &JoinData, update: &mut StateUpdate, attacks
|
||||
}
|
||||
|
||||
pub fn input_is_pressed(data: &JoinData, input: InputKind) -> bool {
|
||||
data.controller.queued_inputs.contains(&input)
|
||||
data.controller.queued_inputs.contains_key(&input)
|
||||
}
|
||||
|
||||
/// Determines what portion a state is in. Used in all attacks (eventually). Is
|
||||
@ -691,10 +707,16 @@ pub struct AbilityInfo {
|
||||
pub tool: Option<ToolKind>,
|
||||
pub hand: Option<HandInfo>,
|
||||
pub input: InputKind,
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
impl AbilityInfo {
|
||||
pub fn from_input(data: &JoinData, from_offhand: bool, input: InputKind) -> Self {
|
||||
pub fn from_input(
|
||||
data: &JoinData,
|
||||
from_offhand: bool,
|
||||
input: InputKind,
|
||||
input_attr: InputAttr,
|
||||
) -> Self {
|
||||
let tool_data = if from_offhand {
|
||||
unwrap_tool_data(data, EquipSlot::Offhand)
|
||||
} else {
|
||||
@ -709,7 +731,12 @@ impl AbilityInfo {
|
||||
)
|
||||
};
|
||||
|
||||
Self { tool, hand, input }
|
||||
Self {
|
||||
tool,
|
||||
hand,
|
||||
input,
|
||||
select_pos: input_attr.select_pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::SpriteKind;
|
||||
use crate::make_case_elim;
|
||||
use crate::{comp::tool::ToolKind, make_case_elim};
|
||||
use enum_iterator::IntoEnumIterator;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
@ -238,6 +238,16 @@ impl Block {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// The tool required to mine this block. For blocks that cannot be mined,
|
||||
/// `None` is returned.
|
||||
#[inline]
|
||||
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||
match self.kind() {
|
||||
BlockKind::WeakRock => Some(ToolKind::Pick),
|
||||
_ => self.get_sprite().and_then(|s| s.mine_tool()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_opaque(&self) -> bool { self.kind().is_filled() }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::make_case_elim;
|
||||
use crate::{comp::tool::ToolKind, make_case_elim};
|
||||
use enum_iterator::IntoEnumIterator;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
@ -222,8 +222,8 @@ impl SpriteKind {
|
||||
SpriteKind::Apple => true,
|
||||
SpriteKind::Mushroom => true,
|
||||
SpriteKind::CaveMushroom => true,
|
||||
SpriteKind::Velorite => true,
|
||||
SpriteKind::VeloriteFrag => true,
|
||||
// SpriteKind::Velorite => true,
|
||||
// SpriteKind::VeloriteFrag => true,
|
||||
SpriteKind::Chest => true,
|
||||
SpriteKind::Coconut => true,
|
||||
SpriteKind::Stones => true,
|
||||
@ -235,23 +235,44 @@ impl SpriteKind {
|
||||
SpriteKind::Bowl => true,
|
||||
SpriteKind::ChestBurried => true,
|
||||
SpriteKind::Mud => true,
|
||||
SpriteKind::Amethyst => true,
|
||||
SpriteKind::Ruby => true,
|
||||
SpriteKind::Diamond => true,
|
||||
SpriteKind::Sapphire => true,
|
||||
SpriteKind::Emerald => true,
|
||||
SpriteKind::Topaz => true,
|
||||
SpriteKind::AmethystSmall => true,
|
||||
SpriteKind::TopazSmall => true,
|
||||
SpriteKind::DiamondSmall => true,
|
||||
SpriteKind::RubySmall => true,
|
||||
SpriteKind::EmeraldSmall => true,
|
||||
SpriteKind::SapphireSmall => true,
|
||||
// SpriteKind::Amethyst => true,
|
||||
// SpriteKind::Ruby => true,
|
||||
// SpriteKind::Diamond => true,
|
||||
// SpriteKind::Sapphire => true,
|
||||
// SpriteKind::Emerald => true,
|
||||
// SpriteKind::Topaz => true,
|
||||
// SpriteKind::AmethystSmall => true,
|
||||
// SpriteKind::TopazSmall => true,
|
||||
// SpriteKind::DiamondSmall => true,
|
||||
// SpriteKind::RubySmall => true,
|
||||
// SpriteKind::EmeraldSmall => true,
|
||||
// SpriteKind::SapphireSmall => true,
|
||||
SpriteKind::Seashells => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||
match self {
|
||||
SpriteKind::Velorite
|
||||
| SpriteKind::VeloriteFrag
|
||||
// Gems
|
||||
| SpriteKind::Amethyst
|
||||
| SpriteKind::Ruby
|
||||
| SpriteKind::Diamond
|
||||
| SpriteKind::Sapphire
|
||||
| SpriteKind::Emerald
|
||||
| SpriteKind::Topaz
|
||||
| SpriteKind::AmethystSmall
|
||||
| SpriteKind::TopazSmall
|
||||
| SpriteKind::DiamondSmall
|
||||
| SpriteKind::RubySmall
|
||||
| SpriteKind::EmeraldSmall
|
||||
| SpriteKind::SapphireSmall => Some(ToolKind::Pick),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_ori(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
@ -63,6 +63,21 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
melee_attack.applied = true;
|
||||
|
||||
// Scales
|
||||
let eye_pos = pos.0 + Vec3::unit_z() * body.eye_height();
|
||||
let scale = read_data.scales.get(attacker).map_or(1.0, |s| s.0);
|
||||
let rad = body.radius() * scale;
|
||||
|
||||
// Mine blocks broken by the attack
|
||||
if let Some(block_pos) = melee_attack.break_block {
|
||||
// Check distance to block
|
||||
if eye_pos.distance_squared(block_pos.map(|e| e as f32 + 0.5))
|
||||
< (rad + scale * melee_attack.range).powi(2)
|
||||
{
|
||||
server_emitter.emit(ServerEvent::MineBlock { pos: block_pos });
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all other entities
|
||||
for (target, pos_b, health_b, body_b) in (
|
||||
&read_data.entities,
|
||||
@ -80,9 +95,7 @@ impl<'a> System<'a> for Sys {
|
||||
let ori2 = Vec2::from(look_dir);
|
||||
|
||||
// Scales
|
||||
let scale = read_data.scales.get(attacker).map_or(1.0, |s| s.0);
|
||||
let scale_b = read_data.scales.get(target).map_or(1.0, |s| s.0);
|
||||
let rad = body.radius() * scale;
|
||||
let rad_b = body_b.radius() * scale_b;
|
||||
|
||||
// Check if entity is dodging
|
||||
|
@ -1,10 +1,12 @@
|
||||
use specs::{world::WorldExt, Entity as EcsEntity};
|
||||
use specs::{world::WorldExt, Builder, Entity as EcsEntity};
|
||||
use tracing::error;
|
||||
use vek::*;
|
||||
|
||||
use common::{
|
||||
comp::{self, agent::AgentEvent, inventory::slot::EquipSlot, item, slot::Slot, Inventory, Pos},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
||||
|
||||
@ -254,3 +256,21 @@ fn within_mounting_range(player_position: Option<&Pos>, mount_position: Option<&
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_mine_block(server: &mut Server, pos: Vec3<i32>) {
|
||||
let state = server.state_mut();
|
||||
if state.can_set_block(pos) {
|
||||
let block = state.terrain().get(pos).ok().copied();
|
||||
if let Some(block) = block {
|
||||
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
|
||||
state
|
||||
.create_object(Default::default(), comp::object::Body::Pouch)
|
||||
.with(comp::Pos(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)))
|
||||
.with(item)
|
||||
.build();
|
||||
}
|
||||
|
||||
state.set_block(pos, block.into_vacant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ use entity_manipulation::{
|
||||
use group_manip::handle_group;
|
||||
use information::handle_site_info;
|
||||
use interaction::{
|
||||
handle_lantern, handle_mount, handle_npc_interaction, handle_possess, handle_unmount,
|
||||
handle_lantern, handle_mine_block, handle_mount, handle_npc_interaction, handle_possess,
|
||||
handle_unmount,
|
||||
};
|
||||
use inventory_manip::handle_inventory;
|
||||
use invite::{handle_invite, handle_invite_response};
|
||||
@ -190,6 +191,7 @@ impl Server {
|
||||
handle_combo_change(&self, entity, change)
|
||||
},
|
||||
ServerEvent::RequestSiteInfo { entity, id } => handle_site_info(&self, entity, id),
|
||||
ServerEvent::MineBlock { pos } => handle_mine_block(self, pos),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@ pub fn skill_to_db_string(skill: comp::skills::Skill) -> String {
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::SwordSimple))
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Debug))
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Farming))
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick))
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Empty))
|
||||
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Unique(_)))
|
||||
| UnlockGroup(SkillGroupKind::General) => {
|
||||
@ -292,6 +293,7 @@ pub fn skill_group_to_db_string(skill_group: comp::skills::SkillGroupKind) -> St
|
||||
| Weapon(ToolKind::SwordSimple)
|
||||
| Weapon(ToolKind::Debug)
|
||||
| Weapon(ToolKind::Farming)
|
||||
| Weapon(ToolKind::Pick)
|
||||
| Weapon(ToolKind::Empty)
|
||||
| Weapon(ToolKind::Unique(_)) => panic!(
|
||||
"Tried to add unsupported skill group to database: {:?}",
|
||||
|
@ -233,10 +233,9 @@ impl<'a> System<'a> for Sys {
|
||||
// If we need to be able to have entities (dragons maybe?) both fly and
|
||||
// run/jump, we probably need to refactor to avoid resetting the controller
|
||||
// every frame.
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Fly,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Fly));
|
||||
}
|
||||
|
||||
let flees = alignment
|
||||
@ -630,10 +629,9 @@ impl<'a> AgentData<'a> {
|
||||
.1
|
||||
.map_or(true, |b| b.is_some())
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Fly,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Fly));
|
||||
} else {
|
||||
controller
|
||||
.actions
|
||||
@ -1136,10 +1134,9 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
fn jump_if(&self, controller: &mut Controller, condition: bool) {
|
||||
if condition {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Jump,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Jump));
|
||||
} else {
|
||||
controller
|
||||
.actions
|
||||
@ -1259,10 +1256,9 @@ impl<'a> AgentData<'a> {
|
||||
match tactic {
|
||||
Tactic::Melee => {
|
||||
if dist_sqrd < (min_attack_dist * self.scale).powi(2) {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1285,10 +1281,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1303,10 +1298,9 @@ impl<'a> AgentData<'a> {
|
||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 4.0 && self.energy.current() > 10 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if self
|
||||
.stats
|
||||
@ -1315,16 +1309,14 @@ impl<'a> AgentData<'a> {
|
||||
&& self.energy.current() > 800
|
||||
&& thread_rng().gen_bool(0.5)
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1347,10 +1339,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1365,10 +1356,9 @@ impl<'a> AgentData<'a> {
|
||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 2.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if self
|
||||
.stats
|
||||
@ -1377,16 +1367,14 @@ impl<'a> AgentData<'a> {
|
||||
&& self.energy.current() > 700
|
||||
&& thread_rng().gen_bool(0.9)
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1409,10 +1397,9 @@ impl<'a> AgentData<'a> {
|
||||
.has_skill(Skill::Hammer(HammerSkill::UnlockLeap))
|
||||
&& agent.action_timer > 5.0
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer = 0.0;
|
||||
} else {
|
||||
agent.action_timer += dt.0;
|
||||
@ -1428,10 +1415,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1447,18 +1433,16 @@ impl<'a> AgentData<'a> {
|
||||
&& agent.action_timer < 2.0
|
||||
&& self.energy.current() > 600
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer > 2.0 {
|
||||
agent.action_timer = 0.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -1476,10 +1460,9 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
if agent.action_timer > 4.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer = 0.0;
|
||||
} else {
|
||||
agent.action_timer += dt.0;
|
||||
@ -1495,10 +1478,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1508,10 +1490,9 @@ impl<'a> AgentData<'a> {
|
||||
if self.body.map(|b| b.is_humanoid()).unwrap_or(false)
|
||||
&& dist_sqrd < (2.0 * min_attack_dist * self.scale).powi(2)
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -1536,10 +1517,9 @@ impl<'a> AgentData<'a> {
|
||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 2.0 && self.energy.current() > 300 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if self
|
||||
.stats
|
||||
@ -1551,19 +1531,17 @@ impl<'a> AgentData<'a> {
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::CancelInput(InputKind::Secondary));
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else {
|
||||
@ -1577,10 +1555,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1606,10 +1583,9 @@ impl<'a> AgentData<'a> {
|
||||
if self.body.map(|b| b.is_humanoid()).unwrap_or(false)
|
||||
&& dist_sqrd < (min_attack_dist * self.scale).powi(2)
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
} else if dist_sqrd < (5.0 * min_attack_dist * self.scale).powi(2) {
|
||||
if agent.action_timer < 1.5 {
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -1635,20 +1611,17 @@ impl<'a> AgentData<'a> {
|
||||
&& self.energy.current() > 800
|
||||
&& thread_rng().gen::<f32>() > 0.8
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
} else if self.energy.current() > 10 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1668,10 +1641,9 @@ impl<'a> AgentData<'a> {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* speed;
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else {
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
@ -1683,10 +1655,9 @@ impl<'a> AgentData<'a> {
|
||||
&& dist_sqrd < 16.0f32.powi(2)
|
||||
&& thread_rng().gen::<f32>() < 0.02
|
||||
{
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Roll,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Roll));
|
||||
}
|
||||
} else if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
@ -1713,17 +1684,15 @@ 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.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
//controller.inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if self.vel.0.is_approx_zero() {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
}
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -1739,10 +1708,9 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
if agent.action_timer > 5.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer = 0.0;
|
||||
} else {
|
||||
agent.action_timer += dt.0;
|
||||
@ -1765,10 +1733,9 @@ 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.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} 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()
|
||||
@ -1785,10 +1752,9 @@ impl<'a> AgentData<'a> {
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < circle_time as f32 + 0.5 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 2.0 * circle_time as f32 + 0.5 {
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -1798,10 +1764,9 @@ impl<'a> AgentData<'a> {
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 2.0 * circle_time as f32 + 1.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
@ -1832,10 +1797,9 @@ impl<'a> AgentData<'a> {
|
||||
.xy()
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -1867,10 +1831,9 @@ impl<'a> AgentData<'a> {
|
||||
* speed;
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
self.jump_if(controller, bearing.z > 1.5);
|
||||
controller.inputs.move_z = bearing.z;
|
||||
} else {
|
||||
@ -1894,16 +1857,14 @@ impl<'a> AgentData<'a> {
|
||||
.push(ControlAction::CancelInput(InputKind::Primary));
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 1.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -1934,17 +1895,15 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::QuadLowQuick => {
|
||||
if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
} 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.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
.xy()
|
||||
.rotated_z(-0.47 * PI)
|
||||
@ -1976,16 +1935,14 @@ impl<'a> AgentData<'a> {
|
||||
if agent.action_timer > 5.0 {
|
||||
agent.action_timer = 0.0;
|
||||
} else if agent.action_timer > 2.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
}
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
@ -2011,15 +1968,13 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::QuadMedJump => {
|
||||
if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
} else if dist_sqrd < (5.0 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -2032,10 +1987,9 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
) {
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
controller.inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
|
||||
} else {
|
||||
@ -2053,16 +2007,14 @@ impl<'a> AgentData<'a> {
|
||||
if dist_sqrd < (min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
if agent.action_timer < 2.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 3.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
@ -2090,10 +2042,9 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::Lavadrake | Tactic::QuadLowBeam => {
|
||||
if dist_sqrd < (2.5 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Secondary));
|
||||
} else if dist_sqrd < (7.0 * min_attack_dist * self.scale).powi(2) {
|
||||
if agent.action_timer < 2.0 {
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -2101,10 +2052,9 @@ impl<'a> AgentData<'a> {
|
||||
.rotated_z(0.47 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 4.0 {
|
||||
controller.inputs.move_dir = (tgt_pos.0 - self.pos.0)
|
||||
@ -2112,16 +2062,14 @@ impl<'a> AgentData<'a> {
|
||||
.rotated_z(-0.47 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
} else if agent.action_timer < 6.0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
@ -2149,10 +2097,9 @@ 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.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powi(2) {
|
||||
if let Some((bearing, speed)) = agent.chaser.chase(
|
||||
&*terrain,
|
||||
@ -2175,10 +2122,9 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
Tactic::Turret => {
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
@ -2186,10 +2132,9 @@ 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.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
@ -2203,10 +2148,9 @@ impl<'a> AgentData<'a> {
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_start(InputKind::Primary));
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl Animation for AlphaAnimation {
|
||||
next.head.orientation =
|
||||
Quaternion::rotation_z(0.0 + move1 * -1.5 + move2 * 2.5 + move3 * -1.0);
|
||||
},
|
||||
Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) => {
|
||||
Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) | Some(ToolKind::Pick) => {
|
||||
let (move1, move2, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0),
|
||||
Some(StageSection::Swing) => (1.0, anim_time, 0.0),
|
||||
|
@ -52,7 +52,7 @@ impl Animation for ChargeswingAnimation {
|
||||
let slowrise = test * (1.0 - move3);
|
||||
|
||||
let move2 = move2base * (1.0 - move3);
|
||||
if let Some(ToolKind::Hammer) = active_tool_kind {
|
||||
if let Some(ToolKind::Hammer | ToolKind::Pick) = active_tool_kind {
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2 + (move2 * -8.0));
|
||||
|
@ -40,7 +40,7 @@ impl Animation for EquipAnimation {
|
||||
next.hand_l.position = Vec3::new(-7.0, -5.0, 17.0);
|
||||
next.hand_r.position = Vec3::new(-5.0, -4.5, 14.0);
|
||||
},
|
||||
Some(ToolKind::Hammer) => {
|
||||
Some(ToolKind::Hammer | ToolKind::Pick) => {
|
||||
next.hand_l.position = Vec3::new(-5.0, -5.0, 13.0);
|
||||
next.hand_r.position = Vec3::new(-3.0, -4.5, 10.0);
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ impl Animation for LeapAnimation {
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
|
||||
if let Some(ToolKind::Hammer) = active_tool_kind {
|
||||
if let Some(ToolKind::Hammer | ToolKind::Pick) = active_tool_kind {
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3);
|
||||
next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2);
|
||||
|
@ -92,7 +92,7 @@ impl Animation for StaggeredAnimation {
|
||||
* Quaternion::rotation_y(s_a.ac.4)
|
||||
* Quaternion::rotation_z(s_a.ac.5);
|
||||
},
|
||||
Some(ToolKind::Hammer) => {
|
||||
Some(ToolKind::Hammer | ToolKind::Pick) => {
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4);
|
||||
|
@ -90,7 +90,7 @@ impl Animation for StunnedAnimation {
|
||||
* Quaternion::rotation_y(s_a.ac.4)
|
||||
* Quaternion::rotation_z(s_a.ac.5);
|
||||
},
|
||||
Some(ToolKind::Hammer) => {
|
||||
Some(ToolKind::Hammer | ToolKind::Pick) => {
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4);
|
||||
|
@ -217,7 +217,7 @@ impl Animation for WieldAnimation {
|
||||
* Quaternion::rotation_y(s_a.ac.4)
|
||||
* Quaternion::rotation_z(s_a.ac.5);
|
||||
},
|
||||
Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) => {
|
||||
Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) | Some(ToolKind::Pick) => {
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||
next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2);
|
||||
|
@ -217,5 +217,6 @@ fn empty_ability_info() -> states::utils::AbilityInfo {
|
||||
tool: None,
|
||||
hand: None,
|
||||
input: InputKind::Primary,
|
||||
select_pos: None,
|
||||
}
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ fn tool_desc(tool: &Tool, components: &[Item], msm: &MaterialStatManifest, desc:
|
||||
ToolKind::Unique(_) => "Unique",
|
||||
ToolKind::Debug => "Debug",
|
||||
ToolKind::Farming => "Farming Tool",
|
||||
ToolKind::Pick => "Pickaxe",
|
||||
ToolKind::Empty => "Empty",
|
||||
};
|
||||
|
||||
|
@ -10,8 +10,10 @@ use common::{
|
||||
assets::AssetExt,
|
||||
comp,
|
||||
comp::{
|
||||
inventory::slot::Slot, invite::InviteKind, ChatMsg, ChatType, InputKind,
|
||||
InventoryUpdateEvent, Pos, Vel,
|
||||
inventory::slot::{EquipSlot, Slot},
|
||||
invite::InviteKind,
|
||||
item::{tool::ToolKind, ItemDesc},
|
||||
ChatMsg, ChatType, InputKind, InventoryUpdateEvent, Pos, Vel,
|
||||
},
|
||||
consts::{MAX_MOUNT_RANGE, MAX_PICKUP_RANGE},
|
||||
outcome::Outcome,
|
||||
@ -302,30 +304,44 @@ impl PlayState for SessionState {
|
||||
// Throw out distance info, it will be useful in the future
|
||||
self.target_entity = target_entity.map(|x| x.0);
|
||||
|
||||
let player_entity = self.client.borrow().entity();
|
||||
|
||||
let can_build = self
|
||||
.client
|
||||
.borrow()
|
||||
.state()
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(self.client.borrow().entity())
|
||||
.get(player_entity)
|
||||
.is_some();
|
||||
|
||||
let is_mining = self
|
||||
.client
|
||||
.borrow()
|
||||
.inventories()
|
||||
.get(player_entity)
|
||||
.and_then(|inv| inv.equipped(EquipSlot::Mainhand))
|
||||
.and_then(|item| item.tool())
|
||||
.map_or(false, |tool| tool.kind == ToolKind::Pick)
|
||||
&& self.client.borrow().is_wielding() == Some(true);
|
||||
|
||||
self.interactable = select_interactable(
|
||||
&self.client.borrow(),
|
||||
target_entity,
|
||||
select_pos,
|
||||
select_pos.map(|sp| sp.map(|e| e.floor() as i32)),
|
||||
&self.scene,
|
||||
);
|
||||
|
||||
// Only highlight interactables
|
||||
// unless in build mode where select_pos highlighted
|
||||
self.scene
|
||||
.set_select_pos(select_pos.filter(|_| can_build).or_else(
|
||||
|| match self.interactable {
|
||||
self.scene.set_select_pos(
|
||||
select_pos
|
||||
.map(|sp| sp.map(|e| e.floor() as i32))
|
||||
.filter(|_| can_build || is_mining)
|
||||
.or_else(|| match self.interactable {
|
||||
Some(Interactable::Block(_, block_pos)) => Some(block_pos),
|
||||
_ => None,
|
||||
},
|
||||
));
|
||||
}),
|
||||
);
|
||||
|
||||
// Handle window events.
|
||||
for event in events {
|
||||
@ -351,10 +367,10 @@ impl PlayState for SessionState {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if state && can_build {
|
||||
if let Some(select_pos) = select_pos {
|
||||
client.remove_block(select_pos);
|
||||
client.remove_block(select_pos.map(|e| e.floor() as i32));
|
||||
}
|
||||
} else {
|
||||
client.handle_input(InputKind::Primary, state);
|
||||
client.handle_input(InputKind::Primary, state, select_pos);
|
||||
}
|
||||
},
|
||||
GameInput::Secondary => {
|
||||
@ -362,10 +378,13 @@ impl PlayState for SessionState {
|
||||
|
||||
if state && can_build {
|
||||
if let Some(build_pos) = build_pos {
|
||||
client.place_block(build_pos, self.selected_block);
|
||||
client.place_block(
|
||||
build_pos.map(|e| e.floor() as i32),
|
||||
self.selected_block,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
client.handle_input(InputKind::Secondary, state);
|
||||
client.handle_input(InputKind::Secondary, state, select_pos);
|
||||
}
|
||||
},
|
||||
GameInput::Roll => {
|
||||
@ -373,13 +392,18 @@ impl PlayState for SessionState {
|
||||
if can_build {
|
||||
if state {
|
||||
if let Some(block) = select_pos.and_then(|sp| {
|
||||
client.state().terrain().get(sp).ok().copied()
|
||||
client
|
||||
.state()
|
||||
.terrain()
|
||||
.get(sp.map(|e| e.floor() as i32))
|
||||
.ok()
|
||||
.copied()
|
||||
}) {
|
||||
self.selected_block = block;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client.handle_input(InputKind::Roll, state);
|
||||
client.handle_input(InputKind::Roll, state, select_pos);
|
||||
}
|
||||
},
|
||||
GameInput::Respawn => {
|
||||
@ -390,7 +414,7 @@ impl PlayState for SessionState {
|
||||
},
|
||||
GameInput::Jump => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.handle_input(InputKind::Jump, state);
|
||||
client.handle_input(InputKind::Jump, state, select_pos);
|
||||
},
|
||||
GameInput::SwimUp => {
|
||||
self.key_state.swim_up = state;
|
||||
@ -451,7 +475,7 @@ impl PlayState for SessionState {
|
||||
// controller change
|
||||
self.key_state.fly ^= state;
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.handle_input(InputKind::Fly, self.key_state.fly);
|
||||
client.handle_input(InputKind::Fly, self.key_state.fly, select_pos);
|
||||
},
|
||||
GameInput::Climb => {
|
||||
self.key_state.climb_up = state;
|
||||
@ -1209,11 +1233,11 @@ impl PlayState for SessionState {
|
||||
},
|
||||
HudEvent::Ability3(state) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.handle_input(InputKind::Ability(0), state);
|
||||
client.handle_input(InputKind::Ability(0), state, select_pos);
|
||||
},
|
||||
HudEvent::Ability4(state) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.handle_input(InputKind::Ability(1), state);
|
||||
client.handle_input(InputKind::Ability(1), state, select_pos);
|
||||
},
|
||||
HudEvent::ChangeFOV(new_fov) => {
|
||||
global_state.settings.graphics.fov = new_fov;
|
||||
@ -1528,8 +1552,8 @@ fn under_cursor(
|
||||
cam_pos: Vec3<f32>,
|
||||
cam_dir: Vec3<f32>,
|
||||
) -> (
|
||||
Option<Vec3<i32>>,
|
||||
Option<Vec3<i32>>,
|
||||
Option<Vec3<f32>>,
|
||||
Option<Vec3<f32>>,
|
||||
Option<(specs::Entity, f32)>,
|
||||
) {
|
||||
span!(_guard, "under_cursor");
|
||||
@ -1555,7 +1579,7 @@ fn under_cursor(
|
||||
|
||||
let cam_ray = terrain
|
||||
.ray(cam_pos, cam_pos + cam_dir * 100.0)
|
||||
.until(|block| block.is_filled() || block.is_collectible())
|
||||
.until(|block| block.is_filled() || block.is_collectible() || block.mine_tool().is_some())
|
||||
.cast();
|
||||
|
||||
let cam_dist = cam_ray.0;
|
||||
@ -1566,8 +1590,8 @@ fn under_cursor(
|
||||
<= MAX_PICKUP_RANGE)
|
||||
{
|
||||
(
|
||||
Some((cam_pos + cam_dir * (cam_dist - 0.01)).map(|e| e.floor() as i32)),
|
||||
Some((cam_pos + cam_dir * (cam_dist + 0.01)).map(|e| e.floor() as i32)),
|
||||
Some(cam_pos + cam_dir * (cam_dist - 0.01)),
|
||||
Some(cam_pos + cam_dir * (cam_dist + 0.01)),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
@ -1677,7 +1701,8 @@ fn select_interactable(
|
||||
.and_then(|(e, dist_to_player)| (dist_to_player < MAX_PICKUP_RANGE).then_some(Interactable::Entity(e)))
|
||||
.or_else(|| selected_pos.and_then(|sp|
|
||||
client.state().terrain().get(sp).ok().copied()
|
||||
.filter(Block::is_collectible).map(|b| Interactable::Block(b, sp))
|
||||
.filter(|b| b.is_collectible() || b.mine_tool().is_some())
|
||||
.map(|b| Interactable::Block(b, sp))
|
||||
))
|
||||
.or_else(|| {
|
||||
let ecs = client.state().ecs();
|
||||
|
Loading…
Reference in New Issue
Block a user