mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Don't try to mount unmountable entities, clippy fixes and fmt
This commit is contained in:
parent
504e2a38d5
commit
043016a433
@ -34,6 +34,8 @@ use common::{
|
||||
},
|
||||
event::{EventBus, LocalEvent},
|
||||
grid::Grid,
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
outcome::Outcome,
|
||||
recipe::RecipeBook,
|
||||
resources::{PlayerEntity, TimeOfDay},
|
||||
@ -44,8 +46,6 @@ use common::{
|
||||
trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult},
|
||||
uid::{Uid, UidAllocator},
|
||||
vol::RectVolSize,
|
||||
mounting::Rider,
|
||||
link::Is,
|
||||
};
|
||||
use common_base::{prof_span, span};
|
||||
use common_net::{
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::sync;
|
||||
use common::{
|
||||
comp,
|
||||
resources::Time,
|
||||
mounting::{Mount, Rider},
|
||||
link::Is,
|
||||
mounting::{Mount, Rider},
|
||||
resources::Time,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::WorldExt;
|
||||
@ -215,7 +215,9 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPhantom::Vel(_) => sync::handle_interp_remove::<comp::Vel>(entity, world),
|
||||
EcsCompPhantom::Ori(_) => sync::handle_interp_remove::<comp::Ori>(entity, world),
|
||||
EcsCompPhantom::Shockwave(_) => sync::handle_remove::<comp::Shockwave>(entity, world),
|
||||
EcsCompPhantom::BeamSegment(_) => sync::handle_remove::<comp::BeamSegment>(entity, world),
|
||||
EcsCompPhantom::BeamSegment(_) => {
|
||||
sync::handle_remove::<comp::BeamSegment>(entity, world)
|
||||
},
|
||||
EcsCompPhantom::Alignment(_) => sync::handle_remove::<comp::Alignment>(entity, world),
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ use crate::{
|
||||
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
|
||||
uid::Uid,
|
||||
};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use specs::{Component, Entity as EcsEntity, DerefFlaggedStorage};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage, Entity as EcsEntity};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::{collections::VecDeque, fmt};
|
||||
use strum::IntoEnumIterator;
|
||||
|
@ -73,8 +73,7 @@ pub use self::{
|
||||
combo::Combo,
|
||||
controller::{
|
||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputAttr,
|
||||
InputKind, InventoryAction, InventoryEvent, InventoryManip,
|
||||
UtteranceKind,
|
||||
InputKind, InventoryAction, InventoryEvent, InventoryManip, UtteranceKind,
|
||||
},
|
||||
energy::Energy,
|
||||
fluid_dynamics::Fluid,
|
||||
|
@ -48,8 +48,11 @@ pub mod figure;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod generation;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod grid;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod link;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod lottery;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod mounting;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod npc;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod outcome;
|
||||
@ -80,10 +83,6 @@ pub mod uid;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod vol;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod volumes;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod link;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod mounting;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use cached_spatial_grid::CachedSpatialGrid;
|
||||
|
@ -1,14 +1,13 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{SystemData, Component, DerefFlaggedStorage};
|
||||
use specs::{Component, DerefFlaggedStorage, SystemData};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::{
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
pub trait Link: Sized + Send + Sync + 'static {
|
||||
type Error;
|
||||
|
||||
type CreateData<'a>: SystemData<'a>;
|
||||
fn create(this: &LinkHandle<Self>, data: Self::CreateData<'_>) -> Result<(), ()>;
|
||||
fn create(this: &LinkHandle<Self>, data: Self::CreateData<'_>) -> Result<(), Self::Error>;
|
||||
|
||||
type PersistData<'a>: SystemData<'a>;
|
||||
fn persist(this: &LinkHandle<Self>, data: Self::PersistData<'_>) -> bool;
|
||||
@ -35,16 +34,22 @@ impl<R: Role> Is<R> {
|
||||
}
|
||||
|
||||
impl<R: Role> Clone for Is<R> {
|
||||
fn clone(&self) -> Self { Self { link: self.link.clone() } }
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
link: self.link.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Role> Deref for Is<R> {
|
||||
type Target = R::Link;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.link }
|
||||
}
|
||||
|
||||
impl<R: Role + 'static> Component for Is<R>
|
||||
where R::Link: Send + Sync + 'static
|
||||
where
|
||||
R::Link: Send + Sync + 'static,
|
||||
{
|
||||
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
||||
@ -56,21 +61,24 @@ pub struct LinkHandle<L: Link> {
|
||||
|
||||
impl<L: Link> Clone for LinkHandle<L> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { link: self.link.clone() }
|
||||
Self {
|
||||
link: Arc::clone(&self.link),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Link> LinkHandle<L> {
|
||||
pub fn from_link(link: L) -> Self {
|
||||
Self { link: Arc::new(link) }
|
||||
Self {
|
||||
link: Arc::new(link),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_role<R: Role<Link = L>>(&self) -> Is<R> {
|
||||
Is { link: self.clone() }
|
||||
}
|
||||
pub fn make_role<R: Role<Link = L>>(&self) -> Is<R> { Is { link: self.clone() } }
|
||||
}
|
||||
|
||||
impl<L: Link> Deref for LinkHandle<L> {
|
||||
type Target = L;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.link }
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
use crate::{
|
||||
comp,
|
||||
link::{Is, Link, Role, LinkHandle},
|
||||
uid::{Uid, UidAllocator},
|
||||
link::{Is, Link, LinkHandle, Role},
|
||||
terrain::TerrainGrid,
|
||||
uid::{Uid, UidAllocator},
|
||||
};
|
||||
use specs::{Entities, ReadStorage, Read, ReadExpect, WriteStorage};
|
||||
use specs::saveload::MarkerAllocator;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{saveload::MarkerAllocator, Entities, Read, ReadExpect, ReadStorage, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@ -29,35 +28,26 @@ pub struct Mounting {
|
||||
pub rider: Uid,
|
||||
}
|
||||
|
||||
pub enum MountingError {
|
||||
NoSuchEntity,
|
||||
NotMountable,
|
||||
}
|
||||
|
||||
impl Link for Mounting {
|
||||
type CreateData<'a> = (
|
||||
Read<'a, UidAllocator>,
|
||||
WriteStorage<'a, Is<Mount>>,
|
||||
WriteStorage<'a, Is<Rider>>,
|
||||
);
|
||||
fn create(this: &LinkHandle<Self>, (uid_allocator, mut is_mounts, mut is_riders): Self::CreateData<'_>) -> Result<(), ()> {
|
||||
let entity = |uid: Uid| uid_allocator
|
||||
.retrieve_entity_internal(uid.into());
|
||||
|
||||
if this.mount == this.rider {
|
||||
// Forbid self-mounting
|
||||
Err(())
|
||||
} else if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) {
|
||||
let can_mount_with = |entity| is_mounts.get(entity).is_none() && is_riders.get(entity).is_none();
|
||||
|
||||
// Ensure that neither mount or rider are already part of a mounting relationship
|
||||
if can_mount_with(mount) && can_mount_with(rider) {
|
||||
let _ = is_mounts.insert(mount, this.make_role());
|
||||
let _ = is_riders.insert(rider, this.make_role());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
type DeleteData<'a> = (
|
||||
Read<'a, UidAllocator>,
|
||||
WriteStorage<'a, Is<Mount>>,
|
||||
WriteStorage<'a, Is<Rider>>,
|
||||
WriteStorage<'a, comp::Pos>,
|
||||
WriteStorage<'a, comp::ForceUpdate>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
);
|
||||
type Error = MountingError;
|
||||
type PersistData<'a> = (
|
||||
Read<'a, UidAllocator>,
|
||||
Entities<'a>,
|
||||
@ -65,12 +55,44 @@ impl Link for Mounting {
|
||||
ReadStorage<'a, Is<Mount>>,
|
||||
ReadStorage<'a, Is<Rider>>,
|
||||
);
|
||||
fn persist(this: &LinkHandle<Self>, (uid_allocator, entities, healths, is_mounts, is_riders): Self::PersistData<'_>) -> bool {
|
||||
let entity = |uid: Uid| uid_allocator
|
||||
.retrieve_entity_internal(uid.into());
|
||||
|
||||
fn create(
|
||||
this: &LinkHandle<Self>,
|
||||
(uid_allocator, mut is_mounts, mut is_riders): Self::CreateData<'_>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into());
|
||||
|
||||
if this.mount == this.rider {
|
||||
// Forbid self-mounting
|
||||
Err(MountingError::NotMountable)
|
||||
} else if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) {
|
||||
let can_mount_with =
|
||||
|entity| is_mounts.get(entity).is_none() && is_riders.get(entity).is_none();
|
||||
|
||||
// Ensure that neither mount or rider are already part of a mounting
|
||||
// relationship
|
||||
if can_mount_with(mount) && can_mount_with(rider) {
|
||||
let _ = is_mounts.insert(mount, this.make_role());
|
||||
let _ = is_riders.insert(rider, this.make_role());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(MountingError::NotMountable)
|
||||
}
|
||||
} else {
|
||||
Err(MountingError::NoSuchEntity)
|
||||
}
|
||||
}
|
||||
|
||||
fn persist(
|
||||
this: &LinkHandle<Self>,
|
||||
(uid_allocator, entities, healths, is_mounts, is_riders): Self::PersistData<'_>,
|
||||
) -> bool {
|
||||
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into());
|
||||
|
||||
if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) {
|
||||
let is_alive = |entity| entities.is_alive(entity) && healths.get(entity).map_or(true, |h| !h.is_dead);
|
||||
let is_alive = |entity| {
|
||||
entities.is_alive(entity) && healths.get(entity).map_or(true, |h| !h.is_dead)
|
||||
};
|
||||
|
||||
// Ensure that both entities are alive and that they continue to be linked
|
||||
is_alive(mount)
|
||||
@ -82,17 +104,11 @@ impl Link for Mounting {
|
||||
}
|
||||
}
|
||||
|
||||
type DeleteData<'a> = (
|
||||
Read<'a, UidAllocator>,
|
||||
WriteStorage<'a, Is<Mount>>,
|
||||
WriteStorage<'a, Is<Rider>>,
|
||||
WriteStorage<'a, comp::Pos>,
|
||||
WriteStorage<'a, comp::ForceUpdate>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
);
|
||||
fn delete(this: &LinkHandle<Self>, (uid_allocator, mut is_mounts, mut is_riders, mut positions, mut force_update, terrain): Self::DeleteData<'_>) {
|
||||
let entity = |uid: Uid| uid_allocator
|
||||
.retrieve_entity_internal(uid.into());
|
||||
fn delete(
|
||||
this: &LinkHandle<Self>,
|
||||
(uid_allocator, mut is_mounts, mut is_riders, mut positions, mut force_update, terrain): Self::DeleteData<'_>,
|
||||
) {
|
||||
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into());
|
||||
|
||||
let mount = entity(this.mount);
|
||||
let rider = entity(this.rider);
|
||||
@ -105,9 +121,15 @@ impl Link for Mounting {
|
||||
let safe_pos = rider
|
||||
.and_then(|rider| positions.get(rider).copied())
|
||||
.filter(|rider_pos| terrain.is_space(rider_pos.0.map(|e| e.floor() as i32)))
|
||||
.or_else(|| mount
|
||||
.and_then(|mount| positions.get(mount).copied())
|
||||
.filter(|mount_pos| terrain.is_space((mount_pos.0 + Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))));
|
||||
.or_else(|| {
|
||||
mount
|
||||
.and_then(|mount| positions.get(mount).copied())
|
||||
.filter(|mount_pos| {
|
||||
terrain.is_space(
|
||||
(mount_pos.0 + Vec3::unit_z() * 0.1).map(|e| e.floor() as i32),
|
||||
)
|
||||
})
|
||||
});
|
||||
rider
|
||||
.and_then(|rider| Some(rider).zip(positions.get_mut(rider)))
|
||||
.map(|(rider, pos)| {
|
||||
@ -115,7 +137,7 @@ impl Link for Mounting {
|
||||
pos.0 = safe_pos
|
||||
.map(|p| p.0.map(|e| e.floor()))
|
||||
.unwrap_or_else(|| terrain.find_space(old_pos).map(|e| e as f32))
|
||||
+ Vec3::new(0.5, 0.5, 0.0);
|
||||
+ Vec3::new(0.5, 0.5, 0.0);
|
||||
let _ = force_update.insert(rider, comp::ForceUpdate);
|
||||
});
|
||||
}
|
||||
|
@ -174,9 +174,11 @@ impl TerrainGrid {
|
||||
(0..SEARCH_DIST * 2 + 1)
|
||||
.map(|i| if i % 2 == 0 { i } else { -i } / 2)
|
||||
.map(|z_diff| pos + Vec3::unit_z() * z_diff)
|
||||
.find(|pos| self.get(pos - Vec3::unit_z())
|
||||
.map_or(false, |b| b.is_filled())
|
||||
&& self.is_space(*pos))
|
||||
.find(|pos| {
|
||||
self.get(pos - Vec3::unit_z())
|
||||
.map_or(false, |b| b.is_filled())
|
||||
&& self.is_space(*pos)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ use common::{
|
||||
calendar::Calendar,
|
||||
comp,
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
link::Is,
|
||||
mounting::{Mount, Rider},
|
||||
outcome::Outcome,
|
||||
region::RegionMap,
|
||||
resources::{
|
||||
@ -19,8 +21,6 @@ use common::{
|
||||
time::DayPeriod,
|
||||
trade::Trades,
|
||||
vol::{ReadVol, WriteVol},
|
||||
link::Is,
|
||||
mounting::{Mount, Rider},
|
||||
};
|
||||
use common_base::span;
|
||||
use common_ecs::{PhysicsMetrics, SysMetrics};
|
||||
@ -34,10 +34,7 @@ use specs::{
|
||||
storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage},
|
||||
Component, DispatcherBuilder, Entity as EcsEntity, WorldExt,
|
||||
};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
/// How much faster should an in-game day be compared to a real day?
|
||||
|
@ -11,6 +11,8 @@ use common::{
|
||||
StateUpdate, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
outcome::Outcome,
|
||||
resources::{DeltaTime, Time},
|
||||
states::{
|
||||
@ -19,8 +21,6 @@ use common::{
|
||||
},
|
||||
terrain::TerrainGrid,
|
||||
uid::Uid,
|
||||
mounting::Rider,
|
||||
link::Is,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
use common::{
|
||||
comp::{Body, Controller, Ori, Pos, Vel, ForceUpdate},
|
||||
uid::UidAllocator,
|
||||
mounting::{Mount, Rider},
|
||||
comp::{Body, Controller, Ori, Pos, Vel},
|
||||
link::Is,
|
||||
uid::Uid,
|
||||
mounting::Mount,
|
||||
uid::UidAllocator,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use specs::{
|
||||
saveload::{Marker, MarkerAllocator},
|
||||
Entities, Join, Read, ReadStorage, WriteStorage, WriteExpect,
|
||||
Entities, Join, Read, ReadStorage, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
@ -20,14 +19,11 @@ impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, UidAllocator>,
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Uid>,
|
||||
WriteStorage<'a, Controller>,
|
||||
ReadStorage<'a, Is<Rider>>,
|
||||
ReadStorage<'a, Is<Mount>>,
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
ReadStorage<'a, ForceUpdate>,
|
||||
ReadStorage<'a, Body>,
|
||||
);
|
||||
|
||||
@ -40,14 +36,11 @@ impl<'a> System<'a> for Sys {
|
||||
(
|
||||
uid_allocator,
|
||||
entities,
|
||||
uids,
|
||||
mut controllers,
|
||||
is_riders,
|
||||
is_mounts,
|
||||
mut positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
force_updates,
|
||||
bodies,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
@ -71,8 +64,7 @@ impl<'a> System<'a> for Sys {
|
||||
let mounter_body = bodies.get(rider);
|
||||
let mounting_offset = body.map_or(Vec3::unit_z(), Body::mount_offset)
|
||||
+ mounter_body.map_or(Vec3::zero(), Body::rider_offset);
|
||||
let _ = positions
|
||||
.insert(rider, Pos(pos.0 + ori.to_quat() * mounting_offset));
|
||||
let _ = positions.insert(rider, Pos(pos.0 + ori.to_quat() * mounting_offset));
|
||||
let _ = orientations.insert(rider, ori);
|
||||
let _ = velocities.insert(rider, vel);
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ use common::{
|
||||
comp::{
|
||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||
fluid_dynamics::{Fluid, LiquidKind, Wings},
|
||||
Body, CharacterState, Collider, Density, Mass, Ori, PhysicsState, Pos,
|
||||
PosVelOriDefer, PreviousPhysCache, Projectile, Scale, Stats, Sticky, Vel,
|
||||
Body, CharacterState, Collider, Density, Mass, Ori, PhysicsState, Pos, PosVelOriDefer,
|
||||
PreviousPhysCache, Projectile, Scale, Stats, Sticky, Vel,
|
||||
},
|
||||
consts::{AIR_DENSITY, FRIC_GROUND, GRAVITY},
|
||||
event::{EventBus, ServerEvent},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
outcome::Outcome,
|
||||
resources::DeltaTime,
|
||||
states,
|
||||
@ -14,8 +16,6 @@ use common::{
|
||||
uid::Uid,
|
||||
util::{Projection, SpatialGrid},
|
||||
vol::{BaseVol, ReadVol},
|
||||
mounting::Rider,
|
||||
link::Is,
|
||||
};
|
||||
use common_base::{prof_span, span};
|
||||
use common_ecs::{Job, Origin, ParMode, Phase, PhysicsMetrics, System};
|
||||
@ -1851,7 +1851,8 @@ fn resolve_e2e_collision(
|
||||
//
|
||||
// This allows using e2e pushback to gain speed by jumping out of a roll
|
||||
// while in the middle of a collider, this is an intentional combat mechanic.
|
||||
let forced_movement = matches!(char_state_maybe, Some(cs) if cs.is_forced_movement()) || is_riding;
|
||||
let forced_movement =
|
||||
matches!(char_state_maybe, Some(cs) if cs.is_forced_movement()) || is_riding;
|
||||
|
||||
// Don't apply repulsive force to projectiles,
|
||||
// or if we're colliding with a terrain-like entity,
|
||||
@ -1873,7 +1874,14 @@ fn resolve_e2e_collision(
|
||||
|
||||
let diff = diff.normalized();
|
||||
|
||||
*vel_delta += Vec3::from(diff) * force * step_delta * vel.0.xy().try_normalized().map_or(1.0, |dir| diff.dot(-dir).max(0.025));
|
||||
*vel_delta += Vec3::from(diff)
|
||||
* force
|
||||
* step_delta
|
||||
* vel
|
||||
.0
|
||||
.xy()
|
||||
.try_normalized()
|
||||
.map_or(1.0, |dir| diff.dot(-dir).max(0.025));
|
||||
}
|
||||
|
||||
*collision_registered = true;
|
||||
|
@ -34,14 +34,14 @@ use common::{
|
||||
effect::Effect,
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::{EntityConfig, EntityInfo},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
npc::{self, get_npc_name},
|
||||
resources::{BattleMode, PlayerPhysicsSettings, Time, TimeOfDay},
|
||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
||||
uid::{Uid, UidAllocator},
|
||||
vol::{ReadVol, RectVolSize},
|
||||
Damage, DamageKind, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
};
|
||||
use common_net::{
|
||||
msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral},
|
||||
@ -52,7 +52,9 @@ use core::{cmp::Ordering, convert::TryFrom, time::Duration};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use humantime::Duration as HumanDuration;
|
||||
use rand::Rng;
|
||||
use specs::{storage::StorageEntry, Builder, Entity as EcsEntity, Join, WorldExt, saveload::MarkerAllocator};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, storage::StorageEntry, Builder, Entity as EcsEntity, Join, WorldExt,
|
||||
};
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
use vek::*;
|
||||
use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement};
|
||||
@ -203,24 +205,30 @@ fn position_mut<T>(
|
||||
descriptor: &str,
|
||||
f: impl for<'a> FnOnce(&'a mut comp::Pos) -> T,
|
||||
) -> CmdResult<T> {
|
||||
let entity = server.state
|
||||
let entity = server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<Is<Rider>>()
|
||||
.get(entity)
|
||||
.and_then(|is_rider| server.state
|
||||
.ecs()
|
||||
.read_resource::<UidAllocator>()
|
||||
.retrieve_entity_internal(is_rider.mount.into()))
|
||||
.and_then(|is_rider| {
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<UidAllocator>()
|
||||
.retrieve_entity_internal(is_rider.mount.into())
|
||||
})
|
||||
.unwrap_or(entity);
|
||||
|
||||
let res = server.state
|
||||
let res = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(f)
|
||||
.ok_or_else(|| format!("Cannot get position for {:?}!", descriptor));
|
||||
if res.is_ok() {
|
||||
let _ = server.state
|
||||
let _ = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::ForceUpdate>()
|
||||
.insert(entity, comp::ForceUpdate);
|
||||
|
@ -15,12 +15,12 @@ use common::{
|
||||
Inventory, Pos, SkillGroupKind,
|
||||
},
|
||||
consts::{MAX_MOUNT_RANGE, SOUND_TRAVEL_DIST_PER_VOLUME},
|
||||
link::Is,
|
||||
mounting::{Mount, Mounting, Rider},
|
||||
outcome::Outcome,
|
||||
terrain::{Block, SpriteKind},
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
mounting::{Mount, Rider, Mounting},
|
||||
link::Is,
|
||||
};
|
||||
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
||||
|
||||
@ -102,17 +102,8 @@ pub fn handle_npc_interaction(server: &mut Server, interactor: EcsEntity, npc_en
|
||||
pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) {
|
||||
let state = server.state_mut();
|
||||
|
||||
if state
|
||||
.ecs()
|
||||
.read_storage::<Is<Rider>>()
|
||||
.get(rider)
|
||||
.is_none()
|
||||
{
|
||||
let not_mounting_yet = state
|
||||
.ecs()
|
||||
.read_storage::<Is<Mount>>()
|
||||
.get(mount)
|
||||
.is_none();
|
||||
if state.ecs().read_storage::<Is<Rider>>().get(rider).is_none() {
|
||||
let not_mounting_yet = state.ecs().read_storage::<Is<Mount>>().get(mount).is_none();
|
||||
|
||||
let within_range = || {
|
||||
let positions = state.ecs().read_storage::<comp::Pos>();
|
||||
@ -126,10 +117,13 @@ pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) {
|
||||
if let (Some(rider_uid), Some(mount_uid)) =
|
||||
(uids.get(rider).copied(), uids.get(mount).copied())
|
||||
{
|
||||
let is_pet = match state.ecs().read_storage::<comp::Alignment>().get(mount) {
|
||||
Some(comp::Alignment::Owned(owner)) if *owner == rider_uid => true,
|
||||
_ => false,
|
||||
};
|
||||
let is_pet = matches!(
|
||||
state
|
||||
.ecs()
|
||||
.read_storage::<comp::Alignment>()
|
||||
.get(mount),
|
||||
Some(comp::Alignment::Owned(owner)) if *owner == rider_uid,
|
||||
);
|
||||
|
||||
if is_pet {
|
||||
drop(uids);
|
||||
@ -146,10 +140,7 @@ pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) {
|
||||
|
||||
pub fn handle_unmount(server: &mut Server, rider: EcsEntity) {
|
||||
let state = server.state_mut();
|
||||
state
|
||||
.ecs()
|
||||
.write_storage::<Is<Rider>>()
|
||||
.remove(rider);
|
||||
state.ecs().write_storage::<Is<Rider>>().remove(rider);
|
||||
}
|
||||
|
||||
/// FIXME: This code is dangerous and needs to be refactored. We can't just
|
||||
|
@ -1,6 +1,9 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
comp::inventory::{loadout_builder::{make_potion_bag, make_food_bag}, slot::ArmorSlot},
|
||||
comp::inventory::{
|
||||
loadout_builder::{make_food_bag, make_potion_bag},
|
||||
slot::ArmorSlot,
|
||||
},
|
||||
resources::Time,
|
||||
rtsim::{Memory, MemoryItem},
|
||||
store::Id,
|
||||
@ -142,9 +145,8 @@ impl Entity {
|
||||
|
||||
// give potions to traveler humanoids or return loadout as is otherwise
|
||||
match (body, kind) {
|
||||
(comp::Body::Humanoid(_), RtSimEntityKind::Random) => {
|
||||
|l, _| l
|
||||
.bag(ArmorSlot::Bag1, Some(make_potion_bag(100)))
|
||||
(comp::Body::Humanoid(_), RtSimEntityKind::Random) => |l, _| {
|
||||
l.bag(ArmorSlot::Bag1, Some(make_potion_bag(100)))
|
||||
.bag(ArmorSlot::Bag2, Some(make_food_bag(100)))
|
||||
},
|
||||
(_, RtSimEntityKind::Merchant) => {
|
||||
|
@ -18,11 +18,11 @@ use common::{
|
||||
Group, Inventory, Poise,
|
||||
},
|
||||
effect::Effect,
|
||||
link::{Link, LinkHandle},
|
||||
mounting::Mounting,
|
||||
resources::{Time, TimeOfDay},
|
||||
slowjob::SlowJobPool,
|
||||
uid::{Uid, UidAllocator},
|
||||
link::{Is, Link, Role, LinkHandle},
|
||||
mounting::Mounting,
|
||||
};
|
||||
use common_net::{
|
||||
msg::{CharacterInfo, PlayerListUpdate, PresenceKind, ServerGeneral},
|
||||
@ -32,7 +32,7 @@ use common_state::State;
|
||||
use rand::prelude::*;
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
|
||||
Join, WorldExt, Component,
|
||||
Join, WorldExt,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use tracing::{trace, warn};
|
||||
@ -112,8 +112,9 @@ pub trait StateExt {
|
||||
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
|
||||
fn notify_players(&self, msg: ServerGeneral);
|
||||
fn notify_in_game_clients(&self, msg: ServerGeneral);
|
||||
/// Create a new link between entities (see [`common::mounting`] for an example).
|
||||
fn link<L: Link>(&mut self, link: L) -> Result<(), ()>;
|
||||
/// Create a new link between entities (see [`common::mounting`] for an
|
||||
/// example).
|
||||
fn link<L: Link>(&mut self, link: L) -> Result<(), L::Error>;
|
||||
/// Maintain active links between entities
|
||||
fn maintain_links(&mut self);
|
||||
/// Delete an entity, recording the deletion in [`DeletedEntities`]
|
||||
@ -277,7 +278,7 @@ impl StateExt for State {
|
||||
mountable: bool,
|
||||
) -> EcsEntityBuilder {
|
||||
let body = comp::Body::Ship(ship);
|
||||
let mut builder = self
|
||||
let builder = self
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
@ -831,13 +832,10 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
|
||||
fn link<L: Link>(&mut self, link: L) -> Result<(), ()> {
|
||||
fn link<L: Link>(&mut self, link: L) -> Result<(), L::Error> {
|
||||
let linker = LinkHandle::from_link(link);
|
||||
|
||||
L::create(
|
||||
&linker,
|
||||
self.ecs().system_data(),
|
||||
)?;
|
||||
L::create(&linker, self.ecs().system_data())?;
|
||||
|
||||
self.ecs_mut()
|
||||
.entry::<Vec<LinkHandle<L>>>()
|
||||
@ -850,11 +848,13 @@ impl StateExt for State {
|
||||
fn maintain_links(&mut self) {
|
||||
fn maintain_link<L: Link>(state: &State) {
|
||||
if let Some(mut handles) = state.ecs().try_fetch_mut::<Vec<LinkHandle<L>>>() {
|
||||
handles.retain(|link| if L::persist(link, state.ecs().system_data()) {
|
||||
true
|
||||
} else {
|
||||
L::delete(link, state.ecs().system_data());
|
||||
false
|
||||
handles.retain(|link| {
|
||||
if L::persist(link, state.ecs().system_data()) {
|
||||
true
|
||||
} else {
|
||||
L::delete(link, state.ecs().system_data());
|
||||
false
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ use common::{
|
||||
consts::GRAVITY,
|
||||
effect::{BuffEffect, Effect},
|
||||
event::{Emitter, EventBus, ServerEvent},
|
||||
link::Is,
|
||||
mounting::Mount,
|
||||
path::TraversalConfig,
|
||||
resources::{DeltaTime, Time, TimeOfDay},
|
||||
rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent},
|
||||
@ -37,8 +39,6 @@ use common::{
|
||||
uid::{Uid, UidAllocator},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
mounting::Mount,
|
||||
link::Is,
|
||||
};
|
||||
use common_base::prof_span;
|
||||
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||
@ -1428,18 +1428,16 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
/// Attempt to consume a healing item, and return whether any healing items
|
||||
/// were queued. Callers should use this to implement a delay so that
|
||||
/// the healing isn't interrupted. If `relaxed` is `true`, we allow eating food and prioritise healing.
|
||||
/// the healing isn't interrupted. If `relaxed` is `true`, we allow eating
|
||||
/// food and prioritise healing.
|
||||
fn heal_self(&self, _agent: &mut Agent, controller: &mut Controller, relaxed: bool) -> bool {
|
||||
let healing_value = |item: &Item| {
|
||||
let mut value = 0.0;
|
||||
|
||||
if let ItemKind::Consumable {
|
||||
kind,
|
||||
effects,
|
||||
..
|
||||
} = &item.kind
|
||||
{
|
||||
if matches!(kind, ConsumableKind::Drink) || (relaxed && matches!(kind, ConsumableKind::Food)) {
|
||||
if let ItemKind::Consumable { kind, effects, .. } = &item.kind {
|
||||
if matches!(kind, ConsumableKind::Drink)
|
||||
|| (relaxed && matches!(kind, ConsumableKind::Food))
|
||||
{
|
||||
for effect in effects.iter() {
|
||||
use BuffKind::*;
|
||||
match effect {
|
||||
@ -1449,8 +1447,8 @@ impl<'a> AgentData<'a> {
|
||||
Effect::Buff(BuffEffect { kind, data, .. })
|
||||
if matches!(kind, Regeneration | Saturation | Potion) =>
|
||||
{
|
||||
value +=
|
||||
data.strength * data.duration.map_or(0.0, |d| d.as_secs() as f32);
|
||||
value += data.strength
|
||||
* data.duration.map_or(0.0, |d| d.as_secs() as f32);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@ -1469,10 +1467,12 @@ impl<'a> AgentData<'a> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
consumables.sort_by_key(|(_, item)| if relaxed {
|
||||
-healing_value(item)
|
||||
} else {
|
||||
healing_value(item)
|
||||
consumables.sort_by_key(|(_, item)| {
|
||||
if relaxed {
|
||||
-healing_value(item)
|
||||
} else {
|
||||
healing_value(item)
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((id, _)) = consumables.last() {
|
||||
|
@ -7,14 +7,14 @@ use crate::{
|
||||
use common::{
|
||||
calendar::Calendar,
|
||||
comp::{Collider, ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
outcome::Outcome,
|
||||
region::{Event as RegionEvent, RegionMap},
|
||||
resources::{PlayerPhysicsSettings, TimeOfDay},
|
||||
terrain::TerrainChunkSize,
|
||||
uid::Uid,
|
||||
vol::RectVolSize,
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
|
||||
|
@ -2,13 +2,13 @@
|
||||
use common::{
|
||||
comp::{
|
||||
item::{tool::AbilityMap, MaterialStatManifest},
|
||||
ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider,
|
||||
Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass,
|
||||
Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, Alignment,
|
||||
ActiveAbilities, Alignment, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState,
|
||||
Collider, Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, Ori,
|
||||
Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel,
|
||||
},
|
||||
uid::Uid,
|
||||
mounting::{Mount, Rider},
|
||||
link::Is,
|
||||
mounting::{Mount, Rider},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use common_net::{
|
||||
|
@ -83,6 +83,8 @@ use common::{
|
||||
BuffData, BuffKind, Item,
|
||||
},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
link::Is,
|
||||
mounting::Mount,
|
||||
outcome::Outcome,
|
||||
slowjob::SlowJobPool,
|
||||
terrain::{SpriteKind, TerrainChunk},
|
||||
@ -90,8 +92,6 @@ use common::{
|
||||
uid::Uid,
|
||||
util::{srgba_to_linear, Dir},
|
||||
vol::RectRasterableVol,
|
||||
mounting::Mount,
|
||||
link::Is,
|
||||
};
|
||||
use common_base::{prof_span, span};
|
||||
use common_net::{
|
||||
@ -1668,32 +1668,33 @@ impl Hud {
|
||||
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
||||
let pulse = self.pulse;
|
||||
|
||||
let make_overitem = |item: &Item, pos, distance, properties, fonts, interaction_options| {
|
||||
let text = if item.amount() > 1 {
|
||||
format!("{} x {}", item.amount(), item.name())
|
||||
} else {
|
||||
item.name().to_string()
|
||||
let make_overitem =
|
||||
|item: &Item, pos, distance, properties, fonts, interaction_options| {
|
||||
let text = if item.amount() > 1 {
|
||||
format!("{} x {}", item.amount(), item.name())
|
||||
} else {
|
||||
item.name().to_string()
|
||||
};
|
||||
|
||||
let quality = get_quality_col(item);
|
||||
|
||||
// Item
|
||||
overitem::Overitem::new(
|
||||
text.into(),
|
||||
quality,
|
||||
distance,
|
||||
fonts,
|
||||
i18n,
|
||||
&global_state.settings.controls,
|
||||
properties,
|
||||
pulse,
|
||||
&global_state.window.key_layout,
|
||||
interaction_options,
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(pos)
|
||||
};
|
||||
|
||||
let quality = get_quality_col(item);
|
||||
|
||||
// Item
|
||||
overitem::Overitem::new(
|
||||
text.into(),
|
||||
quality,
|
||||
distance,
|
||||
fonts,
|
||||
i18n,
|
||||
&global_state.settings.controls,
|
||||
properties,
|
||||
pulse,
|
||||
&global_state.window.key_layout,
|
||||
interaction_options,
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(pos)
|
||||
};
|
||||
|
||||
self.failed_block_pickups
|
||||
.retain(|_, t| pulse - *t < overitem::PICKUP_FAILED_FADE_OUT_TIME);
|
||||
self.failed_entity_pickups
|
||||
@ -1788,7 +1789,22 @@ impl Hud {
|
||||
let speech_bubbles = &self.speech_bubbles;
|
||||
|
||||
// Render overhead name tags and health bars
|
||||
for (entity, pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group, dist_sqr, alignment, is_mount) in (
|
||||
for (
|
||||
entity,
|
||||
pos,
|
||||
info,
|
||||
bubble,
|
||||
_,
|
||||
_,
|
||||
health,
|
||||
_,
|
||||
height_offset,
|
||||
hpfl,
|
||||
in_group,
|
||||
dist_sqr,
|
||||
alignment,
|
||||
is_mount,
|
||||
) in (
|
||||
&entities,
|
||||
&pos,
|
||||
interpolated.maybe(),
|
||||
@ -1932,16 +1948,23 @@ impl Hud {
|
||||
&global_state.window.key_layout,
|
||||
match alignment {
|
||||
// TODO: Don't use `MAX_MOUNT_RANGE` here, add dedicated interaction range
|
||||
Some(comp::Alignment::Npc) if dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2)
|
||||
&& interactable.as_ref().and_then(|i| i.entity()) == Some(entity) =>
|
||||
Some(comp::Alignment::Npc)
|
||||
if dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2)
|
||||
&& interactable.as_ref().and_then(|i| i.entity())
|
||||
== Some(entity) =>
|
||||
{
|
||||
vec![
|
||||
(GameInput::Interact, i18n.get("hud.talk").to_string()),
|
||||
(GameInput::Trade, i18n.get("hud.trade").to_string()),
|
||||
],
|
||||
Some(comp::Alignment::Owned(owner)) if Some(*owner) == client.uid()
|
||||
&& is_mount.is_none()
|
||||
&& dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) =>
|
||||
vec![(GameInput::Mount, i18n.get("hud.mount").to_string())],
|
||||
]
|
||||
},
|
||||
Some(comp::Alignment::Owned(owner))
|
||||
if Some(*owner) == client.uid()
|
||||
&& is_mount.is_none()
|
||||
&& dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) =>
|
||||
{
|
||||
vec![(GameInput::Mount, i18n.get("hud.mount").to_string())]
|
||||
},
|
||||
_ => Vec::new(),
|
||||
},
|
||||
)
|
||||
|
@ -9,15 +9,15 @@ use crate::{
|
||||
settings::{ControlSettings, InterfaceSettings},
|
||||
ui::{fonts::Fonts, Ingameable},
|
||||
};
|
||||
use keyboard_keynames::key_layout::KeyLayout;
|
||||
use common::comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType};
|
||||
use conrod_core::{
|
||||
color,
|
||||
position::Align,
|
||||
widget::{self, Image, Rectangle, Text, RoundedRectangle},
|
||||
widget::{self, Image, Rectangle, RoundedRectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use i18n::Localization;
|
||||
use keyboard_keynames::key_layout::KeyLayout;
|
||||
|
||||
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
||||
widget_ids! {
|
||||
@ -101,6 +101,7 @@ pub struct Overhead<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Overhead<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
info: Option<Info<'a>>,
|
||||
bubble: Option<&'a SpeechBubble>,
|
||||
@ -467,25 +468,30 @@ impl<'a> Widget for Overhead<'a> {
|
||||
|
||||
// Interaction hints
|
||||
if !self.interaction_options.is_empty() {
|
||||
let text = self.interaction_options
|
||||
let text = self
|
||||
.interaction_options
|
||||
.iter()
|
||||
.filter_map(|(input, action)| Some((self
|
||||
.controls
|
||||
.get_binding(*input)?, action)))
|
||||
.map(|(input, action)| format!("{} {}", input.display_string(self.key_layout).as_str(), action))
|
||||
.filter_map(|(input, action)| {
|
||||
Some((self.controls.get_binding(*input)?, action))
|
||||
})
|
||||
.map(|(input, action)| {
|
||||
format!(
|
||||
"{} {}",
|
||||
input.display_string(self.key_layout).as_str(),
|
||||
action
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
let scale = 30.0;
|
||||
let btn_rect_size = scale * 0.8;
|
||||
let btn_font_size = scale * 0.6;
|
||||
let btn_rect_pos_y = 0.0;
|
||||
let btn_text_pos_y = btn_rect_pos_y + ((btn_rect_size - btn_font_size) * 0.5);
|
||||
let btn_radius = btn_rect_size / 5.0;
|
||||
let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.8);
|
||||
|
||||
// RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius, btn_color)
|
||||
// .x_y(0.0, btn_rect_pos_y)
|
||||
// RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius,
|
||||
// btn_color) .x_y(0.0, btn_rect_pos_y)
|
||||
// .depth(self.distance_from_player_sqr + 2.0)
|
||||
// .parent(id)
|
||||
// .set(state.ids.btn_bg, ui);
|
||||
@ -494,11 +500,20 @@ impl<'a> Widget for Overhead<'a> {
|
||||
.font_size(btn_font_size as u32)
|
||||
.color(TEXT_COLOR)
|
||||
.parent(id)
|
||||
.down_from(self.info.map_or(state.ids.name, |info| if info.health.map_or(false, should_show_healthbar) {
|
||||
if info.energy.is_some() { state.ids.mana_bar } else { state.ids.health_bar }
|
||||
} else {
|
||||
state.ids.name
|
||||
}), 12.0)
|
||||
.down_from(
|
||||
self.info.map_or(state.ids.name, |info| {
|
||||
if info.health.map_or(false, should_show_healthbar) {
|
||||
if info.energy.is_some() {
|
||||
state.ids.mana_bar
|
||||
} else {
|
||||
state.ids.health_bar
|
||||
}
|
||||
} else {
|
||||
state.ids.name
|
||||
}
|
||||
}),
|
||||
12.0,
|
||||
)
|
||||
.align_middle_x_of(state.ids.name)
|
||||
.depth(1.0);
|
||||
|
||||
@ -506,12 +521,16 @@ impl<'a> Widget for Overhead<'a> {
|
||||
|
||||
hints_text.set(state.ids.interaction_hints, ui);
|
||||
|
||||
RoundedRectangle::fill_with([w + btn_radius * 2.0, h + btn_radius * 2.0], btn_radius, btn_color)
|
||||
.depth(2.0)
|
||||
.middle_of(state.ids.interaction_hints)
|
||||
.align_middle_y_of(state.ids.interaction_hints)
|
||||
.parent(id)
|
||||
.set(state.ids.interaction_hints_bg, ui);
|
||||
RoundedRectangle::fill_with(
|
||||
[w + btn_radius * 2.0, h + btn_radius * 2.0],
|
||||
btn_radius,
|
||||
btn_color,
|
||||
)
|
||||
.depth(2.0)
|
||||
.middle_of(state.ids.interaction_hints)
|
||||
.align_middle_y_of(state.ids.interaction_hints)
|
||||
.parent(id)
|
||||
.set(state.ids.interaction_hints_bg, ui);
|
||||
}
|
||||
}
|
||||
// Speech bubble
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
use conrod_core::{
|
||||
color,
|
||||
widget::{self, RoundedRectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon, Sizeable,
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use i18n::Localization;
|
||||
use std::borrow::Cow;
|
||||
@ -172,13 +172,24 @@ impl<'a> Widget for Overitem<'a> {
|
||||
|
||||
// Interaction hints
|
||||
if !self.interaction_options.is_empty() {
|
||||
let text = self.interaction_options
|
||||
let text = self
|
||||
.interaction_options
|
||||
.iter()
|
||||
.filter_map(|(input, action)| Some((self
|
||||
.controls
|
||||
.get_binding(*input)
|
||||
.filter(|_| self.properties.active)?, action)))
|
||||
.map(|(input, action)| format!("{} {}", input.display_string(self.key_layout).as_str(), action))
|
||||
.filter_map(|(input, action)| {
|
||||
Some((
|
||||
self.controls
|
||||
.get_binding(*input)
|
||||
.filter(|_| self.properties.active)?,
|
||||
action,
|
||||
))
|
||||
})
|
||||
.map(|(input, action)| {
|
||||
format!(
|
||||
"{} {}",
|
||||
input.display_string(self.key_layout).as_str(),
|
||||
action
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
@ -194,11 +205,15 @@ impl<'a> Widget for Overitem<'a> {
|
||||
|
||||
hints_text.set(state.ids.btn, ui);
|
||||
|
||||
RoundedRectangle::fill_with([w + btn_radius * 2.0, h + btn_radius * 2.0], btn_radius, btn_color)
|
||||
.x_y(0.0, btn_rect_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 2.0)
|
||||
.parent(id)
|
||||
.set(state.ids.btn_bg, ui);
|
||||
RoundedRectangle::fill_with(
|
||||
[w + btn_radius * 2.0, h + btn_radius * 2.0],
|
||||
btn_radius,
|
||||
btn_color,
|
||||
)
|
||||
.x_y(0.0, btn_rect_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 2.0)
|
||||
.parent(id)
|
||||
.set(state.ids.btn_bg, ui);
|
||||
}
|
||||
if let Some(time) = self.properties.pickup_failed_pulse {
|
||||
//should never exceed 1.0, but just in case
|
||||
|
@ -35,13 +35,13 @@ use common::{
|
||||
Body, CharacterState, Collider, Controller, Health, Inventory, Item, Last, LightAnimation,
|
||||
LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
resources::{DeltaTime, Time},
|
||||
states::{equipping, idle, utils::StageSection, wielding},
|
||||
terrain::TerrainChunk,
|
||||
uid::UidAllocator,
|
||||
vol::RectRasterableVol,
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
};
|
||||
use common_base::span;
|
||||
use common_state::State;
|
||||
@ -489,8 +489,15 @@ impl FigureMgr {
|
||||
.and_then(|body| self.states.get_mut(body, &entity))
|
||||
.and_then(|state| {
|
||||
// Calculate the correct lantern position
|
||||
let pos = anim::vek::Vec3::from(interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array());
|
||||
Some(state.mount_world_pos + state.mount_transform.orientation * anim::vek::Vec3::from(state.lantern_offset?.into_array()) - pos)
|
||||
let pos = anim::vek::Vec3::from(
|
||||
interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array(),
|
||||
);
|
||||
Some(
|
||||
state.mount_world_pos
|
||||
+ state.mount_transform.orientation
|
||||
* anim::vek::Vec3::from(state.lantern_offset?.into_array())
|
||||
- pos,
|
||||
)
|
||||
})
|
||||
{
|
||||
light_anim.offset = vek::Vec3::from(lantern_offset);
|
||||
@ -739,7 +746,9 @@ impl FigureMgr {
|
||||
let (in_frustum, lpindex) = if let Some(ref mut meta) = state {
|
||||
let (in_frustum, lpindex) = BoundingSphere::new(pos.0.into_array(), radius)
|
||||
.coherent_test_against_frustum(frustum, meta.lpindex);
|
||||
let in_frustum = in_frustum || matches!(body, Body::Ship(_));
|
||||
let in_frustum = in_frustum
|
||||
|| matches!(body, Body::Ship(_))
|
||||
|| pos.0.distance_squared(focus_pos) < 32.0f32.powi(2);
|
||||
meta.visible = in_frustum;
|
||||
meta.lpindex = lpindex;
|
||||
if in_frustum {
|
||||
|
@ -22,13 +22,13 @@ use common::{
|
||||
ChatMsg, ChatType, InputKind, InventoryUpdateEvent, Pos, Stats, UtteranceKind, Vel,
|
||||
},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
link::Is,
|
||||
mounting::Mount,
|
||||
outcome::Outcome,
|
||||
terrain::{Block, BlockKind},
|
||||
trade::TradeResult,
|
||||
util::{Dir, Plane},
|
||||
vol::ReadVol,
|
||||
link::Is,
|
||||
mounting::{Mounting, Mount},
|
||||
};
|
||||
use common_base::{prof_span, span};
|
||||
use common_net::{
|
||||
@ -687,10 +687,12 @@ impl PlayState for SessionState {
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
// TODO: More cleverly filter by things that can actually be mounted
|
||||
!&client.state().ecs().read_storage::<Is<Mount>>(),
|
||||
client.state().ecs().read_storage::<comp::Alignment>().maybe(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(entity, _, _)| *entity != client.entity())
|
||||
.map(|(entity, pos, _)| {
|
||||
.filter(|(entity, _, _, _)| *entity != client.entity())
|
||||
.filter(|(_, _, _, alignment)| matches!(alignment, Some(comp::Alignment::Owned(owner)) if Some(*owner) == client.uid()))
|
||||
.map(|(entity, pos, _, _)| {
|
||||
(entity, player_pos.0.distance_squared(pos.0))
|
||||
})
|
||||
.filter(|(_, dist_sqr)| {
|
||||
|
Loading…
Reference in New Issue
Block a user