From 26da091b0bc427e6070d5fb6bd0f22bd3ea12bad Mon Sep 17 00:00:00 2001 From: jshipsey Date: Sat, 25 May 2019 23:31:41 -0400 Subject: [PATCH] add wolf Former-commit-id: b16aa2e7c382710c0705371cd36d57ddf62cf13c --- assets/voxygen/voxel/npc/wolf/wolf_ears.vox | 3 + assets/voxygen/voxel/npc/wolf/wolf_jaw.vox | 3 + .../voxygen/voxel/npc/wolf/wolf_lb_foot.vox | 3 + .../voxygen/voxel/npc/wolf/wolf_lf_foot.vox | 3 + .../voxel/npc/wolf/wolf_lower_head.vox | 3 + .../voxygen/voxel/npc/wolf/wolf_rb_foot.vox | 3 + .../voxygen/voxel/npc/wolf/wolf_rf_foot.vox | 3 + assets/voxygen/voxel/npc/wolf/wolf_tail.vox | 3 + .../voxel/npc/wolf/wolf_torso_back.vox | 3 + .../voxygen/voxel/npc/wolf/wolf_torso_mid.vox | 3 + .../voxel/npc/wolf/wolf_upper_head.vox | 3 + common/src/comp/actor.rs | 111 +++++++++++ common/src/comp/mod.rs | 3 + server/src/cmd.rs | 41 +++- voxygen/src/anim/mod.rs | 1 + voxygen/src/anim/quadrupedmedium/idle.rs | 105 ++++++++++ voxygen/src/anim/quadrupedmedium/jump.rs | 84 ++++++++ voxygen/src/anim/quadrupedmedium/mod.rs | 92 +++++++++ voxygen/src/anim/quadrupedmedium/run.rs | 116 +++++++++++ voxygen/src/scene/figure.rs | 185 +++++++++++++++++- 20 files changed, 759 insertions(+), 12 deletions(-) create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_ears.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_jaw.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_rb_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_tail.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_torso_back.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_upper_head.vox create mode 100644 voxygen/src/anim/quadrupedmedium/idle.rs create mode 100644 voxygen/src/anim/quadrupedmedium/jump.rs create mode 100644 voxygen/src/anim/quadrupedmedium/mod.rs create mode 100644 voxygen/src/anim/quadrupedmedium/run.rs diff --git a/assets/voxygen/voxel/npc/wolf/wolf_ears.vox b/assets/voxygen/voxel/npc/wolf/wolf_ears.vox new file mode 100644 index 0000000000..7f1ef0d71a --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_ears.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:894814110d328942a5d4beb13d5152c2e30a6d25466b73996b87858d8173626b +size 1160 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_jaw.vox b/assets/voxygen/voxel/npc/wolf/wolf_jaw.vox new file mode 100644 index 0000000000..95485232fe --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_jaw.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f4e6f80a06a74930b13b44973253ff9617e0b3e52c5b8965db42b2015e031bc +size 1280 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox new file mode 100644 index 0000000000..ce27f62f42 --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b36a638e9ddd22b7edbb69194bd7867c97353374dad24110346ca71a71d51e36 +size 1344 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox new file mode 100644 index 0000000000..3d032fd351 --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6569c6bcc2cdab88950bc2e50bfb3033c0f12c87032f248995d324e4f4241a75 +size 1344 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox b/assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox new file mode 100644 index 0000000000..8d6190af5d --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79402309388f714c412daf46cb6ca1c4c57751c9cd4c11f627cf1d5da861c909 +size 3552 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_rb_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_rb_foot.vox new file mode 100644 index 0000000000..d9177dbe6c --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_rb_foot.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:553e8b5c04dc87766fd9c12da28f5ed32b6dc0c6726b8ff9d947219353a943de +size 1344 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox new file mode 100644 index 0000000000..9b3638294b --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a5edbc41efd7406f88129ab9973bf167067cd3ffe8d358cc8c11201d60195fa +size 1344 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_tail.vox b/assets/voxygen/voxel/npc/wolf/wolf_tail.vox new file mode 100644 index 0000000000..cdf00babd5 --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_tail.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ccd769ae44f888daa53097161ef440c93805479224094fa25d31f1c7a0e76ce +size 1672 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_torso_back.vox b/assets/voxygen/voxel/npc/wolf/wolf_torso_back.vox new file mode 100644 index 0000000000..b893688dba --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_torso_back.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1543beca2bc9487d5f85035d481f118a2863ccf3c7f0ca5a709ae5e1bb3d8d04 +size 5504 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox b/assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox new file mode 100644 index 0000000000..29b2d1bfb0 --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d268d096fb5f69d0d1eb693595112c3e095e492a311eeffcbe0cd2459da7591 +size 5932 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_upper_head.vox b/assets/voxygen/voxel/npc/wolf/wolf_upper_head.vox new file mode 100644 index 0000000000..8ff0fca5b3 --- /dev/null +++ b/assets/voxygen/voxel/npc/wolf/wolf_upper_head.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc326cdab30057cac8a204d43ae4007985ca38d21c6a9f734ac8c50cb74dfed8 +size 4656 diff --git a/common/src/comp/actor.rs b/common/src/comp/actor.rs index 60cf6941e7..acebc8bb57 100644 --- a/common/src/comp/actor.rs +++ b/common/src/comp/actor.rs @@ -101,6 +101,57 @@ pub enum PigLegL { pub enum PigLegR { Default, } +///// +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfUpperHead { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfJaw { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfLowerHead { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfTail { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfTorsoBack { + Default, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfTorsoMid { + Default, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfEars { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfLFFoot { + Default, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfRFFoot { + Default, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfLBFoot { + Default, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum WolfRBFoot { + Default, +} pub const ALL_RACES: [Race; 6] = [ Race::Danari, @@ -178,6 +229,7 @@ impl HumanoidBody { } } } +/////////// const ALL_QRACES: [Race; 6] = [ Race::Danari, Race::Dwarf, @@ -214,11 +266,70 @@ impl QuadrupedBody { } } } +///////////// +const ALL_QMRACES: [Race; 6] = [ + Race::Danari, + Race::Dwarf, + Race::Elf, + Race::Human, + Race::Orc, + Race::Undead, +]; +const ALL_QMBODY_TYPES: [BodyType; 3] = [BodyType::Female, BodyType::Male, BodyType::Unspecified]; +const ALL_QMWOLF_UPPERHEADS: [WolfUpperHead; 1] = [WolfUpperHead::Default]; +const ALL_QMWOLF_JAWS: [WolfJaw; 1] = [WolfJaw::Default]; +const ALL_QMWOLF_LOWERHEADS: [WolfLowerHead; 1] = [WolfLowerHead::Default]; +const ALL_QMWOLF_TAILS: [WolfTail; 1] = [WolfTail::Default]; +const ALL_QMWOLF_TORSOBACKS: [WolfTorsoBack; 1] = [WolfTorsoBack::Default]; +const ALL_QMWOLF_TORSOMIDS: [WolfTorsoMid; 1] = [WolfTorsoMid::Default]; +const ALL_QMWOLF_EARS: [WolfEars; 1] = [WolfEars::Default]; +const ALL_QMWOLF_LFFEET: [WolfLFFoot; 1] = [WolfLFFoot::Default]; +const ALL_QMWOLF_RFFEET: [WolfRFFoot; 1] = [WolfRFFoot::Default]; +const ALL_QMWOLF_LBFEET: [WolfLBFoot; 1] = [WolfLBFoot::Default]; +const ALL_QMWOLF_RBFEET: [WolfRBFoot; 1] = [WolfRBFoot::Default]; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct QuadrupedMediumBody { + pub race: Race, + pub body_type: BodyType, + pub wolf_upperhead: WolfUpperHead, + pub wolf_jaw: WolfJaw, + pub wolf_lowerhead: WolfLowerHead, + pub wolf_tail: WolfTail, + pub wolf_torsoback: WolfTorsoBack, + pub wolf_torsomid: WolfTorsoMid, + pub wolf_ears: WolfEars, + pub wolf_lffoot: WolfLFFoot, + pub wolf_rffoot: WolfRFFoot, + pub wolf_lbfoot: WolfLBFoot, + pub wolf_rbfoot: WolfRBFoot, +} + +impl QuadrupedMediumBody { + pub fn random() -> Self { + Self { + race: *thread_rng().choose(&ALL_QMRACES).unwrap(), + body_type: *thread_rng().choose(&ALL_QMBODY_TYPES).unwrap(), + wolf_upperhead: *thread_rng().choose(&ALL_QMWOLF_UPPERHEADS).unwrap(), + wolf_jaw: *thread_rng().choose(&ALL_QMWOLF_JAWS).unwrap(), + wolf_lowerhead: *thread_rng().choose(&ALL_QMWOLF_LOWERHEADS).unwrap(), + wolf_tail: *thread_rng().choose(&ALL_QMWOLF_TAILS).unwrap(), + wolf_torsoback: *thread_rng().choose(&ALL_QMWOLF_TORSOBACKS).unwrap(), + wolf_torsomid: *thread_rng().choose(&ALL_QMWOLF_TORSOMIDS).unwrap(), + wolf_ears: *thread_rng().choose(&ALL_QMWOLF_EARS).unwrap(), + wolf_lffoot: *thread_rng().choose(&ALL_QMWOLF_LFFEET).unwrap(), + wolf_rffoot: *thread_rng().choose(&ALL_QMWOLF_RFFEET).unwrap(), + wolf_lbfoot: *thread_rng().choose(&ALL_QMWOLF_LBFEET).unwrap(), + wolf_rbfoot: *thread_rng().choose(&ALL_QMWOLF_RBFEET).unwrap(), + } + } +} #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Body { Humanoid(HumanoidBody), Quadruped(QuadrupedBody), + QuadrupedMedium(QuadrupedMediumBody), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 03fb57f617..8de7e629d3 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -11,6 +11,7 @@ pub use actor::Actor; pub use actor::Body; pub use actor::HumanoidBody; pub use actor::QuadrupedBody; +pub use actor::QuadrupedMediumBody; pub use agent::Agent; pub use animation::Animation; pub use animation::AnimationInfo; @@ -19,6 +20,8 @@ pub use inputs::Control; pub use inputs::Gliding; pub use inputs::Jumping; pub use inputs::Respawning; +pub use agent::{Agent, Control}; +>>>>>>> add wolf pub use player::Player; pub use stats::Dying; pub use stats::Stats; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 1c420cc701..bc8f64e740 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -82,10 +82,16 @@ lazy_static! { handle_kill ), ChatCommand::new( - "pet", + "pig", "{}", - "/pet : Spawn a test pet NPC", - handle_pet + "/pig : Spawn a test pig NPC", + handle_petpig + ), + ChatCommand::new( + "wolf", + "{}", + "/wolf : Spawn a test wolf NPC", + handle_petwolf ), ChatCommand::new( "help", "", "/help: Display this message", handle_help) @@ -206,7 +212,7 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat } } -fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { +fn handle_petpig(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { match server .state .read_component_cloned::(entity) @@ -233,6 +239,33 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), } } +fn handle_petwolf(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { + match server + .state + .read_component_cloned::(entity) + { + Some(pos) => { + server + .create_npc( + "Tobermory".to_owned(), + comp::Body::QuadrupedMedium(comp::QuadrupedMediumBody::random()), + ) + .with(comp::Control::default()) + .with(comp::Agent::Pet { + target: entity, + offset: Vec2::zero(), + }) + .with(pos) + .build(); + server + .clients + .notify(entity, ServerMsg::Chat("Spawned pet!".to_owned())); + } + None => server + .clients + .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), + } +} fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) { for cmd in CHAT_COMMANDS.iter() { diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index 7bbee6358b..6908d9b002 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -1,3 +1,4 @@ +pub mod QuadrupedMedium; pub mod character; pub mod fixture; pub mod quadruped; diff --git a/voxygen/src/anim/quadrupedmedium/idle.rs b/voxygen/src/anim/quadrupedmedium/idle.rs new file mode 100644 index 0000000000..3bbfa0d7ef --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/idle.rs @@ -0,0 +1,105 @@ +// Standard +use std::{f32::consts::PI, ops::Mul}; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct IdleAnimation; + +impl Animation for IdleAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_dip = (wave_slow.abs() - 0.5).abs(); + + let wolf_look = Vec2::new( + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(7331.0) + .sin() + * 0.5, + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(1337.0) + .sin() + * 0.25, + ); + let wolf_tail = Vec2::new( + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + + next.wolf_upperhead.offset = Vec3::new(0.0, 7.5, 15.0 + wave_ultra_slow * 0.4) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_z(wolf_look.x) * Quaternion::rotation_x(wolf_look.y); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = + Vec3::new(0.0, 4.5 - wave_ultra_slow_cos * 0.12, 2.0 + wave_slow * 0.2); + next.wolf_jaw.ori = Quaternion::rotation_x(wave_slow * 0.05); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5 + wave_ultra_slow * 0.20); + next.wolf_lowerhead.ori = Quaternion::rotation_z(0.0); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -13.0, 8.0 + wave_ultra_slow * 1.2) / 11.0; + next.wolf_tail.ori = Quaternion::rotation_z(0.0 + wave_slow * 0.2 + wolf_tail.x) + * Quaternion::rotation_x(wolf_tail.y); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = Vec3::new(0.0, -9.5, 11.0 + wave_ultra_slow * 1.2) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_y(wave_slow_cos * 0.015); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = Vec3::new(0.0, 0.0, 12.0 + wave_ultra_slow * 0.7) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_y(wave_slow * 0.015); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(0.0 + wave_slow * 0.1); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = Vec3::new(-5.0, 5.0, 2.5) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = Vec3::new(5.0, 5.0, 2.5) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = Vec3::new(-5.0, -10.0, 2.5) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = Vec3::new(5.0, -10.0, 2.5) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/anim/quadrupedmedium/jump.rs b/voxygen/src/anim/quadrupedmedium/jump.rs new file mode 100644 index 0000000000..0ed7c70ee8 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/jump.rs @@ -0,0 +1,84 @@ +// Standard +use std::f32::consts::PI; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct JumpAnimation; + +impl Animation for JumpAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f32, f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_stop = (anim_time as f32 * 5.0).min(PI / 2.0).sin(); + + next.wolf_upperhead.offset = Vec3::new(0.0, 7.5, 15.0 + wave_stop * 4.8) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_z(0.0) * Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = Vec3::new(0.0, 4.5, 2.0); + next.wolf_jaw.ori = Quaternion::rotation_x(0.0); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5); + next.wolf_lowerhead.ori = Quaternion::rotation_x(wave_stop * -0.1); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -12.0, 8.0) / 11.0; + next.wolf_tail.ori = + Quaternion::rotation_z(0.0) * Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = + Vec3::new(0.0, -9.5 + wave_stop * 1.0, 11.0 + wave_stop * 2.2) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = Vec3::new(0.0, 0.0, 12.0 + wave_stop * 3.6) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(0.0); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = + Vec3::new(-5.0, 5.0 + wave_stop * 3.0, 5.0 + wave_stop * 7.0) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(wave_stop * 1.0 + wave * 0.15); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = + Vec3::new(5.0, 5.0 - wave_stop * 3.0, 5.0 + wave_stop * 5.0) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(wave_stop * -1.0 + wave * 0.15); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = + Vec3::new(-5.0, -10.0 - wave_stop * 2.0, 5.0 + wave_stop * 0.0) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(wave_stop * -1.0 + wave * 0.15); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = + Vec3::new(5.0, -10.0 + wave_stop * 2.0, 5.0 + wave_stop * 2.0) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(wave_stop * 1.0 + wave * 0.15); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/anim/quadrupedmedium/mod.rs b/voxygen/src/anim/quadrupedmedium/mod.rs new file mode 100644 index 0000000000..78ec5764a6 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/mod.rs @@ -0,0 +1,92 @@ +pub mod idle; +pub mod jump; +pub mod run; + +// Reexports +pub use self::idle::IdleAnimation; +pub use self::jump::JumpAnimation; +pub use self::run::RunAnimation; + +// Crate +use crate::render::FigureBoneData; + +// Local +use super::{Bone, Skeleton}; + +const SCALE: f32 = 11.0; + +#[derive(Clone)] +pub struct QuadrupedMediumSkeleton { + wolf_upperhead: Bone, + wolf_jaw: Bone, + wolf_lowerhead: Bone, + wolf_tail: Bone, + wolf_torsoback: Bone, + wolf_torsomid: Bone, + wolf_ears: Bone, + wolf_LFFoot: Bone, + wolf_RFFoot: Bone, + wolf_LBFoot: Bone, + wolf_RBFoot: Bone, +} + +impl QuadrupedMediumSkeleton { + pub fn new() -> Self { + Self { + wolf_upperhead: Bone::default(), + wolf_jaw: Bone::default(), + wolf_lowerhead: Bone::default(), + wolf_tail: Bone::default(), + wolf_torsoback: Bone::default(), + wolf_torsomid: Bone::default(), + wolf_ears: Bone::default(), + wolf_LFFoot: Bone::default(), + wolf_RFFoot: Bone::default(), + wolf_LBFoot: Bone::default(), + wolf_RBFoot: Bone::default(), + } + } +} + +impl Skeleton for QuadrupedMediumSkeleton { + fn compute_matrices(&self) -> [FigureBoneData; 16] { + let ears_mat = self.wolf_ears.compute_base_matrix(); + let upperhead_mat = self.wolf_upperhead.compute_base_matrix(); + let lowerhead_mat = self.wolf_lowerhead.compute_base_matrix(); + + [ + FigureBoneData::new(upperhead_mat), + FigureBoneData::new( + upperhead_mat * lowerhead_mat * self.wolf_jaw.compute_base_matrix(), + ), + FigureBoneData::new(upperhead_mat * lowerhead_mat), + FigureBoneData::new(self.wolf_tail.compute_base_matrix()), + FigureBoneData::new(self.wolf_torsoback.compute_base_matrix()), + FigureBoneData::new(self.wolf_torsomid.compute_base_matrix()), + FigureBoneData::new(upperhead_mat * ears_mat), + FigureBoneData::new(self.wolf_LFFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_RFFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_LBFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_RBFoot.compute_base_matrix()), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + ] + } + + fn interpolate(&mut self, target: &Self) { + self.wolf_upperhead.interpolate(&target.wolf_upperhead); + self.wolf_jaw.interpolate(&target.wolf_jaw); + self.wolf_lowerhead.interpolate(&target.wolf_lowerhead); + self.wolf_tail.interpolate(&target.wolf_tail); + self.wolf_torsoback.interpolate(&target.wolf_torsoback); + self.wolf_torsomid.interpolate(&target.wolf_torsomid); + self.wolf_ears.interpolate(&target.wolf_ears); + self.wolf_LFFoot.interpolate(&target.wolf_LFFoot); + self.wolf_RFFoot.interpolate(&target.wolf_RFFoot); + self.wolf_LBFoot.interpolate(&target.wolf_LBFoot); + self.wolf_RBFoot.interpolate(&target.wolf_RBFoot); + } +} diff --git a/voxygen/src/anim/quadrupedmedium/run.rs b/voxygen/src/anim/quadrupedmedium/run.rs new file mode 100644 index 0000000000..f9ac6c77f0 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/run.rs @@ -0,0 +1,116 @@ +// Standard +use std::{f32::consts::PI, ops::Mul}; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct RunAnimation; + +impl Animation for RunAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f32, f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + (velocity, global_time): Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_dip = (wave_slow.abs() - 0.5).abs(); + let wave_quick = (anim_time as f32 * 18.0).sin(); + let wave_med = (anim_time as f32 * 12.0).sin(); + let wave_med_cos = (anim_time as f32 * 12.0).cos(); + + let wave_quick_cos = (anim_time as f32 * 18.0).cos(); + + let wolf_look = Vec2::new( + ((global_time + anim_time) as f32 / 4.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 4.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + let wolf_tail = Vec2::new( + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + + next.wolf_upperhead.offset = + Vec3::new(0.0, 9.5 + wave_quick_cos * 2.0, 15.0 + wave_med * 3.0) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_x(-0.12 + wave_quick_cos * 0.12 + wolf_look.y) + * Quaternion::rotation_z(wolf_look.x); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = Vec3::new(0.0, 4.5, 2.0 + wave_slow_cos * 1.0); + next.wolf_jaw.ori = Quaternion::rotation_x(wave_slow * 0.05); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5 + wave_med * 1.0); + next.wolf_lowerhead.ori = Quaternion::rotation_z(0.0); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -12.0, 10.0) / 11.0; + next.wolf_tail.ori = Quaternion::rotation_x(wave_quick * 0.18); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = + Vec3::new(0.0, -9.5 + wave_quick_cos * 2.2, 13.0 + wave_med * 2.8) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_x(-0.15 + wave_med_cos * 0.14); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = + Vec3::new(0.0, 0.0 + wave_quick_cos * 2.2, 14.0 + wave_med * 3.2) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_x(-0.15 + wave_med_cos * 0.12); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75 + wave * 0.4, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(wave * 0.2); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = + Vec3::new(-5.0, 5.0 + wave_quick * 3.0, 7.0 + wave_quick_cos * 4.0) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(0.0 + wave_quick * 0.8); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = + Vec3::new(5.0, 5.0 - wave_quick_cos * 3.0, 7.0 + wave_quick * 4.0) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(0.0 - wave_quick_cos * 0.8); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = + Vec3::new(-5.0, -10.0 - wave_quick_cos * 3.0, 7.0 + wave_quick * 4.0) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(0.0 - wave_quick_cos * 0.8); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = + Vec3::new(5.0, -10.0 + wave_quick * 3.0, 7.0 + wave_quick_cos * 4.0) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(0.0 + wave_quick * 0.8); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index fb57e018dd..171c7b09d2 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -2,7 +2,9 @@ use crate::{ anim::{ character::{self, CharacterSkeleton}, quadruped::{self, QuadrupedSkeleton}, - Animation, Skeleton, + Animation, + QuadrupedMedium::{self, QuadrupedMediumSkeleton}, + Skeleton, }, mesh::Meshable, render::{ @@ -17,9 +19,10 @@ use common::{ self, actor::{ Belt, Chest, Draw, Foot, Hand, Head, Pants, PigChest, PigHead, PigLegL, PigLegR, - Shoulder, Weapon, + Shoulder, Weapon, WolfEars, WolfJaw, WolfLBFoot, WolfLFFoot, WolfLowerHead, WolfRBFoot, + WolfRFFoot, WolfTail, WolfTorsoBack, WolfTorsoMid, WolfUpperHead, }, - Body, HumanoidBody, QuadrupedBody, + Body, HumanoidBody, QuadrupedBody, QuadrupedMediumBody, }, figure::Segment, msg, @@ -95,6 +98,24 @@ impl FigureModelCache { None, None, ], + Body::QuadrupedMedium(body) => [ + Some(Self::load_wolf_upperhead(body.wolf_upperhead)), + Some(Self::load_wolf_jaw(body.wolf_jaw)), + Some(Self::load_wolf_lowerhead(body.wolf_lowerhead)), + Some(Self::load_wolf_tail(body.wolf_tail)), + Some(Self::load_wolf_torsoback(body.wolf_torsoback)), + Some(Self::load_wolf_torsomid(body.wolf_torsomid)), + Some(Self::load_wolf_ears(body.wolf_ears)), + Some(Self::load_wolf_lffoot(body.wolf_lffoot)), + Some(Self::load_wolf_rffoot(body.wolf_rffoot)), + Some(Self::load_wolf_lbfoot(body.wolf_lbfoot)), + Some(Self::load_wolf_rbfoot(body.wolf_rbfoot)), + None, + None, + None, + None, + None, + ], }; let mut mesh = Mesh::new(); @@ -220,9 +241,9 @@ impl FigureModelCache { fn load_weapon(weapon: Weapon) -> Mesh { Self::load_mesh( match weapon { - Weapon::Sword => "weapon/sword/sword_wood_2h.vox", + Weapon::Sword => "weapon/sword/sword_rusty_2h.vox", // TODO actually match against other weapons and set the right model - _ => "weapon/sword/sword_wood_2h.vox", + _ => "weapon/sword/sword_rusty_2h.vox", }, Vec3::new(-6.5, -1.5, -4.0), ) @@ -258,8 +279,8 @@ impl FigureModelCache { fn load_left_equip(weapon: Weapon) -> Mesh { Self::load_mesh( match weapon { - Weapon::Sword => "weapon/sword/sword_wood_2h.vox", - _ => "weapon/sword/sword_wood_2h.vox", + Weapon::Sword => "weapon/sword/sword_rusty_2h.vox", + _ => "weapon/sword/sword_rusty_2h.vox", }, Vec3::new(-6.5, -1.5, -5.0), ) @@ -272,7 +293,7 @@ impl FigureModelCache { Vec3::new(-2.0, -2.5, -2.0), ) } - + ///////// fn load_pig_head(pig_head: PigHead) -> Mesh { Self::load_mesh( match pig_head { @@ -326,12 +347,102 @@ impl FigureModelCache { Vec3::new(0.0, -1.0, -1.5), ) } + ////// + fn load_wolf_upperhead(wolf_upperhead: WolfUpperHead) -> Mesh { + Self::load_mesh( + match wolf_upperhead { + WolfUpperHead::Default => "npc/wolf/wolf_upper_head.vox", + }, + Vec3::new(-7.0, -6.0, -5.5), + ) + } + fn load_wolf_jaw(wolf_jaw: WolfJaw) -> Mesh { + Self::load_mesh( + match wolf_jaw { + WolfJaw::Default => "npc/wolf/wolf_jaw.vox", + }, + Vec3::new(-3.0, -3.0, -2.5), + ) + } + fn load_wolf_lowerhead(wolf_lowerhead: WolfLowerHead) -> Mesh { + Self::load_mesh( + match wolf_lowerhead { + WolfLowerHead::Default => "npc/wolf/wolf_lower_head.vox", + }, + Vec3::new(-7.0, -6.0, -5.5), + ) + } + fn load_wolf_tail(wolf_tail: WolfTail) -> Mesh { + Self::load_mesh( + match wolf_tail { + WolfTail::Default => "npc/wolf/wolf_tail.vox", + }, + Vec3::new(-2.0, -12.0, -5.0), + ) + } + fn load_wolf_torsoback(wolf_torsoback: WolfTorsoBack) -> Mesh { + Self::load_mesh( + match wolf_torsoback { + WolfTorsoBack::Default => "npc/wolf/wolf_torso_back.vox", + }, + Vec3::new(-7.0, -6.0, -6.0), + ) + } + fn load_wolf_torsomid(wolf_torsomid: WolfTorsoMid) -> Mesh { + Self::load_mesh( + match wolf_torsomid { + WolfTorsoMid::Default => "npc/wolf/wolf_torso_mid.vox", + }, + Vec3::new(-8.0, -5.5, -6.0), + ) + } + fn load_wolf_ears(wolf_ears: WolfEars) -> Mesh { + Self::load_mesh( + match wolf_ears { + WolfEars::Default => "npc/wolf/wolf_ears.vox", + }, + Vec3::new(-4.0, -1.0, -1.0), + ) + } + fn load_wolf_lffoot(wolf_lffoot: WolfLFFoot) -> Mesh { + Self::load_mesh( + match wolf_lffoot { + WolfLFFoot::Default => "npc/wolf/wolf_lf_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_rffoot(wolf_rffoot: WolfRFFoot) -> Mesh { + Self::load_mesh( + match wolf_rffoot { + WolfRFFoot::Default => "npc/wolf/wolf_rf_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_lbfoot(wolf_lbfoot: WolfLBFoot) -> Mesh { + Self::load_mesh( + match wolf_lbfoot { + WolfLBFoot::Default => "npc/wolf/wolf_lb_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_rbfoot(wolf_rbfoot: WolfRBFoot) -> Mesh { + Self::load_mesh( + match wolf_rbfoot { + WolfRBFoot::Default => "npc/wolf/wolf_rb_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } } pub struct FigureMgr { model_cache: FigureModelCache, character_states: HashMap>, quadruped_states: HashMap>, + QuadrupedMedium_states: HashMap>, } impl FigureMgr { @@ -340,6 +451,7 @@ impl FigureMgr { model_cache: FigureModelCache::new(), character_states: HashMap::new(), quadruped_states: HashMap::new(), + QuadrupedMedium_states: HashMap::new(), } } @@ -440,6 +552,57 @@ impl FigureMgr { state.skeleton.interpolate(&target_skeleton); state.update(renderer, pos.0, dir.0, col); } + Body::QuadrupedMedium(body) => { + let state = + self.QuadrupedMedium_states + .entry(entity) + .or_insert_with(|| { + FigureState::new(renderer, QuadrupedMediumSkeleton::new()) + }); + + let target_skeleton = match animation_history.current { + comp::Animation::Run => QuadrupedMedium::RunAnimation::update_skeleton( + state.skeleton_mut(), + (vel.0.magnitude(), time), + animation_history.time, + ), + comp::Animation::Idle => { + QuadrupedMedium::IdleAnimation::update_skeleton( + state.skeleton_mut(), + time, + animation_history.time, + ) + } + comp::Animation::Jump => { + QuadrupedMedium::JumpAnimation::update_skeleton( + state.skeleton_mut(), + (vel.0.magnitude(), time), + animation_history.time, + ) + } + + // TODO! + _ => state.skeleton_mut().clone(), + }; + + state.skeleton.interpolate(&target_skeleton); + + // Change in health as color! + let col = stats + .and_then(|stats| stats.hp.last_change) + .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) + .unwrap_or(Rgba::broadcast(1.0)); + + // Change in health as color! + let col = stats + .and_then(|stats| stats.hp.last_change) + .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) + .unwrap_or(Rgba::broadcast(1.0)); + + state.update(renderer, pos.0, dir.0, col); + + state.update(renderer, pos.0, dir.0, col); + } }, // TODO: Non-character actors } @@ -450,6 +613,8 @@ impl FigureMgr { .retain(|entity, _| ecs.entities().is_alive(*entity)); self.quadruped_states .retain(|entity, _| ecs.entities().is_alive(*entity)); + self.QuadrupedMedium_states + .retain(|entity, _| ecs.entities().is_alive(*entity)); } pub fn render( @@ -483,6 +648,10 @@ impl FigureMgr { .quadruped_states .get(&entity) .map(|state| (state.locals(), state.bone_consts())), + Body::QuadrupedMedium(_) => self + .QuadrupedMedium_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), } { let model = self.model_cache.get_or_create_model(renderer, *body, tick);