diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 587b3f5b1f..553384db9f 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -167,6 +167,18 @@ impl CharacterState { ) } + pub fn is_using_hands(&self) -> bool { + matches!( + self, + CharacterState::Climb(_) + | CharacterState::Equipping(_) + | CharacterState::Dance + | CharacterState::Glide + | CharacterState::GlideWield + | CharacterState::Roll(_), + ) + } + pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock) } pub fn is_dodge(&self) -> bool { matches!(self, CharacterState::Roll(_)) } diff --git a/voxygen/anim/src/character/jump.rs b/voxygen/anim/src/character/jump.rs index 8d1742aaf4..7bf3948940 100644 --- a/voxygen/anim/src/character/jump.rs +++ b/voxygen/anim/src/character/jump.rs @@ -192,6 +192,16 @@ impl Animation for JumpAnimation { next.lantern.scale = Vec3::one() * 0.65; next.hold.scale = Vec3::one() * 0.0; + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new(s_a.hand.0, s_a.hand.1 + 5.0, s_a.hand.2 + 9.0); + next.hand_r.orientation = Quaternion::rotation_x(2.25) * Quaternion::rotation_z(0.9); + + next.lantern.position = Vec3::new(0.0, 0.0, -3.5); + next.lantern.orientation = next.hand_r.orientation.inverse() + * Quaternion::rotation_x(slow * 0.5) + * Quaternion::rotation_y(tilt * 4.0 * slow + tilt * 3.0); + } + next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler; next.torso.orientation = Quaternion::rotation_x(0.0); next.torso.scale = Vec3::one() / 11.0 * s_a.scaler; diff --git a/voxygen/anim/src/character/mod.rs b/voxygen/anim/src/character/mod.rs index 96fb1b01dc..a060291196 100644 --- a/voxygen/anim/src/character/mod.rs +++ b/voxygen/anim/src/character/mod.rs @@ -69,8 +69,19 @@ skeleton_impls!(struct CharacterSkeleton { control, control_l, control_r, + :: // Begin non-bone fields + holding_lantern: bool, }); +impl CharacterSkeleton { + pub fn new(holding_lantern: bool) -> Self { + Self { + holding_lantern, + ..Self::default() + } + } +} + impl Skeleton for CharacterSkeleton { type Attr = SkeletonAttr; type Body = Body; @@ -93,9 +104,14 @@ impl Skeleton for CharacterSkeleton { let control_mat = chest_mat * Mat4::::from(self.control); let control_l_mat = control_mat * Mat4::::from(self.control_l); let control_r_mat = control_mat * Mat4::::from(self.control_r); + let hand_r_mat = control_r_mat * Mat4::::from(self.hand_r); let hand_l_mat = Mat4::::from(self.hand_l); - let lantern_mat = Mat4::::from(self.lantern); + let lantern_mat = if self.holding_lantern { + hand_r_mat + } else { + shorts_mat + } * Mat4::::from(self.lantern); *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [ make_bone(head_mat), @@ -104,7 +120,7 @@ impl Skeleton for CharacterSkeleton { make_bone(chest_mat * Mat4::::from(self.back)), make_bone(shorts_mat), make_bone(control_l_mat * hand_l_mat), - make_bone(control_r_mat * Mat4::::from(self.hand_r)), + make_bone(hand_r_mat), make_bone(torso_mat * Mat4::::from(self.foot_l)), make_bone(torso_mat * Mat4::::from(self.foot_r)), make_bone(chest_mat * Mat4::::from(self.shoulder_l)), @@ -112,12 +128,11 @@ impl Skeleton for CharacterSkeleton { make_bone(chest_mat * Mat4::::from(self.glider)), make_bone(control_l_mat * Mat4::::from(self.main)), make_bone(control_r_mat * Mat4::::from(self.second)), - make_bone(shorts_mat * lantern_mat), + make_bone(lantern_mat), // FIXME: Should this be control_l_mat? make_bone(control_mat * hand_l_mat * Mat4::::from(self.hold)), ]; - // NOTE: lantern_mat.cols.w = lantern_mat * Vec4::unit_w() - Vec3::new(-0.3, 0.1, 0.8) + (lantern_mat.cols.w / 13.0).xyz() + (lantern_mat * Vec4::new(-0.0, -0.0, -1.5, 1.0)).xyz() } } diff --git a/voxygen/anim/src/character/run.rs b/voxygen/anim/src/character/run.rs index 5d5100f8d7..3c0afdbe14 100644 --- a/voxygen/anim/src/character/run.rs +++ b/voxygen/anim/src/character/run.rs @@ -256,6 +256,20 @@ impl Animation for RunAnimation { next.lantern.scale = Vec3::one() * 0.65; next.hold.scale = Vec3::one() * 0.0; + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0, + s_a.hand.1 + 5.0 - impact * 0.2, + s_a.hand.2 + 11.0 + impact * -0.1, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25) * Quaternion::rotation_z(0.9); + + next.lantern.position = Vec3::new(0.0, 0.0, -3.5); + next.lantern.orientation = next.hand_r.orientation.inverse() + * Quaternion::rotation_x((foothorir + 0.5) * 1.0 * speednorm) + * Quaternion::rotation_y(tilt * 4.0 * foothorir + tilt * 3.0); + } + next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler; next.torso.scale = Vec3::one() / 11.0 * s_a.scaler; diff --git a/voxygen/anim/src/character/sit.rs b/voxygen/anim/src/character/sit.rs index 74cd609d60..4de7063908 100644 --- a/voxygen/anim/src/character/sit.rs +++ b/voxygen/anim/src/character/sit.rs @@ -29,8 +29,16 @@ impl Animation for SitAnimation { let stop = (anim_time * 3.0).min(PI / 2.0).sin(); let head_look = Vec2::new( - (global_time + anim_time / 18.0).floor().mul(7331.0).sin() * 0.25, - (global_time + anim_time / 18.0).floor().mul(1337.0).sin() * 0.125, + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, ); next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.1 + stop * -0.8); next.head.orientation = Quaternion::rotation_z(head_look.x + slow * 0.2 - slow * 0.1) @@ -79,6 +87,21 @@ impl Animation for SitAnimation { next.torso.position = Vec3::new(0.0, -0.2, stop * -0.16) * s_a.scaler; + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 - head_look.x * 10.0, + s_a.hand.1 + 5.0 - head_look.y * 8.0, + s_a.hand.2 + 11.0, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 3.0) + * Quaternion::rotation_x(head_look.y * 3.0); + + next.lantern.position = Vec3::new(0.0, 0.0, -3.5); + next.lantern.orientation = next.hand_r.orientation.inverse(); + } + next } } diff --git a/voxygen/anim/src/character/sneak.rs b/voxygen/anim/src/character/sneak.rs index ca0a41d99e..13897e5a0a 100644 --- a/voxygen/anim/src/character/sneak.rs +++ b/voxygen/anim/src/character/sneak.rs @@ -158,6 +158,15 @@ impl Animation for SneakAnimation { next.foot_r.position = Vec3::new(s_a.foot.0, 4.0 + s_a.foot.1, s_a.foot.2); } + + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new(s_a.hand.0, s_a.hand.1 + 5.0, s_a.hand.2 + 9.0); + next.hand_r.orientation = Quaternion::rotation_x(2.5); + + next.lantern.position = Vec3::new(0.0, 1.5, -5.5); + next.lantern.orientation = next.hand_r.orientation.inverse(); + } + next } } diff --git a/voxygen/anim/src/character/stand.rs b/voxygen/anim/src/character/stand.rs index 34f8cbcb38..c093140847 100644 --- a/voxygen/anim/src/character/stand.rs +++ b/voxygen/anim/src/character/stand.rs @@ -32,6 +32,7 @@ impl Animation for StandAnimation { let mut next = (*skeleton).clone(); let slow = (anim_time * 1.0).sin(); + let fast = (anim_time * 5.0).sin(); let impact = (avg_vel.z).max(-15.0); let head_look = Vec2::new( ((global_time + anim_time) / 10.0).floor().mul(7331.0).sin() * 0.15, @@ -142,6 +143,22 @@ impl Animation for StandAnimation { next.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2); next.lantern.orientation = Quaternion::rotation_x(0.1) * Quaternion::rotation_y(0.1); + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 - head_look.x * 10.0, + s_a.hand.1 + 5.0 - head_look.y * 8.0 + slow * 0.15 - impact * 0.2, + s_a.hand.2 + 11.0 + slow * 0.5 + impact * -0.1, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25 + slow * -0.06 + impact * -0.1) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 3.0) + * Quaternion::rotation_x(head_look.y * 3.0); + + next.lantern.position = Vec3::new(0.0, 0.0, -3.5); + next.lantern.orientation = + next.hand_r.orientation.inverse() * Quaternion::rotation_x(fast * 0.1); + } + next.torso.position = Vec3::new(0.0, 0.0, 0.0) * s_a.scaler; next.second.scale = Vec3::one(); next.second.scale = match hands { diff --git a/voxygen/anim/src/character/wield.rs b/voxygen/anim/src/character/wield.rs index 1dc4244f63..4764eedfa2 100644 --- a/voxygen/anim/src/character/wield.rs +++ b/voxygen/anim/src/character/wield.rs @@ -320,15 +320,17 @@ impl Animation for WieldAnimation { }; match hands { (None, None) | (None, Some(Hands::One)) => { - next.hand_l.position = Vec3::new(-4.5, 8.0, 5.0); - next.hand_l.orientation = Quaternion::rotation_x(1.9) * Quaternion::rotation_y(-0.5) + //next.hand_l.position = Vec3::new(-4.5, 8.0, 5.0); + //next.hand_l.orientation = Quaternion::rotation_x(1.9) * + // Quaternion::rotation_y(-0.5) }, (_, _) => {}, }; match hands { (None, None) | (Some(Hands::One), None) => { - next.hand_r.position = Vec3::new(4.5, 8.0, 5.0); - next.hand_r.orientation = Quaternion::rotation_x(1.9) * Quaternion::rotation_y(0.5) + //next.hand_r.position = Vec3::new(4.5, 8.0, 5.0); + //next.hand_r.orientation = Quaternion::rotation_x(1.9) * + // Quaternion::rotation_y(0.5) }, (_, _) => {}, }; @@ -337,6 +339,21 @@ impl Animation for WieldAnimation { next.second = next.main; } + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 - head_look.x * 10.0, + s_a.hand.1 + 5.0 + slow * 0.15, + s_a.hand.2 + 9.0 + head_look.y * 18.0 + slow * 0.5, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25 + slow * -0.06) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 3.0) + * Quaternion::rotation_x(head_look.y * 3.0); + + next.lantern.position = Vec3::new(0.0, 0.0, -3.5); + next.lantern.orientation = next.hand_r.orientation.inverse(); + } + next } } diff --git a/voxygen/anim/src/lib.rs b/voxygen/anim/src/lib.rs index c424b4d869..8895e92841 100644 --- a/voxygen/anim/src/lib.rs +++ b/voxygen/anim/src/lib.rs @@ -5,12 +5,15 @@ compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once"); macro_rules! skeleton_impls { - { struct $Skeleton:ident { $( $(+)? $bone:ident ),* $(,)? } } => { + { struct $Skeleton:ident { $( $(+)? $bone:ident ),* $(,)? $(:: $($field:ident : $field_ty:ty),* $(,)? )? } } => { #[derive(Clone, Default)] pub struct $Skeleton { $( $bone: $crate::Bone, )* + $($( + $field : $field_ty, + )*)? } impl<'a, Factor> $crate::vek::Lerp for &'a $Skeleton @@ -25,6 +28,9 @@ macro_rules! skeleton_impls { $( $bone: Lerp::lerp_unclamped_precise(from.$bone, to.$bone, factor), )* + $($( + $field : to.$field.clone(), + )*)? } } @@ -33,6 +39,9 @@ macro_rules! skeleton_impls { $( $bone: Lerp::lerp_unclamped(from.$bone, to.$bone, factor), )* + $($( + $field : to.$field.clone(), + )*)? } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 5e931d8374..4f4c9c8deb 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -28,7 +28,7 @@ use anim::{ use common::{ comp::{ inventory::slot::EquipSlot, - item::{ItemKind, ToolKind}, + item::{Hands, ItemKind, ToolKind}, Body, CharacterState, Controller, Health, Inventory, Item, Last, LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel, }, @@ -584,6 +584,7 @@ impl FigureMgr { health, inventory, item, + light_emitter, ), ) in ( &ecs.entities(), @@ -599,6 +600,7 @@ impl FigureMgr { ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), ) .join() .enumerate() @@ -760,12 +762,20 @@ impl FigureMgr { &slow_jobs, ); + let holding_lantern = inventory + .map_or(false, |i| i.equipped(EquipSlot::Lantern).is_some()) + && light_emitter.is_some() + && !(matches!(second_tool_hand, Some(_)) + && character.map_or(false, |c| c.is_wield())) + && !character.map_or(false, |c| c.is_using_hands()) + && physics.in_liquid().is_none(); + let state = self .states .character_states .entry(entity) .or_insert_with(|| { - FigureState::new(renderer, CharacterSkeleton::default()) + FigureState::new(renderer, CharacterSkeleton::new(holding_lantern)) }); // Average velocity relative to the current ground @@ -787,7 +797,7 @@ impl FigureMgr { ) { // Standing (true, false, false) => anim::character::StandAnimation::update_skeleton( - &CharacterSkeleton::default(), + &CharacterSkeleton::new(holding_lantern), (active_tool_kind, second_tool_kind, hands, time, rel_avg_vel), state.state_time, &mut state_animation_rate, @@ -795,7 +805,7 @@ impl FigureMgr { ), // Running (true, true, false) => anim::character::RunAnimation::update_skeleton( - &CharacterSkeleton::default(), + &CharacterSkeleton::new(holding_lantern), ( active_tool_kind, second_tool_kind, @@ -814,7 +824,7 @@ impl FigureMgr { ), // In air (false, _, false) => anim::character::JumpAnimation::update_skeleton( - &CharacterSkeleton::default(), + &CharacterSkeleton::new(holding_lantern), ( active_tool_kind, second_tool_kind, @@ -831,7 +841,7 @@ impl FigureMgr { ), // Swim (_, _, true) => anim::character::SwimAnimation::update_skeleton( - &CharacterSkeleton::default(), + &CharacterSkeleton::new(holding_lantern), ( active_tool_kind, second_tool_kind, @@ -1376,7 +1386,7 @@ impl FigureMgr { }, CharacterState::BasicBlock { .. } => { anim::character::BlockAnimation::update_skeleton( - &CharacterSkeleton::default(), + &CharacterSkeleton::new(holding_lantern), (active_tool_kind, second_tool_kind, time), state.state_time, &mut state_animation_rate, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index eccdbf5f90..daff82a064 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -560,7 +560,6 @@ impl Scene { lights.extend( ( &scene_data.state.ecs().read_storage::(), - scene_data.state.ecs().read_storage::().maybe(), scene_data .state .ecs() @@ -572,23 +571,16 @@ impl Scene { .read_storage::(), ) .join() - .filter(|(pos, _, _, light_anim)| { + .filter(|(pos, _, light_anim)| { light_anim.col != Rgb::zero() && light_anim.strength > 0.0 && (pos.0.distance_squared(player_pos) as f32) < loaded_distance.powi(2) + LIGHT_DIST_RADIUS }) - .map(|(pos, ori, interpolated, light_anim)| { + .map(|(pos, interpolated, light_anim)| { // Use interpolated values if they are available - let (pos, rot) = interpolated - .map_or((pos.0, ori.copied().unwrap_or_default()), |i| { - (i.pos, i.ori) - }); - Light::new( - pos + (rot.to_quat() * light_anim.offset), - light_anim.col, - light_anim.strength, - ) + let pos = interpolated.map_or(pos.0, |i| i.pos); + Light::new(pos + light_anim.offset, light_anim.col, light_anim.strength) }) .chain( self.event_lights