mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added overhead hints, smoother mount movement
This commit is contained in:
@ -26,7 +26,7 @@
|
|||||||
"hud.tutorial_elements": r#"Crafting"#,
|
"hud.tutorial_elements": r#"Crafting"#,
|
||||||
|
|
||||||
"hud.temp_quest_headline": r#"Greetings Traveller!"#,
|
"hud.temp_quest_headline": r#"Greetings Traveller!"#,
|
||||||
"hud.temp_quest_text": r#"To begin your journey you could start looking through this village and gather some supplies.
|
"hud.temp_quest_text": r#"To begin your journey you could start looking through this village and gather some supplies.
|
||||||
|
|
||||||
You are welcome to take whatever you need on your journey!
|
You are welcome to take whatever you need on your journey!
|
||||||
|
|
||||||
@ -46,6 +46,13 @@ Whenever you feel ready, try to get even better equipment from the many challeng
|
|||||||
"hud.free_look_indicator": "Free look active. Press {key} to disable.",
|
"hud.free_look_indicator": "Free look active. Press {key} to disable.",
|
||||||
"hud.camera_clamp_indicator": "Camera vertical clamp active. Press {key} to disable.",
|
"hud.camera_clamp_indicator": "Camera vertical clamp active. Press {key} to disable.",
|
||||||
"hud.auto_walk_indicator": "Auto walk/swim active",
|
"hud.auto_walk_indicator": "Auto walk/swim active",
|
||||||
|
"hud.collect": "Collect",
|
||||||
|
"hud.pick_up": "Pick up",
|
||||||
|
"hud.open": "Open",
|
||||||
|
"hud.use": "Use",
|
||||||
|
"hud.talk": "Talk",
|
||||||
|
"hud.trade": "Trade",
|
||||||
|
"hud.mount": "Mount",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ sum_type! {
|
|||||||
Ori(comp::Ori),
|
Ori(comp::Ori),
|
||||||
Shockwave(comp::Shockwave),
|
Shockwave(comp::Shockwave),
|
||||||
BeamSegment(comp::BeamSegment),
|
BeamSegment(comp::BeamSegment),
|
||||||
|
Alignment(comp::Alignment),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Automatically derive From<T> for EcsCompPhantom
|
// Automatically derive From<T> for EcsCompPhantom
|
||||||
@ -80,6 +81,7 @@ sum_type! {
|
|||||||
Ori(PhantomData<comp::Ori>),
|
Ori(PhantomData<comp::Ori>),
|
||||||
Shockwave(PhantomData<comp::Shockwave>),
|
Shockwave(PhantomData<comp::Shockwave>),
|
||||||
BeamSegment(PhantomData<comp::BeamSegment>),
|
BeamSegment(PhantomData<comp::BeamSegment>),
|
||||||
|
Alignment(PhantomData<comp::Alignment>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl sync::CompPacket for EcsCompPacket {
|
impl sync::CompPacket for EcsCompPacket {
|
||||||
@ -127,6 +129,7 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
},
|
},
|
||||||
EcsCompPacket::Shockwave(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Shockwave(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::BeamSegment(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::BeamSegment(comp) => sync::handle_insert(comp, entity, world),
|
||||||
|
EcsCompPacket::Alignment(comp) => sync::handle_insert(comp, entity, world),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +175,7 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
},
|
},
|
||||||
EcsCompPacket::Shockwave(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Shockwave(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::BeamSegment(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::BeamSegment(comp) => sync::handle_modify(comp, entity, world),
|
||||||
|
EcsCompPacket::Alignment(comp) => sync::handle_modify(comp, entity, world),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +215,8 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPhantom::Vel(_) => sync::handle_interp_remove::<comp::Vel>(entity, world),
|
EcsCompPhantom::Vel(_) => sync::handle_interp_remove::<comp::Vel>(entity, world),
|
||||||
EcsCompPhantom::Ori(_) => sync::handle_interp_remove::<comp::Ori>(entity, world),
|
EcsCompPhantom::Ori(_) => sync::handle_interp_remove::<comp::Ori>(entity, world),
|
||||||
EcsCompPhantom::Shockwave(_) => sync::handle_remove::<comp::Shockwave>(entity, world),
|
EcsCompPhantom::Shockwave(_) => sync::handle_remove::<comp::Shockwave>(entity, world),
|
||||||
EcsCompPhantom::BeamSegment(_) => sync::handle_remove::<comp::Ori>(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},
|
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::{Serialize, Deserialize};
|
||||||
use specs::{Component, Entity as EcsEntity};
|
use specs::{Component, Entity as EcsEntity, DerefFlaggedStorage};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
use std::{collections::VecDeque, fmt};
|
use std::{collections::VecDeque, fmt};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
@ -21,7 +21,7 @@ use super::dialogue::Subject;
|
|||||||
pub const DEFAULT_INTERACTION_TIME: f32 = 3.0;
|
pub const DEFAULT_INTERACTION_TIME: f32 = 3.0;
|
||||||
pub const TRADE_INTERACTION_TIME: f32 = 300.0;
|
pub const TRADE_INTERACTION_TIME: f32 = 300.0;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Alignment {
|
pub enum Alignment {
|
||||||
/// Wild animals and gentle giants
|
/// Wild animals and gentle giants
|
||||||
Wild,
|
Wild,
|
||||||
@ -79,7 +79,7 @@ impl Alignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Alignment {
|
impl Component for Alignment {
|
||||||
type Storage = IdvStorage<Self>;
|
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::{Component, DerefFlaggedStorage};
|
use specs::Component;
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// The limit on distance between the entity and a collectible (squared)
|
// The limit on distance between the entity and a collectible (squared)
|
||||||
pub const MAX_PICKUP_RANGE: f32 = 5.0;
|
pub const MAX_PICKUP_RANGE: f32 = 5.0;
|
||||||
pub const MAX_MOUNT_RANGE: f32 = 14.0;
|
pub const MAX_MOUNT_RANGE: f32 = 5.0;
|
||||||
pub const MAX_TRADE_RANGE: f32 = 20.0;
|
pub const MAX_TRADE_RANGE: f32 = 20.0;
|
||||||
|
|
||||||
pub const GRAVITY: f32 = 25.0;
|
pub const GRAVITY: f32 = 25.0;
|
||||||
|
@ -158,6 +158,7 @@ impl State {
|
|||||||
ecs.register::<comp::Shockwave>();
|
ecs.register::<comp::Shockwave>();
|
||||||
ecs.register::<comp::ShockwaveHitEntities>();
|
ecs.register::<comp::ShockwaveHitEntities>();
|
||||||
ecs.register::<comp::BeamSegment>();
|
ecs.register::<comp::BeamSegment>();
|
||||||
|
ecs.register::<comp::Alignment>();
|
||||||
|
|
||||||
// Register components send from clients -> server
|
// Register components send from clients -> server
|
||||||
ecs.register::<comp::Controller>();
|
ecs.register::<comp::Controller>();
|
||||||
@ -187,7 +188,6 @@ impl State {
|
|||||||
ecs.register::<comp::Last<comp::Pos>>();
|
ecs.register::<comp::Last<comp::Pos>>();
|
||||||
ecs.register::<comp::Last<comp::Vel>>();
|
ecs.register::<comp::Last<comp::Vel>>();
|
||||||
ecs.register::<comp::Last<comp::Ori>>();
|
ecs.register::<comp::Last<comp::Ori>>();
|
||||||
ecs.register::<comp::Alignment>();
|
|
||||||
ecs.register::<comp::Agent>();
|
ecs.register::<comp::Agent>();
|
||||||
ecs.register::<comp::WaypointArea>();
|
ecs.register::<comp::WaypointArea>();
|
||||||
ecs.register::<comp::ForceUpdate>();
|
ecs.register::<comp::ForceUpdate>();
|
||||||
|
@ -400,6 +400,7 @@ impl<'a> PhysicsData<'a> {
|
|||||||
mass,
|
mass,
|
||||||
collider,
|
collider,
|
||||||
read.char_states.get(entity),
|
read.char_states.get(entity),
|
||||||
|
read.is_ridings.get(entity),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.for_each(
|
.for_each(
|
||||||
@ -411,6 +412,7 @@ impl<'a> PhysicsData<'a> {
|
|||||||
mass_other,
|
mass_other,
|
||||||
collider_other,
|
collider_other,
|
||||||
char_state_other_maybe,
|
char_state_other_maybe,
|
||||||
|
other_is_riding_maybe,
|
||||||
)| {
|
)| {
|
||||||
let collision_boundary = previous_cache.collision_boundary
|
let collision_boundary = previous_cache.collision_boundary
|
||||||
+ previous_cache_other.collision_boundary;
|
+ previous_cache_other.collision_boundary;
|
||||||
@ -473,7 +475,7 @@ impl<'a> PhysicsData<'a> {
|
|||||||
*mass,
|
*mass,
|
||||||
*mass_other,
|
*mass_other,
|
||||||
vel,
|
vel,
|
||||||
is_riding.is_some(),
|
is_riding.is_some() || other_is_riding_maybe.is_some(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@ use common::{
|
|||||||
item::{tool::AbilityMap, MaterialStatManifest},
|
item::{tool::AbilityMap, MaterialStatManifest},
|
||||||
ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider,
|
ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider,
|
||||||
Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass,
|
Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass,
|
||||||
Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel,
|
Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, Alignment,
|
||||||
},
|
},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
mounting::{Mount, Rider},
|
mounting::{Mount, Rider},
|
||||||
@ -69,6 +69,8 @@ pub struct TrackedComps<'a> {
|
|||||||
pub character_state: ReadStorage<'a, CharacterState>,
|
pub character_state: ReadStorage<'a, CharacterState>,
|
||||||
pub shockwave: ReadStorage<'a, Shockwave>,
|
pub shockwave: ReadStorage<'a, Shockwave>,
|
||||||
pub beam_segment: ReadStorage<'a, BeamSegment>,
|
pub beam_segment: ReadStorage<'a, BeamSegment>,
|
||||||
|
pub alignment: ReadStorage<'a, Alignment>,
|
||||||
|
|
||||||
pub ability_map: ReadExpect<'a, AbilityMap>,
|
pub ability_map: ReadExpect<'a, AbilityMap>,
|
||||||
pub msm: ReadExpect<'a, MaterialStatManifest>,
|
pub msm: ReadExpect<'a, MaterialStatManifest>,
|
||||||
}
|
}
|
||||||
@ -180,6 +182,10 @@ impl<'a> TrackedComps<'a> {
|
|||||||
.get(entity)
|
.get(entity)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|c| comps.push(c.into()));
|
.map(|c| comps.push(c.into()));
|
||||||
|
self.alignment
|
||||||
|
.get(entity)
|
||||||
|
.cloned()
|
||||||
|
.map(|c| comps.push(c.into()));
|
||||||
// Add untracked comps
|
// Add untracked comps
|
||||||
pos.map(|c| comps.push(c.into()));
|
pos.map(|c| comps.push(c.into()));
|
||||||
vel.map(|c| comps.push(c.into()));
|
vel.map(|c| comps.push(c.into()));
|
||||||
@ -217,6 +223,7 @@ pub struct ReadTrackers<'a> {
|
|||||||
pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
|
pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
|
||||||
pub shockwave: ReadExpect<'a, UpdateTracker<Shockwave>>,
|
pub shockwave: ReadExpect<'a, UpdateTracker<Shockwave>>,
|
||||||
pub beam_segment: ReadExpect<'a, UpdateTracker<BeamSegment>>,
|
pub beam_segment: ReadExpect<'a, UpdateTracker<BeamSegment>>,
|
||||||
|
pub alignment: ReadExpect<'a, UpdateTracker<Alignment>>,
|
||||||
}
|
}
|
||||||
impl<'a> ReadTrackers<'a> {
|
impl<'a> ReadTrackers<'a> {
|
||||||
pub fn create_sync_packages(
|
pub fn create_sync_packages(
|
||||||
@ -268,7 +275,8 @@ impl<'a> ReadTrackers<'a> {
|
|||||||
filter,
|
filter,
|
||||||
)
|
)
|
||||||
.with_component(&comps.uid, &*self.shockwave, &comps.shockwave, filter)
|
.with_component(&comps.uid, &*self.shockwave, &comps.shockwave, filter)
|
||||||
.with_component(&comps.uid, &*self.beam_segment, &comps.beam_segment, filter);
|
.with_component(&comps.uid, &*self.beam_segment, &comps.beam_segment, filter)
|
||||||
|
.with_component(&comps.uid, &*self.alignment, &comps.alignment, filter);
|
||||||
|
|
||||||
(entity_sync_package, comp_sync_package)
|
(entity_sync_package, comp_sync_package)
|
||||||
}
|
}
|
||||||
@ -303,6 +311,7 @@ pub struct WriteTrackers<'a> {
|
|||||||
character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
|
character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
|
||||||
shockwave: WriteExpect<'a, UpdateTracker<Shockwave>>,
|
shockwave: WriteExpect<'a, UpdateTracker<Shockwave>>,
|
||||||
beam: WriteExpect<'a, UpdateTracker<BeamSegment>>,
|
beam: WriteExpect<'a, UpdateTracker<BeamSegment>>,
|
||||||
|
alignment: WriteExpect<'a, UpdateTracker<Alignment>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
||||||
@ -338,6 +347,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
|||||||
.record_changes(&comps.character_state);
|
.record_changes(&comps.character_state);
|
||||||
trackers.shockwave.record_changes(&comps.shockwave);
|
trackers.shockwave.record_changes(&comps.shockwave);
|
||||||
trackers.beam.record_changes(&comps.beam_segment);
|
trackers.beam.record_changes(&comps.beam_segment);
|
||||||
|
trackers.alignment.record_changes(&comps.alignment);
|
||||||
// Debug how many updates are being sent
|
// Debug how many updates are being sent
|
||||||
/*
|
/*
|
||||||
macro_rules! log_counts {
|
macro_rules! log_counts {
|
||||||
@ -378,6 +388,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
|||||||
log_counts!(character_state, "Character States");
|
log_counts!(character_state, "Character States");
|
||||||
log_counts!(shockwave, "Shockwaves");
|
log_counts!(shockwave, "Shockwaves");
|
||||||
log_counts!(beam, "Beams");
|
log_counts!(beam, "Beams");
|
||||||
|
log_counts!(alignment, "Alignments");
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +420,7 @@ pub fn register_trackers(world: &mut World) {
|
|||||||
world.register_tracker::<CharacterState>();
|
world.register_tracker::<CharacterState>();
|
||||||
world.register_tracker::<Shockwave>();
|
world.register_tracker::<Shockwave>();
|
||||||
world.register_tracker::<BeamSegment>();
|
world.register_tracker::<BeamSegment>();
|
||||||
|
world.register_tracker::<Alignment>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deleted entities grouped by region
|
/// Deleted entities grouped by region
|
||||||
|
@ -90,6 +90,8 @@ use common::{
|
|||||||
uid::Uid,
|
uid::Uid,
|
||||||
util::{srgba_to_linear, Dir},
|
util::{srgba_to_linear, Dir},
|
||||||
vol::RectRasterableVol,
|
vol::RectRasterableVol,
|
||||||
|
mounting::Mount,
|
||||||
|
link::Is,
|
||||||
};
|
};
|
||||||
use common_base::{prof_span, span};
|
use common_base::{prof_span, span};
|
||||||
use common_net::{
|
use common_net::{
|
||||||
@ -1140,6 +1142,8 @@ impl Hud {
|
|||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
let me = client.entity();
|
let me = client.entity();
|
||||||
let poises = ecs.read_storage::<comp::Poise>();
|
let poises = ecs.read_storage::<comp::Poise>();
|
||||||
|
let alignments = ecs.read_storage::<comp::Alignment>();
|
||||||
|
let is_mount = ecs.read_storage::<Is<Mount>>();
|
||||||
|
|
||||||
// Check if there was a persistence load error of the skillset, and if so
|
// Check if there was a persistence load error of the skillset, and if so
|
||||||
// display a dialog prompt
|
// display a dialog prompt
|
||||||
@ -1664,7 +1668,7 @@ impl Hud {
|
|||||||
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
||||||
let pulse = self.pulse;
|
let pulse = self.pulse;
|
||||||
|
|
||||||
let make_overitem = |item: &Item, pos, distance, properties, fonts| {
|
let make_overitem = |item: &Item, pos, distance, properties, fonts, interaction_options| {
|
||||||
let text = if item.amount() > 1 {
|
let text = if item.amount() > 1 {
|
||||||
format!("{} x {}", item.amount(), item.name())
|
format!("{} x {}", item.amount(), item.name())
|
||||||
} else {
|
} else {
|
||||||
@ -1684,6 +1688,7 @@ impl Hud {
|
|||||||
properties,
|
properties,
|
||||||
pulse,
|
pulse,
|
||||||
&global_state.window.key_layout,
|
&global_state.window.key_layout,
|
||||||
|
interaction_options,
|
||||||
)
|
)
|
||||||
.x_y(0.0, 100.0)
|
.x_y(0.0, 100.0)
|
||||||
.position_ingame(pos)
|
.position_ingame(pos)
|
||||||
@ -1714,6 +1719,7 @@ impl Hud {
|
|||||||
pickup_failed_pulse: self.failed_entity_pickups.get(&entity).copied(),
|
pickup_failed_pulse: self.failed_entity_pickups.get(&entity).copied(),
|
||||||
},
|
},
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
|
vec![(GameInput::Interact, i18n.get("hud.pick_up").to_string())],
|
||||||
)
|
)
|
||||||
.set(overitem_id, ui_widgets);
|
.set(overitem_id, ui_widgets);
|
||||||
}
|
}
|
||||||
@ -1733,9 +1739,9 @@ impl Hud {
|
|||||||
let over_pos = pos + Vec3::unit_z() * 0.7;
|
let over_pos = pos + Vec3::unit_z() * 0.7;
|
||||||
|
|
||||||
// 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 block.get_sprite().map_or(false, |s| s.is_container()) {
|
if let Some(sprite) = block.get_sprite().filter(|s| s.is_container()) {
|
||||||
overitem::Overitem::new(
|
overitem::Overitem::new(
|
||||||
"???".into(),
|
format!("{:?}", sprite).into(),
|
||||||
overitem::TEXT_COLOR,
|
overitem::TEXT_COLOR,
|
||||||
pos.distance_squared(player_pos),
|
pos.distance_squared(player_pos),
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
@ -1744,6 +1750,7 @@ impl Hud {
|
|||||||
overitem_properties,
|
overitem_properties,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
&global_state.window.key_layout,
|
&global_state.window.key_layout,
|
||||||
|
vec![(GameInput::Interact, i18n.get("hud.open").to_string())],
|
||||||
)
|
)
|
||||||
.x_y(0.0, 100.0)
|
.x_y(0.0, 100.0)
|
||||||
.position_ingame(over_pos)
|
.position_ingame(over_pos)
|
||||||
@ -1755,6 +1762,7 @@ impl Hud {
|
|||||||
pos.distance_squared(player_pos),
|
pos.distance_squared(player_pos),
|
||||||
overitem_properties,
|
overitem_properties,
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
|
vec![(GameInput::Interact, i18n.get("hud.collect").to_string())],
|
||||||
)
|
)
|
||||||
.set(overitem_id, ui_widgets);
|
.set(overitem_id, ui_widgets);
|
||||||
} else if let Some(desc) = block.get_sprite().and_then(|s| get_sprite_desc(s, i18n))
|
} else if let Some(desc) = block.get_sprite().and_then(|s| get_sprite_desc(s, i18n))
|
||||||
@ -1769,6 +1777,7 @@ impl Hud {
|
|||||||
overitem_properties,
|
overitem_properties,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
&global_state.window.key_layout,
|
&global_state.window.key_layout,
|
||||||
|
vec![(GameInput::Interact, i18n.get("hud.use").to_string())],
|
||||||
)
|
)
|
||||||
.x_y(0.0, 100.0)
|
.x_y(0.0, 100.0)
|
||||||
.position_ingame(over_pos)
|
.position_ingame(over_pos)
|
||||||
@ -1779,7 +1788,7 @@ impl Hud {
|
|||||||
let speech_bubbles = &self.speech_bubbles;
|
let speech_bubbles = &self.speech_bubbles;
|
||||||
|
|
||||||
// Render overhead name tags and health bars
|
// Render overhead name tags and health bars
|
||||||
for (pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group) in (
|
for (entity, pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group, dist_sqr, alignment, is_mount) in (
|
||||||
&entities,
|
&entities,
|
||||||
&pos,
|
&pos,
|
||||||
interpolated.maybe(),
|
interpolated.maybe(),
|
||||||
@ -1795,6 +1804,7 @@ impl Hud {
|
|||||||
&inventories,
|
&inventories,
|
||||||
players.maybe(),
|
players.maybe(),
|
||||||
poises.maybe(),
|
poises.maybe(),
|
||||||
|
(alignments.maybe(), is_mount.maybe()),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|t| {
|
.filter(|t| {
|
||||||
@ -1818,6 +1828,7 @@ impl Hud {
|
|||||||
inventory,
|
inventory,
|
||||||
player,
|
player,
|
||||||
poise,
|
poise,
|
||||||
|
(alignment, is_mount),
|
||||||
)| {
|
)| {
|
||||||
// Use interpolated position if available
|
// Use interpolated position if available
|
||||||
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
||||||
@ -1879,6 +1890,7 @@ impl Hud {
|
|||||||
|
|
||||||
(info.is_some() || bubble.is_some()).then(|| {
|
(info.is_some() || bubble.is_some()).then(|| {
|
||||||
(
|
(
|
||||||
|
entity,
|
||||||
pos,
|
pos,
|
||||||
info,
|
info,
|
||||||
bubble,
|
bubble,
|
||||||
@ -1889,6 +1901,9 @@ impl Hud {
|
|||||||
body.height() * scale.map_or(1.0, |s| s.0) + 0.5,
|
body.height() * scale.map_or(1.0, |s| s.0) + 0.5,
|
||||||
hpfl,
|
hpfl,
|
||||||
in_group,
|
in_group,
|
||||||
|
dist_sqr,
|
||||||
|
alignment,
|
||||||
|
is_mount,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -1911,8 +1926,24 @@ impl Hud {
|
|||||||
&global_state.settings.interface,
|
&global_state.settings.interface,
|
||||||
self.pulse,
|
self.pulse,
|
||||||
i18n,
|
i18n,
|
||||||
|
&global_state.settings.controls,
|
||||||
&self.imgs,
|
&self.imgs,
|
||||||
&self.fonts,
|
&self.fonts,
|
||||||
|
&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) =>
|
||||||
|
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())],
|
||||||
|
_ => Vec::new(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.x_y(0.0, 100.0)
|
.x_y(0.0, 100.0)
|
||||||
.position_ingame(ingame_pos)
|
.position_ingame(ingame_pos)
|
||||||
|
@ -4,15 +4,17 @@ use super::{
|
|||||||
TEXT_BG, TEXT_COLOR,
|
TEXT_BG, TEXT_COLOR,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
game_input::GameInput,
|
||||||
hud::{get_buff_image, get_buff_info},
|
hud::{get_buff_image, get_buff_info},
|
||||||
settings::InterfaceSettings,
|
settings::{ControlSettings, InterfaceSettings},
|
||||||
ui::{fonts::Fonts, Ingameable},
|
ui::{fonts::Fonts, Ingameable},
|
||||||
};
|
};
|
||||||
|
use keyboard_keynames::key_layout::KeyLayout;
|
||||||
use common::comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType};
|
use common::comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
position::Align,
|
position::Align,
|
||||||
widget::{self, Image, Rectangle, Text},
|
widget::{self, Image, Rectangle, Text, RoundedRectangle},
|
||||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use i18n::Localization;
|
use i18n::Localization;
|
||||||
@ -53,6 +55,10 @@ widget_ids! {
|
|||||||
buffs_align,
|
buffs_align,
|
||||||
buffs[],
|
buffs[],
|
||||||
buff_timers[],
|
buff_timers[],
|
||||||
|
|
||||||
|
// Interaction hints
|
||||||
|
interaction_hints,
|
||||||
|
interaction_hints_bg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +90,11 @@ pub struct Overhead<'a> {
|
|||||||
settings: &'a InterfaceSettings,
|
settings: &'a InterfaceSettings,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
i18n: &'a Localization,
|
i18n: &'a Localization,
|
||||||
|
controls: &'a ControlSettings,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
|
key_layout: &'a Option<KeyLayout>,
|
||||||
|
interaction_options: Vec<(GameInput, String)>,
|
||||||
|
|
||||||
#[conrod(common_builder)]
|
#[conrod(common_builder)]
|
||||||
common: widget::CommonBuilder,
|
common: widget::CommonBuilder,
|
||||||
@ -99,8 +108,11 @@ impl<'a> Overhead<'a> {
|
|||||||
settings: &'a InterfaceSettings,
|
settings: &'a InterfaceSettings,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
i18n: &'a Localization,
|
i18n: &'a Localization,
|
||||||
|
controls: &'a ControlSettings,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
|
key_layout: &'a Option<KeyLayout>,
|
||||||
|
interaction_options: Vec<(GameInput, String)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
info,
|
info,
|
||||||
@ -109,8 +121,11 @@ impl<'a> Overhead<'a> {
|
|||||||
settings,
|
settings,
|
||||||
pulse,
|
pulse,
|
||||||
i18n,
|
i18n,
|
||||||
|
controls,
|
||||||
imgs,
|
imgs,
|
||||||
fonts,
|
fonts,
|
||||||
|
key_layout,
|
||||||
|
interaction_options,
|
||||||
common: widget::CommonBuilder::default(),
|
common: widget::CommonBuilder::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,6 +172,7 @@ impl<'a> Ingameable for Overhead<'a> {
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
+ (!self.interaction_options.is_empty()) as usize * 2
|
||||||
}) + if self.bubble.is_some() { 13 } else { 0 }
|
}) + if self.bubble.is_some() { 13 } else { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,6 +464,55 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interaction hints
|
||||||
|
if !self.interaction_options.is_empty() {
|
||||||
|
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))
|
||||||
|
.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)
|
||||||
|
// .depth(self.distance_from_player_sqr + 2.0)
|
||||||
|
// .parent(id)
|
||||||
|
// .set(state.ids.btn_bg, ui);
|
||||||
|
let hints_text = Text::new(&text)
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.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)
|
||||||
|
.align_middle_x_of(state.ids.name)
|
||||||
|
.depth(1.0);
|
||||||
|
|
||||||
|
let [w, h] = hints_text.get_wh(ui).unwrap_or([btn_rect_size; 2]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Speech bubble
|
// Speech bubble
|
||||||
if let Some(bubble) = self.bubble {
|
if let Some(bubble) = self.bubble {
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
widget::{self, RoundedRectangle, Text},
|
widget::{self, RoundedRectangle, Text},
|
||||||
widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon, Sizeable,
|
||||||
};
|
};
|
||||||
use i18n::Localization;
|
use i18n::Localization;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -21,7 +21,7 @@ widget_ids! {
|
|||||||
// Name
|
// Name
|
||||||
name_bg,
|
name_bg,
|
||||||
name,
|
name,
|
||||||
// Key
|
// Interaction hints
|
||||||
btn_bg,
|
btn_bg,
|
||||||
btn,
|
btn,
|
||||||
// Inventory full
|
// Inventory full
|
||||||
@ -45,6 +45,7 @@ pub struct Overitem<'a> {
|
|||||||
properties: OveritemProperties,
|
properties: OveritemProperties,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
key_layout: &'a Option<KeyLayout>,
|
key_layout: &'a Option<KeyLayout>,
|
||||||
|
interaction_options: Vec<(GameInput, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Overitem<'a> {
|
impl<'a> Overitem<'a> {
|
||||||
@ -58,6 +59,7 @@ impl<'a> Overitem<'a> {
|
|||||||
properties: OveritemProperties,
|
properties: OveritemProperties,
|
||||||
pulse: f32,
|
pulse: f32,
|
||||||
key_layout: &'a Option<KeyLayout>,
|
key_layout: &'a Option<KeyLayout>,
|
||||||
|
interaction_options: Vec<(GameInput, String)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
@ -70,6 +72,7 @@ impl<'a> Overitem<'a> {
|
|||||||
properties,
|
properties,
|
||||||
pulse,
|
pulse,
|
||||||
key_layout,
|
key_layout,
|
||||||
|
interaction_options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +123,7 @@ impl<'a> Widget for Overitem<'a> {
|
|||||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||||
let widget::UpdateArgs { id, state, ui, .. } = args;
|
let widget::UpdateArgs { id, state, ui, .. } = args;
|
||||||
|
|
||||||
let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.4);
|
let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.8);
|
||||||
|
|
||||||
// Example:
|
// Example:
|
||||||
// MUSHROOM
|
// MUSHROOM
|
||||||
@ -167,25 +170,35 @@ impl<'a> Widget for Overitem<'a> {
|
|||||||
.parent(id)
|
.parent(id)
|
||||||
.set(state.ids.name, ui);
|
.set(state.ids.name, ui);
|
||||||
|
|
||||||
// Pickup Button
|
// Interaction hints
|
||||||
if let Some(key_button) = self
|
if !self.interaction_options.is_empty() {
|
||||||
.controls
|
let text = self.interaction_options
|
||||||
.get_binding(GameInput::Interact)
|
.iter()
|
||||||
.filter(|_| self.properties.active)
|
.filter_map(|(input, action)| Some((self
|
||||||
{
|
.controls
|
||||||
RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius, btn_color)
|
.get_binding(*input)
|
||||||
.x_y(0.0, btn_rect_pos_y)
|
.filter(|_| self.properties.active)?, action)))
|
||||||
.depth(self.distance_from_player_sqr + 1.0)
|
.map(|(input, action)| format!("{} {}", input.display_string(self.key_layout).as_str(), action))
|
||||||
.parent(id)
|
.collect::<Vec<_>>()
|
||||||
.set(state.ids.btn_bg, ui);
|
.join("\n");
|
||||||
Text::new(key_button.display_string(self.key_layout).as_str())
|
|
||||||
|
let hints_text = Text::new(&text)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(btn_font_size as u32)
|
.font_size(btn_font_size as u32)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.x_y(0.0, btn_text_pos_y)
|
.x_y(0.0, btn_text_pos_y)
|
||||||
|
.depth(self.distance_from_player_sqr + 1.0)
|
||||||
|
.parent(id);
|
||||||
|
|
||||||
|
let [w, h] = hints_text.get_wh(ui).unwrap_or([btn_rect_size; 2]);
|
||||||
|
|
||||||
|
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)
|
.depth(self.distance_from_player_sqr + 2.0)
|
||||||
.parent(id)
|
.parent(id)
|
||||||
.set(state.ids.btn, ui);
|
.set(state.ids.btn_bg, ui);
|
||||||
}
|
}
|
||||||
if let Some(time) = self.properties.pickup_failed_pulse {
|
if let Some(time) = self.properties.pickup_failed_pulse {
|
||||||
//should never exceed 1.0, but just in case
|
//should never exceed 1.0, but just in case
|
||||||
|
Reference in New Issue
Block a user