Merge branch 'timo-bow' into 'master'

Timo bow

See merge request veloren/veloren!513
This commit is contained in:
Timo Koesters 2019-10-04 20:09:29 +00:00
commit 74239c5346
25 changed files with 359 additions and 106 deletions

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

Binary file not shown.

View File

@ -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,

View File

@ -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
}

View File

@ -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;

View File

@ -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,
}

View 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>>;
}

View File

@ -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,

View File

@ -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),
}

View File

@ -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 {

View File

@ -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>();

View File

@ -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 },
});
}
}
}

View File

@ -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

View File

@ -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]);
}

View File

@ -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);
}
}
}

View 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);
}
}
}

View File

@ -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,

View File

@ -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());

View File

@ -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 => {

View File

@ -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 => {

View File

@ -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 => {

View File

@ -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)

View File

@ -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)),

View File

@ -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