mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'timo-bow' into 'master'
Timo bow See merge request veloren/veloren!513
This commit is contained in:
commit
74239c5346
BIN
assets/voxygen/voxel/weapon/bow/simple-arrow.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/bow/simple-arrow.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/weapon/bow/simple-bow.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/bow/simple-bow.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -2,6 +2,7 @@ use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Body {
|
||||
Arrow,
|
||||
Bomb,
|
||||
Scarecrow,
|
||||
Cauldron,
|
||||
@ -59,7 +60,8 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_OBJECTS: [Body; 47] = [
|
||||
const ALL_OBJECTS: [Body; 48] = [
|
||||
Body::Arrow,
|
||||
Body::Bomb,
|
||||
Body::Scarecrow,
|
||||
Body::Cauldron,
|
||||
|
@ -2,7 +2,7 @@
|
||||
pub mod item;
|
||||
|
||||
// Reexports
|
||||
pub use self::item::{Debug, Item, Tool};
|
||||
pub use item::{Debug, Item, Tool};
|
||||
|
||||
use specs::{Component, HashMapStorage, NullStorage};
|
||||
|
||||
@ -74,6 +74,10 @@ impl Default for Inventory {
|
||||
};
|
||||
|
||||
inventory.push(Item::Debug(Debug::Boost));
|
||||
inventory.push(Item::Tool {
|
||||
kind: Tool::Bow,
|
||||
power: 10,
|
||||
});
|
||||
inventory.push(Item::Tool {
|
||||
kind: Tool::Daggers,
|
||||
power: 10,
|
||||
@ -90,9 +94,6 @@ impl Default for Inventory {
|
||||
kind: Tool::Hammer,
|
||||
power: 10,
|
||||
});
|
||||
for _ in 0..10 {
|
||||
inventory.push(Item::default());
|
||||
}
|
||||
|
||||
inventory
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ mod last;
|
||||
mod location;
|
||||
mod phys;
|
||||
mod player;
|
||||
pub mod projectile;
|
||||
mod stats;
|
||||
mod visual;
|
||||
|
||||
@ -22,7 +23,8 @@ pub use inputs::CanBuild;
|
||||
pub use inventory::{item, Inventory, InventoryUpdate, Item};
|
||||
pub use last::Last;
|
||||
pub use location::Waypoint;
|
||||
pub use phys::{ForceUpdate, Mass, Ori, PhysicsState, Pos, Scale, Vel};
|
||||
pub use phys::{ForceUpdate, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel};
|
||||
pub use player::Player;
|
||||
pub use projectile::Projectile;
|
||||
pub use stats::{Equipment, Exp, HealthSource, Level, Stats};
|
||||
pub use visual::LightEmitter;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::state::Uid;
|
||||
use specs::{Component, FlaggedStorage, NullStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use vek::*;
|
||||
@ -42,11 +43,19 @@ impl Component for Mass {
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Sticky;
|
||||
|
||||
impl Component for Sticky {
|
||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
|
||||
}
|
||||
|
||||
// PhysicsState
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PhysicsState {
|
||||
pub on_ground: bool,
|
||||
pub on_wall: Option<Vec3<f32>>,
|
||||
pub touch_entity: Option<Uid>,
|
||||
pub in_fluid: bool,
|
||||
}
|
||||
|
||||
|
20
common/src/comp/projectile.rs
Normal file
20
common/src/comp/projectile.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Damage(u32),
|
||||
Vanish,
|
||||
Stick,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Projectile {
|
||||
pub hit_ground: Vec<Effect>,
|
||||
pub hit_wall: Vec<Effect>,
|
||||
pub hit_entity: Vec<Effect>,
|
||||
}
|
||||
|
||||
impl Component for Projectile {
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
@ -5,6 +5,7 @@ use specs_idvs::IDVStorage;
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum HealthSource {
|
||||
Attack { by: Uid }, // TODO: Implement weapon
|
||||
Projectile,
|
||||
Suicide,
|
||||
World,
|
||||
Revive,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::comp;
|
||||
use parking_lot::Mutex;
|
||||
use specs::Entity as EcsEntity;
|
||||
use sphynx::Uid;
|
||||
use std::{collections::VecDeque, ops::DerefMut};
|
||||
use vek::*;
|
||||
|
||||
@ -25,12 +26,21 @@ pub enum ServerEvent {
|
||||
pos: Vec3<f32>,
|
||||
radius: f32,
|
||||
},
|
||||
Die {
|
||||
Damage {
|
||||
uid: Uid,
|
||||
dmg: u32,
|
||||
cause: comp::HealthSource,
|
||||
},
|
||||
Destroy {
|
||||
entity: EcsEntity,
|
||||
cause: comp::HealthSource,
|
||||
},
|
||||
Respawn(EcsEntity),
|
||||
Shoot(EcsEntity),
|
||||
Shoot {
|
||||
entity: EcsEntity,
|
||||
dir: Vec3<f32>,
|
||||
projectile: comp::Projectile,
|
||||
},
|
||||
Mount(EcsEntity, EcsEntity),
|
||||
Unmount(EcsEntity),
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ sphynx::sum_type! {
|
||||
MountState(comp::MountState),
|
||||
Mounting(comp::Mounting),
|
||||
Mass(comp::Mass),
|
||||
Projectile(comp::Projectile),
|
||||
Sticky(comp::Sticky),
|
||||
}
|
||||
}
|
||||
// Automatically derive From<T> for EcsCompPhantom
|
||||
@ -50,6 +52,8 @@ sphynx::sum_type! {
|
||||
MountState(PhantomData<comp::MountState>),
|
||||
Mounting(PhantomData<comp::Mounting>),
|
||||
Mass(PhantomData<comp::Mass>),
|
||||
Projectile(PhantomData<comp::Projectile>),
|
||||
Sticky(PhantomData<comp::Sticky>),
|
||||
}
|
||||
}
|
||||
impl sphynx::CompPacket for EcsCompPacket {
|
||||
|
@ -132,6 +132,8 @@ impl State {
|
||||
ecs.register_synced::<comp::Mounting>();
|
||||
ecs.register_synced::<comp::MountState>();
|
||||
ecs.register_synced::<comp::Mass>();
|
||||
ecs.register_synced::<comp::Sticky>();
|
||||
ecs.register_synced::<comp::Projectile>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
ActionState::*, CharacterState, Controller, ForceUpdate, HealthSource, Ori, Pos, Stats, Vel,
|
||||
},
|
||||
comp::{item::Item, ActionState::*, CharacterState, Controller, HealthSource, Ori, Pos, Stats},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
state::{DeltaTime, Uid},
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
@ -14,49 +13,55 @@ pub const ATTACK_DURATION: Duration = Duration::from_millis(500);
|
||||
// Delay before hit
|
||||
const PREPARE_DURATION: Duration = Duration::from_millis(100);
|
||||
|
||||
const BASE_DMG: i32 = 10;
|
||||
const BLOCK_EFFICIENCY: f32 = 0.9;
|
||||
|
||||
const ATTACK_RANGE: f32 = 4.0;
|
||||
const BLOCK_ANGLE: f32 = 180.0;
|
||||
|
||||
const KNOCKBACK_XY: f32 = 2.0;
|
||||
const KNOCKBACK_Z: f32 = 2.0;
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or attacking
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Uid>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, EventBus<LocalEvent>>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Ori>,
|
||||
ReadStorage<'a, Controller>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, CharacterState>,
|
||||
WriteStorage<'a, Stats>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
uids,
|
||||
server_bus,
|
||||
local_bus,
|
||||
dt,
|
||||
uids,
|
||||
positions,
|
||||
orientations,
|
||||
controllers,
|
||||
mut velocities,
|
||||
mut character_states,
|
||||
mut stats,
|
||||
mut force_updates,
|
||||
stats,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_bus.emitter();
|
||||
let mut _local_emitter = local_bus.emitter();
|
||||
|
||||
// Attacks
|
||||
for (entity, uid, pos, ori, _) in
|
||||
(&entities, &uids, &positions, &orientations, &controllers).join()
|
||||
for (entity, uid, pos, ori, _, stat) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
&orientations,
|
||||
&controllers,
|
||||
&stats,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let (deal_damage, should_end) = if let Some(Attack { time_left, applied }) =
|
||||
&mut character_states.get_mut(entity).map(|c| &mut c.action)
|
||||
@ -79,13 +84,13 @@ impl<'a> System<'a> for Sys {
|
||||
if deal_damage {
|
||||
if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) {
|
||||
// Go through all other entities
|
||||
for (b, pos_b, ori_b, character_b, mut vel_b, stat_b) in (
|
||||
for (b, uid_b, pos_b, ori_b, character_b, stat_b) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
&orientations,
|
||||
&character_states,
|
||||
&mut velocities,
|
||||
&mut stats,
|
||||
&stats,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -101,22 +106,27 @@ impl<'a> System<'a> for Sys {
|
||||
// TODO: Use size instead of 1.0
|
||||
&& ori2.angle_between(pos_b2 - pos2) < (1.0 / pos2.distance(pos_b2)).atan()
|
||||
{
|
||||
let dmg = if character_b.action.is_block()
|
||||
// Weapon gives base damage
|
||||
let mut dmg =
|
||||
if let Some(Item::Tool { power, .. }) = stat.equipment.main {
|
||||
power
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
// Block
|
||||
if character_b.action.is_block()
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0).to_degrees()
|
||||
< BLOCK_ANGLE / 2.0
|
||||
{
|
||||
(BASE_DMG as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32
|
||||
} else {
|
||||
BASE_DMG
|
||||
};
|
||||
dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as u32
|
||||
}
|
||||
|
||||
// Deal damage
|
||||
stat_b
|
||||
.health
|
||||
.change_by(-dmg, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon
|
||||
vel_b.0 += (pos_b.0 - pos.0).normalized() * KNOCKBACK_XY;
|
||||
vel_b.0.z = KNOCKBACK_Z;
|
||||
let _ = force_updates.insert(b, ForceUpdate);
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
uid: *uid_b,
|
||||
dmg,
|
||||
cause: HealthSource::Attack { by: *uid },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
comp::{
|
||||
item, ActionState::*, Body, CharacterState, ControlEvent, Controller, Item,
|
||||
MovementState::*, PhysicsState, Stats, Vel,
|
||||
item, projectile, ActionState::*, Body, CharacterState, ControlEvent, Controller, Item,
|
||||
MovementState::*, PhysicsState, Projectile, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
};
|
||||
@ -127,6 +127,35 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
match stats.equipment.main {
|
||||
Some(Item::Tool {
|
||||
kind: item::Tool::Bow,
|
||||
..
|
||||
}) => {
|
||||
if controller.primary
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
{
|
||||
if let Wield { time_left } = character.action {
|
||||
if time_left == Duration::default() {
|
||||
// Immediately end the wield
|
||||
character.action = Idle;
|
||||
server_emitter.emit(ServerEvent::Shoot {
|
||||
entity,
|
||||
dir: controller.look_dir,
|
||||
projectile: Projectile {
|
||||
hit_ground: vec![projectile::Effect::Stick],
|
||||
hit_wall: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(10),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Item::Tool { .. }) => {
|
||||
// Attack
|
||||
if controller.primary
|
||||
|
@ -4,6 +4,7 @@ pub mod combat;
|
||||
pub mod controller;
|
||||
pub mod movement;
|
||||
pub mod phys;
|
||||
mod projectile;
|
||||
mod stats;
|
||||
|
||||
// External
|
||||
@ -14,6 +15,7 @@ const AGENT_SYS: &str = "agent_sys";
|
||||
const CONTROLLER_SYS: &str = "controller_sys";
|
||||
const PHYS_SYS: &str = "phys_sys";
|
||||
const MOVEMENT_SYS: &str = "movement_sys";
|
||||
const PROJECTILE_SYS: &str = "projectile_sys";
|
||||
const COMBAT_SYS: &str = "combat_sys";
|
||||
const STATS_SYS: &str = "stats_sys";
|
||||
const CLEANUP_SYS: &str = "cleanup_sys";
|
||||
@ -29,5 +31,6 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
PHYS_SYS,
|
||||
&[CONTROLLER_SYS, MOVEMENT_SYS, COMBAT_SYS, STATS_SYS],
|
||||
);
|
||||
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[PHYS_SYS]);
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
use {
|
||||
crate::{
|
||||
comp::{Body, Mass, Mounting, Ori, PhysicsState, Pos, Scale, Vel},
|
||||
comp::{Body, Mass, Mounting, Ori, PhysicsState, Pos, Scale, Sticky, Vel},
|
||||
event::{EventBus, LocalEvent},
|
||||
state::DeltaTime,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::ReadVol,
|
||||
},
|
||||
specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage},
|
||||
sphynx::Uid,
|
||||
vek::*,
|
||||
};
|
||||
|
||||
@ -41,10 +42,12 @@ pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
Read<'a, EventBus<LocalEvent>>,
|
||||
ReadStorage<'a, Scale>,
|
||||
ReadStorage<'a, Sticky>,
|
||||
ReadStorage<'a, Mass>,
|
||||
ReadStorage<'a, Body>,
|
||||
WriteStorage<'a, PhysicsState>,
|
||||
@ -58,10 +61,12 @@ impl<'a> System<'a> for Sys {
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
uids,
|
||||
terrain,
|
||||
dt,
|
||||
event_bus,
|
||||
scales,
|
||||
stickies,
|
||||
masses,
|
||||
bodies,
|
||||
mut physics_states,
|
||||
@ -74,9 +79,10 @@ impl<'a> System<'a> for Sys {
|
||||
let mut event_emitter = event_bus.emitter();
|
||||
|
||||
// Apply movement inputs
|
||||
for (entity, scale, _b, mut pos, mut vel, _ori, _) in (
|
||||
for (entity, scale, sticky, _b, mut pos, mut vel, _ori, _) in (
|
||||
&entities,
|
||||
scales.maybe(),
|
||||
stickies.maybe(),
|
||||
&bodies,
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
@ -86,6 +92,11 @@ impl<'a> System<'a> for Sys {
|
||||
.join()
|
||||
{
|
||||
let mut physics_state = physics_states.get(entity).cloned().unwrap_or_default();
|
||||
|
||||
if sticky.is_some() && (physics_state.on_wall.is_some() || physics_state.on_ground) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
|
||||
// Basic collision with terrain
|
||||
@ -322,19 +333,22 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Apply pushback
|
||||
for (pos, scale, mass, vel, _, _) in (
|
||||
for (pos, scale, mass, vel, _, _, physics) in (
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
masses.maybe(),
|
||||
&mut velocities,
|
||||
&bodies,
|
||||
!&mountings,
|
||||
&mut physics_states,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
let mass = mass.map(|m| m.0).unwrap_or(scale);
|
||||
for (pos_other, scale_other, mass_other, _, _) in (
|
||||
|
||||
for (other, pos_other, scale_other, mass_other, _, _) in (
|
||||
&uids,
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
masses.maybe(),
|
||||
@ -344,7 +358,12 @@ impl<'a> System<'a> for Sys {
|
||||
.join()
|
||||
{
|
||||
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
|
||||
|
||||
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
|
||||
if mass_other == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let diff = Vec2::<f32>::from(pos.0 - pos_other.0);
|
||||
|
||||
let collision_dist = 0.95 * (scale + scale_other);
|
||||
@ -357,6 +376,7 @@ impl<'a> System<'a> for Sys {
|
||||
let force = (collision_dist - diff.magnitude()) * 2.0 * mass_other
|
||||
/ (mass + mass_other);
|
||||
vel.0 += Vec3::from(diff.normalized()) * force;
|
||||
physics.touch_entity = Some(*other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
91
common/src/sys/projectile.rs
Normal file
91
common/src/sys/projectile.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::{
|
||||
comp::{projectile, HealthSource, Ori, PhysicsState, Projectile, Vel},
|
||||
event::{EventBus, ServerEvent},
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
/// This system is responsible for handling projectile effect triggers
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadStorage<'a, PhysicsState>,
|
||||
ReadStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
WriteStorage<'a, Projectile>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
server_bus,
|
||||
physics_states,
|
||||
velocities,
|
||||
mut orientations,
|
||||
mut projectiles,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_bus.emitter();
|
||||
|
||||
let mut todo = Vec::new();
|
||||
|
||||
// Attacks
|
||||
for (entity, physics, ori, projectile) in (
|
||||
&entities,
|
||||
&physics_states,
|
||||
&mut orientations,
|
||||
&mut projectiles,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Hit entity
|
||||
if let Some(other) = physics.touch_entity {
|
||||
for effect in projectile.hit_entity.drain(..) {
|
||||
match effect {
|
||||
projectile::Effect::Damage(power) => {
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
uid: other,
|
||||
dmg: power,
|
||||
cause: HealthSource::Projectile,
|
||||
})
|
||||
}
|
||||
projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy {
|
||||
entity,
|
||||
cause: HealthSource::World,
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
todo.push(entity);
|
||||
}
|
||||
// Hit ground
|
||||
else if physics.on_ground {
|
||||
for effect in projectile.hit_ground.drain(..) {
|
||||
match effect {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
todo.push(entity);
|
||||
}
|
||||
// Hit wall
|
||||
else if physics.on_wall.is_some() {
|
||||
for effect in projectile.hit_wall.drain(..) {
|
||||
match effect {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
todo.push(entity);
|
||||
} else {
|
||||
if let Some(vel) = velocities.get(entity) {
|
||||
ori.0 = vel.0.normalized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for entity in todo {
|
||||
projectiles.remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
for (entity, mut stat) in (&entities, &mut stats).join() {
|
||||
if stat.should_die() && !stat.is_dead {
|
||||
event_emitter.emit(ServerEvent::Die {
|
||||
event_emitter.emit(ServerEvent::Destroy {
|
||||
entity,
|
||||
cause: match stat.health.last_change {
|
||||
Some(change) => change.2,
|
||||
|
@ -203,14 +203,18 @@ impl Server {
|
||||
pos: comp::Pos,
|
||||
vel: comp::Vel,
|
||||
body: comp::Body,
|
||||
projectile: comp::Projectile,
|
||||
) -> EcsEntityBuilder {
|
||||
state
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(vel)
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Ori(vel.0.normalized()))
|
||||
.with(comp::Mass(0.0))
|
||||
.with(body)
|
||||
.with(projectile)
|
||||
.with(comp::Sticky)
|
||||
}
|
||||
|
||||
pub fn create_player_character(
|
||||
@ -288,7 +292,11 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
ServerEvent::Shoot(entity) => {
|
||||
ServerEvent::Shoot {
|
||||
entity,
|
||||
dir,
|
||||
projectile,
|
||||
} => {
|
||||
let pos = state
|
||||
.ecs()
|
||||
.read_storage::<comp::Pos>()
|
||||
@ -298,13 +306,23 @@ impl Server {
|
||||
Self::create_projectile(
|
||||
state,
|
||||
comp::Pos(pos),
|
||||
comp::Vel(Vec3::new(0.0, 100.0, 3.0)),
|
||||
comp::Body::Object(comp::object::Body::Bomb),
|
||||
comp::Vel(dir * 100.0),
|
||||
comp::Body::Object(comp::object::Body::Arrow),
|
||||
projectile,
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
ServerEvent::Die { entity, cause } => {
|
||||
ServerEvent::Damage { uid, dmg, cause } => {
|
||||
let ecs = state.ecs_mut();
|
||||
if let Some(entity) = ecs.entity_from_uid(uid.into()) {
|
||||
if let Some(stats) = ecs.write_storage::<comp::Stats>().get_mut(entity) {
|
||||
stats.health.change_by(-(dmg as i32), cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServerEvent::Destroy { entity, cause } => {
|
||||
let ecs = state.ecs_mut();
|
||||
// Chat message
|
||||
if let Some(player) = ecs.read_storage::<comp::Player>().get(entity) {
|
||||
@ -327,7 +345,7 @@ impl Server {
|
||||
clients.notify_registered(ServerMsg::kill(msg));
|
||||
}
|
||||
|
||||
// Give EXP to the client
|
||||
// Give EXP to the killer if entity had stats
|
||||
let mut stats = ecs.write_storage::<comp::Stats>();
|
||||
|
||||
if let Some(entity_stats) = stats.get(entity).cloned() {
|
||||
@ -530,7 +548,7 @@ impl Server {
|
||||
"Humanoid".to_string(),
|
||||
Some(comp::Item::Tool {
|
||||
kind: comp::item::Tool::Sword,
|
||||
power: 10,
|
||||
power: 5,
|
||||
}),
|
||||
);
|
||||
let body = comp::Body::Humanoid(comp::humanoid::Body::random());
|
||||
|
@ -62,7 +62,7 @@ impl Animation for CidleAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_x(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
match Tool::Hammer {
|
||||
match Tool::Bow {
|
||||
//TODO: Inventory
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
@ -187,27 +187,31 @@ impl Animation for CidleAnimation {
|
||||
}
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
-4.0 + wave_ultra_slow_cos * 1.0,
|
||||
5.0 + wave_ultra_slow_cos * 0.5,
|
||||
0.0 + wave_ultra_slow * 1.0,
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.9)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
next.r_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.0 + wave_ultra_slow_cos * 0.5,
|
||||
-2.0 + wave_ultra_slow * 1.0,
|
||||
2.0 + wave_ultra_slow_cos * 1.0,
|
||||
8.0 + wave_ultra_slow_cos * 0.5,
|
||||
-3.5 + wave_ultra_slow * 1.0,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.r_hand.scale = Vec3::one() * 1.01;
|
||||
next.weapon.offset = Vec3::new(
|
||||
-6.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0,
|
||||
4.5 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5,
|
||||
0.0 + wave_ultra_slow * 1.0,
|
||||
9.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0,
|
||||
10.0 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5,
|
||||
-3.0 + wave_ultra_slow * 1.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Tool::Daggers => {
|
||||
|
@ -41,7 +41,7 @@ impl Animation for WieldAnimation {
|
||||
* 0.1,
|
||||
);
|
||||
|
||||
match Tool::Hammer {
|
||||
match Tool::Bow {
|
||||
//TODO: Inventory
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.75, 0.25);
|
||||
@ -133,20 +133,32 @@ impl Animation for WieldAnimation {
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0);
|
||||
next.r_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.01;
|
||||
next.weapon.offset = Vec3::new(
|
||||
-6.0 + skeleton_attr.weapon_x,
|
||||
4.5 + skeleton_attr.weapon_y,
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-4.0,
|
||||
5.0,
|
||||
0.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.9)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
next.r_hand.offset = Vec3::new(
|
||||
2.0,
|
||||
8.0,
|
||||
-3.5,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.r_hand.scale = Vec3::one() * 1.01;
|
||||
next.weapon.offset = Vec3::new(
|
||||
9.0 + skeleton_attr.weapon_x,
|
||||
10.0 + skeleton_attr.weapon_y,
|
||||
-3.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85+3.14);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Tool::Daggers => {
|
||||
|
@ -22,7 +22,7 @@ impl Animation for WieldAnimation {
|
||||
|
||||
let wave = (anim_time as f32 * 12.0).sin();
|
||||
|
||||
match Tool::Hammer {
|
||||
match Tool::Bow {
|
||||
//TODO: Inventory
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.75, 0.25);
|
||||
@ -114,20 +114,24 @@ impl Animation for WieldAnimation {
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.offset = Vec3::new(-4.0, 5.0, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.9)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0);
|
||||
next.r_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.r_hand.offset = Vec3::new(2.0, 8.0, -3.5);
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.r_hand.scale = Vec3::one() * 1.01;
|
||||
next.weapon.offset = Vec3::new(
|
||||
-6.0 + skeleton_attr.weapon_x,
|
||||
4.5 + skeleton_attr.weapon_y,
|
||||
0.0,
|
||||
9.0 + skeleton_attr.weapon_x,
|
||||
10.0 + skeleton_attr.weapon_y,
|
||||
-3.0,
|
||||
);
|
||||
next.weapon.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.ori = Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
* Quaternion::rotation_z(0.85);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Tool::Daggers => {
|
||||
|
@ -880,18 +880,18 @@ impl CharSelectionUi {
|
||||
self.imgs.icon_border
|
||||
})
|
||||
.middle_of(self.ids.bow)
|
||||
//.hover_image(self.imgs.icon_border_mo)
|
||||
//.press_image(self.imgs.icon_border_press)
|
||||
//.with_tooltip(tooltip_manager, "Bow", "", &tooltip_human)
|
||||
.hover_image(self.imgs.icon_border_mo)
|
||||
.press_image(self.imgs.icon_border_press)
|
||||
.with_tooltip(tooltip_manager, "Bow", "", &tooltip_human)
|
||||
.set(self.ids.bow_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
//self.character_tool = Some(Tool::Bow);
|
||||
self.character_tool = Some(Tool::Bow);
|
||||
}
|
||||
// REMOVE THIS AFTER IMPLEMENTATION
|
||||
Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
.middle_of(self.ids.bow)
|
||||
.set(self.ids.bow_grey, ui_widgets);
|
||||
/*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
.middle_of(self.ids.bow)
|
||||
.set(self.ids.bow_grey, ui_widgets);*/
|
||||
// Staff
|
||||
Image::new(self.imgs.staff)
|
||||
.w_h(70.0, 70.0)
|
||||
|
@ -357,8 +357,8 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh<FigurePipeline> {
|
||||
Tool::Hammer => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::Daggers => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::SwordShield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
Tool::Bow => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::Bow => ("weapon.bow.simple-bow", Vec3::new(-1.0, -6.0, -2.0)),
|
||||
Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
},
|
||||
Item::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)),
|
||||
_ => return Mesh::new(),
|
||||
@ -581,6 +581,7 @@ pub fn mesh_object(obj: object::Body) -> Mesh<FigurePipeline> {
|
||||
use object::Body;
|
||||
|
||||
let (name, offset) = match obj {
|
||||
Body::Arrow => ("weapon.bow.simple-arrow", Vec3::new(-5.5, -5.5, 0.0)),
|
||||
Body::Bomb => ("object.bomb", Vec3::new(-5.5, -5.5, 0.0)),
|
||||
Body::Scarecrow => ("object.scarecrow", Vec3::new(-9.5, -4.0, 0.0)),
|
||||
Body::Cauldron => ("object.cauldron", Vec3::new(-10.0, -10.0, 0.0)),
|
||||
|
@ -62,10 +62,9 @@ impl FigureMgr {
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, pos, vel, ori, scale, body, character, last_character, stats) in (
|
||||
for (entity, pos, ori, scale, body, character, last_character, stats) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
&ecs.read_storage::<Vel>(),
|
||||
&ecs.read_storage::<Ori>(),
|
||||
ecs.read_storage::<Scale>().maybe(),
|
||||
&ecs.read_storage::<Body>(),
|
||||
@ -130,6 +129,12 @@ impl FigureMgr {
|
||||
let mut movement_animation_rate = 1.0;
|
||||
let mut action_animation_rate = 1.0;
|
||||
|
||||
let vel = ecs
|
||||
.read_storage::<Vel>()
|
||||
.get(entity)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
match body {
|
||||
Body::Humanoid(_) => {
|
||||
let state = self
|
||||
@ -421,10 +426,9 @@ impl FigureMgr {
|
||||
.read_storage::<common::comp::CharacterState>();
|
||||
let character_state = character_state_storage.get(client.entity());
|
||||
|
||||
for (entity, _, _, _, body, stats, _) in (
|
||||
for (entity, _, _, body, stats, _) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
&ecs.read_storage::<Vel>(),
|
||||
&ecs.read_storage::<Ori>(),
|
||||
&ecs.read_storage::<Body>(),
|
||||
ecs.read_storage::<Stats>().maybe(),
|
||||
@ -432,7 +436,7 @@ impl FigureMgr {
|
||||
)
|
||||
.join()
|
||||
// Don't render figures outside of frustum (camera viewport, max draw distance is farplane)
|
||||
.filter(|(_, pos, _, _, _, _, scale)| {
|
||||
.filter(|(_, pos, _, _, _, scale)| {
|
||||
frustum.sphere_intersecting(
|
||||
&pos.0.x,
|
||||
&pos.0.y,
|
||||
@ -441,7 +445,7 @@ impl FigureMgr {
|
||||
)
|
||||
})
|
||||
// Don't render dead entities
|
||||
.filter(|(_, _, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead))
|
||||
.filter(|(_, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead))
|
||||
{
|
||||
if let Some((locals, bone_consts)) = match body {
|
||||
Body::Humanoid(_) => self
|
||||
|
Loading…
Reference in New Issue
Block a user