mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/pick' into 'master'
Pickaxe See merge request veloren/veloren!1959
This commit is contained in:
commit
7ae4230dc8
11
assets/common/abilities/pick/swing.ron
Normal file
11
assets/common/abilities/pick/swing.ron
Normal file
@ -0,0 +1,11 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.6,
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.15,
|
||||
base_damage: 50,
|
||||
base_poise_damage: 0,
|
||||
knockback: 0.0,
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
)
|
@ -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: "Iron Pickaxe",
|
||||
description: "Strike the earth!",
|
||||
kind: Tool((
|
||||
kind: Pick,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.25,
|
||||
power: 0.75,
|
||||
poise_strength: 0.25,
|
||||
speed: 0.75,
|
||||
crit_chance: 0.0,
|
||||
crit_mult: 1.0,
|
||||
)),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
)
|
@ -375,6 +375,15 @@
|
||||
(Item("common.items.crafting_tools.sewing_set"), 0),
|
||||
],
|
||||
),
|
||||
"pickaxe": (
|
||||
("common.items.tool.pick", 1),
|
||||
[
|
||||
(Item("common.items.crafting_ing.wool"), 1), // TODO: Replace with plant fiber when obtainable
|
||||
(Item("common.items.crafting_ing.stones"), 5), // TODO: Replace with iron ingots when obtainable
|
||||
(Item("common.items.crafting_ing.twigs"), 4),
|
||||
(Item("common.items.crafting_tools.craftsman_hammer"), 0),
|
||||
],
|
||||
),
|
||||
"cloth_scraps": (
|
||||
("common.items.crafting_ing.cloth_scraps", 1),
|
||||
[
|
||||
|
@ -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.2 / 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(),
|
||||
})
|
||||
|
@ -1,13 +1,14 @@
|
||||
use crate::{
|
||||
combat::Attack,
|
||||
comp::{Energy, InputKind, Ori, Pos, Vel},
|
||||
comp::{tool::ToolKind, Energy, InputAttr, 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::{BTreeSet, VecDeque};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use vek::*;
|
||||
|
||||
/// Data returned from character behavior fn's to Character Behavior System.
|
||||
pub struct StateUpdate {
|
||||
@ -17,7 +18,7 @@ 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>,
|
||||
@ -32,7 +33,7 @@ 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(),
|
||||
@ -192,6 +193,7 @@ pub struct Melee {
|
||||
pub max_angle: f32,
|
||||
pub applied: bool,
|
||||
pub hit_count: u32,
|
||||
pub break_block: Option<(Vec3<i32>, Option<ToolKind>)>,
|
||||
}
|
||||
|
||||
impl Component for Melee {
|
||||
|
@ -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_input(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 {
|
||||
@ -132,6 +144,11 @@ impl InputKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct InputAttr {
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Climb {
|
||||
Up,
|
||||
@ -146,12 +163,13 @@ pub struct ControllerInputs {
|
||||
pub move_z: f32, /* z axis (not combined with move_dir because they may have independent
|
||||
* limits) */
|
||||
pub look_dir: Dir,
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
#[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>,
|
||||
@ -164,6 +182,7 @@ impl ControllerInputs {
|
||||
self.move_dir = new.move_dir;
|
||||
self.move_z = new.move_z;
|
||||
self.look_dir = new.look_dir;
|
||||
self.select_pos = new.select_pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
@ -61,16 +61,15 @@ pub use self::{
|
||||
},
|
||||
combo::Combo,
|
||||
controller::{
|
||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputKind,
|
||||
InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputAttr,
|
||||
InputKind, InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
||||
},
|
||||
energy::{Energy, EnergyChange, EnergySource},
|
||||
group::Group,
|
||||
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,11 @@ pub enum ServerEvent {
|
||||
entity: EcsEntity,
|
||||
id: SiteId,
|
||||
},
|
||||
// Attempt to mine a block, turning it into an item
|
||||
MineBlock {
|
||||
pos: Vec3<i32>,
|
||||
tool: Option<comp::tool::ToolKind>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -41,6 +41,10 @@ pub enum Outcome {
|
||||
uid: Uid,
|
||||
combo: u32,
|
||||
},
|
||||
BreakBlock {
|
||||
pos: Vec3<i32>,
|
||||
color: Option<Rgb<u8>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Outcome {
|
||||
@ -50,6 +54,7 @@ impl Outcome {
|
||||
| Outcome::ProjectileShot { pos, .. }
|
||||
| Outcome::Beam { pos, .. }
|
||||
| Outcome::SkillPointGain { pos, .. } => Some(*pos),
|
||||
Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)),
|
||||
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None,
|
||||
}
|
||||
}
|
||||
|
@ -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::*,
|
||||
@ -122,6 +122,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle,
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
// Swings
|
||||
|
@ -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,15 @@ 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.queued_inputs.insert(input, InputAttr { select_pos });
|
||||
update
|
||||
}
|
||||
fn cancel_input(&self, data: &JoinData, input: InputKind) -> StateUpdate {
|
||||
@ -51,7 +58,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,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,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
} 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, Melee, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -213,6 +213,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -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,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
}
|
||||
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,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
|
||||
update.character = CharacterState::LeapMelee(Data {
|
||||
|
@ -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,16 @@ impl CharacterBehavior for Data {
|
||||
max_angle: 180_f32.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
break_block: data
|
||||
.inputs
|
||||
.select_pos
|
||||
.map(|p| {
|
||||
(
|
||||
p.map(|e| e.floor() as i32),
|
||||
self.static_data.ability_info.tool,
|
||||
)
|
||||
})
|
||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||
});
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
if matches!(
|
||||
|
@ -356,7 +356,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);
|
||||
}
|
||||
}
|
||||
@ -533,7 +533,7 @@ pub fn handle_ability_input(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Some(input) = data
|
||||
.controller
|
||||
.queued_inputs
|
||||
.iter()
|
||||
.keys()
|
||||
.find(|i| i.is_ability())
|
||||
{
|
||||
handle_ability(data, update, *input);
|
||||
@ -553,7 +553,7 @@ 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() {
|
||||
if let Some(input) = data.controller.queued_inputs.keys().next() {
|
||||
handle_input(data, update, *input);
|
||||
}
|
||||
}
|
||||
@ -646,7 +646,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
|
||||
@ -702,6 +702,7 @@ pub struct AbilityInfo {
|
||||
pub tool: Option<ToolKind>,
|
||||
pub hand: Option<HandInfo>,
|
||||
pub input: InputKind,
|
||||
pub select_pos: Option<Vec3<f32>>,
|
||||
}
|
||||
|
||||
impl AbilityInfo {
|
||||
@ -720,7 +721,18 @@ impl AbilityInfo {
|
||||
)
|
||||
};
|
||||
|
||||
Self { tool, hand, input }
|
||||
Self {
|
||||
tool,
|
||||
hand,
|
||||
input,
|
||||
select_pos: data
|
||||
.controller
|
||||
.queued_inputs
|
||||
.get(&input)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.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,32 @@ 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::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,24 @@ 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, tool)) = 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,
|
||||
tool,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all other entities
|
||||
for (target, pos_b, health_b, body_b) in (
|
||||
&read_data.entities,
|
||||
@ -80,9 +98,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,16 @@
|
||||
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},
|
||||
comp::{
|
||||
self, agent::AgentEvent, inventory::slot::EquipSlot, item, slot::Slot, tool::ToolKind,
|
||||
Inventory, Pos,
|
||||
},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
outcome::Outcome,
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
||||
|
||||
@ -254,3 +260,29 @@ fn within_mounting_range(player_position: Option<&Pos>, mount_position: Option<&
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_mine_block(server: &mut Server, pos: Vec3<i32>, tool: Option<ToolKind>) {
|
||||
let state = server.state_mut();
|
||||
if state.can_set_block(pos) {
|
||||
let block = state.terrain().get(pos).ok().copied();
|
||||
if let Some(block) = block.filter(|b| b.mine_tool().map_or(false, |t| Some(t) == tool)) {
|
||||
// Drop item if one is recoverable from the 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());
|
||||
state
|
||||
.ecs()
|
||||
.write_resource::<Vec<Outcome>>()
|
||||
.push(Outcome::BreakBlock {
|
||||
pos,
|
||||
color: block.get_color(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, tool } => handle_mine_block(self, pos, tool),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,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) => {
|
||||
@ -298,6 +299,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_input(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_input(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_input(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_input(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_input(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_input(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_input(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(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_input(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_input(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_input(InputKind::Ability(0)));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(InputKind::Ability(0)));
|
||||
} else if self.energy.current() > 10 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(InputKind::Primary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Secondary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(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_input(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_input(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_input(InputKind::Secondary));
|
||||
agent.action_timer += dt.0;
|
||||
} else {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Primary,
|
||||
target: None,
|
||||
});
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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_input(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),
|
||||
|
@ -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);
|
||||
},
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -365,6 +365,10 @@ impl SfxMgr {
|
||||
},
|
||||
},
|
||||
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => {},
|
||||
Outcome::BreakBlock { pos, .. } => {
|
||||
let file_ref = "voxygen.audio.sfx.footsteps.stone_step_1";
|
||||
audio.play_sfx(file_ref, pos.map(|e| e as f32 + 0.5), Some(3.0));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -880,7 +880,20 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicMelee(_) => {
|
||||
CharacterState::BasicMelee(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Swing => {
|
||||
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
anim::character::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
@ -888,9 +901,9 @@ impl FigureMgr {
|
||||
second_tool_kind,
|
||||
rel_vel.magnitude(),
|
||||
time,
|
||||
None,
|
||||
Some(s.stage_section),
|
||||
),
|
||||
state.state_time,
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
|
@ -156,6 +156,17 @@ impl ParticleMgr {
|
||||
}
|
||||
},
|
||||
Outcome::ProjectileShot { .. } => {},
|
||||
Outcome::BreakBlock { pos, .. } => {
|
||||
// TODO: Use color field when particle colors are a thing
|
||||
self.particles.resize_with(self.particles.len() + 30, || {
|
||||
Particle::new(
|
||||
Duration::from_millis(100),
|
||||
time,
|
||||
ParticleMode::Shrapnel,
|
||||
pos.map(|e| e as f32 + 0.5),
|
||||
)
|
||||
});
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
@ -296,36 +298,59 @@ impl PlayState for SessionState {
|
||||
};
|
||||
self.is_aiming = is_aiming;
|
||||
|
||||
// Check to see whether we're aiming at anything
|
||||
let (build_pos, select_pos, target_entity) =
|
||||
under_cursor(&self.client.borrow(), cam_pos, cam_dir);
|
||||
// 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);
|
||||
|
||||
// Check to see whether we're aiming at anything
|
||||
let (build_pos, select_pos, target_entity) =
|
||||
under_cursor(&self.client.borrow(), cam_pos, cam_dir, |b| {
|
||||
b.is_filled()
|
||||
|| if is_mining {
|
||||
b.mine_tool().is_some()
|
||||
} else {
|
||||
b.is_collectible()
|
||||
}
|
||||
});
|
||||
self.inputs.select_pos = select_pos;
|
||||
// Throw out distance info, it will be useful in the future
|
||||
self.target_entity = target_entity.map(|x| x.0);
|
||||
|
||||
self.interactable = select_interactable(
|
||||
&self.client.borrow(),
|
||||
target_entity,
|
||||
select_pos,
|
||||
select_pos.map(|sp| sp.map(|e| e.floor() as i32)),
|
||||
&self.scene,
|
||||
|b| b.is_collectible() || (is_mining && b.mine_tool().is_some()),
|
||||
);
|
||||
|
||||
// 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 +376,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 +387,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 +401,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 +423,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 +484,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 +1242,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;
|
||||
@ -1527,9 +1560,10 @@ fn under_cursor(
|
||||
client: &Client,
|
||||
cam_pos: Vec3<f32>,
|
||||
cam_dir: Vec3<f32>,
|
||||
mut hit: impl FnMut(Block) -> bool,
|
||||
) -> (
|
||||
Option<Vec3<i32>>,
|
||||
Option<Vec3<i32>>,
|
||||
Option<Vec3<f32>>,
|
||||
Option<Vec3<f32>>,
|
||||
Option<(specs::Entity, f32)>,
|
||||
) {
|
||||
span!(_guard, "under_cursor");
|
||||
@ -1555,7 +1589,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| hit(*block))
|
||||
.cast();
|
||||
|
||||
let cam_dist = cam_ray.0;
|
||||
@ -1566,8 +1600,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)
|
||||
@ -1667,6 +1701,7 @@ fn select_interactable(
|
||||
target_entity: Option<(specs::Entity, f32)>,
|
||||
selected_pos: Option<Vec3<i32>>,
|
||||
scene: &Scene,
|
||||
mut hit: impl FnMut(Block) -> bool,
|
||||
) -> Option<Interactable> {
|
||||
span!(_guard, "select_interactable");
|
||||
// TODO: once there are multiple distances for different types of interactions
|
||||
@ -1677,7 +1712,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| hit(*b))
|
||||
.map(|b| Interactable::Block(b, sp))
|
||||
))
|
||||
.or_else(|| {
|
||||
let ecs = client.state().ecs();
|
||||
|
Loading…
Reference in New Issue
Block a user