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
|
- The 'spot' system, which generates smaller site-like structures and scenarios
|
||||||
- Chestnut and cedar tree varieties
|
- Chestnut and cedar tree varieties
|
||||||
- Shooting sprites, such as apples and hives, can knock them out of trees
|
- Shooting sprites, such as apples and hives, can knock them out of trees
|
||||||
|
- Sprite pickup animations
|
||||||
|
|
||||||
### Changed
|
### 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
|
- Enemies no more spawn in dungeon boss room
|
||||||
- Melee critical hit no more applies after reduction by armour
|
- Melee critical hit no more applies after reduction by armour
|
||||||
- Removed Healing Sceptre as a starting weapon as it is considered an advanced weapon
|
- Removed Healing Sceptre as a starting weapon as it is considered an advanced weapon
|
||||||
|
- The ability to pickup sprites through walls
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5859,6 +5859,7 @@ dependencies = [
|
|||||||
"csv",
|
"csv",
|
||||||
"dot_vox",
|
"dot_vox",
|
||||||
"enum-iterator",
|
"enum-iterator",
|
||||||
|
"fxhash",
|
||||||
"hashbrown 0.11.2",
|
"hashbrown 0.11.2",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -1369,8 +1369,8 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_block(&mut self, pos: Vec3<i32>) {
|
pub fn collect_block(&mut self, pos: Vec3<i32>) {
|
||||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryEvent(
|
self.control_action(ControlAction::InventoryAction(InventoryAction::Collect(
|
||||||
InventoryEvent::Collect(pos),
|
pos,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ spin_sleep = "1.0"
|
|||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
|
uuid = { version = "0.8.1", default-features = false, features = ["serde", "v4"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
fxhash = "0.2.1"
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
common-assets = {package = "veloren-common-assets", path = "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
|
is_applied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,9 @@ pub enum CharacterState {
|
|||||||
SpriteSummon(sprite_summon::Data),
|
SpriteSummon(sprite_summon::Data),
|
||||||
/// Handles logic for using an item so it is not simply instant
|
/// Handles logic for using an item so it is not simply instant
|
||||||
UseItem(use_item::Data),
|
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 {
|
impl CharacterState {
|
||||||
@ -255,6 +258,7 @@ impl CharacterState {
|
|||||||
CharacterState::SelfBuff(data) => data.behavior(j),
|
CharacterState::SelfBuff(data) => data.behavior(j),
|
||||||
CharacterState::SpriteSummon(data) => data.behavior(j),
|
CharacterState::SpriteSummon(data) => data.behavior(j),
|
||||||
CharacterState::UseItem(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::SelfBuff(data) => data.handle_event(j, action),
|
||||||
CharacterState::SpriteSummon(data) => data.handle_event(j, action),
|
CharacterState::SpriteSummon(data) => data.handle_event(j, action),
|
||||||
CharacterState::UseItem(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)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum InventoryEvent {
|
pub enum InventoryEvent {
|
||||||
Pickup(Uid),
|
Pickup(Uid),
|
||||||
Collect(Vec3<i32>),
|
|
||||||
Swap(InvSlotId, InvSlotId),
|
Swap(InvSlotId, InvSlotId),
|
||||||
SplitSwap(InvSlotId, InvSlotId),
|
SplitSwap(InvSlotId, InvSlotId),
|
||||||
Drop(InvSlotId),
|
Drop(InvSlotId),
|
||||||
@ -35,6 +34,7 @@ pub enum InventoryAction {
|
|||||||
Drop(EquipSlot),
|
Drop(EquipSlot),
|
||||||
Use(Slot),
|
Use(Slot),
|
||||||
Sort,
|
Sort,
|
||||||
|
Collect(Vec3<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[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::Swap(equip, slot) => Self::Swap(Slot::Equip(equip), slot),
|
||||||
InventoryAction::Drop(equip) => Self::Drop(Slot::Equip(equip)),
|
InventoryAction::Drop(equip) => Self::Drop(Slot::Equip(equip)),
|
||||||
InventoryAction::Sort => Self::Sort,
|
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 {
|
fn from(inv_event: InventoryEvent) -> Self {
|
||||||
match inv_event {
|
match inv_event {
|
||||||
InventoryEvent::Pickup(pickup) => Self::Pickup(pickup),
|
InventoryEvent::Pickup(pickup) => Self::Pickup(pickup),
|
||||||
InventoryEvent::Collect(collect) => Self::Collect(collect),
|
|
||||||
InventoryEvent::Swap(inv1, inv2) => {
|
InventoryEvent::Swap(inv1, inv2) => {
|
||||||
Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
|
Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// The limit on distance between the entity and a collectible (squared)
|
// 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 MAX_MOUNT_RANGE: f32 = 14.0;
|
||||||
|
|
||||||
pub const GRAVITY: f32 = 25.0;
|
pub const GRAVITY: f32 = 25.0;
|
||||||
|
@ -197,6 +197,9 @@ pub enum ServerEvent {
|
|||||||
pet_entity: EcsEntity,
|
pet_entity: EcsEntity,
|
||||||
owner_entity: EcsEntity,
|
owner_entity: EcsEntity,
|
||||||
},
|
},
|
||||||
|
EntityAttackedHook {
|
||||||
|
entity: EcsEntity,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventBus<E> {
|
pub struct EventBus<E> {
|
||||||
|
@ -55,7 +55,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.8);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ impl CharacterBehavior for Data {
|
|||||||
|
|
||||||
let ori_rate = self.static_data.ori_rate;
|
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_move(data, &mut update, 0.4);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.4);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
|
@ -56,10 +56,9 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.7);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
handle_orientation(data, &mut update, 0.35);
|
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
|
@ -48,7 +48,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.3);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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 {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
|
@ -72,7 +72,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.7);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, self.static_data.move_speed);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -175,7 +175,12 @@ impl CharacterBehavior for Data {
|
|||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
if self.timer < self.static_data.stage_data[stage_index].base_buildup_duration {
|
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
|
// Build up
|
||||||
update.character = CharacterState::ComboMelee(Data {
|
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
|
} 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
|
// Forward movement
|
||||||
handle_forced_movement(data, &mut update, ForcedMovement::Forward {
|
handle_forced_movement(data, &mut update, ForcedMovement::Forward {
|
||||||
@ -314,7 +324,12 @@ impl CharacterBehavior for Data {
|
|||||||
},
|
},
|
||||||
StageSection::Recover => {
|
StageSection::Recover => {
|
||||||
if self.timer < self.static_data.stage_data[stage_index].base_recover_duration {
|
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
|
// Recovers
|
||||||
update.character = CharacterState::ComboMelee(Data {
|
update.character = CharacterState::ComboMelee(Data {
|
||||||
static_data: self.static_data.clone(),
|
static_data: self.static_data.clone(),
|
||||||
|
@ -82,7 +82,7 @@ impl CharacterBehavior for Data {
|
|||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
if self.timer < self.static_data.buildup_duration {
|
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
|
// Build up
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: tick_attack_or_default(data, self.timer, None),
|
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())
|
/ self.static_data.charge_duration.as_secs_f32())
|
||||||
.min(1.0);
|
.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 {
|
handle_forced_movement(data, &mut update, ForcedMovement::Forward {
|
||||||
strength: self.static_data.forward_speed * charge_frac.sqrt(),
|
strength: self.static_data.forward_speed * charge_frac.sqrt(),
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 1.0);
|
||||||
handle_jump(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 {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 1.0);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
handle_dodge_input(data, &mut update);
|
handle_dodge_input(data, &mut update);
|
||||||
|
@ -10,7 +10,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 1.0);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
handle_wield(data, &mut update);
|
handle_wield(data, &mut update);
|
||||||
|
@ -60,7 +60,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.3);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ pub mod shockwave;
|
|||||||
pub mod sit;
|
pub mod sit;
|
||||||
pub mod sneak;
|
pub mod sneak;
|
||||||
pub mod spin_melee;
|
pub mod spin_melee;
|
||||||
|
pub mod sprite_interact;
|
||||||
pub mod sprite_summon;
|
pub mod sprite_summon;
|
||||||
pub mod stunned;
|
pub mod stunned;
|
||||||
pub mod talk;
|
pub mod talk;
|
||||||
|
@ -54,7 +54,7 @@ pub struct Data {
|
|||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.3);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
|
@ -54,7 +54,7 @@ impl CharacterBehavior for Data {
|
|||||||
update.should_strafe = false;
|
update.should_strafe = false;
|
||||||
|
|
||||||
// Smooth orientation
|
// Smooth orientation
|
||||||
handle_orientation(data, &mut update, 2.5);
|
handle_orientation(data, &mut update, 2.5, None);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
StageSection::Buildup => {
|
StageSection::Buildup => {
|
||||||
|
@ -65,7 +65,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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);
|
handle_move(data, &mut update, self.static_data.move_efficiency);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
|
@ -10,7 +10,7 @@ impl CharacterBehavior for Data {
|
|||||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 0.4);
|
||||||
handle_jump(data, &mut update, 1.0);
|
handle_jump(data, &mut update, 1.0);
|
||||||
handle_wield(data, &mut update);
|
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 {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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);
|
handle_move(data, &mut update, self.static_data.movement_speed);
|
||||||
|
|
||||||
match self.stage_section {
|
match self.stage_section {
|
||||||
|
@ -15,7 +15,7 @@ impl CharacterBehavior for Data {
|
|||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
handle_wield(data, &mut update);
|
handle_wield(data, &mut update);
|
||||||
handle_orientation(data, &mut update, TURN_RATE);
|
handle_orientation(data, &mut update, TURN_RATE, None);
|
||||||
|
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,11 @@ impl CharacterBehavior for Data {
|
|||||||
|
|
||||||
match self.static_data.item_kind {
|
match self.static_data.item_kind {
|
||||||
ItemUseKind::Consumable(ConsumableKind::Drink) => {
|
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);
|
handle_move(data, &mut update, 1.0);
|
||||||
},
|
},
|
||||||
ItemUseKind::Consumable(ConsumableKind::Food | ConsumableKind::ComplexFood) => {
|
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);
|
handle_move(data, &mut update, 0.0);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
astar::Astar,
|
||||||
combat,
|
combat,
|
||||||
comp::{
|
comp::{
|
||||||
biped_large, biped_small,
|
biped_large, biped_small,
|
||||||
@ -9,11 +10,14 @@ use crate::{
|
|||||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||||
InventoryAction, StateUpdate,
|
InventoryAction, StateUpdate,
|
||||||
},
|
},
|
||||||
consts::{FRIC_GROUND, GRAVITY},
|
consts::{FRIC_GROUND, GRAVITY, MAX_PICKUP_RANGE},
|
||||||
event::{LocalEvent, ServerEvent},
|
event::{LocalEvent, ServerEvent},
|
||||||
states::{behavior::JoinData, *},
|
states::{behavior::JoinData, *},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
|
use core::hash::BuildHasherDefault;
|
||||||
|
use fxhash::FxHasher64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
ops::{Add, Div},
|
ops::{Add, Div},
|
||||||
@ -348,11 +352,23 @@ pub fn handle_forced_movement(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_orientation(data: &JoinData<'_>, update: &mut StateUpdate, efficiency: f32) {
|
pub fn handle_orientation(
|
||||||
let dir = (is_strafing(data, update) || update.character.is_attack())
|
data: &JoinData<'_>,
|
||||||
.then(|| data.inputs.look_dir.to_horizontal().unwrap_or_default())
|
update: &mut StateUpdate,
|
||||||
.or_else(|| Dir::from_unnormalized(data.inputs.move_dir.into()))
|
efficiency: f32,
|
||||||
.unwrap_or_else(|| data.ori.to_horizontal().look_dir());
|
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 rate = {
|
||||||
let angle = update.ori.look_dir().angle_between(*dir);
|
let angle = update.ori.look_dir().angle_between(*dir);
|
||||||
data.body.base_ori_rate() * efficiency * std::f32::consts::PI / angle
|
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 thrust = efficiency * force;
|
||||||
let accel = thrust / data.mass.0;
|
let accel = thrust / data.mass.0;
|
||||||
|
|
||||||
handle_orientation(data, update, efficiency);
|
handle_orientation(data, update, efficiency, None);
|
||||||
|
|
||||||
// Elevation control
|
// Elevation control
|
||||||
match data.body {
|
match data.body {
|
||||||
@ -584,44 +600,145 @@ pub fn handle_manipulate_loadout(
|
|||||||
update: &mut StateUpdate,
|
update: &mut StateUpdate,
|
||||||
inv_action: InventoryAction,
|
inv_action: InventoryAction,
|
||||||
) {
|
) {
|
||||||
use use_item::ItemUseKind;
|
match inv_action {
|
||||||
if let InventoryAction::Use(Slot::Inventory(inv_slot)) = inv_action {
|
InventoryAction::Use(Slot::Inventory(inv_slot)) => {
|
||||||
// If inventory action is using a slot, and slot is in the inventory
|
// 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
|
// 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
|
// the loadout will have effects that are desired to be non-instantaneous
|
||||||
if let Some((item_kind, item)) = data
|
use use_item::ItemUseKind;
|
||||||
.inventory
|
if let Some((item_kind, item)) = data
|
||||||
.and_then(|inv| inv.get(inv_slot))
|
.inventory
|
||||||
.and_then(|item| Option::<ItemUseKind>::from(item.kind()).zip(Some(item)))
|
.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
|
let (buildup_duration, use_duration, recover_duration) = item_kind.durations();
|
||||||
update.character = CharacterState::UseItem(use_item::Data {
|
// If item returns a valid kind for item use, do into use item character state
|
||||||
static_data: use_item::StaticData {
|
update.character = CharacterState::UseItem(use_item::Data {
|
||||||
buildup_duration,
|
static_data: use_item::StaticData {
|
||||||
use_duration,
|
buildup_duration,
|
||||||
recover_duration,
|
use_duration,
|
||||||
inv_slot,
|
recover_duration,
|
||||||
item_kind,
|
inv_slot,
|
||||||
item_definition_id: item.item_definition_id().to_string(),
|
item_kind,
|
||||||
was_wielded: matches!(data.character, CharacterState::Wielding),
|
item_definition_id: item.item_definition_id().to_string(),
|
||||||
was_sneak: matches!(data.character, CharacterState::Sneak),
|
was_wielded: matches!(data.character, CharacterState::Wielding),
|
||||||
},
|
was_sneak: matches!(data.character, CharacterState::Sneak),
|
||||||
timer: Duration::default(),
|
},
|
||||||
stage_section: StageSection::Buildup,
|
timer: Duration::default(),
|
||||||
});
|
stage_section: StageSection::Buildup,
|
||||||
} else {
|
});
|
||||||
// Else emit inventory action instantnaneously
|
} 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
|
update
|
||||||
.server_events
|
.server_events
|
||||||
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
|
.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 {
|
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
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_move(data, &mut update, 1.0);
|
||||||
handle_climb(data, &mut update);
|
handle_climb(data, &mut update);
|
||||||
attempt_input(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 was_wielded = char_state.is_wield();
|
||||||
let poise_state = poise.poise_state();
|
let poise_state = poise.poise_state();
|
||||||
let pos = pos.0;
|
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 {
|
match poise_state {
|
||||||
PoiseState::Normal => {},
|
PoiseState::Normal => {},
|
||||||
PoiseState::Interrupted => {
|
PoiseState::Interrupted => {
|
||||||
|
@ -261,7 +261,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
| CharacterState::Climb { .. }
|
| CharacterState::Climb { .. }
|
||||||
| CharacterState::Stunned { .. }
|
| CharacterState::Stunned { .. }
|
||||||
| CharacterState::BasicBlock { .. }
|
| 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 let Some(block) = block {
|
||||||
if block.is_collectible() && state.can_set_block(pos) {
|
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) {
|
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
|
||||||
// NOTE: We dup the item for message purposes.
|
// NOTE: We dup the item for message purposes.
|
||||||
let item_msg = item.duplicate(
|
let item_msg = item.duplicate(
|
||||||
|
@ -7,8 +7,8 @@ use entity_creation::{
|
|||||||
};
|
};
|
||||||
use entity_manipulation::{
|
use entity_manipulation::{
|
||||||
handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete,
|
handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete,
|
||||||
handle_destroy, handle_energy_change, handle_explosion, handle_knockback,
|
handle_destroy, handle_energy_change, handle_entity_attacked_hook, handle_explosion,
|
||||||
handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
|
handle_knockback, handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
|
||||||
};
|
};
|
||||||
use group_manip::handle_group;
|
use group_manip::handle_group;
|
||||||
use information::handle_site_info;
|
use information::handle_site_info;
|
||||||
@ -229,6 +229,9 @@ impl Server {
|
|||||||
pet_entity,
|
pet_entity,
|
||||||
owner_entity,
|
owner_entity,
|
||||||
} => handle_tame_pet(self, 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 block;
|
||||||
pub mod chargeswing;
|
pub mod chargeswing;
|
||||||
pub mod climb;
|
pub mod climb;
|
||||||
|
pub mod collect;
|
||||||
pub mod consume;
|
pub mod consume;
|
||||||
pub mod dance;
|
pub mod dance;
|
||||||
pub mod dash;
|
pub mod dash;
|
||||||
@ -34,8 +35,8 @@ pub mod wield;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, block::BlockAnimation,
|
alpha::AlphaAnimation, beam::BeamAnimation, beta::BetaAnimation, block::BlockAnimation,
|
||||||
chargeswing::ChargeswingAnimation, climb::ClimbAnimation, consume::ConsumeAnimation,
|
chargeswing::ChargeswingAnimation, climb::ClimbAnimation, collect::CollectAnimation,
|
||||||
dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
|
consume::ConsumeAnimation, dance::DanceAnimation, dash::DashAnimation, equip::EquipAnimation,
|
||||||
glidewield::GlideWieldAnimation, gliding::GlidingAnimation, idle::IdleAnimation,
|
glidewield::GlideWieldAnimation, gliding::GlidingAnimation, idle::IdleAnimation,
|
||||||
jump::JumpAnimation, leapmelee::LeapAnimation, mount::MountAnimation,
|
jump::JumpAnimation, leapmelee::LeapAnimation, mount::MountAnimation,
|
||||||
repeater::RepeaterAnimation, roll::RollAnimation, run::RunAnimation,
|
repeater::RepeaterAnimation, roll::RollAnimation, run::RunAnimation,
|
||||||
|
@ -1133,6 +1133,32 @@ impl FigureMgr {
|
|||||||
skeleton_attr,
|
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(_) => {
|
CharacterState::Boost(_) => {
|
||||||
anim::character::AlphaAnimation::update_skeleton(
|
anim::character::AlphaAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
|
Loading…
Reference in New Issue
Block a user