mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/sprite-interaction' into 'master'
Sprite Interaction See merge request veloren/veloren!2790
This commit is contained in:
commit
70b3374705
@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- The 'spot' system, which generates smaller site-like structures and scenarios
|
||||
- Chestnut and cedar tree varieties
|
||||
- Shooting sprites, such as apples and hives, can knock them out of trees
|
||||
- Sprite pickup animations
|
||||
|
||||
### Changed
|
||||
|
||||
@ -66,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Enemies no more spawn in dungeon boss room
|
||||
- Melee critical hit no more applies after reduction by armour
|
||||
- Removed Healing Sceptre as a starting weapon as it is considered an advanced weapon
|
||||
- The ability to pickup sprites through walls
|
||||
|
||||
### Fixed
|
||||
|
||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5859,6 +5859,7 @@ dependencies = [
|
||||
"csv",
|
||||
"dot_vox",
|
||||
"enum-iterator",
|
||||
"fxhash",
|
||||
"hashbrown 0.11.2",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
|
@ -1369,8 +1369,8 @@ impl Client {
|
||||
}
|
||||
|
||||
pub fn collect_block(&mut self, pos: Vec3<i32>) {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryEvent(
|
||||
InventoryEvent::Collect(pos),
|
||||
self.control_action(ControlAction::InventoryAction(InventoryAction::Collect(
|
||||
pos,
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ spin_sleep = "1.0"
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
|
||||
rand = "0.8"
|
||||
fxhash = "0.2.1"
|
||||
|
||||
# Assets
|
||||
common-assets = {package = "veloren-common-assets", path = "assets"}
|
||||
|
@ -452,6 +452,13 @@ impl Attack {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Emits event to handle things that should happen for any successful attack,
|
||||
// regardless of if the attack had any damages or effects in it
|
||||
if is_applied {
|
||||
emit(ServerEvent::EntityAttackedHook {
|
||||
entity: target.entity,
|
||||
});
|
||||
}
|
||||
is_applied
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,9 @@ pub enum CharacterState {
|
||||
SpriteSummon(sprite_summon::Data),
|
||||
/// Handles logic for using an item so it is not simply instant
|
||||
UseItem(use_item::Data),
|
||||
/// Handles logic for interacting with a sprite, e.g. using a chest or
|
||||
/// picking a plant
|
||||
SpriteInteract(sprite_interact::Data),
|
||||
}
|
||||
|
||||
impl CharacterState {
|
||||
@ -255,6 +258,7 @@ impl CharacterState {
|
||||
CharacterState::SelfBuff(data) => data.behavior(j),
|
||||
CharacterState::SpriteSummon(data) => data.behavior(j),
|
||||
CharacterState::UseItem(data) => data.behavior(j),
|
||||
CharacterState::SpriteInteract(data) => data.behavior(j),
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +299,7 @@ impl CharacterState {
|
||||
CharacterState::SelfBuff(data) => data.handle_event(j, action),
|
||||
CharacterState::SpriteSummon(data) => data.handle_event(j, action),
|
||||
CharacterState::UseItem(data) => data.handle_event(j, action),
|
||||
CharacterState::SpriteInteract(data) => data.handle_event(j, action),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ use vek::*;
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum InventoryEvent {
|
||||
Pickup(Uid),
|
||||
Collect(Vec3<i32>),
|
||||
Swap(InvSlotId, InvSlotId),
|
||||
SplitSwap(InvSlotId, InvSlotId),
|
||||
Drop(InvSlotId),
|
||||
@ -35,6 +34,7 @@ pub enum InventoryAction {
|
||||
Drop(EquipSlot),
|
||||
Use(Slot),
|
||||
Sort,
|
||||
Collect(Vec3<i32>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -61,6 +61,7 @@ impl From<InventoryAction> for InventoryManip {
|
||||
InventoryAction::Swap(equip, slot) => Self::Swap(Slot::Equip(equip), slot),
|
||||
InventoryAction::Drop(equip) => Self::Drop(Slot::Equip(equip)),
|
||||
InventoryAction::Sort => Self::Sort,
|
||||
InventoryAction::Collect(collect) => Self::Collect(collect),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,7 +70,6 @@ impl From<InventoryEvent> for InventoryManip {
|
||||
fn from(inv_event: InventoryEvent) -> Self {
|
||||
match inv_event {
|
||||
InventoryEvent::Pickup(pickup) => Self::Pickup(pickup),
|
||||
InventoryEvent::Collect(collect) => Self::Collect(collect),
|
||||
InventoryEvent::Swap(inv1, inv2) => {
|
||||
Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
// The limit on distance between the entity and a collectible (squared)
|
||||
pub const MAX_PICKUP_RANGE: f32 = 8.0;
|
||||
pub const MAX_PICKUP_RANGE: f32 = 5.0;
|
||||
pub const MAX_MOUNT_RANGE: f32 = 14.0;
|
||||
|
||||
pub const GRAVITY: f32 = 25.0;
|
||||
|
@ -197,6 +197,9 @@ pub enum ServerEvent {
|
||||
pet_entity: EcsEntity,
|
||||
owner_entity: EcsEntity,
|
||||
},
|
||||
EntityAttackedHook {
|
||||
entity: EcsEntity,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventBus<E> {
|
||||
|
@ -55,7 +55,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.8);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -67,7 +67,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
let ori_rate = self.static_data.ori_rate;
|
||||
|
||||
handle_orientation(data, &mut update, ori_rate);
|
||||
handle_orientation(data, &mut update, ori_rate, None);
|
||||
handle_move(data, &mut update, 0.4);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -36,7 +36,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.4);
|
||||
|
||||
match self.stage_section {
|
||||
|
@ -56,10 +56,9 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.7);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 0.35);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
|
@ -48,7 +48,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.3);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
|
@ -72,7 +72,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.7);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -74,7 +74,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, self.static_data.move_speed);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -175,7 +175,12 @@ impl CharacterBehavior for Data {
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_buildup_duration {
|
||||
handle_orientation(data, &mut update, 0.4 * self.static_data.ori_modifier);
|
||||
handle_orientation(
|
||||
data,
|
||||
&mut update,
|
||||
0.4 * self.static_data.ori_modifier,
|
||||
None,
|
||||
);
|
||||
|
||||
// Build up
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
@ -289,7 +294,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else if self.timer < self.static_data.stage_data[stage_index].base_swing_duration
|
||||
{
|
||||
handle_orientation(data, &mut update, 0.4 * self.static_data.ori_modifier);
|
||||
handle_orientation(
|
||||
data,
|
||||
&mut update,
|
||||
0.4 * self.static_data.ori_modifier,
|
||||
None,
|
||||
);
|
||||
|
||||
// Forward movement
|
||||
handle_forced_movement(data, &mut update, ForcedMovement::Forward {
|
||||
@ -314,7 +324,12 @@ impl CharacterBehavior for Data {
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.stage_data[stage_index].base_recover_duration {
|
||||
handle_orientation(data, &mut update, 0.8 * self.static_data.ori_modifier);
|
||||
handle_orientation(
|
||||
data,
|
||||
&mut update,
|
||||
0.8 * self.static_data.ori_modifier,
|
||||
None,
|
||||
);
|
||||
// Recovers
|
||||
update.character = CharacterState::ComboMelee(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
|
@ -82,7 +82,7 @@ impl CharacterBehavior for Data {
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
// Build up
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
@ -109,7 +109,7 @@ impl CharacterBehavior for Data {
|
||||
/ self.static_data.charge_duration.as_secs_f32())
|
||||
.min(1.0);
|
||||
|
||||
handle_orientation(data, &mut update, self.static_data.ori_modifier);
|
||||
handle_orientation(data, &mut update, self.static_data.ori_modifier, None);
|
||||
handle_forced_movement(data, &mut update, ForcedMovement::Forward {
|
||||
strength: self.static_data.forward_speed * charge_frac.sqrt(),
|
||||
});
|
||||
|
@ -26,7 +26,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -35,7 +35,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
handle_dodge_input(data, &mut update);
|
||||
|
@ -10,7 +10,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
handle_wield(data, &mut update);
|
||||
|
@ -60,7 +60,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.3);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
|
||||
|
@ -25,6 +25,7 @@ pub mod shockwave;
|
||||
pub mod sit;
|
||||
pub mod sneak;
|
||||
pub mod spin_melee;
|
||||
pub mod sprite_interact;
|
||||
pub mod sprite_summon;
|
||||
pub mod stunned;
|
||||
pub mod talk;
|
||||
|
@ -54,7 +54,7 @@ pub struct Data {
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.3);
|
||||
|
||||
match self.stage_section {
|
||||
|
@ -54,7 +54,7 @@ impl CharacterBehavior for Data {
|
||||
update.should_strafe = false;
|
||||
|
||||
// Smooth orientation
|
||||
handle_orientation(data, &mut update, 2.5);
|
||||
handle_orientation(data, &mut update, 2.5, None);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
|
@ -65,7 +65,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, self.static_data.move_efficiency);
|
||||
|
||||
match self.stage_section {
|
||||
|
@ -10,7 +10,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 0.4);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
handle_wield(data, &mut update);
|
||||
|
190
common/src/states/sprite_interact.rs
Normal file
190
common/src/states/sprite_interact.rs
Normal file
@ -0,0 +1,190 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, InventoryManip, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
terrain::SpriteKind,
|
||||
util::Dir,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
/// Separated out to condense update portions of character state
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct StaticData {
|
||||
/// Buildup to sprite interaction
|
||||
pub buildup_duration: Duration,
|
||||
/// Duration of sprite interaction
|
||||
pub use_duration: Duration,
|
||||
/// Recovery after sprite interaction
|
||||
pub recover_duration: Duration,
|
||||
/// Position sprite is located at
|
||||
pub sprite_pos: Vec3<i32>,
|
||||
/// Kind of sprite interacted with
|
||||
pub sprite_kind: SpriteInteractKind,
|
||||
/// Had weapon wielded
|
||||
pub was_wielded: bool,
|
||||
/// Was sneaking
|
||||
pub was_sneak: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// Struct containing data that does not change over the course of the
|
||||
/// character state
|
||||
pub static_data: StaticData,
|
||||
/// Timer for each stage
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
let ori_dir = Dir::from_unnormalized(Vec3::from(
|
||||
(self.static_data.sprite_pos.map(|x| x as f32) - data.pos.0).xy(),
|
||||
));
|
||||
handle_orientation(data, &mut update, 1.0, ori_dir);
|
||||
handle_move(data, &mut update, 0.0);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Buildup => {
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Build up
|
||||
update.character = CharacterState::SpriteInteract(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Transitions to use section of stage
|
||||
update.character = CharacterState::SpriteInteract(Data {
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Action,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Action => {
|
||||
if self.timer < self.static_data.use_duration {
|
||||
// sprite interaction
|
||||
update.character = CharacterState::SpriteInteract(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Transitions to recover section of stage
|
||||
update.character = CharacterState::SpriteInteract(Data {
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Recover,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::SpriteInteract(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Create inventory manipulation event
|
||||
let inv_manip = InventoryManip::Collect(self.static_data.sprite_pos);
|
||||
update
|
||||
.server_events
|
||||
.push_front(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
// Done
|
||||
if self.static_data.was_wielded {
|
||||
update.character = CharacterState::Wielding;
|
||||
} else if self.static_data.was_sneak {
|
||||
update.character = CharacterState::Sneak;
|
||||
} else {
|
||||
update.character = CharacterState::Idle;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// If it somehow ends up in an incorrect stage section
|
||||
update.character = CharacterState::Idle;
|
||||
},
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
handle_state_interrupt(data, &mut update, false);
|
||||
|
||||
update
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to control effects based off of the type of sprite interacted with
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SpriteInteractKind {
|
||||
Chest,
|
||||
Harvestable,
|
||||
Collectible,
|
||||
Fallback,
|
||||
}
|
||||
|
||||
impl From<SpriteKind> for Option<SpriteInteractKind> {
|
||||
fn from(sprite_kind: SpriteKind) -> Self {
|
||||
match sprite_kind {
|
||||
SpriteKind::Apple
|
||||
| SpriteKind::Mushroom
|
||||
| SpriteKind::RedFlower
|
||||
| SpriteKind::Sunflower
|
||||
| SpriteKind::Coconut
|
||||
| SpriteKind::Beehive
|
||||
| SpriteKind::Cotton
|
||||
| SpriteKind::Moonbell
|
||||
| SpriteKind::Pyrebloom
|
||||
| SpriteKind::WildFlax
|
||||
| SpriteKind::RoundCactus
|
||||
| SpriteKind::ShortFlatCactus
|
||||
| SpriteKind::MedFlatCactus => Some(SpriteInteractKind::Harvestable),
|
||||
SpriteKind::Stones
|
||||
| SpriteKind::Twigs
|
||||
| SpriteKind::VialEmpty
|
||||
| SpriteKind::Bowl
|
||||
| SpriteKind::PotionMinor
|
||||
| SpriteKind::Seashells => Some(SpriteInteractKind::Collectible),
|
||||
// Collectible checked in addition to container for case that sprite requires a tool to
|
||||
// collect and cannot be collected by hand, yet still meets the container check
|
||||
_ if sprite_kind.is_container() && sprite_kind.is_collectible() => {
|
||||
Some(SpriteInteractKind::Chest)
|
||||
},
|
||||
_ if sprite_kind.is_collectible() => Some(SpriteInteractKind::Fallback),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpriteInteractKind {
|
||||
/// Returns (buildup, use, recover)
|
||||
pub fn durations(&self) -> (Duration, Duration, Duration) {
|
||||
match self {
|
||||
Self::Chest => (
|
||||
Duration::from_secs_f32(0.5),
|
||||
Duration::from_secs_f32(2.0),
|
||||
Duration::from_secs_f32(0.5),
|
||||
),
|
||||
Self::Collectible => (
|
||||
Duration::from_secs_f32(0.1),
|
||||
Duration::from_secs_f32(0.3),
|
||||
Duration::from_secs_f32(0.1),
|
||||
),
|
||||
Self::Harvestable => (
|
||||
Duration::from_secs_f32(0.3),
|
||||
Duration::from_secs_f32(0.5),
|
||||
Duration::from_secs_f32(0.2),
|
||||
),
|
||||
Self::Fallback => (
|
||||
Duration::from_secs_f32(5.0),
|
||||
Duration::from_secs_f32(5.0),
|
||||
Duration::from_secs_f32(5.0),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, self.static_data.movement_speed);
|
||||
|
||||
match self.stage_section {
|
||||
|
@ -15,7 +15,7 @@ impl CharacterBehavior for Data {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_wield(data, &mut update);
|
||||
handle_orientation(data, &mut update, TURN_RATE);
|
||||
handle_orientation(data, &mut update, TURN_RATE, None);
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ impl CharacterBehavior for Data {
|
||||
|
||||
match self.static_data.item_kind {
|
||||
ItemUseKind::Consumable(ConsumableKind::Drink) => {
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
},
|
||||
ItemUseKind::Consumable(ConsumableKind::Food | ConsumableKind::ComplexFood) => {
|
||||
handle_orientation(data, &mut update, 0.0);
|
||||
handle_orientation(data, &mut update, 0.0, None);
|
||||
handle_move(data, &mut update, 0.0);
|
||||
},
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
astar::Astar,
|
||||
combat,
|
||||
comp::{
|
||||
biped_large, biped_small,
|
||||
@ -9,11 +10,14 @@ use crate::{
|
||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||
InventoryAction, StateUpdate,
|
||||
},
|
||||
consts::{FRIC_GROUND, GRAVITY},
|
||||
consts::{FRIC_GROUND, GRAVITY, MAX_PICKUP_RANGE},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
states::{behavior::JoinData, *},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use core::hash::BuildHasherDefault;
|
||||
use fxhash::FxHasher64;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
ops::{Add, Div},
|
||||
@ -348,11 +352,23 @@ pub fn handle_forced_movement(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_orientation(data: &JoinData<'_>, update: &mut StateUpdate, efficiency: f32) {
|
||||
let dir = (is_strafing(data, update) || update.character.is_attack())
|
||||
.then(|| data.inputs.look_dir.to_horizontal().unwrap_or_default())
|
||||
.or_else(|| Dir::from_unnormalized(data.inputs.move_dir.into()))
|
||||
.unwrap_or_else(|| data.ori.to_horizontal().look_dir());
|
||||
pub fn handle_orientation(
|
||||
data: &JoinData<'_>,
|
||||
update: &mut StateUpdate,
|
||||
efficiency: f32,
|
||||
dir_override: Option<Dir>,
|
||||
) {
|
||||
// Direction is set to the override if one is provided, else if entity is
|
||||
// strafing or attacking the horiontal component of the look direction is used,
|
||||
// else the current horizontal movement direction is used
|
||||
let dir = if let Some(dir_override) = dir_override {
|
||||
dir_override
|
||||
} else if is_strafing(data, update) || update.character.is_attack() {
|
||||
data.inputs.look_dir.to_horizontal().unwrap_or_default()
|
||||
} else {
|
||||
Dir::from_unnormalized(data.inputs.move_dir.into())
|
||||
.unwrap_or_else(|| data.ori.to_horizontal().look_dir())
|
||||
};
|
||||
let rate = {
|
||||
let angle = update.ori.look_dir().angle_between(*dir);
|
||||
data.body.base_ori_rate() * efficiency * std::f32::consts::PI / angle
|
||||
@ -421,7 +437,7 @@ pub fn fly_move(data: &JoinData<'_>, update: &mut StateUpdate, efficiency: f32)
|
||||
let thrust = efficiency * force;
|
||||
let accel = thrust / data.mass.0;
|
||||
|
||||
handle_orientation(data, update, efficiency);
|
||||
handle_orientation(data, update, efficiency, None);
|
||||
|
||||
// Elevation control
|
||||
match data.body {
|
||||
@ -584,44 +600,145 @@ pub fn handle_manipulate_loadout(
|
||||
update: &mut StateUpdate,
|
||||
inv_action: InventoryAction,
|
||||
) {
|
||||
use use_item::ItemUseKind;
|
||||
if let InventoryAction::Use(Slot::Inventory(inv_slot)) = inv_action {
|
||||
// If inventory action is using a slot, and slot is in the inventory
|
||||
// TODO: Do some non lazy way of handling the possibility that items equipped in
|
||||
// the loadout will have effects that are desired to be non-instantaneous
|
||||
if let Some((item_kind, item)) = data
|
||||
.inventory
|
||||
.and_then(|inv| inv.get(inv_slot))
|
||||
.and_then(|item| Option::<ItemUseKind>::from(item.kind()).zip(Some(item)))
|
||||
{
|
||||
let (buildup_duration, use_duration, recover_duration) = item_kind.durations();
|
||||
// If item returns a valid kind for item use, do into use item character state
|
||||
update.character = CharacterState::UseItem(use_item::Data {
|
||||
static_data: use_item::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
inv_slot,
|
||||
item_kind,
|
||||
item_definition_id: item.item_definition_id().to_string(),
|
||||
was_wielded: matches!(data.character, CharacterState::Wielding),
|
||||
was_sneak: matches!(data.character, CharacterState::Sneak),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
});
|
||||
} else {
|
||||
// Else emit inventory action instantnaneously
|
||||
match inv_action {
|
||||
InventoryAction::Use(Slot::Inventory(inv_slot)) => {
|
||||
// If inventory action is using a slot, and slot is in the inventory
|
||||
// TODO: Do some non lazy way of handling the possibility that items equipped in
|
||||
// the loadout will have effects that are desired to be non-instantaneous
|
||||
use use_item::ItemUseKind;
|
||||
if let Some((item_kind, item)) = data
|
||||
.inventory
|
||||
.and_then(|inv| inv.get(inv_slot))
|
||||
.and_then(|item| Option::<ItemUseKind>::from(item.kind()).zip(Some(item)))
|
||||
{
|
||||
let (buildup_duration, use_duration, recover_duration) = item_kind.durations();
|
||||
// If item returns a valid kind for item use, do into use item character state
|
||||
update.character = CharacterState::UseItem(use_item::Data {
|
||||
static_data: use_item::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
inv_slot,
|
||||
item_kind,
|
||||
item_definition_id: item.item_definition_id().to_string(),
|
||||
was_wielded: matches!(data.character, CharacterState::Wielding),
|
||||
was_sneak: matches!(data.character, CharacterState::Sneak),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
});
|
||||
} else {
|
||||
// Else emit inventory action instantnaneously
|
||||
update
|
||||
.server_events
|
||||
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
|
||||
}
|
||||
},
|
||||
InventoryAction::Collect(sprite_pos) => {
|
||||
let sprite_pos_f32 = sprite_pos.map(|x| x as f32);
|
||||
// CLosure to check if distance between a point and the sprite is less than
|
||||
// MAX_PICKUP_RANGE and the radius of the body
|
||||
let sprite_range_check = |pos: Vec3<f32>| {
|
||||
(sprite_pos_f32 - pos).magnitude_squared()
|
||||
< (MAX_PICKUP_RANGE + data.body.radius()).powi(2)
|
||||
};
|
||||
|
||||
// Checks if player's feet or head is near to sprite
|
||||
let close_to_sprite = sprite_range_check(data.pos.0)
|
||||
|| sprite_range_check(data.pos.0 + Vec3::new(0.0, 0.0, data.body.height()));
|
||||
if close_to_sprite {
|
||||
// First, get sprite data for position, if there is a sprite
|
||||
use sprite_interact::SpriteInteractKind;
|
||||
let sprite_at_pos = data
|
||||
.terrain
|
||||
.get(sprite_pos)
|
||||
.ok()
|
||||
.copied()
|
||||
.and_then(|b| b.get_sprite());
|
||||
|
||||
// Checks if position has a collectible sprite as well as what sprite is at the
|
||||
// position
|
||||
let sprite_interact = sprite_at_pos.and_then(Option::<SpriteInteractKind>::from);
|
||||
|
||||
if let Some(sprite_interact) = sprite_interact {
|
||||
// Do a check that a path can be found between sprite and entity
|
||||
// interacting with sprite Use manhattan distance * 1.5 for number
|
||||
// of iterations
|
||||
let iters =
|
||||
(3.0 * (sprite_pos_f32 - data.pos.0).map(|x| x.abs()).sum()) as usize;
|
||||
// Heuristic compares manhattan distance of start and end pos
|
||||
let heuristic =
|
||||
move |pos: &Vec3<i32>| (sprite_pos - pos).map(|x| x.abs()).sum() as f32;
|
||||
|
||||
let mut astar = Astar::new(
|
||||
iters,
|
||||
data.pos.0.map(|x| x.floor() as i32),
|
||||
heuristic,
|
||||
BuildHasherDefault::<FxHasher64>::default(),
|
||||
);
|
||||
|
||||
// Neighbors are all neighboring blocks that are air
|
||||
let neighbors = |pos: &Vec3<i32>| {
|
||||
const DIRS: [Vec3<i32>; 6] = [
|
||||
Vec3::new(1, 0, 0),
|
||||
Vec3::new(-1, 0, 0),
|
||||
Vec3::new(0, 1, 0),
|
||||
Vec3::new(0, -1, 0),
|
||||
Vec3::new(0, 0, 1),
|
||||
Vec3::new(0, 0, -1),
|
||||
];
|
||||
let pos = *pos;
|
||||
DIRS.iter().map(move |dir| dir + pos).filter(|pos| {
|
||||
data.terrain
|
||||
.get(*pos)
|
||||
.ok()
|
||||
.map_or(false, |block| !block.is_filled())
|
||||
})
|
||||
};
|
||||
// Transition uses manhattan distance as the cost, which is always 1 since we
|
||||
// only ever step one block at a time
|
||||
let transition = |_: &Vec3<i32>, _: &Vec3<i32>| 1.0;
|
||||
// Pathing satisfied when it reaches the sprite position
|
||||
let satisfied = |pos: &Vec3<i32>| *pos == sprite_pos;
|
||||
|
||||
let not_blocked_by_terrain = astar
|
||||
.poll(iters, heuristic, neighbors, transition, satisfied)
|
||||
.into_path()
|
||||
.is_some();
|
||||
|
||||
// If path can be found between entity interacting with sprite and entity, start
|
||||
// interaction with sprite
|
||||
if not_blocked_by_terrain {
|
||||
// If the sprite is collectible, enter the sprite interaction character
|
||||
// state TODO: Handle cases for sprite being
|
||||
// interactible, but not collectible (none currently
|
||||
// exist)
|
||||
let (buildup_duration, use_duration, recover_duration) =
|
||||
sprite_interact.durations();
|
||||
|
||||
update.character = CharacterState::SpriteInteract(sprite_interact::Data {
|
||||
static_data: sprite_interact::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
sprite_pos,
|
||||
sprite_kind: sprite_interact,
|
||||
was_wielded: matches!(data.character, CharacterState::Wielding),
|
||||
was_sneak: matches!(data.character, CharacterState::Sneak),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// Else just do event instantaneously
|
||||
update
|
||||
.server_events
|
||||
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
|
||||
}
|
||||
} else {
|
||||
// Else if inventory action is not item use, or if slot is in loadout, just do
|
||||
// event instantaneously
|
||||
update
|
||||
.server_events
|
||||
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_climb(data, &mut update);
|
||||
attempt_input(data, &mut update);
|
||||
|
@ -134,18 +134,6 @@ impl<'a> System<'a> for Sys {
|
||||
let was_wielded = char_state.is_wield();
|
||||
let poise_state = poise.poise_state();
|
||||
let pos = pos.0;
|
||||
// Remove potion/saturation buff if knocked into poise state
|
||||
if !matches!(poise_state, PoiseState::Normal) {
|
||||
use comp::buff::{BuffChange, BuffKind};
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
entity,
|
||||
buff_change: BuffChange::RemoveByKind(BuffKind::Potion),
|
||||
});
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
entity,
|
||||
buff_change: BuffChange::RemoveByKind(BuffKind::Saturation),
|
||||
});
|
||||
}
|
||||
match poise_state {
|
||||
PoiseState::Normal => {},
|
||||
PoiseState::Interrupted => {
|
||||
|
@ -261,7 +261,8 @@ impl<'a> System<'a> for Sys {
|
||||
| CharacterState::Climb { .. }
|
||||
| CharacterState::Stunned { .. }
|
||||
| CharacterState::BasicBlock { .. }
|
||||
| CharacterState::UseItem { .. } => {},
|
||||
| CharacterState::UseItem { .. }
|
||||
| CharacterState::SpriteInteract { .. } => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1230,3 +1230,30 @@ pub fn handle_teleport_to(server: &Server, entity: EcsEntity, target: Uid, max_r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Intended to handle things that should happen for any successful attack,
|
||||
/// regardless of the damages and effects specific to that attack
|
||||
pub fn handle_entity_attacked_hook(server: &Server, entity: EcsEntity) {
|
||||
let ecs = &server.state.ecs();
|
||||
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
|
||||
|
||||
if let Some(mut char_state) = ecs.write_storage::<CharacterState>().get_mut(entity) {
|
||||
// Interrupt sprite interaction and item use if any attack is applied to entity
|
||||
if matches!(
|
||||
*char_state,
|
||||
CharacterState::SpriteInteract(_) | CharacterState::UseItem(_)
|
||||
) {
|
||||
*char_state = CharacterState::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove potion/saturation buff if attacked
|
||||
server_eventbus.emit_now(ServerEvent::Buff {
|
||||
entity,
|
||||
buff_change: buff::BuffChange::RemoveByKind(buff::BuffKind::Potion),
|
||||
});
|
||||
server_eventbus.emit_now(ServerEvent::Buff {
|
||||
entity,
|
||||
buff_change: buff::BuffChange::RemoveByKind(buff::BuffKind::Saturation),
|
||||
});
|
||||
}
|
||||
|
@ -188,21 +188,6 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
|
||||
if let Some(block) = block {
|
||||
if block.is_collectible() && state.can_set_block(pos) {
|
||||
// Check if the block is within pickup range
|
||||
let entity_cylinder = get_cylinder(state, entity);
|
||||
if !within_pickup_range(entity_cylinder, || {
|
||||
Some(find_dist::Cube {
|
||||
min: pos.as_(),
|
||||
side_length: 1.0,
|
||||
})
|
||||
}) {
|
||||
debug!(
|
||||
?entity_cylinder,
|
||||
"Failed to pick up block as not within range, block pos: {}", pos
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
|
||||
// NOTE: We dup the item for message purposes.
|
||||
let item_msg = item.duplicate(
|
||||
|
@ -7,8 +7,8 @@ use entity_creation::{
|
||||
};
|
||||
use entity_manipulation::{
|
||||
handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete,
|
||||
handle_destroy, handle_energy_change, handle_explosion, handle_knockback,
|
||||
handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
|
||||
handle_destroy, handle_energy_change, handle_entity_attacked_hook, handle_explosion,
|
||||
handle_knockback, handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
|
||||
};
|
||||
use group_manip::handle_group;
|
||||
use information::handle_site_info;
|
||||
@ -229,6 +229,9 @@ impl Server {
|
||||
pet_entity,
|
||||
owner_entity,
|
||||
} => handle_tame_pet(self, pet_entity, owner_entity),
|
||||
ServerEvent::EntityAttackedHook { entity } => {
|
||||
handle_entity_attacked_hook(self, entity)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
104
voxygen/anim/src/character/collect.rs
Normal file
104
voxygen/anim/src/character/collect.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::states::utils::StageSection;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct CollectAnimation;
|
||||
|
||||
impl Animation for CollectAnimation {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Dependency<'a> = (Vec3<f32>, f32, Option<StageSection>, Vec3<f32>);
|
||||
type Skeleton = CharacterSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"character_collect\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_collect")]
|
||||
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner<'a>(
|
||||
skeleton: &Self::Skeleton,
|
||||
(position, _global_time, stage_section, sprite_pos): Self::Dependency<'a>,
|
||||
anim_time: f32,
|
||||
rate: &mut f32,
|
||||
s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
*rate = 1.0;
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (movement1, move2, move2alt, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0, 0.0),
|
||||
Some(StageSection::Action) => (
|
||||
1.0,
|
||||
(anim_time * 12.0).sin(),
|
||||
(anim_time * 9.0 + PI / 2.0).sin(),
|
||||
0.0,
|
||||
),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, 1.0, anim_time.powi(4)),
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
let z_diff = (sprite_pos.z - position.z).round();
|
||||
let z_diff = if z_diff > 0.0 { z_diff / 9.0 } else { 0.0 };
|
||||
let squat = (1.0 - z_diff).powf(4.0);
|
||||
|
||||
let pullback = 1.0 - move3;
|
||||
|
||||
let move1 = movement1 * pullback * squat;
|
||||
let move1_nosquat = movement1 * pullback;
|
||||
let upshift = if squat < 0.35 {
|
||||
move1_nosquat * 0.3
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
next.head.orientation = Quaternion::rotation_x(move1_nosquat * 0.2 + upshift * 1.3);
|
||||
|
||||
next.chest.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.chest.0 + upshift * 3.0,
|
||||
s_a.chest.1 + move2 * 0.15 + upshift * 3.0,
|
||||
);
|
||||
next.chest.orientation = Quaternion::rotation_x(move1 * -1.0 + move2alt * 0.015);
|
||||
|
||||
next.belt.position = Vec3::new(0.0, s_a.belt.0 + move1 * 1.0, s_a.belt.1 + move1 * -0.0);
|
||||
next.belt.orientation = Quaternion::rotation_x(move1 * 0.2);
|
||||
|
||||
next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1);
|
||||
|
||||
next.shorts.position =
|
||||
Vec3::new(0.0, s_a.shorts.0 + move1 * 2.0, s_a.shorts.1 + move1 * -0.0);
|
||||
next.shorts.orientation = Quaternion::rotation_x(move1 * 0.3);
|
||||
|
||||
next.hand_l.position = Vec3::new(
|
||||
-s_a.hand.0 + move1_nosquat * 4.0 - move2alt * 1.0,
|
||||
s_a.hand.1 + move1_nosquat * 8.0 + move2 * 1.0 + upshift * -5.0,
|
||||
s_a.hand.2 + move1_nosquat * 5.0 + upshift * 15.0,
|
||||
);
|
||||
|
||||
next.hand_l.orientation = Quaternion::rotation_x(move1_nosquat * 1.9 + upshift * 2.0)
|
||||
* Quaternion::rotation_y(move1_nosquat * -0.3 + move2alt * -0.2);
|
||||
|
||||
next.hand_r.position = Vec3::new(
|
||||
s_a.hand.0 + move1_nosquat * -4.0 - move2 * 1.0,
|
||||
s_a.hand.1 + move1_nosquat * 8.0 + move2alt * -1.0 + upshift * -5.0,
|
||||
s_a.hand.2 + move1_nosquat * 5.0 + upshift * 15.0,
|
||||
);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(move1_nosquat * 1.9 + upshift * 2.0)
|
||||
* Quaternion::rotation_y(move1_nosquat * 0.3 + move2 * 0.3);
|
||||
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0,
|
||||
s_a.foot.1 + move1 * 2.0 + upshift * -3.5,
|
||||
s_a.foot.2 + upshift * 2.0,
|
||||
);
|
||||
next.foot_l.orientation = Quaternion::rotation_x(move1 * -0.2 + upshift * -2.2);
|
||||
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0,
|
||||
s_a.foot.1 + move1 * -4.0 + upshift * -0.5,
|
||||
s_a.foot.2 + upshift * 2.0,
|
||||
);
|
||||
next.foot_r.orientation = Quaternion::rotation_x(move1 * -0.8 + upshift * -1.2);
|
||||
next
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ pub mod beta;
|
||||
pub mod block;
|
||||
pub mod chargeswing;
|
||||
pub mod climb;
|
||||
pub mod collect;
|
||||
pub mod consume;
|
||||
pub mod dance;
|
||||
pub mod dash;
|
||||
@ -34,8 +35,8 @@ pub mod wield;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, block::BlockAnimation,
|
||||
chargeswing::ChargeswingAnimation, climb::ClimbAnimation, consume::ConsumeAnimation,
|
||||
dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
|
||||
chargeswing::ChargeswingAnimation, climb::ClimbAnimation, collect::CollectAnimation,
|
||||
consume::ConsumeAnimation, dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
|
||||
glidewield::GlideWieldAnimation, gliding::GlidingAnimation, idle::IdleAnimation,
|
||||
jump::JumpAnimation, leapmelee::LeapAnimation, mount::MountAnimation,
|
||||
repeater::RepeaterAnimation, roll::RollAnimation, run::RunAnimation,
|
||||
|
@ -1133,6 +1133,32 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::SpriteInteract(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
let sprite_pos = s.static_data.sprite_pos;
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Action => s.timer.as_secs_f32(),
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
anim::character::CollectAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
pos.0,
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
anim::vek::Vec3::from(sprite_pos.map(|x| x as f32)),
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Boost(_) => {
|
||||
anim::character::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
|
Loading…
Reference in New Issue
Block a user