mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Skiing and ice skating
This commit is contained in:
parent
ca1a27bd11
commit
2bf8e1865f
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Water caves
|
||||
- Modular weapons
|
||||
- Added Thai translation
|
||||
- Skiing and ice skating
|
||||
|
||||
### Changed
|
||||
|
||||
|
15
assets/common/items/armor/misc/foot/iceskate.ron
Normal file
15
assets/common/items/armor/misc/foot/iceskate.ron
Normal file
@ -0,0 +1,15 @@
|
||||
ItemDef(
|
||||
name: "Ice Skates",
|
||||
description: "Best used on a frozen lake.",
|
||||
kind: Armor((
|
||||
kind: Foot,
|
||||
stats: (
|
||||
protection: Some(Normal(3.0)),
|
||||
ground_contact: Skate,
|
||||
),
|
||||
)),
|
||||
quality: Moderate,
|
||||
tags: [
|
||||
Material(Steel),
|
||||
],
|
||||
)
|
16
assets/common/items/armor/misc/foot/ski.ron
Normal file
16
assets/common/items/armor/misc/foot/ski.ron
Normal file
@ -0,0 +1,16 @@
|
||||
ItemDef(
|
||||
name: "Wooden skis",
|
||||
description: "Best used downhill on snow.",
|
||||
kind: Armor((
|
||||
kind: Foot,
|
||||
stats: (
|
||||
protection: Some(Normal(3.0)),
|
||||
ground_contact: Ski,
|
||||
),
|
||||
)),
|
||||
quality: Moderate,
|
||||
tags: [
|
||||
Material(Wood),
|
||||
// SalvageInto(Twigs),
|
||||
],
|
||||
)
|
@ -2699,6 +2699,14 @@
|
||||
"voxel.armor.misc.pants.grayscale",
|
||||
(0.0, 1.0, 0.0), (-120.0, 210.0,15.0), 0.9,
|
||||
),
|
||||
Simple("common.items.armor.misc.foot.ski"): VoxTrans(
|
||||
"voxel.armor.misc.foot.ski",
|
||||
(0.0, 0.0, 0.0), (-120.0, 210.0,15.0), 0.9,
|
||||
),
|
||||
Simple("common.items.armor.misc.foot.iceskate"): VoxTrans(
|
||||
"voxel.armor.misc.foot.iceskate",
|
||||
(0.0, 0.0, 0.0), (-120.0, 210.0,15.0), 0.9,
|
||||
),
|
||||
// Backs
|
||||
Simple("common.items.armor.misc.back.short_0"): VoxTrans(
|
||||
"voxel.armor.misc.back.short-0",
|
||||
|
BIN
assets/voxygen/voxel/armor/misc/foot/iceskate.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/armor/misc/foot/iceskate.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/armor/misc/foot/ski.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/armor/misc/foot/ski.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -164,5 +164,13 @@
|
||||
vox_spec: ("armor.merchant.foot", (-2.5, -3.5, -2.0)),
|
||||
color: None
|
||||
),
|
||||
"common.items.armor.misc.foot.ski": (
|
||||
vox_spec: ("armor.misc.foot.ski", (-2.5, -15.5, -2.0)),
|
||||
color: None
|
||||
),
|
||||
"common.items.armor.misc.foot.iceskate": (
|
||||
vox_spec: ("armor.misc.foot.iceskate", (-2.5, -3.5, -2.0)),
|
||||
color: None
|
||||
),
|
||||
},
|
||||
))
|
||||
|
@ -402,6 +402,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
||||
| CharacterState::SpriteSummon(_)
|
||||
| CharacterState::UseItem(_)
|
||||
| CharacterState::SpriteInteract(_)
|
||||
| CharacterState::Skate(_)
|
||||
| CharacterState::Wallrun(_) => Self::Other,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
item::ConsumableKind, ControlAction, Density, Energy, InputAttr, InputKind, Ori, Pos, Vel,
|
||||
inventory::item::armor::Friction, item::ConsumableKind, ControlAction, Density, Energy,
|
||||
InputAttr, InputKind, Ori, Pos, Vel,
|
||||
},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
states::{
|
||||
@ -123,6 +124,8 @@ pub enum CharacterState {
|
||||
SpriteInteract(sprite_interact::Data),
|
||||
/// Runs on the wall
|
||||
Wallrun(wallrun::Data),
|
||||
/// Ice skating or skiing
|
||||
Skate(skate::Data),
|
||||
}
|
||||
|
||||
impl CharacterState {
|
||||
@ -153,15 +156,16 @@ impl CharacterState {
|
||||
pub fn is_stealthy(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
CharacterState::Idle(idle::Data { is_sneaking: true })
|
||||
| CharacterState::Wielding(wielding::Data {
|
||||
is_sneaking: true,
|
||||
..
|
||||
})
|
||||
| CharacterState::Roll(roll::Data {
|
||||
is_sneaking: true,
|
||||
..
|
||||
})
|
||||
CharacterState::Idle(idle::Data {
|
||||
is_sneaking: true,
|
||||
footwear: _
|
||||
}) | CharacterState::Wielding(wielding::Data {
|
||||
is_sneaking: true,
|
||||
..
|
||||
}) | CharacterState::Roll(roll::Data {
|
||||
is_sneaking: true,
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@ -227,6 +231,8 @@ impl CharacterState {
|
||||
|
||||
pub fn is_glide(&self) -> bool { matches!(self, CharacterState::Glide(_)) }
|
||||
|
||||
pub fn is_skate(&self) -> bool { matches!(self, CharacterState::Skate(_)) }
|
||||
|
||||
pub fn is_melee_dodge(&self) -> bool {
|
||||
matches!(self, CharacterState::Roll(d) if d.static_data.immune_melee)
|
||||
}
|
||||
@ -329,6 +335,7 @@ impl CharacterState {
|
||||
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
|
||||
CharacterState::UseItem(data) => data.behavior(j, output_events),
|
||||
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
|
||||
CharacterState::Skate(data) => data.behavior(j, output_events),
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,12 +382,26 @@ impl CharacterState {
|
||||
CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
|
||||
CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
|
||||
CharacterState::SpriteInteract(data) => data.handle_event(j, output_events, action),
|
||||
CharacterState::Skate(data) => data.handle_event(j, output_events, action),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn footwear(&self) -> Option<Friction> {
|
||||
match &self {
|
||||
CharacterState::Idle(data) => data.footwear,
|
||||
CharacterState::Skate(data) => Some(data.footwear),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CharacterState {
|
||||
fn default() -> Self { Self::Idle(idle::Data { is_sneaking: false }) }
|
||||
fn default() -> Self {
|
||||
Self::Idle(idle::Data {
|
||||
is_sneaking: false,
|
||||
footwear: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for CharacterState {
|
||||
|
@ -1,3 +1,7 @@
|
||||
use crate::{
|
||||
comp::item::Rgb,
|
||||
terrain::{Block, BlockKind},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::Ordering, ops::Sub};
|
||||
|
||||
@ -26,6 +30,45 @@ impl Armor {
|
||||
}
|
||||
}
|
||||
|
||||
/// longitudinal and lateral friction, only meaningful for footwear
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Friction {
|
||||
Normal,
|
||||
Ski,
|
||||
Skate,
|
||||
// Snowshoe,
|
||||
// Spikes,
|
||||
}
|
||||
|
||||
impl Default for Friction {
|
||||
fn default() -> Self { Self::Normal }
|
||||
}
|
||||
|
||||
impl Friction {
|
||||
pub fn can_skate_on(&self, b: BlockKind) -> bool {
|
||||
match self {
|
||||
Friction::Ski => matches!(b, BlockKind::Snow | BlockKind::Ice | BlockKind::Air),
|
||||
Friction::Skate => b == BlockKind::Ice,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// longitudinal (forward) and lateral (side) friction
|
||||
pub fn get_friction(&self, b: BlockKind) -> (f32, f32) {
|
||||
match (self, b) {
|
||||
(Friction::Ski, BlockKind::Snow) => (0.01, 0.95),
|
||||
(Friction::Ski, BlockKind::Ice) => (0.001, 0.5),
|
||||
(Friction::Ski, BlockKind::Water) => (0.1, 0.7),
|
||||
(Friction::Ski, BlockKind::Air) => (0.0, 0.0),
|
||||
(Friction::Skate, BlockKind::Ice) => (0.001, 0.99),
|
||||
_ => {
|
||||
let non_directional_friction = Block::new(b, Rgb::new(0, 0, 0)).get_friction();
|
||||
(non_directional_friction, non_directional_friction)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stats {
|
||||
/// Protection is non-linearly transformed (following summation) to a damage
|
||||
@ -46,6 +89,9 @@ pub struct Stats {
|
||||
/// Stealth is summed along with the base stealth bonus (2.0), and then
|
||||
/// the agent's perception distance is divided by this value
|
||||
stealth: Option<f32>,
|
||||
/// Ground contact type, mostly for shoes
|
||||
#[serde(default)]
|
||||
ground_contact: Friction,
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
@ -66,6 +112,7 @@ impl Stats {
|
||||
energy_reward,
|
||||
crit_power,
|
||||
stealth,
|
||||
ground_contact: Friction::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +127,8 @@ impl Stats {
|
||||
pub fn crit_power(&self) -> Option<f32> { self.crit_power }
|
||||
|
||||
pub fn stealth(&self) -> Option<f32> { self.stealth }
|
||||
|
||||
pub fn ground_contact(&self) -> Friction { self.ground_contact }
|
||||
}
|
||||
|
||||
impl Sub<Stats> for Stats {
|
||||
@ -99,6 +148,7 @@ impl Sub<Stats> for Stats {
|
||||
.map(|(a, b)| a - b),
|
||||
crit_power: self.crit_power.zip(other.crit_power).map(|(a, b)| a - b),
|
||||
stealth: self.stealth.zip(other.stealth).map(|(a, b)| a - b),
|
||||
ground_contact: Friction::Normal,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,6 +209,8 @@ impl Armor {
|
||||
|
||||
pub fn stealth(&self) -> Option<f32> { self.stats.stealth }
|
||||
|
||||
pub fn ground_contact(&self) -> Friction { self.stats.ground_contact }
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn test_armor(
|
||||
kind: ArmorKind,
|
||||
@ -174,6 +226,7 @@ impl Armor {
|
||||
energy_reward: None,
|
||||
crit_power: None,
|
||||
stealth: None,
|
||||
ground_contact: Friction::Normal,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use super::{Fluid, Ori};
|
||||
use crate::{
|
||||
comp::body::ship::figuredata::VoxelCollider, consts::WATER_DENSITY, terrain::Block, uid::Uid,
|
||||
comp::{body::ship::figuredata::VoxelCollider, inventory::item::armor::Friction},
|
||||
consts::WATER_DENSITY,
|
||||
terrain::Block,
|
||||
uid::Uid,
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -182,6 +185,9 @@ pub struct PhysicsState {
|
||||
pub touch_entities: HashSet<Uid>,
|
||||
pub in_fluid: Option<Fluid>,
|
||||
pub ground_vel: Vec3<f32>,
|
||||
pub footwear: Friction,
|
||||
pub skating_last_height: f32,
|
||||
pub skating_active: bool,
|
||||
}
|
||||
|
||||
impl PhysicsState {
|
||||
|
@ -79,7 +79,7 @@ impl CharacterBehavior for Data {
|
||||
CLIMB_BOOST_JUMP_FACTOR * impulse / data.mass.0,
|
||||
));
|
||||
};
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
return update;
|
||||
};
|
||||
// Move player
|
||||
@ -103,7 +103,7 @@ impl CharacterBehavior for Data {
|
||||
.try_change_by(-energy_use * data.dt.0)
|
||||
.is_err()
|
||||
{
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
|
||||
// Set orientation direction based on wall direction
|
||||
|
@ -20,7 +20,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Try to Fall/Stand up/Move
|
||||
if data.physics.on_ground.is_none() || data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
|
||||
update
|
||||
@ -52,7 +52,7 @@ impl CharacterBehavior for Data {
|
||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ impl CharacterBehavior for Data {
|
||||
.and_then(|inv| inv.equipped(EquipSlot::Glider))
|
||||
.is_none()
|
||||
{
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
} else if !handle_climb(data, &mut update) {
|
||||
let air_flow = data
|
||||
.physics
|
||||
@ -207,7 +207,7 @@ impl CharacterBehavior for Data {
|
||||
pos: data.pos.0,
|
||||
wielded: false,
|
||||
}));
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl CharacterBehavior for Data {
|
||||
..*self
|
||||
})
|
||||
} else {
|
||||
CharacterState::Idle(idle::Data { is_sneaking: false })
|
||||
CharacterState::Idle(idle::Data::default())
|
||||
};
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ impl CharacterBehavior for Data {
|
||||
pos: data.pos.0,
|
||||
wielded: false,
|
||||
}));
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,25 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, InventoryAction, StateUpdate},
|
||||
comp::{
|
||||
character_state::OutputEvents, inventory::item::armor::Friction, CharacterState,
|
||||
InventoryAction, StateUpdate,
|
||||
},
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct Data {
|
||||
pub is_sneaking: bool,
|
||||
// None means unknown
|
||||
pub(crate) footwear: Option<Friction>,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_skating(data, &mut update);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, if self.is_sneaking { 0.4 } else { 1.0 });
|
||||
handle_jump(data, output_events, &mut update, 1.0);
|
||||
@ -26,7 +32,10 @@ impl CharacterBehavior for Data {
|
||||
if self.is_sneaking
|
||||
&& (data.physics.on_ground.is_none() || data.physics.in_liquid().is_some())
|
||||
{
|
||||
update.character = CharacterState::Idle(Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(Data {
|
||||
is_sneaking: false,
|
||||
footwear: self.footwear,
|
||||
});
|
||||
}
|
||||
|
||||
update
|
||||
@ -75,13 +84,16 @@ impl CharacterBehavior for Data {
|
||||
|
||||
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(Data { is_sneaking: true });
|
||||
update.character = CharacterState::Idle(Data {
|
||||
is_sneaking: true,
|
||||
footwear: self.footwear,
|
||||
});
|
||||
update
|
||||
}
|
||||
|
||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(Data::default());
|
||||
update
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ pub mod roll;
|
||||
pub mod self_buff;
|
||||
pub mod shockwave;
|
||||
pub mod sit;
|
||||
pub mod skate;
|
||||
pub mod spin_melee;
|
||||
pub mod sprite_interact;
|
||||
pub mod sprite_summon;
|
||||
|
@ -142,6 +142,7 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.is_sneaking,
|
||||
footwear: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -151,6 +152,7 @@ impl CharacterBehavior for Data {
|
||||
// If it somehow ends up in an incorrect stage section
|
||||
update.character = CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.is_sneaking,
|
||||
footwear: None,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Try to Fall/Stand up/Move
|
||||
if data.physics.on_ground.is_none() || data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
|
||||
update
|
||||
@ -52,7 +52,7 @@ impl CharacterBehavior for Data {
|
||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
}
|
||||
|
118
common/src/states/skate.rs
Normal file
118
common/src/states/skate.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{
|
||||
character_state::OutputEvents, item::armor::Friction, CharacterState, InventoryAction,
|
||||
StateUpdate,
|
||||
},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
idle,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
pub(crate) footwear: Friction,
|
||||
// hints for animation
|
||||
pub turn: f32, // negative to left, positive to right, 1.0=45°
|
||||
pub accelerate: f32, // negative to brake
|
||||
pub sidewalk: f32, // negative to left
|
||||
}
|
||||
|
||||
impl Data {
|
||||
pub fn new(_: &JoinData, footwear: Friction) -> Self {
|
||||
Self {
|
||||
footwear,
|
||||
turn: Default::default(),
|
||||
accelerate: Default::default(),
|
||||
sidewalk: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_wield(data, &mut update);
|
||||
handle_jump(data, output_events, &mut update, 1.0);
|
||||
|
||||
if !data.physics.skating_active {
|
||||
update.character = CharacterState::Idle(idle::Data {
|
||||
is_sneaking: false,
|
||||
footwear: Some(self.footwear),
|
||||
});
|
||||
} else {
|
||||
let plane_ori = data.inputs.look_dir.xy();
|
||||
let orthogonal = vek::Vec2::new(plane_ori.y, -plane_ori.x);
|
||||
update.ori = vek::Vec3::new(plane_ori.x, plane_ori.y, 0.0).into();
|
||||
let current_planar_velocity = data.vel.0.xy().magnitude();
|
||||
let long_input = data.inputs.move_dir.dot(plane_ori);
|
||||
let lat_input = data.inputs.move_dir.dot(orthogonal);
|
||||
let acceleration = if long_input.abs() > lat_input.abs() {
|
||||
if long_input > 0.0 {
|
||||
if let CharacterState::Skate(data) = &mut update.character {
|
||||
data.accelerate = 1.0;
|
||||
data.sidewalk = 0.0;
|
||||
}
|
||||
// forward, max at 8u/s
|
||||
(data.dt.0 * 3.0)
|
||||
.min(8.0 - current_planar_velocity)
|
||||
.max(0.0)
|
||||
} else {
|
||||
if let CharacterState::Skate(data) = &mut update.character {
|
||||
data.accelerate = -1.0;
|
||||
data.sidewalk = 0.0;
|
||||
}
|
||||
//brake up to 4u/s², but never backwards
|
||||
(data.dt.0 * 4.0).min(current_planar_velocity)
|
||||
}
|
||||
} else {
|
||||
if let CharacterState::Skate(data) = &mut update.character {
|
||||
data.accelerate = 0.0;
|
||||
data.sidewalk = lat_input;
|
||||
}
|
||||
// sideways: constant speed
|
||||
(0.5 - current_planar_velocity).max(0.0)
|
||||
};
|
||||
if let CharacterState::Skate(skate_data) = &mut update.character {
|
||||
skate_data.turn = orthogonal.dot(data.vel.0.xy());
|
||||
}
|
||||
let delta_vel = acceleration * data.inputs.move_dir;
|
||||
update.vel.0 += vek::Vec3::new(delta_vel.x, delta_vel.y, 0.0);
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
||||
fn manipulate_loadout(
|
||||
&self,
|
||||
data: &JoinData,
|
||||
output_events: &mut OutputEvents,
|
||||
inv_action: InventoryAction,
|
||||
) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
|
||||
update
|
||||
}
|
||||
|
||||
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_wield(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_sit(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
}
|
@ -106,13 +106,14 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.static_data.was_sneak,
|
||||
footwear: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// If it somehow ends up in an incorrect stage section
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ impl CharacterBehavior for Data {
|
||||
update.character =
|
||||
CharacterState::Wielding(wielding::Data { is_sneaking: false });
|
||||
} else {
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -82,7 +82,7 @@ impl CharacterBehavior for Data {
|
||||
update.character =
|
||||
CharacterState::Wielding(wielding::Data { is_sneaking: false });
|
||||
} else {
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -42,14 +42,14 @@ impl CharacterBehavior for Data {
|
||||
|
||||
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
attempt_sit(data, &mut update);
|
||||
update
|
||||
}
|
||||
|
||||
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
attempt_dance(data, &mut update);
|
||||
update
|
||||
}
|
||||
@ -57,7 +57,7 @@ impl CharacterBehavior for Data {
|
||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
update
|
||||
}
|
||||
}
|
||||
|
@ -132,13 +132,14 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.static_data.was_sneak,
|
||||
footwear: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// If it somehow ends up in an incorrect stage section
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@ use crate::{
|
||||
comp::{
|
||||
arthropod, biped_large, biped_small,
|
||||
character_state::OutputEvents,
|
||||
inventory::slot::{EquipSlot, Slot},
|
||||
item::{Hands, ItemKind, ToolKind},
|
||||
inventory::slot::{ArmorSlot, EquipSlot, Slot},
|
||||
item::{armor::Friction, Hands, ItemKind, ToolKind},
|
||||
quadruped_low, quadruped_medium, quadruped_small,
|
||||
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||
@ -14,7 +14,7 @@ use crate::{
|
||||
consts::{FRIC_GROUND, GRAVITY, MAX_PICKUP_RANGE},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
states::{behavior::JoinData, *},
|
||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
};
|
||||
@ -301,6 +301,35 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
/// set footwear in idle data and potential state change to Skate
|
||||
pub fn handle_skating(data: &JoinData, update: &mut StateUpdate) {
|
||||
if let Idle(crate::states::idle::Data {
|
||||
is_sneaking,
|
||||
mut footwear,
|
||||
}) = data.character
|
||||
{
|
||||
if footwear.is_none() {
|
||||
footwear = data.inventory.and_then(|inv| {
|
||||
inv.equipped(EquipSlot::Armor(ArmorSlot::Feet))
|
||||
.map(|armor| match armor.kind().as_ref() {
|
||||
ItemKind::Armor(a) => a.ground_contact(),
|
||||
_ => crate::comp::inventory::item::armor::Friction::Normal,
|
||||
})
|
||||
});
|
||||
update.character = Idle(crate::states::idle::Data {
|
||||
is_sneaking: *is_sneaking,
|
||||
footwear,
|
||||
});
|
||||
}
|
||||
if data.physics.skating_active {
|
||||
update.character = CharacterState::Skate(crate::states::skate::Data::new(
|
||||
data,
|
||||
footwear.unwrap_or(Friction::Normal),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles updating `Components` to move player based on state of `JoinData`
|
||||
pub fn handle_move(data: &JoinData<'_>, update: &mut StateUpdate, efficiency: f32) {
|
||||
let submersion = data
|
||||
@ -635,7 +664,10 @@ pub fn attempt_talk(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
|
||||
pub fn attempt_sneak(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
if data.physics.on_ground.is_some() && data.body.is_humanoid() {
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: true });
|
||||
update.character = CharacterState::Idle(idle::Data {
|
||||
is_sneaking: true,
|
||||
footwear: data.character.footwear(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ impl CharacterBehavior for Data {
|
||||
|| data.physics.on_ground.is_some()
|
||||
|| data.physics.in_liquid().is_some()
|
||||
{
|
||||
update.character = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
}
|
||||
|
||||
update
|
||||
|
@ -58,6 +58,7 @@ impl CharacterBehavior for Data {
|
||||
) => {
|
||||
update.character = CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.is_sneaking,
|
||||
footwear: None,
|
||||
});
|
||||
},
|
||||
_ => (),
|
||||
@ -76,6 +77,7 @@ impl CharacterBehavior for Data {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(idle::Data {
|
||||
is_sneaking: self.is_sneaking,
|
||||
footwear: None,
|
||||
});
|
||||
update
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ impl<'a> System<'a> for Sys {
|
||||
// If mounted, character state is controlled by mount
|
||||
if is_rider.is_some() && !join_struct.char_state.can_perform_mounted() {
|
||||
// TODO: A better way to swap between mount inputs and rider inputs
|
||||
*join_struct.char_state = CharacterState::Idle(idle::Data { is_sneaking: false });
|
||||
*join_struct.char_state = CharacterState::Idle(idle::Data::default());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use common::{
|
||||
comp::{
|
||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||
fluid_dynamics::{Fluid, LiquidKind, Wings},
|
||||
inventory::item::armor::Friction,
|
||||
Body, CharacterState, Collider, Density, Immovable, Mass, Ori, PhysicsState, Pos,
|
||||
PosVelOriDefer, PreviousPhysCache, Projectile, Scale, Stats, Sticky, Vel,
|
||||
},
|
||||
@ -12,7 +13,7 @@ use common::{
|
||||
outcome::Outcome,
|
||||
resources::DeltaTime,
|
||||
states,
|
||||
terrain::{Block, TerrainGrid},
|
||||
terrain::{Block, BlockKind, TerrainGrid},
|
||||
uid::Uid,
|
||||
util::{Projection, SpatialGrid},
|
||||
vol::{BaseVol, ReadVol},
|
||||
@ -780,6 +781,13 @@ impl<'a> PhysicsData<'a> {
|
||||
1.0
|
||||
};
|
||||
|
||||
if let Some(state) = character_state {
|
||||
let footwear = state.footwear().unwrap_or(Friction::Normal);
|
||||
if footwear != physics_state.footwear {
|
||||
physics_state.footwear = footwear;
|
||||
}
|
||||
}
|
||||
|
||||
let in_loaded_chunk = read
|
||||
.terrain
|
||||
.get_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)))
|
||||
@ -846,6 +854,7 @@ impl<'a> PhysicsData<'a> {
|
||||
climbing,
|
||||
|entity, vel| land_on_ground = Some((entity, vel)),
|
||||
read,
|
||||
&ori,
|
||||
);
|
||||
tgt_pos = cpos.0;
|
||||
},
|
||||
@ -878,6 +887,7 @@ impl<'a> PhysicsData<'a> {
|
||||
climbing,
|
||||
|entity, vel| land_on_ground = Some((entity, vel)),
|
||||
read,
|
||||
&ori,
|
||||
);
|
||||
|
||||
// Sticky things shouldn't move when on a surface
|
||||
@ -1142,6 +1152,7 @@ impl<'a> PhysicsData<'a> {
|
||||
Some((entity, Vel(ori_from.mul_direction(vel.0))));
|
||||
},
|
||||
read,
|
||||
&ori,
|
||||
);
|
||||
|
||||
cpos.0 = transform_from.mul_point(cpos.0) + wpos;
|
||||
@ -1339,6 +1350,7 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
|
||||
climbing: bool,
|
||||
mut land_on_ground: impl FnMut(Entity, Vel),
|
||||
read: &PhysicsRead,
|
||||
ori: &Ori,
|
||||
) {
|
||||
// FIXME: Review these
|
||||
#![allow(
|
||||
@ -1700,19 +1712,84 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
|
||||
physics_state.on_wall = on_wall;
|
||||
let fric_mod = read.stats.get(entity).map_or(1.0, |s| s.friction_modifier);
|
||||
|
||||
let ground_fric = physics_state
|
||||
.on_ground
|
||||
.map(|b| b.get_friction())
|
||||
.unwrap_or(0.0);
|
||||
let wall_fric = if physics_state.on_wall.is_some() && climbing {
|
||||
FRIC_GROUND
|
||||
// skating (ski)
|
||||
if !vel.0.xy().is_approx_zero()
|
||||
&& physics_state
|
||||
.on_ground
|
||||
.map_or(false, |g| physics_state.footwear.can_skate_on(g.kind()))
|
||||
{
|
||||
const DT_SCALE: f32 = 1.0; // other areas use 60.0???
|
||||
const POTENTIAL_TO_KINETIC: f32 = 8.0; // * 2.0 * GRAVITY;
|
||||
|
||||
let kind = physics_state.on_ground.map_or(BlockKind::Air, |g| g.kind());
|
||||
let (longitudinal_friction, lateral_friction) = physics_state.footwear.get_friction(kind);
|
||||
// the amount of longitudinal speed preserved
|
||||
let longitudinal_friction_factor_squared =
|
||||
(1.0 - longitudinal_friction).powf(dt.0 * DT_SCALE * 2.0);
|
||||
let lateral_friction_factor = (1.0 - lateral_friction).powf(dt.0 * DT_SCALE);
|
||||
let groundplane_velocity = vel.0.xy();
|
||||
let mut longitudinal_dir = ori.look_vec().xy();
|
||||
if longitudinal_dir.is_approx_zero() {
|
||||
// fall back to travelling dir (in case we look up)
|
||||
longitudinal_dir = groundplane_velocity;
|
||||
}
|
||||
let longitudinal_dir = longitudinal_dir.normalized();
|
||||
let lateral_dir = Vec2::new(longitudinal_dir.y, -longitudinal_dir.x);
|
||||
let squared_velocity = groundplane_velocity.magnitude_squared();
|
||||
// if we crossed an edge up or down accelerate in travelling direction,
|
||||
// as potential energy is converted into kinetic energy we compare it with the
|
||||
// square of velocity
|
||||
let vertical_difference = physics_state.skating_last_height - pos.0.z;
|
||||
// might become negative when skating slowly uphill
|
||||
let height_factor_squared = if vertical_difference != 0.0 {
|
||||
// E=½mv², we scale both energies by ½m
|
||||
let kinetic = squared_velocity;
|
||||
// positive accelerate, negative decelerate, ΔE=mgΔh
|
||||
let delta_potential = vertical_difference.max(-1.0).min(2.0) * POTENTIAL_TO_KINETIC;
|
||||
let new_energy = kinetic + delta_potential;
|
||||
physics_state.skating_last_height = pos.0.z;
|
||||
new_energy / kinetic
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
// we calculate these squared as we need to combined them Euclidianly anyway,
|
||||
// skiing: separate speed into longitudinal and lateral component
|
||||
let long_speed = groundplane_velocity.dot(longitudinal_dir);
|
||||
let lat_speed = groundplane_velocity.dot(lateral_dir);
|
||||
let long_speed_squared = long_speed.powi(2);
|
||||
|
||||
// lateral speed is reduced by lateral_friction,
|
||||
let new_lateral = lat_speed * lateral_friction_factor;
|
||||
let lateral_speed_reduction = lat_speed - new_lateral;
|
||||
// we convert this reduction partically (by the cosine of the angle) into
|
||||
// longitudinal (elastic collision) and the remainder into heat
|
||||
let cosine_squared_aoa = long_speed_squared / squared_velocity;
|
||||
let converted_lateral_squared = cosine_squared_aoa * lateral_speed_reduction.powi(2);
|
||||
let new_longitudinal_squared = longitudinal_friction_factor_squared
|
||||
* (long_speed_squared + converted_lateral_squared)
|
||||
* height_factor_squared;
|
||||
let new_longitudinal =
|
||||
new_longitudinal_squared.signum() * new_longitudinal_squared.abs().sqrt();
|
||||
let new_ground_speed = new_longitudinal * longitudinal_dir + new_lateral * lateral_dir;
|
||||
physics_state.skating_active = true;
|
||||
vel.0 = Vec3::new(new_ground_speed.x, new_ground_speed.y, 0.0);
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let fric = ground_fric.max(wall_fric);
|
||||
if fric > 0.0 {
|
||||
vel.0 *= (1.0 - fric.min(1.0) * fric_mod).powf(dt.0 * 60.0);
|
||||
physics_state.ground_vel = ground_vel;
|
||||
let ground_fric = physics_state
|
||||
.on_ground
|
||||
.map(|b| b.get_friction())
|
||||
.unwrap_or(0.0);
|
||||
let wall_fric = if physics_state.on_wall.is_some() && climbing {
|
||||
FRIC_GROUND
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let fric = ground_fric.max(wall_fric);
|
||||
if fric > 0.0 {
|
||||
vel.0 *= (1.0 - fric.min(1.0) * fric_mod).powf(dt.0 * 60.0);
|
||||
physics_state.ground_vel = ground_vel;
|
||||
}
|
||||
physics_state.skating_active = false;
|
||||
}
|
||||
|
||||
physics_state.in_fluid = liquid
|
||||
|
@ -147,6 +147,7 @@ impl<'a> System<'a> for Sys {
|
||||
| CharacterState::Sit { .. }
|
||||
| CharacterState::Dance { .. }
|
||||
| CharacterState::Glide { .. }
|
||||
| CharacterState::Skate { .. }
|
||||
| CharacterState::GlideWield { .. }
|
||||
| CharacterState::Wielding { .. }
|
||||
| CharacterState::Equipping { .. }
|
||||
|
@ -11,7 +11,7 @@ mod widgets;
|
||||
use client::{Client, Join, World, WorldExt};
|
||||
use common::{
|
||||
comp,
|
||||
comp::{Poise, PoiseState},
|
||||
comp::{inventory::item::armor::Friction, Poise, PoiseState},
|
||||
};
|
||||
use core::mem;
|
||||
use egui::{
|
||||
@ -708,6 +708,7 @@ fn selected_entity_window(
|
||||
Some(Fluid::Liquid { depth, kind, .. }) => format!("{:?} (Depth: {:.1})", kind, depth),
|
||||
_ => "None".to_owned() });
|
||||
});
|
||||
two_col_row(ui, "Footwear", match physics_state.footwear{ Friction::Ski => "Ski", Friction::Skate => "Skate", /* Friction::Snowshoe => "Snowshoe", Friction::Spikes => "Spikes", */ Friction::Normal=>"Normal",}.to_string());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -93,7 +93,7 @@ fn same_previous_event_elapsed_emits() {
|
||||
#[test]
|
||||
fn maps_idle() {
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(common::states::idle::Data { is_sneaking: false }),
|
||||
&CharacterState::Idle(common::states::idle::Data::default()),
|
||||
&PhysicsState {
|
||||
on_ground: Some(Block::empty()),
|
||||
..Default::default()
|
||||
@ -115,7 +115,7 @@ fn maps_idle() {
|
||||
#[test]
|
||||
fn maps_run_with_sufficient_velocity() {
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(common::states::idle::Data { is_sneaking: false }),
|
||||
&CharacterState::Idle(common::states::idle::Data::default()),
|
||||
&PhysicsState {
|
||||
on_ground: Some(Block::empty()),
|
||||
..Default::default()
|
||||
@ -137,7 +137,7 @@ fn maps_run_with_sufficient_velocity() {
|
||||
#[test]
|
||||
fn does_not_map_run_with_insufficient_velocity() {
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(common::states::idle::Data { is_sneaking: false }),
|
||||
&CharacterState::Idle(common::states::idle::Data::default()),
|
||||
&PhysicsState {
|
||||
on_ground: Some(Block::empty()),
|
||||
..Default::default()
|
||||
@ -159,7 +159,7 @@ fn does_not_map_run_with_insufficient_velocity() {
|
||||
#[test]
|
||||
fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() {
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(common::states::idle::Data { is_sneaking: false }),
|
||||
&CharacterState::Idle(common::states::idle::Data::default()),
|
||||
&Default::default(),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
@ -214,7 +214,7 @@ fn maps_roll() {
|
||||
#[test]
|
||||
fn maps_land_on_ground_to_run() {
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Idle(common::states::idle::Data { is_sneaking: false }),
|
||||
&CharacterState::Idle(common::states::idle::Data::default()),
|
||||
&PhysicsState {
|
||||
on_ground: Some(Block::empty()),
|
||||
..Default::default()
|
||||
|
@ -976,9 +976,10 @@ impl FigureMgr {
|
||||
rel_vel.magnitude_squared() > 0.01, // Moving
|
||||
physics.in_liquid().is_some(), // In water
|
||||
is_rider.is_some(),
|
||||
physics.skating_active,
|
||||
) {
|
||||
// Standing
|
||||
(true, false, false, false) => {
|
||||
// Standing or Skating
|
||||
(true, false, false, false, _) | (_, _, false, false, true) => {
|
||||
anim::character::StandAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(holding_lantern),
|
||||
(
|
||||
@ -997,7 +998,7 @@ impl FigureMgr {
|
||||
)
|
||||
},
|
||||
// Running
|
||||
(true, true, false, false) => {
|
||||
(true, true, false, false, _) => {
|
||||
anim::character::RunAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(holding_lantern),
|
||||
(
|
||||
@ -1019,7 +1020,7 @@ impl FigureMgr {
|
||||
)
|
||||
},
|
||||
// In air
|
||||
(false, _, false, false) => {
|
||||
(false, _, false, false, _) => {
|
||||
anim::character::JumpAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(holding_lantern),
|
||||
(
|
||||
@ -1038,7 +1039,7 @@ impl FigureMgr {
|
||||
)
|
||||
},
|
||||
// Swim
|
||||
(_, _, true, false) => anim::character::SwimAnimation::update_skeleton(
|
||||
(_, _, true, false, _) => anim::character::SwimAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(holding_lantern),
|
||||
(
|
||||
active_tool_kind,
|
||||
@ -1056,7 +1057,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
),
|
||||
// Mount
|
||||
(_, _, _, true) => anim::character::MountAnimation::update_skeleton(
|
||||
(_, _, _, true, _) => anim::character::MountAnimation::update_skeleton(
|
||||
&CharacterSkeleton::new(holding_lantern),
|
||||
(
|
||||
active_tool_kind,
|
||||
@ -1260,7 +1261,9 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Idle(idle::Data { is_sneaking: true }) => {
|
||||
CharacterState::Idle(idle::Data {
|
||||
is_sneaking: true, ..
|
||||
}) => {
|
||||
anim::character::SneakAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
@ -5257,16 +5260,11 @@ impl FigureMgr {
|
||||
// Average velocity relative to the current ground
|
||||
let _rel_avg_vel = state.avg_vel - physics.ground_vel;
|
||||
|
||||
let idlestate = CharacterState::Idle(common::states::idle::Data::default());
|
||||
let last = Last(idlestate.clone());
|
||||
let (character, last_character) = match (character, last_character) {
|
||||
(Some(c), Some(l)) => (c, l),
|
||||
_ => (
|
||||
&CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
}),
|
||||
&Last(CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
})),
|
||||
),
|
||||
_ => (&idlestate, &last),
|
||||
};
|
||||
|
||||
if !character.same_variant(&last_character.0) {
|
||||
@ -5388,16 +5386,11 @@ impl FigureMgr {
|
||||
// Average velocity relative to the current ground
|
||||
let _rel_avg_vel = state.avg_vel - physics.ground_vel;
|
||||
|
||||
let idle_state = CharacterState::Idle(common::states::idle::Data::default());
|
||||
let last = Last(idle_state.clone());
|
||||
let (character, last_character) = match (character, last_character) {
|
||||
(Some(c), Some(l)) => (c, l),
|
||||
_ => (
|
||||
&CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
}),
|
||||
&Last(CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
})),
|
||||
),
|
||||
_ => (&idle_state, &last),
|
||||
};
|
||||
|
||||
if !character.same_variant(&last_character.0) {
|
||||
@ -5486,16 +5479,11 @@ impl FigureMgr {
|
||||
// Average velocity relative to the current ground
|
||||
let _rel_avg_vel = state.avg_vel - physics.ground_vel;
|
||||
|
||||
let idlestate = CharacterState::Idle(common::states::idle::Data::default());
|
||||
let last = Last(idlestate.clone());
|
||||
let (character, last_character) = match (character, last_character) {
|
||||
(Some(c), Some(l)) => (c, l),
|
||||
_ => (
|
||||
&CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
}),
|
||||
&Last(CharacterState::Idle(common::states::idle::Data {
|
||||
is_sneaking: false,
|
||||
})),
|
||||
),
|
||||
_ => (&idlestate, &last),
|
||||
};
|
||||
|
||||
if !character.same_variant(&last_character.0) {
|
||||
|
Loading…
Reference in New Issue
Block a user