diff --git a/assets/voxygen/font/alkhemikal.ttf b/assets/voxygen/font/Alkhemikal.ttf similarity index 100% rename from assets/voxygen/font/alkhemikal.ttf rename to assets/voxygen/font/Alkhemikal.ttf diff --git a/assets/voxygen/voxel/weapon/bow/simple-arrow.vox b/assets/voxygen/voxel/weapon/bow/simple-arrow.vox new file mode 100644 index 0000000000..4cfe04e2da --- /dev/null +++ b/assets/voxygen/voxel/weapon/bow/simple-arrow.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cb25e13383c652a6b1cd27282db67ed86f1954e784e4d645d676df125742a9a +size 55647 diff --git a/assets/voxygen/voxel/weapon/bow/simple-bow.vox b/assets/voxygen/voxel/weapon/bow/simple-bow.vox new file mode 100644 index 0000000000..0f80a4d007 --- /dev/null +++ b/assets/voxygen/voxel/weapon/bow/simple-bow.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:758753476c3d81f0fb81acbfe469cf1c349ac2a24f9626f2a74675e414ba04c4 +size 55928 diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs index dca036f425..ad0ceb8ea4 100644 --- a/common/src/comp/body/object.rs +++ b/common/src/comp/body/object.rs @@ -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, diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index caaec49b8e..f9869ead91 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -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 } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index fb04b9f253..0ded6a15a8 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -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; diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs index eb22625800..b1c71b223a 100644 --- a/common/src/comp/phys.rs +++ b/common/src/comp/phys.rs @@ -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>; } +#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct Sticky; + +impl Component for Sticky { + type Storage = FlaggedStorage>; +} + // PhysicsState #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct PhysicsState { pub on_ground: bool, pub on_wall: Option>, + pub touch_entity: Option, pub in_fluid: bool, } diff --git a/common/src/comp/projectile.rs b/common/src/comp/projectile.rs new file mode 100644 index 0000000000..4b9c7d0bb9 --- /dev/null +++ b/common/src/comp/projectile.rs @@ -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, + pub hit_wall: Vec, + pub hit_entity: Vec, +} + +impl Component for Projectile { + type Storage = FlaggedStorage>; +} diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 1a97e59ae8..37adfed283 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -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, diff --git a/common/src/event.rs b/common/src/event.rs index 4fb1bc4c09..623a546057 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -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, 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, + projectile: comp::Projectile, + }, Mount(EcsEntity, EcsEntity), Unmount(EcsEntity), } diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index 2b129023a3..d0f4c3839b 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -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 for EcsCompPhantom @@ -50,6 +52,8 @@ sphynx::sum_type! { MountState(PhantomData), Mounting(PhantomData), Mass(PhantomData), + Projectile(PhantomData), + Sticky(PhantomData), } } impl sphynx::CompPacket for EcsCompPacket { diff --git a/common/src/state.rs b/common/src/state.rs index 488bd91a06..cab489eb5b 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -132,6 +132,8 @@ impl State { ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); + ecs.register_synced::(); + ecs.register_synced::(); // Register components send from clients -> server ecs.register::(); diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index c5372d2425..1b586bdf22 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -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>, + Read<'a, EventBus>, 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 }, + }); } } } diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs index 23d5304dca..4300513aa5 100644 --- a/common/src/sys/controller.rs +++ b/common/src/sys/controller.rs @@ -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 diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index adeee4c759..f9f154c82d 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -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]); } diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index e63234a5c1..462e0038f0 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -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>, 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::::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); } } } diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs new file mode 100644 index 0000000000..f2ade8f972 --- /dev/null +++ b/common/src/sys/projectile.rs @@ -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>, + 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); + } + } +} diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index a943335970..5746777ef0 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -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, diff --git a/server/src/lib.rs b/server/src/lib.rs index fda74b059a..cc1b60f42a 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -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::() @@ -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::().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::().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::(); 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()); diff --git a/voxygen/src/anim/character/cidle.rs b/voxygen/src/anim/character/cidle.rs index f06292e8a8..d830c2396d 100644 --- a/voxygen/src/anim/character/cidle.rs +++ b/voxygen/src/anim/character/cidle.rs @@ -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 => { diff --git a/voxygen/src/anim/character/crun.rs b/voxygen/src/anim/character/crun.rs index 7f33c43187..2eeaaac20e 100644 --- a/voxygen/src/anim/character/crun.rs +++ b/voxygen/src/anim/character/crun.rs @@ -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 => { diff --git a/voxygen/src/anim/character/wield.rs b/voxygen/src/anim/character/wield.rs index ab1d1e2118..dece8f89bc 100644 --- a/voxygen/src/anim/character/wield.rs +++ b/voxygen/src/anim/character/wield.rs @@ -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 => { diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index e604ac55dd..dfdbca7078 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -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) diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 0b0765aff0..db34806be3 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -357,8 +357,8 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh { 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 { 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)), diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index b1c8b94d6c..aec533c3cf 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -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::(), - &ecs.read_storage::(), &ecs.read_storage::(), ecs.read_storage::().maybe(), &ecs.read_storage::(), @@ -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::() + .get(entity) + .cloned() + .unwrap_or_default(); + match body { Body::Humanoid(_) => { let state = self @@ -421,10 +426,9 @@ impl FigureMgr { .read_storage::(); let character_state = character_state_storage.get(client.entity()); - for (entity, _, _, _, body, stats, _) in ( + for (entity, _, _, body, stats, _) in ( &ecs.entities(), &ecs.read_storage::(), - &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), ecs.read_storage::().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