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-hide = Hide
|
||||
common-sprite-chest = Chest
|
||||
common-sprite-chair = Chair
|
||||
|
@ -1530,7 +1530,7 @@ impl Client {
|
||||
.ecs()
|
||||
.read_storage::<CharacterState>()
|
||||
.get(self.entity())
|
||||
.map(|cs| matches!(cs, CharacterState::Sit));
|
||||
.map(|cs| matches!(cs, CharacterState::Sit | CharacterState::MountSprite(_)));
|
||||
|
||||
match is_sitting {
|
||||
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) {
|
||||
let is_dancing = self
|
||||
.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) {
|
||||
let auxiliary_key = self
|
||||
.inventories()
|
||||
|
@ -470,6 +470,7 @@ impl From<&CharacterState> for CharacterAbilityType {
|
||||
| CharacterState::SpriteSummon(_)
|
||||
| CharacterState::UseItem(_)
|
||||
| CharacterState::SpriteInteract(_)
|
||||
| CharacterState::MountSprite(_)
|
||||
| CharacterState::Skate(_)
|
||||
| CharacterState::Wallrun(_) => Self::Other,
|
||||
}
|
||||
|
@ -130,6 +130,8 @@ pub enum CharacterState {
|
||||
/// Handles logic for interacting with a sprite, e.g. using a chest or
|
||||
/// picking a plant
|
||||
SpriteInteract(sprite_interact::Data),
|
||||
// Mounted to a sprite
|
||||
MountSprite(mount_sprite::Data),
|
||||
/// Runs on the wall
|
||||
Wallrun(wallrun::Data),
|
||||
/// Ice skating or skiing
|
||||
@ -470,6 +472,7 @@ impl CharacterState {
|
||||
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
|
||||
CharacterState::UseItem(data) => data.behavior(j, output_events),
|
||||
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
|
||||
CharacterState::MountSprite(data) => data.behavior(j, output_events),
|
||||
CharacterState::Skate(data) => data.behavior(j, output_events),
|
||||
CharacterState::Music(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::UseItem(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::Music(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::UseItem(_) => None,
|
||||
CharacterState::SpriteInteract(_) => None,
|
||||
CharacterState::MountSprite(_) => None,
|
||||
CharacterState::FinisherMelee(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),
|
||||
@ -623,6 +628,7 @@ impl CharacterState {
|
||||
CharacterState::SpriteSummon(data) => Some(data.stage_section),
|
||||
CharacterState::UseItem(data) => Some(data.stage_section),
|
||||
CharacterState::SpriteInteract(data) => Some(data.stage_section),
|
||||
CharacterState::MountSprite(_) => None,
|
||||
CharacterState::FinisherMelee(data) => Some(data.stage_section),
|
||||
CharacterState::Music(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),
|
||||
..Default::default()
|
||||
}),
|
||||
CharacterState::MountSprite(_) => None,
|
||||
CharacterState::FinisherMelee(data) => Some(DurationsInfo {
|
||||
buildup: Some(data.static_data.buildup_duration),
|
||||
action: Some(data.static_data.swing_duration),
|
||||
@ -862,6 +869,7 @@ impl CharacterState {
|
||||
CharacterState::SpriteSummon(data) => Some(data.timer),
|
||||
CharacterState::UseItem(data) => Some(data.timer),
|
||||
CharacterState::SpriteInteract(data) => Some(data.timer),
|
||||
CharacterState::MountSprite(_) => None,
|
||||
CharacterState::FinisherMelee(data) => Some(data.timer),
|
||||
CharacterState::Music(data) => Some(data.timer),
|
||||
CharacterState::DiveMelee(data) => Some(data.timer),
|
||||
@ -881,6 +889,7 @@ impl CharacterState {
|
||||
CharacterState::GlideWield(_) => None,
|
||||
CharacterState::Stunned(_) => None,
|
||||
CharacterState::Sit => None,
|
||||
CharacterState::MountSprite(_) => None,
|
||||
CharacterState::Dance => None,
|
||||
CharacterState::BasicBlock(_) => None,
|
||||
CharacterState::Roll(_) => None,
|
||||
|
@ -165,6 +165,7 @@ pub enum ControlAction {
|
||||
GlideWield,
|
||||
Unwield,
|
||||
Sit,
|
||||
MountSprite(Vec3<i32>),
|
||||
Dance,
|
||||
Sneak,
|
||||
Stand,
|
||||
|
@ -59,6 +59,9 @@ pub trait CharacterBehavior {
|
||||
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||
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
|
||||
// may also need to be modified when changes are made here: ComboMelee2
|
||||
fn start_input(
|
||||
@ -111,6 +114,7 @@ pub trait CharacterBehavior {
|
||||
select_pos,
|
||||
} => self.start_input(data, input, target_entity, select_pos),
|
||||
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 vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct Data;
|
||||
@ -50,6 +51,12 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
|
@ -12,6 +12,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
@ -110,6 +111,12 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_dance(data, &mut update);
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct Data {
|
||||
@ -86,6 +87,12 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_dance(data, &mut update);
|
||||
|
@ -40,3 +40,4 @@ pub mod use_item;
|
||||
pub mod utils;
|
||||
pub mod wallrun;
|
||||
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 vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
@ -108,6 +109,12 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
// Try to Fall/Stand up/Move
|
||||
|
@ -7,6 +7,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::Vec3;
|
||||
|
||||
const TURN_RATE: f32 = 40.0;
|
||||
|
||||
@ -47,6 +48,13 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
update.character = CharacterState::Idle(idle::Data::default());
|
||||
|
@ -23,10 +23,11 @@ use crate::{
|
||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||
terrain::{TerrainGrid, UnlockKind},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
vol::ReadVol, terrain::SpriteKind,
|
||||
};
|
||||
use core::hash::BuildHasherDefault;
|
||||
use fxhash::FxHasher64;
|
||||
use ordered_float::OrderedFloat;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
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) {
|
||||
if data.physics.on_ground.is_some() && data.body.is_humanoid() {
|
||||
update.character = CharacterState::Dance;
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
@ -93,6 +94,12 @@ impl CharacterBehavior for Data {
|
||||
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 {
|
||||
let mut update = StateUpdate::from(data);
|
||||
attempt_dance(data, &mut update);
|
||||
|
@ -420,6 +420,12 @@ impl Block {
|
||||
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]
|
||||
pub fn is_bonkable(&self) -> bool {
|
||||
match self.get_sprite() {
|
||||
|
@ -12,6 +12,7 @@ use num_derive::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{convert::TryFrom, fmt};
|
||||
use strum::EnumIter;
|
||||
use vek::Vec3;
|
||||
|
||||
make_case_elim!(
|
||||
sprite_kind,
|
||||
@ -474,6 +475,39 @@ impl SpriteKind {
|
||||
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?
|
||||
#[inline]
|
||||
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||
|
@ -366,7 +366,8 @@ impl<'a> PhysicsData<'a> {
|
||||
char_state_maybe,
|
||||
)| {
|
||||
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 mut entity_entity_collision_checks = 0;
|
||||
let mut entity_entity_collisions = 0;
|
||||
@ -621,6 +622,7 @@ impl<'a> PhysicsData<'a> {
|
||||
!&read.is_ridings,
|
||||
)
|
||||
.par_join()
|
||||
.filter(|tuple| !matches!(tuple.4, Some(CharacterState::MountSprite(_))))
|
||||
.for_each_init(
|
||||
|| {
|
||||
prof_span!(guard, "velocity update rayon job");
|
||||
@ -751,7 +753,10 @@ impl<'a> PhysicsData<'a> {
|
||||
!&read.is_ridings,
|
||||
)
|
||||
.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(
|
||||
|| {
|
||||
prof_span!(guard, "physics e<>t rayon job");
|
||||
|
@ -145,7 +145,7 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
match character_state {
|
||||
// Sitting accelerates recharging energy the most
|
||||
CharacterState::Sit => {
|
||||
CharacterState::Sit | CharacterState::MountSprite(_) => {
|
||||
if energy.needs_regen() {
|
||||
energy.regen(SIT_ENERGY_REGEN_ACCEL, dt);
|
||||
}
|
||||
|
@ -71,10 +71,9 @@ use crate::{
|
||||
render::UiDrawer,
|
||||
scene::camera::{self, Camera},
|
||||
session::{
|
||||
interactable::{BlockInteraction, Interactable},
|
||||
settings_change::{
|
||||
Audio, Chat as ChatChange, Interface as InterfaceChange, SettingsChange,
|
||||
},
|
||||
}, interactable::{Interactable, BlockInteraction},
|
||||
},
|
||||
settings::chat::ChatFilter,
|
||||
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
|
||||
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()
|
||||
.filter(|s| s.is_container())
|
||||
.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::DungeonChest4
|
||||
| SpriteKind::DungeonChest5 => "common-sprite-chest",
|
||||
SpriteKind::ChairSingle | SpriteKind::ChairDouble => "common-sprite-chair",
|
||||
sprite => return Some(Cow::Owned(format!("{:?}", sprite))),
|
||||
};
|
||||
Some(localized_strings.get_msg(i18n_key))
|
||||
|
@ -1977,7 +1977,7 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Sit { .. } => {
|
||||
CharacterState::Sit { .. } | CharacterState::MountSprite(_) => {
|
||||
anim::character::SitAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, second_tool_kind, time),
|
||||
|
@ -1,16 +1,20 @@
|
||||
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 rand::prelude::*;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Interaction {
|
||||
/// This covers mining, unlocking, and regular collectable things (e.g.
|
||||
/// twigs).
|
||||
Collect,
|
||||
Craft(CraftingTab),
|
||||
Mount(Vec<Vec3<f32>>),
|
||||
}
|
||||
|
||||
pub enum FireplaceType {
|
||||
@ -168,6 +172,21 @@ impl BlocksOfInterest {
|
||||
Some(SpriteKind::RepairBench) => {
|
||||
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 common::{
|
||||
comp,
|
||||
comp::tool::ToolKind,
|
||||
comp::{tool::ToolKind, CharacterState},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
link::Is,
|
||||
mounting::Mount,
|
||||
terrain::{Block, TerrainGrid, UnlockKind},
|
||||
util::find_dist::{Cube, Cylinder, FindDist},
|
||||
vol::ReadVol,
|
||||
vol::ReadVol, states::utils::SPRITE_MOUNT_DIST_SQR,
|
||||
};
|
||||
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
|
||||
// to have them here, will see how things turn out
|
||||
Mine(ToolKind),
|
||||
Mount(Vec<Vec3<f32>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -82,6 +83,7 @@ impl Interactable {
|
||||
}
|
||||
},
|
||||
Interaction::Craft(tab) => BlockInteraction::Craft(tab),
|
||||
Interaction::Mount(points) => BlockInteraction::Mount(points),
|
||||
};
|
||||
Some(Self::Block(block, pos, block_interaction))
|
||||
}
|
||||
@ -176,11 +178,12 @@ pub(super) fn select_interactable(
|
||||
let items = ecs.read_storage::<comp::Item>();
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
|
||||
let player_char_state = char_states.get(player_entity);
|
||||
let player_cylinder = Cylinder::from_components(
|
||||
player_pos,
|
||||
scales.get(player_entity).copied(),
|
||||
colliders.get(player_entity),
|
||||
char_states.get(player_entity),
|
||||
player_char_state,
|
||||
);
|
||||
|
||||
let closest_interactable_entity = (
|
||||
@ -248,11 +251,24 @@ pub(super) fn select_interactable(
|
||||
.interactables
|
||||
.iter()
|
||||
.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.map(|e| e as f32 + 0.5)
|
||||
.distance_squared(player_pos),
|
||||
dis,
|
||||
interaction,
|
||||
))
|
||||
.min_by_key(|(_, dist_sqr, _)| OrderedFloat(*dist_sqr))
|
||||
@ -267,7 +283,7 @@ pub(super) fn select_interactable(
|
||||
}) < search_dist
|
||||
})
|
||||
.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)))
|
||||
}
|
||||
|
@ -921,8 +921,8 @@ impl PlayState for SessionState {
|
||||
},
|
||||
GameInput::Interact => {
|
||||
if state {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if let Some(interactable) = &self.interactable {
|
||||
let mut client = self.client.borrow_mut();
|
||||
match interactable {
|
||||
Interactable::Block(block, pos, interaction) => {
|
||||
match interaction {
|
||||
@ -938,6 +938,11 @@ impl PlayState for SessionState {
|
||||
block.get_sprite().map(|s| (*pos, s)),
|
||||
)
|
||||
},
|
||||
BlockInteraction::Mount(_) => {
|
||||
if block.is_mountable() {
|
||||
client.mount_sprite(*pos);
|
||||
}
|
||||
},
|
||||
BlockInteraction::Mine(_) => {},
|
||||
}
|
||||
},
|
||||
@ -964,6 +969,8 @@ impl PlayState for SessionState {
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
client.stand_if_mounted()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user