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.
|
- Dungeons now have multiple kinds of stairs.
|
||||||
- Trades now display item prices in tooltips.
|
- Trades now display item prices in tooltips.
|
||||||
- Admin designated build areas
|
- Admin designated build areas
|
||||||
|
- Indicator text to collectable terrain sprites
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -597,6 +597,9 @@ impl Item {
|
|||||||
SpriteKind::MediumGrass => "common.items.grasses.medium",
|
SpriteKind::MediumGrass => "common.items.grasses.medium",
|
||||||
SpriteKind::ShortGrass => "common.items.grasses.short",
|
SpriteKind::ShortGrass => "common.items.grasses.short",
|
||||||
SpriteKind::Coconut => "common.items.food.coconut",
|
SpriteKind::Coconut => "common.items.food.coconut",
|
||||||
|
|
||||||
|
// Containers
|
||||||
|
// IMPORTANT: Add any new container to `SpriteKind::is_container`
|
||||||
SpriteKind::Chest => {
|
SpriteKind::Chest => {
|
||||||
chosen = Lottery::<String>::load_expect(match rng.gen_range(0..7) {
|
chosen = Lottery::<String>::load_expect(match rng.gen_range(0..7) {
|
||||||
0 => "common.loot_tables.loot_table_weapon_uncommon",
|
0 => "common.loot_tables.loot_table_weapon_uncommon",
|
||||||
@ -637,6 +640,7 @@ impl Item {
|
|||||||
.read();
|
.read();
|
||||||
chosen.choose()
|
chosen.choose()
|
||||||
},
|
},
|
||||||
|
|
||||||
SpriteKind::Beehive => "common.items.crafting_ing.honey",
|
SpriteKind::Beehive => "common.items.crafting_ing.honey",
|
||||||
SpriteKind::Stones => "common.items.crafting_ing.stones",
|
SpriteKind::Stones => "common.items.crafting_ing.stones",
|
||||||
SpriteKind::Twigs => "common.items.crafting_ing.twigs",
|
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> {
|
pub fn mine_tool(&self) -> Option<ToolKind> {
|
||||||
match self {
|
match self {
|
||||||
SpriteKind::Velorite
|
SpriteKind::Velorite
|
||||||
|
@ -53,6 +53,7 @@ use crate::{
|
|||||||
i18n::{LanguageMetadata, Localization},
|
i18n::{LanguageMetadata, Localization},
|
||||||
render::{Consts, Globals, RenderMode, Renderer},
|
render::{Consts, Globals, RenderMode, Renderer},
|
||||||
scene::camera::{self, Camera},
|
scene::camera::{self, Camera},
|
||||||
|
session::Interactable,
|
||||||
settings::Fps,
|
settings::Fps,
|
||||||
ui::{
|
ui::{
|
||||||
fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui,
|
fonts::Fonts, img_ids::Rotations, slot, slot::SlotKey, Graphic, Ingameable, ScaleMode, Ui,
|
||||||
@ -67,7 +68,7 @@ use common::{
|
|||||||
self,
|
self,
|
||||||
item::{tool::ToolKind, ItemDesc, MaterialStatManifest, Quality},
|
item::{tool::ToolKind, ItemDesc, MaterialStatManifest, Quality},
|
||||||
skills::{Skill, SkillGroupKind},
|
skills::{Skill, SkillGroupKind},
|
||||||
BuffKind,
|
BuffKind, Item,
|
||||||
},
|
},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
terrain::TerrainChunk,
|
terrain::TerrainChunk,
|
||||||
@ -901,6 +902,7 @@ impl Hud {
|
|||||||
dt: Duration,
|
dt: Duration,
|
||||||
info: HudInfo,
|
info: HudInfo,
|
||||||
camera: &Camera,
|
camera: &Camera,
|
||||||
|
interactable: Option<Interactable>,
|
||||||
) -> Vec<Event> {
|
) -> Vec<Event> {
|
||||||
span!(_guard, "update_layout", "Hud::update_layout");
|
span!(_guard, "update_layout", "Hud::update_layout");
|
||||||
let mut events = std::mem::replace(&mut self.events, Vec::new());
|
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_walker = self.ids.scts.walk();
|
||||||
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
||||||
|
|
||||||
// Render overitem: name, etc.
|
let make_overitem = |item: &Item, pos, distance, active, fonts| {
|
||||||
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 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 {
|
||||||
@ -1353,17 +1343,74 @@ impl Hud {
|
|||||||
|
|
||||||
// Item
|
// Item
|
||||||
overitem::Overitem::new(
|
overitem::Overitem::new(
|
||||||
&text,
|
text.into(),
|
||||||
&quality,
|
quality,
|
||||||
&distance,
|
distance,
|
||||||
&self.fonts,
|
fonts,
|
||||||
&global_state.settings.controls,
|
&global_state.settings.controls,
|
||||||
|
// If we're currently set to interact with the item...
|
||||||
|
active,
|
||||||
)
|
)
|
||||||
.x_y(0.0, 100.0)
|
.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);
|
.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;
|
let speech_bubbles = &self.speech_bubbles;
|
||||||
|
|
||||||
// Render overhead name tags and health bars
|
// Render overhead name tags and health bars
|
||||||
@ -3244,6 +3291,7 @@ impl Hud {
|
|||||||
camera: &Camera,
|
camera: &Camera,
|
||||||
dt: Duration,
|
dt: Duration,
|
||||||
info: HudInfo,
|
info: HudInfo,
|
||||||
|
interactable: Option<Interactable>,
|
||||||
) -> Vec<Event> {
|
) -> Vec<Event> {
|
||||||
span!(_guard, "maintain", "Hud::maintain");
|
span!(_guard, "maintain", "Hud::maintain");
|
||||||
// conrod eats tabs. Un-eat a tabstop so tab completion can work
|
// 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() {
|
if let Some(maybe_id) = self.to_focus.take() {
|
||||||
self.ui.focus_widget(maybe_id);
|
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 {
|
let camera::Dependents {
|
||||||
view_mat, proj_mat, ..
|
view_mat, proj_mat, ..
|
||||||
} = camera.dependents();
|
} = camera.dependents();
|
||||||
|
@ -7,6 +7,9 @@ use conrod_core::{
|
|||||||
widget::{self, RoundedRectangle, Text},
|
widget::{self, RoundedRectangle, Text},
|
||||||
widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon,
|
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! {
|
widget_ids! {
|
||||||
struct Ids {
|
struct Ids {
|
||||||
@ -23,22 +26,24 @@ widget_ids! {
|
|||||||
/// (Item, DistanceFromPlayer, Rarity, etc.)
|
/// (Item, DistanceFromPlayer, Rarity, etc.)
|
||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct Overitem<'a> {
|
pub struct Overitem<'a> {
|
||||||
name: &'a str,
|
name: Cow<'a, str>,
|
||||||
quality: &'a Color,
|
quality: Color,
|
||||||
distance_from_player_sqr: &'a f32,
|
distance_from_player_sqr: f32,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
controls: &'a ControlSettings,
|
controls: &'a ControlSettings,
|
||||||
#[conrod(common_builder)]
|
#[conrod(common_builder)]
|
||||||
common: widget::CommonBuilder,
|
common: widget::CommonBuilder,
|
||||||
|
active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Overitem<'a> {
|
impl<'a> Overitem<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &'a str,
|
name: Cow<'a, str>,
|
||||||
quality: &'a Color,
|
quality: Color,
|
||||||
distance_from_player_sqr: &'a f32,
|
distance_from_player_sqr: f32,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
controls: &'a ControlSettings,
|
controls: &'a ControlSettings,
|
||||||
|
active: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
@ -47,6 +52,7 @@ impl<'a> Overitem<'a> {
|
|||||||
fonts,
|
fonts,
|
||||||
controls,
|
controls,
|
||||||
common: widget::CommonBuilder::default(),
|
common: widget::CommonBuilder::default(),
|
||||||
|
active,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +90,6 @@ 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 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);
|
let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.4);
|
||||||
|
|
||||||
// Example:
|
// Example:
|
||||||
@ -121,14 +126,18 @@ impl<'a> Widget for Overitem<'a> {
|
|||||||
Text::new(&self.name)
|
Text::new(&self.name)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(text_font_size as u32)
|
.font_size(text_font_size as u32)
|
||||||
.color(*self.quality)
|
.color(self.quality)
|
||||||
.x_y(0.0, text_pos_y)
|
.x_y(0.0, text_pos_y)
|
||||||
.depth(self.distance_from_player_sqr + 3.0)
|
.depth(self.distance_from_player_sqr + 3.0)
|
||||||
.parent(id)
|
.parent(id)
|
||||||
.set(state.ids.name, ui);
|
.set(state.ids.name, ui);
|
||||||
|
|
||||||
// Pickup Button
|
// 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)
|
RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius, btn_color)
|
||||||
.x_y(0.0, btn_rect_pos_y)
|
.x_y(0.0, btn_rect_pos_y)
|
||||||
.depth(self.distance_from_player_sqr + 1.0)
|
.depth(self.distance_from_player_sqr + 1.0)
|
||||||
@ -137,7 +146,7 @@ impl<'a> Widget for Overitem<'a> {
|
|||||||
Text::new(&format!("{}", key_button))
|
Text::new(&format!("{}", key_button))
|
||||||
.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 + 2.0)
|
.depth(self.distance_from_player_sqr + 2.0)
|
||||||
.parent(id)
|
.parent(id)
|
||||||
|
@ -877,6 +877,7 @@ impl PlayState for SessionState {
|
|||||||
target_entity: self.target_entity,
|
target_entity: self.target_entity,
|
||||||
selected_entity: self.selected_entity,
|
selected_entity: self.selected_entity,
|
||||||
},
|
},
|
||||||
|
self.interactable,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Look for changes in the localization files
|
// Look for changes in the localization files
|
||||||
@ -1678,11 +1679,12 @@ fn under_cursor(
|
|||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&positions,
|
&positions,
|
||||||
scales.maybe(),
|
scales.maybe(),
|
||||||
&ecs.read_storage::<comp::Body>()
|
&ecs.read_storage::<comp::Body>(),
|
||||||
|
ecs.read_storage::<comp::Item>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(e, _, _, _)| *e != player_entity)
|
.filter(|(e, _, _, _, _)| *e != player_entity)
|
||||||
.map(|(e, p, s, b)| {
|
.filter_map(|(e, p, s, b, i)| {
|
||||||
const RADIUS_SCALE: f32 = 3.0;
|
const RADIUS_SCALE: f32 = 3.0;
|
||||||
// TODO: use collider radius instead of body radius?
|
// TODO: use collider radius instead of body radius?
|
||||||
let radius = s.map_or(1.0, |s| s.0) * b.radius() * RADIUS_SCALE;
|
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);
|
let pos = Vec3::new(p.0.x, p.0.y, p.0.z + radius);
|
||||||
// Distance squared from camera to the entity
|
// Distance squared from camera to the entity
|
||||||
let dist_sqr = pos.distance_squared(cam_pos);
|
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
|
// 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))
|
.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)]
|
#[derive(Clone, Copy)]
|
||||||
enum Interactable {
|
pub enum Interactable {
|
||||||
Block(Block, Vec3<i32>),
|
Block(Block, Vec3<i32>),
|
||||||
Entity(specs::Entity),
|
Entity(specs::Entity),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interactable {
|
impl Interactable {
|
||||||
fn entity(self) -> Option<specs::Entity> {
|
pub fn entity(self) -> Option<specs::Entity> {
|
||||||
match self {
|
match self {
|
||||||
Self::Entity(e) => Some(e),
|
Self::Entity(e) => Some(e),
|
||||||
Self::Block(_, _) => None,
|
Self::Block(_, _) => None,
|
||||||
|
Loading…
Reference in New Issue
Block a user