mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
sit on sprites
This commit is contained in:
parent
1cc221f653
commit
2928eb8d15
@ -112,3 +112,4 @@ common-material-stone = Stone
|
|||||||
common-material-cloth = Cloth
|
common-material-cloth = Cloth
|
||||||
common-material-hide = Hide
|
common-material-hide = Hide
|
||||||
common-sprite-chest = Chest
|
common-sprite-chest = Chest
|
||||||
|
common-sprite-chair = Chair
|
||||||
|
@ -1530,7 +1530,7 @@ impl Client {
|
|||||||
.ecs()
|
.ecs()
|
||||||
.read_storage::<CharacterState>()
|
.read_storage::<CharacterState>()
|
||||||
.get(self.entity())
|
.get(self.entity())
|
||||||
.map(|cs| matches!(cs, CharacterState::Sit));
|
.map(|cs| matches!(cs, CharacterState::Sit | CharacterState::MountSprite(_)));
|
||||||
|
|
||||||
match is_sitting {
|
match is_sitting {
|
||||||
Some(true) => self.control_action(ControlAction::Stand),
|
Some(true) => self.control_action(ControlAction::Stand),
|
||||||
@ -1539,6 +1539,21 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stand_if_mounted(&mut self) {
|
||||||
|
let is_sitting = self
|
||||||
|
.state
|
||||||
|
.ecs()
|
||||||
|
.read_storage::<CharacterState>()
|
||||||
|
.get(self.entity())
|
||||||
|
.map(|cs| matches!(cs, CharacterState::MountSprite(_)));
|
||||||
|
|
||||||
|
match is_sitting {
|
||||||
|
Some(true) => self.control_action(ControlAction::Stand),
|
||||||
|
Some(false) => {},
|
||||||
|
None => warn!("Can't stand, client entity doesn't have a `CharacterState`"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toggle_dance(&mut self) {
|
pub fn toggle_dance(&mut self) {
|
||||||
let is_dancing = self
|
let is_dancing = self
|
||||||
.state
|
.state
|
||||||
@ -1722,6 +1737,10 @@ impl Client {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mount_sprite(&mut self, pos: Vec3<i32>) {
|
||||||
|
self.control_action(ControlAction::MountSprite(pos));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn change_ability(&mut self, slot: usize, new_ability: comp::ability::AuxiliaryAbility) {
|
pub fn change_ability(&mut self, slot: usize, new_ability: comp::ability::AuxiliaryAbility) {
|
||||||
let auxiliary_key = self
|
let auxiliary_key = self
|
||||||
.inventories()
|
.inventories()
|
||||||
|
@ -470,6 +470,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
|||||||
| CharacterState::SpriteSummon(_)
|
| CharacterState::SpriteSummon(_)
|
||||||
| CharacterState::UseItem(_)
|
| CharacterState::UseItem(_)
|
||||||
| CharacterState::SpriteInteract(_)
|
| CharacterState::SpriteInteract(_)
|
||||||
|
| CharacterState::MountSprite(_)
|
||||||
| CharacterState::Skate(_)
|
| CharacterState::Skate(_)
|
||||||
| CharacterState::Wallrun(_) => Self::Other,
|
| CharacterState::Wallrun(_) => Self::Other,
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,8 @@ pub enum CharacterState {
|
|||||||
/// Handles logic for interacting with a sprite, e.g. using a chest or
|
/// Handles logic for interacting with a sprite, e.g. using a chest or
|
||||||
/// picking a plant
|
/// picking a plant
|
||||||
SpriteInteract(sprite_interact::Data),
|
SpriteInteract(sprite_interact::Data),
|
||||||
|
// Mounted to a sprite
|
||||||
|
MountSprite(mount_sprite::Data),
|
||||||
/// Runs on the wall
|
/// Runs on the wall
|
||||||
Wallrun(wallrun::Data),
|
Wallrun(wallrun::Data),
|
||||||
/// Ice skating or skiing
|
/// Ice skating or skiing
|
||||||
@ -470,6 +472,7 @@ impl CharacterState {
|
|||||||
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
|
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
|
||||||
CharacterState::UseItem(data) => data.behavior(j, output_events),
|
CharacterState::UseItem(data) => data.behavior(j, output_events),
|
||||||
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
|
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
|
||||||
|
CharacterState::MountSprite(data) => data.behavior(j, output_events),
|
||||||
CharacterState::Skate(data) => data.behavior(j, output_events),
|
CharacterState::Skate(data) => data.behavior(j, output_events),
|
||||||
CharacterState::Music(data) => data.behavior(j, output_events),
|
CharacterState::Music(data) => data.behavior(j, output_events),
|
||||||
CharacterState::FinisherMelee(data) => data.behavior(j, output_events),
|
CharacterState::FinisherMelee(data) => data.behavior(j, output_events),
|
||||||
@ -524,6 +527,7 @@ impl CharacterState {
|
|||||||
CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
|
CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
|
CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::SpriteInteract(data) => data.handle_event(j, output_events, action),
|
CharacterState::SpriteInteract(data) => data.handle_event(j, output_events, action),
|
||||||
|
CharacterState::MountSprite(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::Skate(data) => data.handle_event(j, output_events, action),
|
CharacterState::Skate(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::Music(data) => data.handle_event(j, output_events, action),
|
CharacterState::Music(data) => data.handle_event(j, output_events, action),
|
||||||
CharacterState::FinisherMelee(data) => data.handle_event(j, output_events, action),
|
CharacterState::FinisherMelee(data) => data.handle_event(j, output_events, action),
|
||||||
@ -578,6 +582,7 @@ impl CharacterState {
|
|||||||
CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info),
|
CharacterState::SpriteSummon(data) => Some(data.static_data.ability_info),
|
||||||
CharacterState::UseItem(_) => None,
|
CharacterState::UseItem(_) => None,
|
||||||
CharacterState::SpriteInteract(_) => None,
|
CharacterState::SpriteInteract(_) => None,
|
||||||
|
CharacterState::MountSprite(_) => None,
|
||||||
CharacterState::FinisherMelee(data) => Some(data.static_data.ability_info),
|
CharacterState::FinisherMelee(data) => Some(data.static_data.ability_info),
|
||||||
CharacterState::Music(data) => Some(data.static_data.ability_info),
|
CharacterState::Music(data) => Some(data.static_data.ability_info),
|
||||||
CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
|
CharacterState::DiveMelee(data) => Some(data.static_data.ability_info),
|
||||||
@ -623,6 +628,7 @@ impl CharacterState {
|
|||||||
CharacterState::SpriteSummon(data) => Some(data.stage_section),
|
CharacterState::SpriteSummon(data) => Some(data.stage_section),
|
||||||
CharacterState::UseItem(data) => Some(data.stage_section),
|
CharacterState::UseItem(data) => Some(data.stage_section),
|
||||||
CharacterState::SpriteInteract(data) => Some(data.stage_section),
|
CharacterState::SpriteInteract(data) => Some(data.stage_section),
|
||||||
|
CharacterState::MountSprite(_) => None,
|
||||||
CharacterState::FinisherMelee(data) => Some(data.stage_section),
|
CharacterState::FinisherMelee(data) => Some(data.stage_section),
|
||||||
CharacterState::Music(data) => Some(data.stage_section),
|
CharacterState::Music(data) => Some(data.stage_section),
|
||||||
CharacterState::DiveMelee(data) => Some(data.stage_section),
|
CharacterState::DiveMelee(data) => Some(data.stage_section),
|
||||||
@ -794,6 +800,7 @@ impl CharacterState {
|
|||||||
recover: Some(data.static_data.recover_duration),
|
recover: Some(data.static_data.recover_duration),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
CharacterState::MountSprite(_) => None,
|
||||||
CharacterState::FinisherMelee(data) => Some(DurationsInfo {
|
CharacterState::FinisherMelee(data) => Some(DurationsInfo {
|
||||||
buildup: Some(data.static_data.buildup_duration),
|
buildup: Some(data.static_data.buildup_duration),
|
||||||
action: Some(data.static_data.swing_duration),
|
action: Some(data.static_data.swing_duration),
|
||||||
@ -862,6 +869,7 @@ impl CharacterState {
|
|||||||
CharacterState::SpriteSummon(data) => Some(data.timer),
|
CharacterState::SpriteSummon(data) => Some(data.timer),
|
||||||
CharacterState::UseItem(data) => Some(data.timer),
|
CharacterState::UseItem(data) => Some(data.timer),
|
||||||
CharacterState::SpriteInteract(data) => Some(data.timer),
|
CharacterState::SpriteInteract(data) => Some(data.timer),
|
||||||
|
CharacterState::MountSprite(_) => None,
|
||||||
CharacterState::FinisherMelee(data) => Some(data.timer),
|
CharacterState::FinisherMelee(data) => Some(data.timer),
|
||||||
CharacterState::Music(data) => Some(data.timer),
|
CharacterState::Music(data) => Some(data.timer),
|
||||||
CharacterState::DiveMelee(data) => Some(data.timer),
|
CharacterState::DiveMelee(data) => Some(data.timer),
|
||||||
@ -881,6 +889,7 @@ impl CharacterState {
|
|||||||
CharacterState::GlideWield(_) => None,
|
CharacterState::GlideWield(_) => None,
|
||||||
CharacterState::Stunned(_) => None,
|
CharacterState::Stunned(_) => None,
|
||||||
CharacterState::Sit => None,
|
CharacterState::Sit => None,
|
||||||
|
CharacterState::MountSprite(_) => None,
|
||||||
CharacterState::Dance => None,
|
CharacterState::Dance => None,
|
||||||
CharacterState::BasicBlock(_) => None,
|
CharacterState::BasicBlock(_) => None,
|
||||||
CharacterState::Roll(_) => None,
|
CharacterState::Roll(_) => None,
|
||||||
|
@ -165,6 +165,7 @@ pub enum ControlAction {
|
|||||||
GlideWield,
|
GlideWield,
|
||||||
Unwield,
|
Unwield,
|
||||||
Sit,
|
Sit,
|
||||||
|
MountSprite(Vec3<i32>),
|
||||||
Dance,
|
Dance,
|
||||||
Sneak,
|
Sneak,
|
||||||
Stand,
|
Stand,
|
||||||
|
@ -59,6 +59,9 @@ pub trait CharacterBehavior {
|
|||||||
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
StateUpdate::from(data)
|
StateUpdate::from(data)
|
||||||
}
|
}
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _output_events: &mut OutputEvents, _pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
StateUpdate::from(data)
|
||||||
|
}
|
||||||
// start_input has custom implementation in the following character states that
|
// start_input has custom implementation in the following character states that
|
||||||
// may also need to be modified when changes are made here: ComboMelee2
|
// may also need to be modified when changes are made here: ComboMelee2
|
||||||
fn start_input(
|
fn start_input(
|
||||||
@ -111,6 +114,7 @@ pub trait CharacterBehavior {
|
|||||||
select_pos,
|
select_pos,
|
||||||
} => self.start_input(data, input, target_entity, select_pos),
|
} => self.start_input(data, input, target_entity, select_pos),
|
||||||
ControlAction::CancelInput(input) => self.cancel_input(data, input),
|
ControlAction::CancelInput(input) => self.cancel_input(data, input),
|
||||||
|
ControlAction::MountSprite(pos) => self.mount_sprite(data, output_events, pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||||
pub struct Data;
|
pub struct Data;
|
||||||
@ -50,6 +51,12 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
// Try to Fall/Stand up/Move
|
// Try to Fall/Stand up/Move
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
@ -110,6 +111,12 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
attempt_dance(data, &mut update);
|
attempt_dance(data, &mut update);
|
||||||
|
@ -8,6 +8,7 @@ use crate::{
|
|||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
@ -86,6 +87,12 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
attempt_dance(data, &mut update);
|
attempt_dance(data, &mut update);
|
||||||
|
@ -40,3 +40,4 @@ pub mod use_item;
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod wallrun;
|
pub mod wallrun;
|
||||||
pub mod wielding;
|
pub mod wielding;
|
||||||
|
pub mod mount_sprite;
|
||||||
|
48
common/src/states/mount_sprite.rs
Normal file
48
common/src/states/mount_sprite.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
|
use crate::{comp::{character_state::OutputEvents, StateUpdate, CharacterState}, util::Dir};
|
||||||
|
|
||||||
|
use super::{behavior::{CharacterBehavior, JoinData}, utils::{handle_orientation, end_ability, handle_wield}, idle};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct StaticData {
|
||||||
|
pub mount_pos: Vec3<f32>,
|
||||||
|
pub mount_dir: Vec3<f32>,
|
||||||
|
/// Position sprite is located at
|
||||||
|
pub sprite_pos: Vec3<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterBehavior for Data {
|
||||||
|
fn behavior(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
update.pos.0 = self.static_data.mount_pos;
|
||||||
|
|
||||||
|
handle_orientation(data, &mut update, 1.0, Some(Dir::new(self.static_data.mount_dir)));
|
||||||
|
|
||||||
|
handle_wield(data, &mut update);
|
||||||
|
|
||||||
|
// Try to Fall/Stand up/Move
|
||||||
|
if data.physics.on_ground.is_none() || data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||||
|
update.character = CharacterState::Idle(idle::Data::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stand(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
|
end_ability(data, &mut update);
|
||||||
|
|
||||||
|
update
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
@ -108,6 +109,12 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
// Try to Fall/Stand up/Move
|
// Try to Fall/Stand up/Move
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
const TURN_RATE: f32 = 40.0;
|
const TURN_RATE: f32 = 40.0;
|
||||||
|
|
||||||
@ -47,6 +48,13 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
update.character = CharacterState::Idle(idle::Data::default());
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
update.character = CharacterState::Idle(idle::Data::default());
|
update.character = CharacterState::Idle(idle::Data::default());
|
||||||
|
@ -23,10 +23,11 @@ use crate::{
|
|||||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||||
terrain::{TerrainGrid, UnlockKind},
|
terrain::{TerrainGrid, UnlockKind},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol, terrain::SpriteKind,
|
||||||
};
|
};
|
||||||
use core::hash::BuildHasherDefault;
|
use core::hash::BuildHasherDefault;
|
||||||
use fxhash::FxHasher64;
|
use fxhash::FxHasher64;
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
f32::consts::PI,
|
f32::consts::PI,
|
||||||
@ -784,6 +785,37 @@ pub fn attempt_sit(data: &JoinData<'_>, update: &mut StateUpdate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sprite_mount_points(sprite_kind: SpriteKind, pos: Vec3<i32>, ori: u8) -> impl ExactSizeIterator<Item = (Vec3<f32>, Vec3<f32>)> {
|
||||||
|
let mat = Mat4::identity()
|
||||||
|
.rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
||||||
|
.translated_3d(
|
||||||
|
pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)
|
||||||
|
);
|
||||||
|
sprite_kind.mount_offsets().iter().map(move |(pos, dir)| {
|
||||||
|
((mat * pos.with_w(1.0)).xyz(), (mat * dir.with_w(0.0)).xyz())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const SPRITE_MOUNT_DIST_SQR: f32 = 5.0;
|
||||||
|
|
||||||
|
pub fn attempt_mount_sprite(data: &JoinData<'_>, update: &mut StateUpdate, pos: Vec3<i32>) {
|
||||||
|
if let Some((kind, ori)) = data.terrain.get(pos).ok().and_then(|block| block.get_sprite().zip(block.get_ori())) {
|
||||||
|
if let Some((mount_pos, mount_dir)) = sprite_mount_points(kind, pos, ori).min_by_key(|(pos, _)| {
|
||||||
|
OrderedFloat(data.pos.0.distance_squared(*pos))
|
||||||
|
}) {
|
||||||
|
if mount_pos.distance_squared(data.pos.0) < SPRITE_MOUNT_DIST_SQR {
|
||||||
|
update.character = CharacterState::MountSprite(mount_sprite::Data {
|
||||||
|
static_data: mount_sprite::StaticData {
|
||||||
|
mount_pos,
|
||||||
|
mount_dir,
|
||||||
|
sprite_pos: pos,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn attempt_dance(data: &JoinData<'_>, update: &mut StateUpdate) {
|
pub fn attempt_dance(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||||
if data.physics.on_ground.is_some() && data.body.is_humanoid() {
|
if data.physics.on_ground.is_some() && data.body.is_humanoid() {
|
||||||
update.character = CharacterState::Dance;
|
update.character = CharacterState::Dance;
|
||||||
|
@ -11,6 +11,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
@ -93,6 +94,12 @@ impl CharacterBehavior for Data {
|
|||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_sprite(&self, data: &JoinData, _: &mut OutputEvents, pos: Vec3<i32>) -> StateUpdate {
|
||||||
|
let mut update = StateUpdate::from(data);
|
||||||
|
attempt_mount_sprite(data, &mut update, pos);
|
||||||
|
update
|
||||||
|
}
|
||||||
|
|
||||||
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
attempt_dance(data, &mut update);
|
attempt_dance(data, &mut update);
|
||||||
|
@ -420,6 +420,12 @@ impl Block {
|
|||||||
self.collectible_id().is_some() && self.mine_tool().is_none()
|
self.collectible_id().is_some() && self.mine_tool().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_mountable(&self) -> bool {
|
||||||
|
self.get_sprite()
|
||||||
|
.map_or(false, |s| s.is_mountable())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_bonkable(&self) -> bool {
|
pub fn is_bonkable(&self) -> bool {
|
||||||
match self.get_sprite() {
|
match self.get_sprite() {
|
||||||
|
@ -12,6 +12,7 @@ use num_derive::FromPrimitive;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{convert::TryFrom, fmt};
|
use std::{convert::TryFrom, fmt};
|
||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
make_case_elim!(
|
make_case_elim!(
|
||||||
sprite_kind,
|
sprite_kind,
|
||||||
@ -474,6 +475,39 @@ impl SpriteKind {
|
|||||||
matches!(self.collectible_id(), Some(Some(LootSpec::LootTable(_))))
|
matches!(self.collectible_id(), Some(Some(LootSpec::LootTable(_))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the sprite a container that will emit a mystery item?
|
||||||
|
#[inline]
|
||||||
|
pub fn mount_offsets(&self) -> &'static [(Vec3<f32>, Vec3<f32>)] {
|
||||||
|
const UNIT_Y: Vec3<f32> = Vec3 {
|
||||||
|
x: 0.0,
|
||||||
|
y: -1.0,
|
||||||
|
z: 0.0,
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
SpriteKind::ChairSingle => &[(Vec3 {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.5,
|
||||||
|
}, UNIT_Y)],
|
||||||
|
SpriteKind::ChairDouble => &[(Vec3 {
|
||||||
|
x: -0.5,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.6,
|
||||||
|
}, UNIT_Y),
|
||||||
|
(Vec3 {
|
||||||
|
x: 0.5,
|
||||||
|
y: -0.1,
|
||||||
|
z: 0.6,
|
||||||
|
}, UNIT_Y)],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_mountable(&self) -> bool {
|
||||||
|
!self.mount_offsets().is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Which tool (if any) is needed to collect this sprite?
|
/// Which tool (if any) is needed to collect this sprite?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mine_tool(&self) -> Option<ToolKind> {
|
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||||
|
@ -366,7 +366,8 @@ impl<'a> PhysicsData<'a> {
|
|||||||
char_state_maybe,
|
char_state_maybe,
|
||||||
)| {
|
)| {
|
||||||
let is_sticky = sticky.is_some();
|
let is_sticky = sticky.is_some();
|
||||||
let is_immovable = immovable.is_some();
|
let is_immovable = immovable.is_some()
|
||||||
|
|| matches!(char_state_maybe, Some(CharacterState::MountSprite(_)));
|
||||||
let is_mid_air = physics.on_surface().is_none();
|
let is_mid_air = physics.on_surface().is_none();
|
||||||
let mut entity_entity_collision_checks = 0;
|
let mut entity_entity_collision_checks = 0;
|
||||||
let mut entity_entity_collisions = 0;
|
let mut entity_entity_collisions = 0;
|
||||||
@ -621,6 +622,7 @@ impl<'a> PhysicsData<'a> {
|
|||||||
!&read.is_ridings,
|
!&read.is_ridings,
|
||||||
)
|
)
|
||||||
.par_join()
|
.par_join()
|
||||||
|
.filter(|tuple| !matches!(tuple.4, Some(CharacterState::MountSprite(_))))
|
||||||
.for_each_init(
|
.for_each_init(
|
||||||
|| {
|
|| {
|
||||||
prof_span!(guard, "velocity update rayon job");
|
prof_span!(guard, "velocity update rayon job");
|
||||||
@ -751,7 +753,10 @@ impl<'a> PhysicsData<'a> {
|
|||||||
!&read.is_ridings,
|
!&read.is_ridings,
|
||||||
)
|
)
|
||||||
.par_join()
|
.par_join()
|
||||||
.filter(|tuple| tuple.3.is_voxel() == terrain_like_entities)
|
.filter(|tuple| {
|
||||||
|
tuple.3.is_voxel() == terrain_like_entities
|
||||||
|
&& !matches!(tuple.8, Some(CharacterState::MountSprite(_)))
|
||||||
|
})
|
||||||
.map_init(
|
.map_init(
|
||||||
|| {
|
|| {
|
||||||
prof_span!(guard, "physics e<>t rayon job");
|
prof_span!(guard, "physics e<>t rayon job");
|
||||||
|
@ -145,7 +145,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
{
|
{
|
||||||
match character_state {
|
match character_state {
|
||||||
// Sitting accelerates recharging energy the most
|
// Sitting accelerates recharging energy the most
|
||||||
CharacterState::Sit => {
|
CharacterState::Sit | CharacterState::MountSprite(_) => {
|
||||||
if energy.needs_regen() {
|
if energy.needs_regen() {
|
||||||
energy.regen(SIT_ENERGY_REGEN_ACCEL, dt);
|
energy.regen(SIT_ENERGY_REGEN_ACCEL, dt);
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,9 @@ use crate::{
|
|||||||
render::UiDrawer,
|
render::UiDrawer,
|
||||||
scene::camera::{self, Camera},
|
scene::camera::{self, Camera},
|
||||||
session::{
|
session::{
|
||||||
interactable::{BlockInteraction, Interactable},
|
|
||||||
settings_change::{
|
settings_change::{
|
||||||
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
||||||
},
|
}, interactable::{Interactable, BlockInteraction},
|
||||||
},
|
},
|
||||||
settings::chat::ChatFilter,
|
settings::chat::ChatFilter,
|
||||||
ui::{
|
ui::{
|
||||||
@ -2107,10 +2106,34 @@ impl Hud {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
BlockInteraction::Mount(_) => vec![(
|
||||||
|
Some(GameInput::Interact),
|
||||||
|
i18n.get_msg("hud-sit").to_string(),
|
||||||
|
)],
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is only done once per frame, so it's not a performance issue
|
// This is only done once per frame, so it's not a performance issue
|
||||||
if let Some(desc) = block
|
if let Some(desc) = block
|
||||||
|
.get_sprite()
|
||||||
|
.filter(|s| s.is_mountable())
|
||||||
|
.and_then(|s| get_sprite_desc(s, i18n))
|
||||||
|
{
|
||||||
|
overitem::Overitem::new(
|
||||||
|
desc,
|
||||||
|
overitem::TEXT_COLOR,
|
||||||
|
pos.distance_squared(player_pos),
|
||||||
|
&self.fonts,
|
||||||
|
i18n,
|
||||||
|
&global_state.settings.controls,
|
||||||
|
overitem_properties,
|
||||||
|
self.pulse,
|
||||||
|
&global_state.window.key_layout,
|
||||||
|
vec![(Some(GameInput::Interact), i18n.get_msg("hud-sit").to_string())],
|
||||||
|
)
|
||||||
|
.x_y(0.0, 100.0)
|
||||||
|
.position_ingame(over_pos)
|
||||||
|
.set(overitem_id, ui_widgets);
|
||||||
|
} else if let Some(desc) = block
|
||||||
.get_sprite()
|
.get_sprite()
|
||||||
.filter(|s| s.is_container())
|
.filter(|s| s.is_container())
|
||||||
.and_then(|s| get_sprite_desc(s, i18n))
|
.and_then(|s| get_sprite_desc(s, i18n))
|
||||||
@ -5130,6 +5153,7 @@ pub fn get_sprite_desc(sprite: SpriteKind, localized_strings: &Localization) ->
|
|||||||
| SpriteKind::DungeonChest3
|
| SpriteKind::DungeonChest3
|
||||||
| SpriteKind::DungeonChest4
|
| SpriteKind::DungeonChest4
|
||||||
| SpriteKind::DungeonChest5 => "common-sprite-chest",
|
| SpriteKind::DungeonChest5 => "common-sprite-chest",
|
||||||
|
SpriteKind::ChairSingle | SpriteKind::ChairDouble => "common-sprite-chair",
|
||||||
sprite => return Some(Cow::Owned(format!("{:?}", sprite))),
|
sprite => return Some(Cow::Owned(format!("{:?}", sprite))),
|
||||||
};
|
};
|
||||||
Some(localized_strings.get_msg(i18n_key))
|
Some(localized_strings.get_msg(i18n_key))
|
||||||
|
@ -1977,7 +1977,7 @@ impl FigureMgr {
|
|||||||
skeleton_attr,
|
skeleton_attr,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
CharacterState::Sit { .. } => {
|
CharacterState::Sit { .. } | CharacterState::MountSprite(_) => {
|
||||||
anim::character::SitAnimation::update_skeleton(
|
anim::character::SitAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(active_tool_kind, second_tool_kind, time),
|
(active_tool_kind, second_tool_kind, time),
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
use crate::hud::CraftingTab;
|
use crate::hud::CraftingTab;
|
||||||
use common::terrain::{BlockKind, SpriteKind, TerrainChunk};
|
use common::{
|
||||||
|
states::utils::sprite_mount_points,
|
||||||
|
terrain::{BlockKind, SpriteKind, TerrainChunk},
|
||||||
|
};
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Interaction {
|
pub enum Interaction {
|
||||||
/// This covers mining, unlocking, and regular collectable things (e.g.
|
/// This covers mining, unlocking, and regular collectable things (e.g.
|
||||||
/// twigs).
|
/// twigs).
|
||||||
Collect,
|
Collect,
|
||||||
Craft(CraftingTab),
|
Craft(CraftingTab),
|
||||||
|
Mount(Vec<Vec3<f32>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FireplaceType {
|
pub enum FireplaceType {
|
||||||
@ -168,6 +172,21 @@ impl BlocksOfInterest {
|
|||||||
Some(SpriteKind::RepairBench) => {
|
Some(SpriteKind::RepairBench) => {
|
||||||
interactables.push((pos, Interaction::Craft(CraftingTab::All)))
|
interactables.push((pos, Interaction::Craft(CraftingTab::All)))
|
||||||
},
|
},
|
||||||
|
Some(
|
||||||
|
sprite_kind @ SpriteKind::ChairSingle
|
||||||
|
| sprite_kind @ SpriteKind::ChairDouble,
|
||||||
|
) => interactables.push((
|
||||||
|
pos,
|
||||||
|
Interaction::Mount(
|
||||||
|
sprite_mount_points(
|
||||||
|
sprite_kind,
|
||||||
|
Vec3::zero(),
|
||||||
|
block.get_ori().unwrap_or(0),
|
||||||
|
)
|
||||||
|
.map(|(pos, _)| pos)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
)),
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,13 @@ use super::{
|
|||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
comp::tool::ToolKind,
|
comp::{tool::ToolKind, CharacterState},
|
||||||
consts::MAX_PICKUP_RANGE,
|
consts::MAX_PICKUP_RANGE,
|
||||||
link::Is,
|
link::Is,
|
||||||
mounting::Mount,
|
mounting::Mount,
|
||||||
terrain::{Block, TerrainGrid, UnlockKind},
|
terrain::{Block, TerrainGrid, UnlockKind},
|
||||||
util::find_dist::{Cube, Cylinder, FindDist},
|
util::find_dist::{Cube, Cylinder, FindDist},
|
||||||
vol::ReadVol,
|
vol::ReadVol, states::utils::SPRITE_MOUNT_DIST_SQR,
|
||||||
};
|
};
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
|
|
||||||
@ -32,6 +32,7 @@ pub enum BlockInteraction {
|
|||||||
// TODO: mining blocks don't use the interaction key, so it might not be the best abstraction
|
// TODO: mining blocks don't use the interaction key, so it might not be the best abstraction
|
||||||
// to have them here, will see how things turn out
|
// to have them here, will see how things turn out
|
||||||
Mine(ToolKind),
|
Mine(ToolKind),
|
||||||
|
Mount(Vec<Vec3<f32>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -82,6 +83,7 @@ impl Interactable {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Interaction::Craft(tab) => BlockInteraction::Craft(tab),
|
Interaction::Craft(tab) => BlockInteraction::Craft(tab),
|
||||||
|
Interaction::Mount(points) => BlockInteraction::Mount(points),
|
||||||
};
|
};
|
||||||
Some(Self::Block(block, pos, block_interaction))
|
Some(Self::Block(block, pos, block_interaction))
|
||||||
}
|
}
|
||||||
@ -176,11 +178,12 @@ pub(super) fn select_interactable(
|
|||||||
let items = ecs.read_storage::<comp::Item>();
|
let items = ecs.read_storage::<comp::Item>();
|
||||||
let stats = ecs.read_storage::<comp::Stats>();
|
let stats = ecs.read_storage::<comp::Stats>();
|
||||||
|
|
||||||
|
let player_char_state = char_states.get(player_entity);
|
||||||
let player_cylinder = Cylinder::from_components(
|
let player_cylinder = Cylinder::from_components(
|
||||||
player_pos,
|
player_pos,
|
||||||
scales.get(player_entity).copied(),
|
scales.get(player_entity).copied(),
|
||||||
colliders.get(player_entity),
|
colliders.get(player_entity),
|
||||||
char_states.get(player_entity),
|
player_char_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let closest_interactable_entity = (
|
let closest_interactable_entity = (
|
||||||
@ -248,11 +251,24 @@ pub(super) fn select_interactable(
|
|||||||
.interactables
|
.interactables
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |(block_offset, interaction)| (chunk_pos + block_offset, interaction))
|
.map(move |(block_offset, interaction)| (chunk_pos + block_offset, interaction))
|
||||||
|
.filter_map(|(pos, interaction)| {
|
||||||
|
if matches!(player_char_state, Some(CharacterState::MountSprite(_))) && matches!(interaction, Interaction::Mount(_) | Interaction::Collect) {
|
||||||
|
None
|
||||||
|
} else if let Interaction::Mount(mount_points) = interaction {
|
||||||
|
mount_points.iter()
|
||||||
|
.map(|p| (p + pos.as_()).distance_squared(player_pos))
|
||||||
|
.filter(|dist| *dist < SPRITE_MOUNT_DIST_SQR)
|
||||||
|
.min_by_key(|dist| OrderedFloat(*dist))
|
||||||
|
.map(|dist| (pos, dist))
|
||||||
|
.zip(Some(interaction))
|
||||||
|
} else {
|
||||||
|
Some(((pos, (pos.as_() + 0.5).distance_squared(player_pos)), interaction))
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.map(|(block_pos, interaction)| (
|
.map(|((block_pos, dis), interaction)| (
|
||||||
block_pos,
|
block_pos,
|
||||||
block_pos.map(|e| e as f32 + 0.5)
|
dis,
|
||||||
.distance_squared(player_pos),
|
|
||||||
interaction,
|
interaction,
|
||||||
))
|
))
|
||||||
.min_by_key(|(_, dist_sqr, _)| OrderedFloat(*dist_sqr))
|
.min_by_key(|(_, dist_sqr, _)| OrderedFloat(*dist_sqr))
|
||||||
@ -267,7 +283,7 @@ pub(super) fn select_interactable(
|
|||||||
}) < search_dist
|
}) < search_dist
|
||||||
})
|
})
|
||||||
.and_then(|(block_pos, interaction)| {
|
.and_then(|(block_pos, interaction)| {
|
||||||
Interactable::from_block_pos(&terrain, block_pos, *interaction)
|
Interactable::from_block_pos(&terrain, block_pos, interaction.clone())
|
||||||
})
|
})
|
||||||
.or_else(|| closest_interactable_entity.map(|(e, _)| Interactable::Entity(e)))
|
.or_else(|| closest_interactable_entity.map(|(e, _)| Interactable::Entity(e)))
|
||||||
}
|
}
|
||||||
|
@ -921,8 +921,8 @@ impl PlayState for SessionState {
|
|||||||
},
|
},
|
||||||
GameInput::Interact => {
|
GameInput::Interact => {
|
||||||
if state {
|
if state {
|
||||||
|
let mut client = self.client.borrow_mut();
|
||||||
if let Some(interactable) = &self.interactable {
|
if let Some(interactable) = &self.interactable {
|
||||||
let mut client = self.client.borrow_mut();
|
|
||||||
match interactable {
|
match interactable {
|
||||||
Interactable::Block(block, pos, interaction) => {
|
Interactable::Block(block, pos, interaction) => {
|
||||||
match interaction {
|
match interaction {
|
||||||
@ -938,6 +938,11 @@ impl PlayState for SessionState {
|
|||||||
block.get_sprite().map(|s| (*pos, s)),
|
block.get_sprite().map(|s| (*pos, s)),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
BlockInteraction::Mount(_) => {
|
||||||
|
if block.is_mountable() {
|
||||||
|
client.mount_sprite(*pos);
|
||||||
|
}
|
||||||
|
},
|
||||||
BlockInteraction::Mine(_) => {},
|
BlockInteraction::Mine(_) => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -964,6 +969,8 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
client.stand_if_mounted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user