mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added indicator text to terrain sprites
This commit is contained in:
parent
88f99986af
commit
bed863c50c
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Dungeons now have multiple kinds of stairs.
|
||||
- Trades now display item prices in tooltips.
|
||||
- Admin designated build areas
|
||||
- Indicator text to collectable terrain sprites
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -597,6 +597,9 @@ impl Item {
|
||||
SpriteKind::MediumGrass => "common.items.grasses.medium",
|
||||
SpriteKind::ShortGrass => "common.items.grasses.short",
|
||||
SpriteKind::Coconut => "common.items.food.coconut",
|
||||
|
||||
// Containers
|
||||
// IMPORTANT: Add any new container to `SpriteKind::is_container`
|
||||
SpriteKind::Chest => {
|
||||
chosen = Lottery::<String>::load_expect(match rng.gen_range(0..7) {
|
||||
0 => "common.loot_tables.loot_table_weapon_uncommon",
|
||||
@ -637,6 +640,7 @@ impl Item {
|
||||
.read();
|
||||
chosen.choose()
|
||||
},
|
||||
|
||||
SpriteKind::Beehive => "common.items.crafting_ing.honey",
|
||||
SpriteKind::Stones => "common.items.crafting_ing.stones",
|
||||
SpriteKind::Twigs => "common.items.crafting_ing.twigs",
|
||||
|
@ -240,6 +240,14 @@ impl SpriteKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the sprite a container that will emit a mystery item?
|
||||
pub fn is_container(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
SpriteKind::Chest | SpriteKind::ChestBurried | SpriteKind::Mud | SpriteKind::Crate,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||
match self {
|
||||
SpriteKind::Velorite
|
||||
|
@ -53,6 +53,7 @@ use crate::{
|
||||
i18n::{LanguageMetadata, Localization},
|
||||
render::{Consts, Globals, RenderMode, Renderer},
|
||||
scene::camera::{self, Camera},
|
||||
session::Interactable,
|
||||
settings::Fps,
|
||||
ui::{
|
||||
fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui,
|
||||
@ -67,7 +68,7 @@ use common::{
|
||||
self,
|
||||
item::{tool::ToolKind, ItemDesc, MaterialStatManifest, Quality},
|
||||
skills::{Skill, SkillGroupKind},
|
||||
BuffKind,
|
||||
BuffKind, Item,
|
||||
},
|
||||
outcome::Outcome,
|
||||
terrain::TerrainChunk,
|
||||
@ -901,6 +902,7 @@ impl Hud {
|
||||
dt: Duration,
|
||||
info: HudInfo,
|
||||
camera: &Camera,
|
||||
interactable: Option<Interactable>,
|
||||
) -> Vec<Event> {
|
||||
span!(_guard, "update_layout", "Hud::update_layout");
|
||||
let mut events = std::mem::replace(&mut self.events, Vec::new());
|
||||
@ -1330,19 +1332,7 @@ impl Hud {
|
||||
let mut sct_walker = self.ids.scts.walk();
|
||||
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
||||
|
||||
// Render overitem: name, etc.
|
||||
for (pos, item, distance) in (&entities, &pos, &items)
|
||||
.join()
|
||||
.map(|(_, pos, item)| (pos, item, pos.0.distance_squared(player_pos)))
|
||||
.filter(|(_, _, distance)| distance < &common::consts::MAX_PICKUP_RANGE.powi(2))
|
||||
{
|
||||
let overitem_id = overitem_walker.next(
|
||||
&mut self.ids.overitems,
|
||||
&mut ui_widgets.widget_id_generator(),
|
||||
);
|
||||
|
||||
let ingame_pos = pos.0 + Vec3::unit_z() * 1.2;
|
||||
|
||||
let make_overitem = |item: &Item, pos, distance, active, fonts| {
|
||||
let text = if item.amount() > 1 {
|
||||
format!("{} x {}", item.amount(), item.name())
|
||||
} else {
|
||||
@ -1353,17 +1343,74 @@ impl Hud {
|
||||
|
||||
// Item
|
||||
overitem::Overitem::new(
|
||||
&text,
|
||||
&quality,
|
||||
&distance,
|
||||
&self.fonts,
|
||||
text.into(),
|
||||
quality,
|
||||
distance,
|
||||
fonts,
|
||||
&global_state.settings.controls,
|
||||
// If we're currently set to interact with the item...
|
||||
active,
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(ingame_pos)
|
||||
.position_ingame(pos)
|
||||
};
|
||||
|
||||
// Render overitem: name, etc.
|
||||
for (entity, pos, item, distance) in (&entities, &pos, &items)
|
||||
.join()
|
||||
.map(|(entity, pos, item)| (entity, pos, item, pos.0.distance_squared(player_pos)))
|
||||
.filter(|(_, _, _, distance)| distance < &common::consts::MAX_PICKUP_RANGE.powi(2))
|
||||
{
|
||||
let overitem_id = overitem_walker.next(
|
||||
&mut self.ids.overitems,
|
||||
&mut ui_widgets.widget_id_generator(),
|
||||
);
|
||||
|
||||
make_overitem(
|
||||
item,
|
||||
pos.0 + Vec3::unit_z() * 1.2,
|
||||
distance,
|
||||
interactable.as_ref().and_then(|i| i.entity()) == Some(entity),
|
||||
&self.fonts,
|
||||
)
|
||||
.set(overitem_id, ui_widgets);
|
||||
}
|
||||
|
||||
// Render overtime for an interactable block
|
||||
if let Some(Interactable::Block(block, pos)) = interactable {
|
||||
let overitem_id = overitem_walker.next(
|
||||
&mut self.ids.overitems,
|
||||
&mut ui_widgets.widget_id_generator(),
|
||||
);
|
||||
|
||||
let pos = pos.map(|e| e as f32 + 0.5);
|
||||
let over_pos = pos + Vec3::unit_z() * 0.7;
|
||||
|
||||
// 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()) {
|
||||
overitem::Overitem::new(
|
||||
"???".into(),
|
||||
overitem::TEXT_COLOR,
|
||||
pos.distance_squared(player_pos),
|
||||
&self.fonts,
|
||||
&global_state.settings.controls,
|
||||
true,
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(over_pos)
|
||||
.set(overitem_id, ui_widgets);
|
||||
} else if let Some(item) = Item::try_reclaim_from_block(block) {
|
||||
make_overitem(
|
||||
&item,
|
||||
over_pos,
|
||||
pos.distance_squared(player_pos),
|
||||
true,
|
||||
&self.fonts,
|
||||
)
|
||||
.set(overitem_id, ui_widgets);
|
||||
}
|
||||
}
|
||||
|
||||
let speech_bubbles = &self.speech_bubbles;
|
||||
|
||||
// Render overhead name tags and health bars
|
||||
@ -3244,6 +3291,7 @@ impl Hud {
|
||||
camera: &Camera,
|
||||
dt: Duration,
|
||||
info: HudInfo,
|
||||
interactable: Option<Interactable>,
|
||||
) -> Vec<Event> {
|
||||
span!(_guard, "maintain", "Hud::maintain");
|
||||
// conrod eats tabs. Un-eat a tabstop so tab completion can work
|
||||
@ -3272,7 +3320,15 @@ impl Hud {
|
||||
if let Some(maybe_id) = self.to_focus.take() {
|
||||
self.ui.focus_widget(maybe_id);
|
||||
}
|
||||
let events = self.update_layout(client, global_state, debug_info, dt, info, camera);
|
||||
let events = self.update_layout(
|
||||
client,
|
||||
global_state,
|
||||
debug_info,
|
||||
dt,
|
||||
info,
|
||||
camera,
|
||||
interactable,
|
||||
);
|
||||
let camera::Dependents {
|
||||
view_mat, proj_mat, ..
|
||||
} = camera.dependents();
|
||||
|
@ -7,6 +7,9 @@ use conrod_core::{
|
||||
widget::{self, RoundedRectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub const TEXT_COLOR: Color = Color::Rgba(0.61, 0.61, 0.89, 1.0);
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
@ -23,22 +26,24 @@ widget_ids! {
|
||||
/// (Item, DistanceFromPlayer, Rarity, etc.)
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Overitem<'a> {
|
||||
name: &'a str,
|
||||
quality: &'a Color,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
name: Cow<'a, str>,
|
||||
quality: Color,
|
||||
distance_from_player_sqr: f32,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl<'a> Overitem<'a> {
|
||||
pub fn new(
|
||||
name: &'a str,
|
||||
quality: &'a Color,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
name: Cow<'a, str>,
|
||||
quality: Color,
|
||||
distance_from_player_sqr: f32,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
active: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
@ -47,6 +52,7 @@ impl<'a> Overitem<'a> {
|
||||
fonts,
|
||||
controls,
|
||||
common: widget::CommonBuilder::default(),
|
||||
active,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,7 +90,6 @@ impl<'a> Widget for Overitem<'a> {
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { id, state, ui, .. } = args;
|
||||
|
||||
let text_color = Color::Rgba(0.61, 0.61, 0.89, 1.0);
|
||||
let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.4);
|
||||
|
||||
// Example:
|
||||
@ -121,14 +126,18 @@ impl<'a> Widget for Overitem<'a> {
|
||||
Text::new(&self.name)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(text_font_size as u32)
|
||||
.color(*self.quality)
|
||||
.color(self.quality)
|
||||
.x_y(0.0, text_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 3.0)
|
||||
.parent(id)
|
||||
.set(state.ids.name, ui);
|
||||
|
||||
// Pickup Button
|
||||
if let Some(key_button) = self.controls.get_binding(GameInput::Interact) {
|
||||
if let Some(key_button) = self
|
||||
.controls
|
||||
.get_binding(GameInput::Interact)
|
||||
.filter(|_| self.active)
|
||||
{
|
||||
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 + 1.0)
|
||||
@ -137,7 +146,7 @@ impl<'a> Widget for Overitem<'a> {
|
||||
Text::new(&format!("{}", key_button))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(btn_font_size as u32)
|
||||
.color(text_color)
|
||||
.color(TEXT_COLOR)
|
||||
.x_y(0.0, btn_text_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 2.0)
|
||||
.parent(id)
|
||||
|
@ -877,6 +877,7 @@ impl PlayState for SessionState {
|
||||
target_entity: self.target_entity,
|
||||
selected_entity: self.selected_entity,
|
||||
},
|
||||
self.interactable,
|
||||
);
|
||||
|
||||
// Look for changes in the localization files
|
||||
@ -1678,11 +1679,12 @@ fn under_cursor(
|
||||
&ecs.entities(),
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
&ecs.read_storage::<comp::Body>()
|
||||
&ecs.read_storage::<comp::Body>(),
|
||||
ecs.read_storage::<comp::Item>().maybe(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(e, _, _, _)| *e != player_entity)
|
||||
.map(|(e, p, s, b)| {
|
||||
.filter(|(e, _, _, _, _)| *e != player_entity)
|
||||
.filter_map(|(e, p, s, b, i)| {
|
||||
const RADIUS_SCALE: f32 = 3.0;
|
||||
// TODO: use collider radius instead of body radius?
|
||||
let radius = s.map_or(1.0, |s| s.0) * b.radius() * RADIUS_SCALE;
|
||||
@ -1690,7 +1692,12 @@ fn under_cursor(
|
||||
let pos = Vec3::new(p.0.x, p.0.y, p.0.z + radius);
|
||||
// Distance squared from camera to the entity
|
||||
let dist_sqr = pos.distance_squared(cam_pos);
|
||||
(e, pos, radius, dist_sqr)
|
||||
// We only care about interacting with entities that contain items, or are not inanimate (to trade with)
|
||||
if i.is_some() || !matches!(b, comp::Body::Object(_)) {
|
||||
Some((e, pos, radius, dist_sqr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
// Roughly filter out entities farther than ray distance
|
||||
.filter(|(_, _, r, d_sqr)| *d_sqr <= cast_dist.powi(2) + 2.0 * cast_dist * r + r.powi(2))
|
||||
@ -1730,13 +1737,13 @@ fn under_cursor(
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Interactable {
|
||||
pub enum Interactable {
|
||||
Block(Block, Vec3<i32>),
|
||||
Entity(specs::Entity),
|
||||
}
|
||||
|
||||
impl Interactable {
|
||||
fn entity(self) -> Option<specs::Entity> {
|
||||
pub fn entity(self) -> Option<specs::Entity> {
|
||||
match self {
|
||||
Self::Entity(e) => Some(e),
|
||||
Self::Block(_, _) => None,
|
||||
|
Loading…
Reference in New Issue
Block a user