mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'snowram/items-infos' into 'master'
Snowram/items infos See merge request veloren/veloren!1956
This commit is contained in:
commit
88f99986af
@ -24,9 +24,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Separated character randomization buttons into appearance and name.
|
||||
- Reworked mindflayer to have unique attacks
|
||||
- Glowing remains are now `Armor` instead of `Ingredients`.
|
||||
|
||||
- Generated a net world map
|
||||
- Overhauled clouds for more verticality and performance
|
||||
- New tooltip for items with stats comparison
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -7,8 +7,8 @@ ItemDef(
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.0,
|
||||
power: 1000.0,
|
||||
poise_strength: 1000.0,
|
||||
power: 999.9,
|
||||
poise_strength: 999.9,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.5,
|
||||
crit_mult: 2.0,
|
||||
|
BIN
assets/voxygen/font/haxrcorp_4089_cyrillic_altgr_extended.ttf
(Stored with Git LFS)
BIN
assets/voxygen/font/haxrcorp_4089_cyrillic_altgr_extended.ttf
(Stored with Git LFS)
Binary file not shown.
@ -24,6 +24,14 @@
|
||||
"buff.desc.bleed": "Inflicts regular damage.",
|
||||
"buff.title.cursed": "Cursed",
|
||||
"buff.desc.cursed": "You are cursed.",
|
||||
// Buffs stats
|
||||
"buff.stat.health": "Restores {str_total} Health",
|
||||
"buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}",
|
||||
"buff.stat.increase_max_health": "Raises Maximum Health by {strength}",
|
||||
"buff.stat.invulnerability": "Grants invulnerability",
|
||||
// Text
|
||||
"buff.text.over_seconds": "over {dur_secs} seconds",
|
||||
"buff.text.for_seconds": "for {dur_secs} seconds",
|
||||
},
|
||||
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
"common.you": "You",
|
||||
"common.automatic": "Auto",
|
||||
"common.random": "Random",
|
||||
"common.empty": "Empty",
|
||||
|
||||
// Settings Window title
|
||||
"common.interface_settings": "Interface Settings",
|
||||
@ -64,8 +65,39 @@ Is the client up to date?"#,
|
||||
"common.weapons.hammer": "Hammer",
|
||||
"common.weapons.general": "General Combat",
|
||||
"common.weapons.sceptre": "Healing Sceptre",
|
||||
"common.weapons.sceptre": "Shield",
|
||||
"common.weapons.spear": "Spear",
|
||||
"common.weapons.hammer_simple": "Simple Hammer",
|
||||
"common.weapons.sword_simple": "Simple Sword",
|
||||
"common.weapons.staff_simple": "Simple Staff",
|
||||
"common.weapons.axe_simple": "Simple Axe",
|
||||
"common.weapons.bow_simple": "Simple Bow",
|
||||
"common.weapons.unique": "Unique",
|
||||
"common.tool.debug": "Debug",
|
||||
"common.tool.faming": "Farming Tool",
|
||||
"common.tool.pick": "Pickaxe",
|
||||
"common.kind.modular_component": "Modular Component",
|
||||
"common.kind.glider": "Glider",
|
||||
"common.kind.consumable": "Consumable",
|
||||
"common.kind.throwable": "Can be thrown",
|
||||
"common.kind.utility": "Utility",
|
||||
"common.kind.ingredient": "Ingredient",
|
||||
"common.kind.lantern": "Lantern",
|
||||
"common.hands.one": "One-Handed",
|
||||
"common.hands.two": "Two-Handed",
|
||||
|
||||
"common.rand_appearance": "Random appearance",
|
||||
"common.rand_name": "Random name",
|
||||
|
||||
"common.stats.dps": "DPS",
|
||||
"common.stats.power": "Power",
|
||||
"common.stats.speed": "Speed",
|
||||
"common.stats.poise": "Poise",
|
||||
"common.stats.crit_chance": "Crit Chance",
|
||||
"common.stats.crit_mult": "Crit Mult",
|
||||
"common.stats.armor": "Armor",
|
||||
"common.stats.poise_res": "Poise res",
|
||||
"common.stats.slots": "Slots",
|
||||
},
|
||||
|
||||
|
||||
|
@ -25,6 +25,12 @@
|
||||
"hud.bag.mainhand": "Mainhand",
|
||||
"hud.bag.offhand": "Offhand",
|
||||
"hud.bag.bag": "Bag",
|
||||
"hud.bag.health": "Health",
|
||||
"hud.bag.stamina": "Stamina",
|
||||
"hud.bag.combat_rating": "Combat Rating",
|
||||
"hud.bag.protection": "Protection",
|
||||
"hud.bag.combat_rating_desc": "Calculated from your\nequipment and health.",
|
||||
"hud.bag.protection": "Damage reduction through armor",
|
||||
},
|
||||
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
"hud.trade.result.completed": "Trade completed successfully.",
|
||||
"hud.trade.result.declined": "Trade declined.",
|
||||
"hud.trade.result.nospace": "Not enough space to complete the trade.",
|
||||
"hud.trade.buy_price": "Buy price",
|
||||
"hud.trade.sell_price": "Sell Price",
|
||||
"hud.trade.coin": "coin(s)",
|
||||
},
|
||||
|
||||
|
||||
|
@ -24,6 +24,15 @@
|
||||
"buff.desc.bleed": "Inflige régulièrement des dommages.",
|
||||
"buff.title.cursed": "Maudit",
|
||||
"buff.desc.cursed": "Vous êtes maudit.",
|
||||
// Buffs stats
|
||||
"buff.stat.health": "Restaure {str_total} points de vie",
|
||||
"buff.stat.increase_max_stamina": "Augmente la vigueur maximale de {strength}",
|
||||
"buff.stat.increase_max_health": "Augmente la santé maximale de {strength}",
|
||||
"buff.stat.invulnerability": "Rend invincible",
|
||||
// Text
|
||||
"buff.text.over_seconds": "pendant {dur_secs} secondes",
|
||||
"buff.text.for_seconds": "pour {dur_secs} secondes",
|
||||
"buff.text.every_second": "chaque seconde",
|
||||
},
|
||||
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
"common.you": "Toi",
|
||||
"common.automatic": "Auto",
|
||||
"common.random": "Aléatoire",
|
||||
"common.empty": "Vide",
|
||||
|
||||
// Settings Window title
|
||||
"common.interface_settings": "Options de l'interface",
|
||||
"common.gameplay_settings": "Options de gameplay",
|
||||
@ -62,7 +64,38 @@ Le client est-il à jour?"#,
|
||||
"common.weapons.bow": "Arc",
|
||||
"common.weapons.hammer": "Marteau",
|
||||
"common.weapons.sceptre": "Sceptre de soin",
|
||||
"common.weapons.sceptre": "Bouclier",
|
||||
"common.weapons.spear": "Lance",
|
||||
"common.weapons.hammer_simple": "Marteau Simple",
|
||||
"common.weapons.sword_simple": "Épée Simple",
|
||||
"common.weapons.staff_simple": "Bâton Simple",
|
||||
"common.weapons.axe_simple": "Hache Simple",
|
||||
"common.weapons.bow_simple": "Arc Simple",
|
||||
"common.weapons.unique": "Unique",
|
||||
"common.tool.debug": "Debug",
|
||||
"common.tool.faming": "Outil agricole",
|
||||
"common.tool.pick": "Pioche",
|
||||
"common.kind.modular_component": "Composant Modulaire",
|
||||
"common.kind.glider": "Planeur",
|
||||
"common.kind.consumable": "Consommable",
|
||||
"common.kind.throwable": "Peut être lancé",
|
||||
"common.kind.utility": "Utilitaire",
|
||||
"common.kind.ingredient": "Ingrédient",
|
||||
"common.kind.lantern": "Lanterne",
|
||||
"common.hands.one": "Une main",
|
||||
"common.hands.two": "Deux mains",
|
||||
|
||||
"common.rand_appearance": "Apparence et nom aléatoire",
|
||||
|
||||
"common.stats.dps": "DPS",
|
||||
"common.stats.power": "Puissance",
|
||||
"common.stats.speed": "Vitesse",
|
||||
"common.stats.poise": "Impact",
|
||||
"common.stats.crit_chance": "Chance Crit",
|
||||
"common.stats.crit_mult": "Mult Crit",
|
||||
"common.stats.armor": "Armure",
|
||||
"common.stats.poise_res": "Res Impact",
|
||||
"common.stats.slots": "Emplacements",
|
||||
},
|
||||
|
||||
|
||||
|
@ -25,6 +25,12 @@
|
||||
"hud.bag.mainhand": "Main Dominante",
|
||||
"hud.bag.offhand": "Main Secondaire",
|
||||
"hud.bag.bag": "Sac",
|
||||
"hud.bag.health": "Santé",
|
||||
"hud.bag.stamina": "Vigueur",
|
||||
"hud.bag.combat_rating": "Niveau de Combat",
|
||||
"hud.bag.protection": "Protection",
|
||||
"hud.bag.combat_rating_desc": "Calculé depuis votre\néquipement et votre santé",
|
||||
"hud.bag.protection_desc": "Réduction des dégats de votre armure",
|
||||
},
|
||||
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
"hud.trade.result.completed": "Échange complété avec succès.",
|
||||
"hud.trade.result.declined": "Échange décliné.",
|
||||
"hud.trade.result.nospace": "Pas assez d'espace libre pour compléter l'échange.",
|
||||
"hud.trade.buy_price": "Prix d'achat",
|
||||
"hud.trade.sell_price": "Prix de vente",
|
||||
"hud.trade.coin": "pièce(s)",
|
||||
},
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::Ordering, ops::Sub};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ArmorKind {
|
||||
@ -40,6 +41,21 @@ impl Stats {
|
||||
poise_resilience,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_protection(&self) -> Protection { self.protection }
|
||||
|
||||
pub fn get_poise_resilience(&self) -> Protection { self.poise_resilience }
|
||||
}
|
||||
|
||||
impl Sub<Stats> for Stats {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
protection: self.protection - other.protection,
|
||||
poise_resilience: self.poise_resilience - other.poise_resilience,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -48,6 +64,31 @@ pub enum Protection {
|
||||
Normal(f32),
|
||||
}
|
||||
|
||||
impl Sub for Protection {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
let diff = match (self, other) {
|
||||
(Protection::Invincible, Protection::Normal(_)) => f32::INFINITY,
|
||||
(Protection::Invincible, Protection::Invincible) => 0_f32,
|
||||
(Protection::Normal(_), Protection::Invincible) => -f32::INFINITY,
|
||||
(Protection::Normal(a), Protection::Normal(b)) => a - b,
|
||||
};
|
||||
Protection::Normal(diff)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Protection {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (*self, *other) {
|
||||
(Protection::Invincible, Protection::Invincible) => Some(Ordering::Equal),
|
||||
(Protection::Invincible, _) => Some(Ordering::Greater),
|
||||
(_, Protection::Invincible) => Some(Ordering::Less),
|
||||
(Protection::Normal(a), Protection::Normal(b)) => f32::partial_cmp(&a, &b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Armor {
|
||||
pub kind: ArmorKind,
|
||||
|
@ -728,3 +728,21 @@ pub struct ItemDrop(pub Item);
|
||||
impl Component for ItemDrop {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
impl<'a, T: ItemDesc + ?Sized> ItemDesc for &'a T {
|
||||
fn description(&self) -> &str { (*self).description() }
|
||||
|
||||
fn name(&self) -> &str { (*self).name() }
|
||||
|
||||
fn kind(&self) -> &ItemKind { (*self).kind() }
|
||||
|
||||
fn quality(&self) -> &Quality { (*self).quality() }
|
||||
|
||||
fn num_slots(&self) -> u16 { (*self).num_slots() }
|
||||
|
||||
fn item_definition_id(&self) -> &str { (*self).item_definition_id() }
|
||||
|
||||
fn components(&self) -> &[Item] { (*self).components() }
|
||||
|
||||
fn tags(&self) -> &[ItemTag] { (*self).tags() }
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
ops::{AddAssign, DivAssign, MulAssign},
|
||||
ops::{AddAssign, DivAssign, MulAssign, Sub},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::error;
|
||||
@ -139,6 +139,21 @@ impl DivAssign<usize> for Stats {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Stats> for Stats {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
equip_time_secs: self.equip_time_secs - other.equip_time_secs,
|
||||
power: self.power - other.power,
|
||||
poise_strength: self.poise_strength - other.poise_strength,
|
||||
speed: self.speed - other.speed,
|
||||
crit_chance: self.crit_chance - other.crit_chance,
|
||||
crit_mult: self.crit_mult - other.crit_mult,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MaterialStatManifest(pub HashMap<String, Stats>);
|
||||
|
||||
|
@ -206,6 +206,18 @@ impl Loadout {
|
||||
.or_else(|| first.map(|x| x.equip_slot))
|
||||
}
|
||||
|
||||
/// Returns all items currently equipped that an item of the given ItemKind
|
||||
/// could replace
|
||||
pub(super) fn equipped_items_of_kind(
|
||||
&self,
|
||||
item_kind: ItemKind,
|
||||
) -> impl Iterator<Item = &Item> {
|
||||
self.slots
|
||||
.iter()
|
||||
.filter(move |s| s.equip_slot.can_hold(&item_kind))
|
||||
.filter_map(|s| s.slot.as_ref())
|
||||
}
|
||||
|
||||
/// Returns the `InvSlot` for a given `LoadoutSlotId`
|
||||
pub(super) fn inv_slot(&self, loadout_slot_id: LoadoutSlotId) -> Option<&InvSlot> {
|
||||
self.slots
|
||||
|
@ -9,7 +9,7 @@ use tracing::{debug, trace, warn};
|
||||
use crate::{
|
||||
comp::{
|
||||
inventory::{
|
||||
item::{ItemDef, MaterialStatManifest},
|
||||
item::{ItemDef, ItemKind, MaterialStatManifest},
|
||||
loadout::Loadout,
|
||||
slot::{EquipSlot, Slot, SlotError},
|
||||
},
|
||||
@ -676,6 +676,10 @@ impl Inventory {
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn equipped_items_of_kind(&self, item_kind: ItemKind) -> impl Iterator<Item = &Item> {
|
||||
self.loadout.equipped_items_of_kind(item_kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Inventory {
|
||||
|
@ -3,16 +3,15 @@ use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
item_imgs::ItemImgs,
|
||||
slots::{ArmorSlot, EquipSlot, InventorySlot, SlotManager},
|
||||
util::loadout_slot_text,
|
||||
Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, QUALITY_COMMON, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
hud::get_quality_col,
|
||||
i18n::Localization,
|
||||
ui::{
|
||||
fonts::Fonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable, Tooltip, TooltipManager,
|
||||
Tooltipable,
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
@ -70,15 +69,14 @@ pub struct InventoryScroller<'a> {
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
show_stats: bool,
|
||||
show_bag_inv: bool,
|
||||
msm: &'a MaterialStatManifest,
|
||||
on_right: bool,
|
||||
item_tooltip: &'a Tooltip<'a>,
|
||||
item_tooltip: &'a ItemTooltip<'a>,
|
||||
playername: String,
|
||||
is_us: bool,
|
||||
inventory: &'a Inventory,
|
||||
@ -92,15 +90,14 @@ impl<'a> InventoryScroller<'a> {
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a Fonts,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
show_stats: bool,
|
||||
show_bag_inv: bool,
|
||||
msm: &'a MaterialStatManifest,
|
||||
on_right: bool,
|
||||
item_tooltip: &'a Tooltip<'a>,
|
||||
item_tooltip: &'a ItemTooltip<'a>,
|
||||
playername: String,
|
||||
is_us: bool,
|
||||
inventory: &'a Inventory,
|
||||
@ -112,13 +109,12 @@ impl<'a> InventoryScroller<'a> {
|
||||
item_imgs,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
slot_manager,
|
||||
pulse,
|
||||
localized_strings,
|
||||
show_stats,
|
||||
show_bag_inv,
|
||||
msm,
|
||||
on_right,
|
||||
item_tooltip,
|
||||
playername,
|
||||
@ -293,8 +289,6 @@ impl<'a> InventoryScroller<'a> {
|
||||
}
|
||||
|
||||
if let Some(item) = item {
|
||||
let (title, desc) = super::util::item_text(item, &self.msm);
|
||||
let quality_col = get_quality_col(item);
|
||||
let quality_col_img = match item.quality() {
|
||||
Quality::Low => self.imgs.inv_slot_grey,
|
||||
Quality::Common => self.imgs.inv_slot,
|
||||
@ -305,19 +299,20 @@ impl<'a> InventoryScroller<'a> {
|
||||
Quality::Artifact => self.imgs.inv_slot_orange,
|
||||
_ => self.imgs.inv_slot_red,
|
||||
};
|
||||
let mut desc = desc.to_string();
|
||||
let i18n = &self.localized_strings;
|
||||
|
||||
let mut prices_info: Option<String> = None;
|
||||
if let Some((_, _, prices)) = self.client.pending_trade() {
|
||||
super::util::append_price_desc(&mut desc, prices, item.item_definition_id());
|
||||
prices_info = super::util::price_desc(prices, item.item_definition_id(), i18n);
|
||||
}
|
||||
|
||||
slot_widget
|
||||
.filled_slot(quality_col_img)
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
.with_item_tooltip(
|
||||
self.item_tooltip_manager,
|
||||
item,
|
||||
prices_info,
|
||||
self.item_tooltip,
|
||||
quality_col,
|
||||
)
|
||||
.set(state.ids.inv_slots[i], ui);
|
||||
} else {
|
||||
@ -451,6 +446,7 @@ pub struct Bag<'a> {
|
||||
common: widget::CommonBuilder,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
@ -471,6 +467,7 @@ impl<'a> Bag<'a> {
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
@ -489,6 +486,7 @@ impl<'a> Bag<'a> {
|
||||
common: widget::CommonBuilder::default(),
|
||||
rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
slot_manager,
|
||||
pulse,
|
||||
localized_strings,
|
||||
@ -560,7 +558,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
};
|
||||
|
||||
// Tooltips
|
||||
let item_tooltip = Tooltip::new({
|
||||
let tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
@ -578,18 +576,43 @@ impl<'a> Widget for Bag<'a> {
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
|
||||
let item_tooltip = ItemTooltip::new(
|
||||
{
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
},
|
||||
self.client,
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.pulse,
|
||||
self.msm,
|
||||
self.localized_strings,
|
||||
)
|
||||
.title_font_size(self.fonts.cyri.scale(20))
|
||||
.parent(ui.window)
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
|
||||
InventoryScroller::new(
|
||||
self.client,
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.fonts,
|
||||
self.tooltip_manager,
|
||||
self.item_tooltip_manager,
|
||||
self.slot_manager,
|
||||
self.pulse,
|
||||
self.localized_strings,
|
||||
self.show.stats,
|
||||
self.show.bag_inv,
|
||||
self.msm,
|
||||
true,
|
||||
&item_tooltip,
|
||||
self.stats.name.to_string(),
|
||||
@ -717,18 +740,16 @@ impl<'a> Widget for Bag<'a> {
|
||||
} else {
|
||||
btn.down_from(state.ids.stat_icons[i.0 - 1], 7.0)
|
||||
};
|
||||
// TODO: Translation
|
||||
let tooltip_head = match i.1 {
|
||||
"Health" => "Health",
|
||||
"Stamina" => "Stamina",
|
||||
"Combat Rating" => "Combat Rating",
|
||||
"Protection" => "Protection",
|
||||
"Health" => i18n.get("hud.bag.health"),
|
||||
"Stamina" => i18n.get("hud.bag.stamina"),
|
||||
"Combat Rating" => i18n.get("hud.bag.combat_rating"),
|
||||
"Protection" => i18n.get("hud.bag.protection"),
|
||||
_ => "",
|
||||
};
|
||||
// TODO: Translation
|
||||
let tooltip_txt = match i.1 {
|
||||
"Combat Rating" => "Calculated from your\nequipment and health.",
|
||||
"Protection" => "Damage reduction through armor",
|
||||
"Combat Rating" => i18n.get("hud.bag.combat_rating_desc"),
|
||||
"Protection" => i18n.get("hud.bag.protection_desc"),
|
||||
_ => "",
|
||||
};
|
||||
btn.with_tooltip(
|
||||
@ -755,386 +776,369 @@ impl<'a> Widget for Bag<'a> {
|
||||
}
|
||||
// Loadout Slots
|
||||
// Head
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Head)),
|
||||
|| (i18n.get("hud.bag.head"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let head_q_col = inventory
|
||||
let head_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Head))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Head), [45.0; 2])
|
||||
.mid_top_with_margin_on(state.bg_ids.bg_frame, 60.0)
|
||||
.with_icon(self.imgs.head_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = head_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.head_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
head_q_col,
|
||||
i18n.get("hud.bag.head"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.head_slot, ui);
|
||||
.set(state.ids.head_slot, ui)
|
||||
}
|
||||
|
||||
// Necklace
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Neck)),
|
||||
|| (i18n.get("hud.bag.neck"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let neck_q_col = inventory
|
||||
let neck_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Neck))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Neck), [45.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.head_slot, -55.0)
|
||||
.with_icon(self.imgs.necklace_bg, Vec2::new(40.0, 31.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = neck_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.neck_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
neck_q_col,
|
||||
i18n.get("hud.bag.neck"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.neck_slot, ui);
|
||||
.set(state.ids.neck_slot, ui)
|
||||
}
|
||||
// Chest
|
||||
//Image::new(self.imgs.armor_slot) // different graphics for empty/non empty
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Chest)),
|
||||
|| (i18n.get("hud.bag.chest"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let chest_q_col = inventory
|
||||
let chest_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Chest))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Chest), [85.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.neck_slot, -95.0)
|
||||
.with_icon(self.imgs.chest_bg, Vec2::new(64.0, 42.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = chest_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.chest_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
chest_q_col,
|
||||
i18n.get("hud.bag.chest"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.chest_slot, ui);
|
||||
.set(state.ids.chest_slot, ui)
|
||||
}
|
||||
// Shoulders
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Shoulders)),
|
||||
|| (i18n.get("hud.bag.shoulders"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let shoulder_q_col = inventory
|
||||
let shoulder_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Shoulders))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Shoulders), [70.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
||||
.with_icon(self.imgs.shoulders_bg, Vec2::new(60.0, 36.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = shoulder_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.shoulders_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
shoulder_q_col,
|
||||
i18n.get("hud.bag.shoulders"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.shoulders_slot, ui);
|
||||
.set(state.ids.shoulders_slot, ui)
|
||||
}
|
||||
// Hands
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Hands)),
|
||||
|| (i18n.get("hud.bag.hands"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let chest_q_col = inventory
|
||||
let hands_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Hands))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Hands), [70.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
||||
.with_icon(self.imgs.hands_bg, Vec2::new(55.0, 60.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = hands_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.hands_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
chest_q_col,
|
||||
i18n.get("hud.bag.hands"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.hands_slot, ui);
|
||||
.set(state.ids.hands_slot, ui)
|
||||
}
|
||||
// Belt
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Belt)),
|
||||
|| (i18n.get("hud.bag.belt"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let belt_q_col = inventory
|
||||
let belt_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Belt))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Belt), [45.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.chest_slot, -55.0)
|
||||
.with_icon(self.imgs.belt_bg, Vec2::new(40.0, 23.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = belt_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.belt_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
belt_q_col,
|
||||
i18n.get("hud.bag.belt"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.belt_slot, ui);
|
||||
.set(state.ids.belt_slot, ui)
|
||||
}
|
||||
// Legs
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Legs)),
|
||||
|| (i18n.get("hud.bag.legs"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let legs_q_col = inventory
|
||||
let legs_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Legs))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Legs), [85.0; 2])
|
||||
.mid_bottom_with_margin_on(state.ids.belt_slot, -95.0)
|
||||
.with_icon(self.imgs.legs_bg, Vec2::new(48.0, 70.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = legs_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.legs_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
legs_q_col,
|
||||
i18n.get("hud.bag.legs"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.legs_slot, ui);
|
||||
.set(state.ids.legs_slot, ui)
|
||||
}
|
||||
// Ring
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Ring1)),
|
||||
|| (i18n.get("hud.bag.ring"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let ring_q_col = inventory
|
||||
let ring1_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Ring1))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Ring1), [45.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.hands_slot, -55.0, 0.0)
|
||||
.with_icon(self.imgs.ring_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = ring1_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.ring1_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
ring_q_col,
|
||||
i18n.get("hud.bag.ring"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.ring1_slot, ui);
|
||||
.set(state.ids.ring1_slot, ui)
|
||||
}
|
||||
// Ring 2
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Ring2)),
|
||||
|| (i18n.get("hud.bag.ring"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let ring2_q_col = inventory
|
||||
let ring2_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Ring2))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Ring2), [45.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.shoulders_slot, -55.0, 0.0)
|
||||
.with_icon(self.imgs.ring_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = ring2_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.ring2_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
ring2_q_col,
|
||||
i18n.get("hud.bag.ring"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.ring2_slot, ui);
|
||||
.set(state.ids.ring2_slot, ui)
|
||||
}
|
||||
// Back
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Back)),
|
||||
|| (i18n.get("hud.bag.back"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let back_q_col = inventory
|
||||
let back_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Back))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Back), [45.0; 2])
|
||||
.down_from(state.ids.ring2_slot, 10.0)
|
||||
.with_icon(self.imgs.back_bg, Vec2::new(33.0, 40.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = back_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.back_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
back_q_col,
|
||||
i18n.get("hud.bag.back"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.back_slot, ui);
|
||||
.set(state.ids.back_slot, ui)
|
||||
}
|
||||
// Foot
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Feet)),
|
||||
|| (i18n.get("hud.bag.feet"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let foot_q_col = inventory
|
||||
let feet_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Feet))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Feet), [45.0; 2])
|
||||
.down_from(state.ids.ring1_slot, 10.0)
|
||||
.with_icon(self.imgs.feet_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = feet_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.feet_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
foot_q_col,
|
||||
i18n.get("hud.bag.feet"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.feet_slot, ui);
|
||||
.set(state.ids.feet_slot, ui)
|
||||
}
|
||||
// Lantern
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Lantern),
|
||||
|| (i18n.get("hud.bag.lantern"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let lantern_q_col = inventory
|
||||
let lantern_item = inventory
|
||||
.equipped(EquipSlot::Lantern)
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Lantern, [45.0; 2])
|
||||
.top_right_with_margins_on(state.bg_ids.bg_frame, 60.0, 5.0)
|
||||
.with_icon(self.imgs.lantern_bg, Vec2::new(24.0, 38.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = lantern_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.lantern_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
lantern_q_col,
|
||||
i18n.get("hud.bag.lantern"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.lantern_slot, ui);
|
||||
.set(state.ids.lantern_slot, ui)
|
||||
}
|
||||
// Glider
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Glider),
|
||||
|| (i18n.get("hud.bag.glider"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let glider_q_col = inventory
|
||||
let glider_item = inventory
|
||||
.equipped(EquipSlot::Glider)
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Glider, [45.0; 2])
|
||||
.down_from(state.ids.lantern_slot, 5.0)
|
||||
.with_icon(self.imgs.glider_bg, Vec2::new(38.0, 38.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = glider_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.glider_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
glider_q_col,
|
||||
i18n.get("hud.bag.glider"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.glider_slot, ui);
|
||||
.set(state.ids.glider_slot, ui)
|
||||
}
|
||||
// Tabard
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Tabard)),
|
||||
|| (i18n.get("hud.bag.tabard"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let tabard_q_col = inventory
|
||||
let tabard_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Tabard))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Tabard), [45.0; 2])
|
||||
.down_from(state.ids.glider_slot, 5.0)
|
||||
.with_icon(self.imgs.tabard_bg, Vec2::new(38.0, 38.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = tabard_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.tabard_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
tabard_q_col,
|
||||
i18n.get("hud.bag.tabard"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.tabard_slot, ui);
|
||||
.set(state.ids.tabard_slot, ui)
|
||||
}
|
||||
// Mainhand/Left-Slot
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Mainhand),
|
||||
|| (i18n.get("hud.bag.mainhand"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let mainhand_q_col = inventory
|
||||
let mainhand_item = inventory
|
||||
.equipped(EquipSlot::Mainhand)
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Mainhand, [85.0; 2])
|
||||
.bottom_right_with_margins_on(state.ids.back_slot, -95.0, 0.0)
|
||||
.with_icon(self.imgs.mainhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = mainhand_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.mainhand_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
mainhand_q_col,
|
||||
i18n.get("hud.bag.mainhand"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.mainhand_slot, ui);
|
||||
.set(state.ids.mainhand_slot, ui)
|
||||
}
|
||||
// Offhand/Right-Slot
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Offhand),
|
||||
|| (i18n.get("hud.bag.offhand"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let offhand_q_col = inventory
|
||||
let offhand_item = inventory
|
||||
.equipped(EquipSlot::Offhand)
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Offhand, [85.0; 2])
|
||||
.bottom_left_with_margins_on(state.ids.feet_slot, -95.0, 0.0)
|
||||
.with_icon(self.imgs.offhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = offhand_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.offhand_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
offhand_q_col,
|
||||
i18n.get("hud.bag.offhand"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.offhand_slot, ui);
|
||||
.set(state.ids.offhand_slot, ui)
|
||||
}
|
||||
}
|
||||
// Bag 1
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag1)),
|
||||
|| (i18n.get("hud.bag.bag"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let bag1_q_col = inventory
|
||||
let bag1_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Bag1))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Bag1), [35.0; 2])
|
||||
.bottom_left_with_margins_on(
|
||||
state.bg_ids.bg_frame,
|
||||
@ -1142,84 +1146,86 @@ impl<'a> Widget for Bag<'a> {
|
||||
3.0,
|
||||
)
|
||||
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = bag1_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.bag1_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
bag1_q_col,
|
||||
i18n.get("hud.bag.bag"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.bag1_slot, ui);
|
||||
.set(state.ids.bag1_slot, ui)
|
||||
}
|
||||
// Bag 2
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag2)),
|
||||
|| (i18n.get("hud.bag.bag"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let bag2_q_col = inventory
|
||||
let bag2_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Bag2))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Bag2), [35.0; 2])
|
||||
.down_from(state.ids.bag1_slot, 2.0)
|
||||
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = bag2_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.bag2_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
bag2_q_col,
|
||||
i18n.get("hud.bag.bag"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.bag2_slot, ui);
|
||||
.set(state.ids.bag2_slot, ui)
|
||||
}
|
||||
// Bag 3
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag3)),
|
||||
|| (i18n.get("hud.bag.bag"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let bag3_q_col = inventory
|
||||
let bag3_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Bag3))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Bag3), [35.0; 2])
|
||||
.down_from(state.ids.bag2_slot, 2.0)
|
||||
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = bag3_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.bag3_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
bag3_q_col,
|
||||
i18n.get("hud.bag.bag"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.bag3_slot, ui);
|
||||
.set(state.ids.bag3_slot, ui)
|
||||
}
|
||||
// Bag 4
|
||||
let (title, desc) = loadout_slot_text(
|
||||
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag4)),
|
||||
|| (i18n.get("hud.bag.bag"), ""),
|
||||
&self.msm,
|
||||
);
|
||||
let bag4_q_col = inventory
|
||||
let bag4_item = inventory
|
||||
.equipped(EquipSlot::Armor(ArmorSlot::Bag4))
|
||||
.map(|item| get_quality_col(item))
|
||||
.unwrap_or(QUALITY_COMMON);
|
||||
slot_maker
|
||||
.map(|item| item.to_owned());
|
||||
let slot = slot_maker
|
||||
.fabricate(EquipSlot::Armor(ArmorSlot::Bag4), [35.0; 2])
|
||||
.down_from(state.ids.bag3_slot, 2.0)
|
||||
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
||||
.filled_slot(filled_slot)
|
||||
.with_tooltip(
|
||||
.filled_slot(filled_slot);
|
||||
if let Some(item) = bag4_item {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, &item, None, &item_tooltip)
|
||||
.set(state.ids.bag4_slot, ui)
|
||||
} else {
|
||||
slot.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
bag4_q_col,
|
||||
i18n.get("hud.bag.bag"),
|
||||
"",
|
||||
&tooltip,
|
||||
color::WHITE,
|
||||
)
|
||||
.set(state.ids.bag4_slot, ui);
|
||||
.set(state.ids.bag4_slot, ui)
|
||||
}
|
||||
|
||||
// Close button
|
||||
if Button::image(self.imgs.close_btn)
|
||||
|
@ -4,9 +4,8 @@ use super::{
|
||||
TEXT_COLOR, TEXT_DULL_RED_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
hud::get_quality_col,
|
||||
i18n::Localization,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
ui::{fonts::Fonts, ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable},
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{
|
||||
@ -65,7 +64,7 @@ pub struct Crafting<'a> {
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
item_imgs: &'a ItemImgs,
|
||||
inventory: &'a Inventory,
|
||||
msm: &'a MaterialStatManifest,
|
||||
@ -81,7 +80,7 @@ impl<'a> Crafting<'a> {
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
item_imgs: &'a ItemImgs,
|
||||
inventory: &'a Inventory,
|
||||
msm: &'a MaterialStatManifest,
|
||||
@ -93,7 +92,7 @@ impl<'a> Crafting<'a> {
|
||||
localized_strings,
|
||||
pulse,
|
||||
rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
item_imgs,
|
||||
inventory,
|
||||
msm,
|
||||
@ -138,17 +137,27 @@ impl<'a> Widget for Crafting<'a> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
// Tooltips
|
||||
let item_tooltip = Tooltip::new({
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
})
|
||||
.title_font_size(self.fonts.cyri.scale(15))
|
||||
let item_tooltip = ItemTooltip::new(
|
||||
{
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
},
|
||||
self.client,
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.pulse,
|
||||
self.msm,
|
||||
self.localized_strings,
|
||||
)
|
||||
.title_font_size(self.fonts.cyri.scale(20))
|
||||
.parent(ui.window)
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
@ -300,8 +309,6 @@ impl<'a> Widget for Crafting<'a> {
|
||||
{
|
||||
let output_text = format!("x{}", &recipe.output.1.to_string());
|
||||
// Output Image
|
||||
let (title, desc) = super::util::item_text(&*recipe.output.0, self.msm);
|
||||
let quality_col = get_quality_col(&*recipe.output.0);
|
||||
Button::image(animate_by_pulse(
|
||||
&self
|
||||
.item_imgs
|
||||
@ -316,12 +323,11 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.label_y(conrod_core::position::Relative::Scalar(-24.0))
|
||||
.label_x(conrod_core::position::Relative::Scalar(24.0))
|
||||
.middle_of(state.ids.output_img_frame)
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
.with_item_tooltip(
|
||||
self.item_tooltip_manager,
|
||||
&*recipe.output.0,
|
||||
None,
|
||||
&item_tooltip,
|
||||
quality_col,
|
||||
)
|
||||
.set(state.ids.output_img, ui);
|
||||
}
|
||||
@ -472,7 +478,6 @@ impl<'a> Widget for Crafting<'a> {
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let quality_col = get_quality_col(&*item_def);
|
||||
let quality_col_img = match &item_def.quality {
|
||||
Quality::Low => self.imgs.inv_slot_grey,
|
||||
Quality::Common => self.imgs.inv_slot,
|
||||
@ -491,20 +496,13 @@ impl<'a> Widget for Crafting<'a> {
|
||||
};
|
||||
frame.set(state.ids.ingredient_frame[i], ui);
|
||||
//Item Image
|
||||
let (title, desc) = super::util::item_text(&*item_def, self.msm);
|
||||
Button::image(animate_by_pulse(
|
||||
&self.item_imgs.img_ids_or_not_found_img((&*item_def).into()),
|
||||
self.pulse,
|
||||
))
|
||||
.w_h(22.0, 22.0)
|
||||
.middle_of(state.ids.ingredient_frame[i])
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
quality_col,
|
||||
)
|
||||
.with_item_tooltip(self.item_tooltip_manager, &*item_def, None, &item_tooltip)
|
||||
.set(state.ids.ingredient_img[i], ui);
|
||||
// Ingredients text and amount
|
||||
// Don't show inventory amounts above 999 to avoid the widget clipping
|
||||
|
@ -7,8 +7,8 @@ mod diary;
|
||||
mod esc_menu;
|
||||
mod group;
|
||||
mod hotbar;
|
||||
mod img_ids;
|
||||
mod item_imgs;
|
||||
pub mod img_ids;
|
||||
pub mod item_imgs;
|
||||
mod map;
|
||||
mod minimap;
|
||||
mod overhead;
|
||||
@ -20,7 +20,7 @@ mod skillbar;
|
||||
mod slots;
|
||||
mod social;
|
||||
mod trade;
|
||||
mod util;
|
||||
pub mod util;
|
||||
|
||||
pub use hotbar::{SlotContents as HotbarSlotContents, State as HotbarState};
|
||||
pub use item_imgs::animate_by_pulse;
|
||||
@ -263,6 +263,7 @@ widget_ids! {
|
||||
crafting_window,
|
||||
settings_window,
|
||||
group_window,
|
||||
item_info,
|
||||
|
||||
// Free look indicator
|
||||
free_look_txt,
|
||||
@ -903,8 +904,9 @@ impl Hud {
|
||||
) -> Vec<Event> {
|
||||
span!(_guard, "update_layout", "Hud::update_layout");
|
||||
let mut events = std::mem::replace(&mut self.events, Vec::new());
|
||||
let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets();
|
||||
// pulse time for pulsating elements
|
||||
let (ref mut ui_widgets, ref mut item_tooltip_manager, ref mut tooltip_manager) =
|
||||
&mut self.ui.set_widgets();
|
||||
// self.ui.set_item_widgets(); pulse time for pulsating elements
|
||||
self.pulse = self.pulse + dt.as_secs_f32();
|
||||
// FPS
|
||||
let fps = global_state.clock.stats().average_tps;
|
||||
@ -1338,6 +1340,7 @@ impl Hud {
|
||||
&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 {
|
||||
@ -1346,9 +1349,12 @@ impl Hud {
|
||||
item.name().to_string()
|
||||
};
|
||||
|
||||
let quality = get_quality_col(item);
|
||||
|
||||
// Item
|
||||
overitem::Overitem::new(
|
||||
&text,
|
||||
&quality,
|
||||
&distance,
|
||||
&self.fonts,
|
||||
&global_state.settings.controls,
|
||||
@ -2226,6 +2232,7 @@ impl Hud {
|
||||
controllers.get(entity).map(|c| &c.inputs),
|
||||
) {
|
||||
Skillbar::new(
|
||||
client,
|
||||
global_state,
|
||||
&self.imgs,
|
||||
&self.item_imgs,
|
||||
@ -2239,6 +2246,7 @@ impl Hud {
|
||||
//&controller,
|
||||
&self.hotbar,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
&mut self.slot_manager,
|
||||
i18n,
|
||||
&ability_map,
|
||||
@ -2262,6 +2270,7 @@ impl Hud {
|
||||
&self.fonts,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
&mut self.slot_manager,
|
||||
self.pulse,
|
||||
i18n,
|
||||
@ -2298,7 +2307,7 @@ impl Hud {
|
||||
&self.item_imgs,
|
||||
&self.fonts,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
&mut self.slot_manager,
|
||||
i18n,
|
||||
&msm,
|
||||
@ -2363,7 +2372,7 @@ impl Hud {
|
||||
i18n,
|
||||
self.pulse,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
&self.item_imgs,
|
||||
&inventory,
|
||||
&msm,
|
||||
@ -3323,7 +3332,7 @@ impl Hud {
|
||||
}
|
||||
}
|
||||
// Get item qualities of equipped items and assign a tooltip title/frame color
|
||||
pub fn get_quality_col<I: ItemDesc>(item: &I) -> Color {
|
||||
pub fn get_quality_col<I: ItemDesc + ?Sized>(item: &I) -> Color {
|
||||
match item.quality() {
|
||||
Quality::Low => QUALITY_LOW,
|
||||
Quality::Common => QUALITY_COMMON,
|
||||
|
@ -24,6 +24,7 @@ widget_ids! {
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Overitem<'a> {
|
||||
name: &'a str,
|
||||
quality: &'a Color,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
@ -34,12 +35,14 @@ pub struct Overitem<'a> {
|
||||
impl<'a> Overitem<'a> {
|
||||
pub fn new(
|
||||
name: &'a str,
|
||||
quality: &'a Color,
|
||||
distance_from_player_sqr: &'a f32,
|
||||
fonts: &'a Fonts,
|
||||
controls: &'a ControlSettings,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
quality,
|
||||
distance_from_player_sqr,
|
||||
fonts,
|
||||
controls,
|
||||
@ -118,7 +121,7 @@ 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(text_color)
|
||||
.color(*self.quality)
|
||||
.x_y(0.0, text_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 3.0)
|
||||
.parent(id)
|
||||
|
@ -11,11 +11,14 @@ use crate::{
|
||||
ui::{
|
||||
fonts::Fonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable, Tooltip, TooltipManager,
|
||||
Tooltipable,
|
||||
},
|
||||
window::GameInput,
|
||||
GlobalState,
|
||||
};
|
||||
|
||||
use client::{self, Client};
|
||||
use common::comp::{
|
||||
self,
|
||||
inventory::slot::EquipSlot,
|
||||
@ -130,6 +133,7 @@ widget_ids! {
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Skillbar<'a> {
|
||||
client: &'a Client,
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
@ -142,6 +146,7 @@ pub struct Skillbar<'a> {
|
||||
// controller: &'a ControllerInputs,
|
||||
hotbar: &'a hotbar::State,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut slots::SlotManager,
|
||||
localized_strings: &'a Localization,
|
||||
pulse: f32,
|
||||
@ -155,6 +160,7 @@ pub struct Skillbar<'a> {
|
||||
impl<'a> Skillbar<'a> {
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
pub fn new(
|
||||
client: &'a Client,
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
@ -168,6 +174,7 @@ impl<'a> Skillbar<'a> {
|
||||
// controller: &'a ControllerInputs,
|
||||
hotbar: &'a hotbar::State,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut slots::SlotManager,
|
||||
localized_strings: &'a Localization,
|
||||
ability_map: &'a AbilityMap,
|
||||
@ -175,6 +182,7 @@ impl<'a> Skillbar<'a> {
|
||||
combo: Option<ComboFloater>,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
global_state,
|
||||
imgs,
|
||||
item_imgs,
|
||||
@ -189,6 +197,7 @@ impl<'a> Skillbar<'a> {
|
||||
// controller,
|
||||
hotbar,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
slot_manager,
|
||||
localized_strings,
|
||||
ability_map,
|
||||
@ -464,7 +473,9 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
slot_manager: Some(self.slot_manager),
|
||||
pulse: self.pulse,
|
||||
};
|
||||
let item_tooltip = Tooltip::new({
|
||||
|
||||
// Tooltips
|
||||
let tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
@ -481,6 +492,43 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
|
||||
let item_tooltip = ItemTooltip::new(
|
||||
{
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
},
|
||||
self.client,
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.pulse,
|
||||
self.msm,
|
||||
self.localized_strings,
|
||||
)
|
||||
.title_font_size(self.fonts.cyri.scale(20))
|
||||
.parent(ui.window)
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
|
||||
let slot_content = |slot| {
|
||||
content_source
|
||||
.0
|
||||
.get(slot)
|
||||
.and_then(|content| match content {
|
||||
hotbar::SlotContents::Inventory(i) => content_source.1.get(i),
|
||||
_ => None,
|
||||
})
|
||||
};
|
||||
|
||||
// Helper
|
||||
let tooltip_text = |slot| {
|
||||
content_source
|
||||
@ -542,8 +590,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::One, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.bottom_left_with_margins_on(state.ids.frame, 0.0, 0.0);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::One) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::One) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot1, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::One) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot1, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot1, ui);
|
||||
@ -553,8 +604,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Two, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot1, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Two) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Two) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot2, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Two) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot2, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot2, ui);
|
||||
@ -564,8 +618,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Three, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot2, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Three) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Three) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot3, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Three) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot3, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot3, ui);
|
||||
@ -575,8 +632,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Four, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot3, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Four) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Four) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot4, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Four) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot4, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot4, ui);
|
||||
@ -586,8 +646,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Five, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot4, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Five) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Five) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot5, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Five) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot5, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot5, ui);
|
||||
@ -690,8 +753,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Six, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.m2_slot_bg, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Six) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Six) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot6, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Six) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot6, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot6, ui);
|
||||
@ -701,8 +767,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Seven, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot6, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Seven) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Seven) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot7, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Seven) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot7, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot7, ui);
|
||||
@ -712,8 +781,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Eight, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot7, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Eight) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Eight) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot8, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Eight) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot8, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot8, ui);
|
||||
@ -723,8 +795,11 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.fabricate(hotbar::Slot::Nine, [40.0; 2])
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot8, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Nine) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
if let Some(item) = slot_content(hotbar::Slot::Nine) {
|
||||
slot.with_item_tooltip(self.item_tooltip_manager, item, None, &item_tooltip)
|
||||
.set(state.ids.slot9, ui);
|
||||
} else if let Some((title, desc)) = tooltip_text(hotbar::Slot::Nine) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot9, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot9, ui);
|
||||
@ -737,7 +812,7 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.filled_slot(self.imgs.skillbar_slot)
|
||||
.right_from(state.ids.slot9, slot_offset);
|
||||
if let Some((title, desc)) = tooltip_text(hotbar::Slot::Ten) {
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &item_tooltip, TEXT_COLOR)
|
||||
slot.with_tooltip(self.tooltip_manager, title, desc, &tooltip, TEXT_COLOR)
|
||||
.set(state.ids.slot10, ui);
|
||||
} else {
|
||||
slot.set(state.ids.slot10, ui);
|
||||
|
@ -1,5 +1,4 @@
|
||||
use super::{
|
||||
get_quality_col,
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
item_imgs::ItemImgs,
|
||||
slots::{SlotManager, TradeSlot},
|
||||
@ -11,7 +10,7 @@ use crate::{
|
||||
ui::{
|
||||
fonts::Fonts,
|
||||
slot::{ContentSize, SlotMaker},
|
||||
ImageFrame, Tooltip, TooltipManager, Tooltipable,
|
||||
ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable,
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
@ -63,7 +62,7 @@ pub struct Trade<'a> {
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
@ -79,7 +78,7 @@ impl<'a> Trade<'a> {
|
||||
item_imgs: &'a ItemImgs,
|
||||
fonts: &'a Fonts,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
item_tooltip_manager: &'a mut ItemTooltipManager,
|
||||
slot_manager: &'a mut SlotManager,
|
||||
localized_strings: &'a Localization,
|
||||
msm: &'a MaterialStatManifest,
|
||||
@ -91,7 +90,7 @@ impl<'a> Trade<'a> {
|
||||
item_imgs,
|
||||
fonts,
|
||||
rot_imgs,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
common: widget::CommonBuilder::default(),
|
||||
slot_manager,
|
||||
localized_strings,
|
||||
@ -264,19 +263,28 @@ impl<'a> Trade<'a> {
|
||||
prices: &'a Option<SitePrices>,
|
||||
tradeslots: &[TradeSlot],
|
||||
) {
|
||||
let item_tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
})
|
||||
.title_font_size(self.fonts.cyri.scale(15))
|
||||
// Tooltips
|
||||
let item_tooltip = ItemTooltip::new(
|
||||
{
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
},
|
||||
self.client,
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.pulse,
|
||||
self.msm,
|
||||
self.localized_strings,
|
||||
)
|
||||
.title_font_size(self.fonts.cyri.scale(20))
|
||||
.parent(ui.window)
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
@ -288,13 +296,12 @@ impl<'a> Trade<'a> {
|
||||
self.imgs,
|
||||
self.item_imgs,
|
||||
self.fonts,
|
||||
self.tooltip_manager,
|
||||
self.item_tooltip_manager,
|
||||
self.slot_manager,
|
||||
self.pulse,
|
||||
self.localized_strings,
|
||||
false,
|
||||
true,
|
||||
self.msm,
|
||||
false,
|
||||
&item_tooltip,
|
||||
name,
|
||||
@ -354,8 +361,6 @@ impl<'a> Trade<'a> {
|
||||
);
|
||||
let slot_id = state.ids.inv_slots[i + who * MAX_TRADE_SLOTS];
|
||||
if let Some(Some(item)) = slot.invslot.and_then(|slotid| inventory.slot(slotid)) {
|
||||
let (title, desc) = super::util::item_text(item, self.msm);
|
||||
let quality_col = get_quality_col(item);
|
||||
let quality_col_img = match item.quality() {
|
||||
Quality::Low => self.imgs.inv_slot_grey,
|
||||
Quality::Common => self.imgs.inv_slot,
|
||||
@ -366,17 +371,12 @@ impl<'a> Trade<'a> {
|
||||
Quality::Artifact => self.imgs.inv_slot_orange,
|
||||
_ => self.imgs.inv_slot_red,
|
||||
};
|
||||
let mut desc = desc.to_string();
|
||||
super::util::append_price_desc(&mut desc, prices, item.item_definition_id());
|
||||
let i18n = &self.localized_strings;
|
||||
|
||||
let prices_info = super::util::price_desc(prices, item.item_definition_id(), i18n);
|
||||
slot_widget
|
||||
.filled_slot(quality_col_img)
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&*desc,
|
||||
&item_tooltip,
|
||||
quality_col,
|
||||
)
|
||||
.with_item_tooltip(self.item_tooltip_manager, item, prices_info, &item_tooltip)
|
||||
.set(slot_id, ui);
|
||||
} else {
|
||||
slot_widget.set(slot_id, ui);
|
||||
|
@ -4,7 +4,7 @@ use common::{
|
||||
item::{
|
||||
armor::{Armor, ArmorKind, Protection},
|
||||
tool::{Hands, StatKind, Stats, Tool, ToolKind},
|
||||
Item, ItemDesc, ItemKind, MaterialStatManifest, ModularComponent,
|
||||
Item, ItemKind, MaterialStatManifest, ModularComponent,
|
||||
},
|
||||
BuffKind,
|
||||
},
|
||||
@ -13,75 +13,53 @@ use common::{
|
||||
};
|
||||
use std::{borrow::Cow, fmt::Write};
|
||||
|
||||
pub fn loadout_slot_text<'a>(
|
||||
item: Option<&'a impl ItemDesc>,
|
||||
mut empty: impl FnMut() -> (&'a str, &'a str),
|
||||
msm: &'a MaterialStatManifest,
|
||||
) -> (&'a str, Cow<'a, str>) {
|
||||
item.map_or_else(
|
||||
|| {
|
||||
let (title, desc) = empty();
|
||||
(title, Cow::Borrowed(desc))
|
||||
},
|
||||
|item| item_text(item, msm),
|
||||
)
|
||||
}
|
||||
use crate::i18n::Localization;
|
||||
|
||||
pub fn item_text<'a>(
|
||||
item: &'a impl ItemDesc,
|
||||
msm: &'a MaterialStatManifest,
|
||||
) -> (&'a str, Cow<'a, str>) {
|
||||
let desc: Cow<str> = match item.kind() {
|
||||
ItemKind::Armor(armor) => {
|
||||
Cow::Owned(armor_desc(armor, item.description(), item.num_slots()))
|
||||
},
|
||||
ItemKind::Tool(tool) => Cow::Owned(tool_desc(
|
||||
&tool,
|
||||
item.components(),
|
||||
&msm,
|
||||
item.description(),
|
||||
)),
|
||||
ItemKind::ModularComponent(mc) => Cow::Owned(modular_component_desc(
|
||||
mc,
|
||||
item.components(),
|
||||
&msm,
|
||||
item.description(),
|
||||
)),
|
||||
ItemKind::Glider(_glider) => Cow::Owned(glider_desc(item.description())),
|
||||
ItemKind::Consumable { effect, .. } => {
|
||||
Cow::Owned(consumable_desc(effect, item.description()))
|
||||
},
|
||||
ItemKind::Throwable { .. } => Cow::Owned(throwable_desc(item.description())),
|
||||
ItemKind::Utility { .. } => Cow::Owned(utility_desc(item.description())),
|
||||
ItemKind::Ingredient { .. } => Cow::Owned(ingredient_desc(
|
||||
item.description(),
|
||||
item.item_definition_id(),
|
||||
msm,
|
||||
)),
|
||||
ItemKind::Lantern { .. } => Cow::Owned(lantern_desc(item.description())),
|
||||
ItemKind::TagExamples { .. } => Cow::Borrowed(item.description()),
|
||||
//_ => Cow::Borrowed(item.description()),
|
||||
};
|
||||
|
||||
(item.name(), desc)
|
||||
}
|
||||
|
||||
pub fn append_price_desc(desc: &mut String, prices: &Option<SitePrices>, item_definition_id: &str) {
|
||||
pub fn price_desc(
|
||||
prices: &Option<SitePrices>,
|
||||
item_definition_id: &str,
|
||||
i18n: &Localization,
|
||||
) -> Option<String> {
|
||||
if let Some(prices) = prices {
|
||||
let (material, factor) = TradePricing::get_material(item_definition_id);
|
||||
let coinprice = prices.values.get(&Good::Coin).cloned().unwrap_or(1.0);
|
||||
let buyprice = prices.values.get(&material).cloned().unwrap_or_default() * factor;
|
||||
let sellprice = buyprice * material.trade_margin();
|
||||
*desc += &format!(
|
||||
"\n\nBuy price: {:0.1} coins\nSell price: {:0.1} coins",
|
||||
Some(format!(
|
||||
"{} : {:0.1} {}\n{} : {:0.1} {}",
|
||||
i18n.get("hud.trade.buy_price"),
|
||||
buyprice / coinprice,
|
||||
sellprice / coinprice
|
||||
);
|
||||
i18n.get("hud.trade.coin"),
|
||||
i18n.get("hud.trade.sell_price"),
|
||||
sellprice / coinprice,
|
||||
i18n.get("hud.trade.coin"),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: localization
|
||||
fn modular_component_desc(
|
||||
pub fn kind_text<'a>(kind: &ItemKind, i18n: &'a Localization) -> Cow<'a, str> {
|
||||
match kind {
|
||||
ItemKind::Armor(armor) => Cow::Borrowed(armor_kind(&armor, &i18n)),
|
||||
ItemKind::Tool(tool) => Cow::Owned(format!(
|
||||
"{} ({})",
|
||||
tool_kind(&tool, i18n),
|
||||
tool_hands(&tool, i18n)
|
||||
)),
|
||||
ItemKind::ModularComponent(_mc) => Cow::Borrowed(i18n.get("common.bag.shoulders")),
|
||||
ItemKind::Glider(_glider) => Cow::Borrowed(i18n.get("common.kind.glider")),
|
||||
ItemKind::Consumable { .. } => Cow::Borrowed(i18n.get("common.kind.consumable")),
|
||||
ItemKind::Throwable { .. } => Cow::Borrowed(i18n.get("common.kind.throwable")),
|
||||
ItemKind::Utility { .. } => Cow::Borrowed(i18n.get("common.kind.utility")),
|
||||
ItemKind::Ingredient { .. } => Cow::Borrowed(i18n.get("common.kind.ingredient")),
|
||||
ItemKind::Lantern { .. } => Cow::Borrowed(i18n.get("common.kind.lantern")),
|
||||
ItemKind::TagExamples { .. } => Cow::Borrowed(""),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: localization, refactor when mc are player facing
|
||||
pub fn modular_component_desc(
|
||||
mc: &ModularComponent,
|
||||
components: &[Item],
|
||||
msm: &MaterialStatManifest,
|
||||
@ -100,11 +78,9 @@ fn modular_component_desc(
|
||||
}
|
||||
result
|
||||
}
|
||||
fn glider_desc(desc: &str) -> String { format!("Glider\n\n{}\n\n<Right-Click to use>", desc) }
|
||||
|
||||
fn consumable_desc(effects: &[Effect], desc: &str) -> String {
|
||||
// TODO: localization
|
||||
let mut description = "Consumable".to_string();
|
||||
pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String {
|
||||
let mut description = String::new();
|
||||
|
||||
for effect in effects {
|
||||
if let Effect::Buff(buff) = effect {
|
||||
@ -113,34 +89,34 @@ fn consumable_desc(effects: &[Effect], desc: &str) -> String {
|
||||
let str_total = dur_secs.map_or(strength, |secs| strength * secs);
|
||||
|
||||
let buff_desc = match buff.kind {
|
||||
BuffKind::Saturation | BuffKind::Regeneration | BuffKind::Potion => {
|
||||
format!("Restores {} Health", str_total)
|
||||
},
|
||||
BuffKind::IncreaseMaxEnergy => {
|
||||
format!("Raises Maximum Stamina by {}", strength)
|
||||
},
|
||||
BuffKind::IncreaseMaxHealth => {
|
||||
format!("Raises Maximum Health by {}", strength)
|
||||
},
|
||||
BuffKind::Invulnerability => "Grants invulnerability".to_string(),
|
||||
BuffKind::Saturation | BuffKind::Regeneration | BuffKind::Potion => i18n
|
||||
.get("buff.stat.health")
|
||||
.replace("{str_total}", &str_total.to_string()),
|
||||
BuffKind::IncreaseMaxEnergy => i18n
|
||||
.get("buff.stat.increase_max_stamina")
|
||||
.replace("{strength}", &strength.to_string()),
|
||||
BuffKind::IncreaseMaxHealth => i18n
|
||||
.get("buff.stat.increase_max_health")
|
||||
.replace("{strength}", &strength.to_string()),
|
||||
BuffKind::Invulnerability => i18n.get("buff.stat.invulenrability").to_string(),
|
||||
BuffKind::Bleeding
|
||||
| BuffKind::CampfireHeal
|
||||
| BuffKind::Cursed
|
||||
| BuffKind::ProtectingWard => continue,
|
||||
};
|
||||
|
||||
write!(&mut description, "\n\n{}", buff_desc).unwrap();
|
||||
write!(&mut description, "{}", buff_desc).unwrap();
|
||||
|
||||
let dur_desc = if dur_secs.is_some() {
|
||||
let dur_desc = if let Some(dur_secs) = dur_secs {
|
||||
match buff.kind {
|
||||
BuffKind::Saturation | BuffKind::Regeneration => {
|
||||
format!("over {} seconds", dur_secs.unwrap())
|
||||
},
|
||||
BuffKind::Saturation | BuffKind::Regeneration => i18n
|
||||
.get("buff.text.over_seconds")
|
||||
.replace("{dur_secs}", &dur_secs.to_string()),
|
||||
BuffKind::IncreaseMaxEnergy
|
||||
| BuffKind::IncreaseMaxHealth
|
||||
| BuffKind::Invulnerability => {
|
||||
format!("for {} seconds", dur_secs.unwrap())
|
||||
},
|
||||
| BuffKind::Invulnerability => i18n
|
||||
.get("buff.text.for_seconds")
|
||||
.replace("{dur_secs}", &dur_secs.to_string()),
|
||||
BuffKind::Bleeding
|
||||
| BuffKind::Potion
|
||||
| BuffKind::CampfireHeal
|
||||
@ -148,7 +124,7 @@ fn consumable_desc(effects: &[Effect], desc: &str) -> String {
|
||||
| BuffKind::ProtectingWard => continue,
|
||||
}
|
||||
} else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind {
|
||||
"every second".to_string()
|
||||
i18n.get("buff.text.every_second").to_string()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
@ -157,119 +133,61 @@ fn consumable_desc(effects: &[Effect], desc: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
if !desc.is_empty() {
|
||||
write!(&mut description, "\n\n{}", desc).unwrap();
|
||||
}
|
||||
|
||||
write!(&mut description, "\n\n<Right-Click to use>").unwrap();
|
||||
description
|
||||
}
|
||||
|
||||
fn throwable_desc(desc: &str) -> String {
|
||||
format!("Can be thrown\n\n{}\n\n<Right-Click to use>", desc)
|
||||
}
|
||||
|
||||
fn utility_desc(desc: &str) -> String { format!("{}\n\n<Right-Click to use>", desc) }
|
||||
|
||||
fn ingredient_desc(desc: &str, item_id: &str, msm: &MaterialStatManifest) -> String {
|
||||
let mut result = format!("Crafting Ingredient\n\n{}", desc);
|
||||
if let Some(stats) = msm.0.get(item_id) {
|
||||
result += "\n\nStat multipliers:\n";
|
||||
result += &statblock_desc(stats);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn lantern_desc(desc: &str) -> String { format!("Lantern\n\n{}\n\n<Right-Click to use>", desc) }
|
||||
|
||||
fn armor_desc(armor: &Armor, desc: &str, slots: u16) -> String {
|
||||
// TODO: localization
|
||||
// Armor
|
||||
fn armor_kind<'a>(armor: &Armor, i18n: &'a Localization) -> &'a str {
|
||||
let kind = match armor.kind {
|
||||
ArmorKind::Shoulder(_) => "Shoulders",
|
||||
ArmorKind::Chest(_) => "Chest",
|
||||
ArmorKind::Belt(_) => "Belt",
|
||||
ArmorKind::Hand(_) => "Hands",
|
||||
ArmorKind::Pants(_) => "Legs",
|
||||
ArmorKind::Foot(_) => "Feet",
|
||||
ArmorKind::Back(_) => "Back",
|
||||
ArmorKind::Ring(_) => "Ring",
|
||||
ArmorKind::Neck(_) => "Neck",
|
||||
ArmorKind::Head(_) => "Head",
|
||||
ArmorKind::Tabard(_) => "Tabard",
|
||||
ArmorKind::Bag(_) => "Bag",
|
||||
ArmorKind::Shoulder(_) => i18n.get("hud.bag.shoulders"),
|
||||
ArmorKind::Chest(_) => i18n.get("hud.bag.chest"),
|
||||
ArmorKind::Belt(_) => i18n.get("hud.bag.belt"),
|
||||
ArmorKind::Hand(_) => i18n.get("hud.bag.hands"),
|
||||
ArmorKind::Pants(_) => i18n.get("hud.bag.legs"),
|
||||
ArmorKind::Foot(_) => i18n.get("hud.bag.feet"),
|
||||
ArmorKind::Back(_) => i18n.get("hud.bag.back"),
|
||||
ArmorKind::Ring(_) => i18n.get("hud.bag.ring"),
|
||||
ArmorKind::Neck(_) => i18n.get("hud.bag.neck"),
|
||||
ArmorKind::Head(_) => i18n.get("hud.bag.head"),
|
||||
ArmorKind::Tabard(_) => i18n.get("hud.bag.tabard"),
|
||||
ArmorKind::Bag(_) => i18n.get("hud.bag.bag"),
|
||||
};
|
||||
let armor_protection = match armor.get_protection() {
|
||||
Protection::Normal(a) => a.to_string(),
|
||||
Protection::Invincible => "Inf".to_string(),
|
||||
};
|
||||
let armor_poise_resilience = match armor.get_poise_resilience() {
|
||||
Protection::Normal(a) => a.to_string(),
|
||||
Protection::Invincible => "Inf".to_string(),
|
||||
};
|
||||
|
||||
let mut description = format!(
|
||||
"{}\n\nArmor: {}\n\nPoise Resilience: {}",
|
||||
kind, armor_protection, armor_poise_resilience
|
||||
);
|
||||
|
||||
if !desc.is_empty() {
|
||||
write!(&mut description, "\n\n{}", desc).unwrap();
|
||||
}
|
||||
|
||||
if slots > 0 {
|
||||
write!(&mut description, "\n\nSlots: {}", slots).unwrap();
|
||||
}
|
||||
|
||||
write!(&mut description, "\n\n<Right-Click to use>").unwrap();
|
||||
description
|
||||
kind
|
||||
}
|
||||
|
||||
fn tool_desc(tool: &Tool, components: &[Item], msm: &MaterialStatManifest, desc: &str) -> String {
|
||||
//Tool
|
||||
|
||||
fn tool_kind<'a>(tool: &Tool, i18n: &'a Localization) -> &'a str {
|
||||
let kind = match tool.kind {
|
||||
ToolKind::Sword => "Sword",
|
||||
ToolKind::Axe => "Axe",
|
||||
ToolKind::Hammer => "Hammer",
|
||||
ToolKind::Bow => "Bow",
|
||||
ToolKind::Dagger => "Dagger",
|
||||
ToolKind::Staff => "Staff",
|
||||
ToolKind::Sceptre => "Sceptre",
|
||||
ToolKind::Shield => "Shield",
|
||||
ToolKind::Spear => "Spear",
|
||||
ToolKind::HammerSimple => "HammerSimple",
|
||||
ToolKind::SwordSimple => "SwordSimple",
|
||||
ToolKind::StaffSimple => "StaffSimple",
|
||||
ToolKind::AxeSimple => "AxeSimple",
|
||||
ToolKind::BowSimple => "BowSimple",
|
||||
ToolKind::Unique(_) => "Unique",
|
||||
ToolKind::Debug => "Debug",
|
||||
ToolKind::Farming => "Farming Tool",
|
||||
ToolKind::Pick => "Pickaxe",
|
||||
ToolKind::Empty => "Empty",
|
||||
ToolKind::Sword => i18n.get("common.weapons.sword"),
|
||||
ToolKind::Axe => i18n.get("common.weapons.axe"),
|
||||
ToolKind::Hammer => i18n.get("common.weapons.hammer"),
|
||||
ToolKind::Bow => i18n.get("common.weapons.bow"),
|
||||
ToolKind::Dagger => i18n.get("common.weapons.dagger"),
|
||||
ToolKind::Staff => i18n.get("common.weapons.staff"),
|
||||
ToolKind::Sceptre => i18n.get("common.weapons.sceptre"),
|
||||
ToolKind::Shield => i18n.get("common.weapons.shield"),
|
||||
ToolKind::Spear => i18n.get("common.weapons.spear"),
|
||||
ToolKind::HammerSimple => i18n.get("common.weapons.hammer_simple"),
|
||||
ToolKind::SwordSimple => i18n.get("common.weapons.sword_simple"),
|
||||
ToolKind::StaffSimple => i18n.get("common.weapons.staff_simple"),
|
||||
ToolKind::AxeSimple => i18n.get("common.weapons.axe_simple"),
|
||||
ToolKind::BowSimple => i18n.get("common.weapons.bow_simple"),
|
||||
ToolKind::Unique(_) => i18n.get("common.weapons.unique_simple"),
|
||||
ToolKind::Debug => i18n.get("common.tool.debug"),
|
||||
ToolKind::Farming => i18n.get("common.tool.farming"),
|
||||
ToolKind::Pick => i18n.get("common.tool.pick"),
|
||||
ToolKind::Empty => i18n.get("common.empty"),
|
||||
};
|
||||
kind
|
||||
}
|
||||
|
||||
// Get tool stats
|
||||
let stats = tool.stats.resolve_stats(msm, components).clamp_speed();
|
||||
|
||||
pub fn tool_hands<'a>(tool: &Tool, i18n: &'a Localization) -> &'a str {
|
||||
let hands = match tool.hands {
|
||||
Hands::One => "One",
|
||||
Hands::Two => "Two",
|
||||
Hands::One => i18n.get("common.hands.one"),
|
||||
Hands::Two => i18n.get("common.hands.two"),
|
||||
};
|
||||
|
||||
let mut result = format!("{}-Handed {}\n\n", hands, kind);
|
||||
result += &statblock_desc(&stats);
|
||||
if !components.is_empty() {
|
||||
result += "Made from:\n";
|
||||
for component in components {
|
||||
result += component.name();
|
||||
result += "\n"
|
||||
}
|
||||
result += "\n";
|
||||
}
|
||||
if !desc.is_empty() {
|
||||
result += &format!("{}\n\n", desc);
|
||||
}
|
||||
result += "<Right-Click to use>";
|
||||
result
|
||||
hands
|
||||
}
|
||||
|
||||
fn statblock_desc(stats: &Stats) -> String {
|
||||
@ -285,87 +203,20 @@ fn statblock_desc(stats: &Stats) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_glider_desc() {
|
||||
let item_description = "mushrooms";
|
||||
|
||||
assert_eq!(
|
||||
"Glider\n\nmushrooms\n\n<Right-Click to use>",
|
||||
glider_desc(item_description)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_consumable_desc() {
|
||||
let item_description = "mushrooms";
|
||||
|
||||
assert_eq!(
|
||||
"Consumable\n\nmushrooms\n\n<Right-Click to use>",
|
||||
consumable_desc(&[], item_description)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_throwable_desc() {
|
||||
let item_description = "mushrooms";
|
||||
|
||||
assert_eq!(
|
||||
"Can be thrown\n\nmushrooms\n\n<Right-Click to use>",
|
||||
throwable_desc(item_description)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utility_desc() {
|
||||
let item_description = "mushrooms";
|
||||
|
||||
assert_eq!(
|
||||
"mushrooms\n\n<Right-Click to use>",
|
||||
utility_desc(item_description)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ingredient_desc() {
|
||||
let mut testmsm = MaterialStatManifest(hashbrown::HashMap::new());
|
||||
testmsm.0.insert(
|
||||
"common.items.crafting_ing.bronze_ingot".to_string(),
|
||||
Stats {
|
||||
equip_time_secs: 0.0,
|
||||
power: 3.0,
|
||||
poise_strength: 5.0,
|
||||
speed: 7.0,
|
||||
crit_chance: 0.5,
|
||||
crit_mult: 2.0,
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"Crafting Ingredient\n\nmushrooms",
|
||||
ingredient_desc("mushrooms", "common.items.food.mushroom", &testmsm)
|
||||
);
|
||||
assert_eq!(
|
||||
"Crafting Ingredient\n\nA bronze ingot.\n\nStat multipliers:\nPower: 30.0\n\nPoise \
|
||||
Strength: 50.0\n\nSpeed: 7.0\n\nCrit chance: 50.0%\n\nCrit damage: x2.0\n\n",
|
||||
ingredient_desc(
|
||||
"A bronze ingot.",
|
||||
"common.items.crafting_ing.bronze_ingot",
|
||||
&testmsm
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lantern_desc() {
|
||||
let item_description = "mushrooms";
|
||||
|
||||
assert_eq!(
|
||||
"Lantern\n\nmushrooms\n\n<Right-Click to use>",
|
||||
lantern_desc(item_description)
|
||||
);
|
||||
// Compare two type, output a colored character to show comparison
|
||||
pub fn comparison<T: PartialOrd>(first: T, other: T) -> (&'static str, conrod_core::Color) {
|
||||
if first == other {
|
||||
("•", conrod_core::color::GREY)
|
||||
} else if other < first {
|
||||
("▲", conrod_core::color::GREEN)
|
||||
} else {
|
||||
("▼", conrod_core::color::RED)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn protec2string(stat: Protection) -> String {
|
||||
match stat {
|
||||
Protection::Normal(a) => format!("{:.1}", a),
|
||||
Protection::Invincible => "Inf".to_string(),
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ pub use widgets::{
|
||||
image_frame::ImageFrame,
|
||||
image_slider::ImageSlider,
|
||||
ingame::{Ingame, Ingameable},
|
||||
item_tooltip::{ItemTooltip, ItemTooltipManager, ItemTooltipable},
|
||||
radio_list::RadioList,
|
||||
slot,
|
||||
toggle_button::ToggleButton,
|
||||
@ -124,6 +125,8 @@ pub struct Ui {
|
||||
scale: Scale,
|
||||
// Tooltips
|
||||
tooltip_manager: TooltipManager,
|
||||
// Item tooltips manager
|
||||
item_tooltip_manager: ItemTooltipManager,
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
@ -138,6 +141,14 @@ impl Ui {
|
||||
// to be updated, there's no reason to set the redraw count higher than
|
||||
// 1.
|
||||
ui.set_num_redraw_frames(1);
|
||||
|
||||
let item_tooltip_manager = ItemTooltipManager::new(
|
||||
ui.widget_id_generator(),
|
||||
Duration::from_millis(1),
|
||||
Duration::from_millis(0),
|
||||
scale.scale_factor_logical(),
|
||||
);
|
||||
|
||||
let tooltip_manager = TooltipManager::new(
|
||||
ui.widget_id_generator(),
|
||||
Duration::from_millis(1),
|
||||
@ -160,6 +171,7 @@ impl Ui {
|
||||
need_cache_resize: false,
|
||||
scale,
|
||||
tooltip_manager,
|
||||
item_tooltip_manager,
|
||||
})
|
||||
}
|
||||
|
||||
@ -223,8 +235,16 @@ impl Ui {
|
||||
|
||||
pub fn id_generator(&mut self) -> Generator { self.ui.widget_id_generator() }
|
||||
|
||||
pub fn set_widgets(&mut self) -> (UiCell, &mut TooltipManager) {
|
||||
(self.ui.set_widgets(), &mut self.tooltip_manager)
|
||||
pub fn set_widgets(&mut self) -> (UiCell, &mut ItemTooltipManager, &mut TooltipManager) {
|
||||
(
|
||||
self.ui.set_widgets(),
|
||||
&mut self.item_tooltip_manager,
|
||||
&mut self.tooltip_manager,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_item_widgets(&mut self) -> (UiCell, &mut ItemTooltipManager) {
|
||||
(self.ui.set_widgets(), &mut self.item_tooltip_manager)
|
||||
}
|
||||
|
||||
// Accepts Option so widget can be unfocused.
|
||||
@ -292,6 +312,10 @@ impl Ui {
|
||||
self.tooltip_manager
|
||||
.maintain(self.ui.global_input(), self.scale.scale_factor_logical());
|
||||
|
||||
// Maintain tooltip manager
|
||||
self.item_tooltip_manager
|
||||
.maintain(self.ui.global_input(), self.scale.scale_factor_logical());
|
||||
|
||||
// Handle scale factor changing
|
||||
let need_resize = if let Some(scale_factor) = self.scale_factor_changed.take() {
|
||||
self.scale.scale_factor_changed(scale_factor)
|
||||
|
990
voxygen/src/ui/widgets/item_tooltip.rs
Normal file
990
voxygen/src/ui/widgets/item_tooltip.rs
Normal file
@ -0,0 +1,990 @@
|
||||
use super::image_frame::ImageFrame;
|
||||
use crate::{
|
||||
hud::{
|
||||
get_quality_col,
|
||||
img_ids::Imgs,
|
||||
item_imgs::{animate_by_pulse, ItemImgs, ItemKey},
|
||||
util,
|
||||
},
|
||||
i18n::Localization,
|
||||
};
|
||||
use client::Client;
|
||||
use common::comp::item::{
|
||||
armor::Protection, Item, ItemDesc, ItemKind, MaterialStatManifest, Quality,
|
||||
};
|
||||
use conrod_core::{
|
||||
builder_method, builder_methods, image, input::global::Global, position::Dimension, text,
|
||||
widget, widget_ids, Color, Colorable, FontSize, Positionable, Scalar, Sizeable, Ui, UiCell,
|
||||
Widget, WidgetCommon, WidgetStyle,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Hover(widget::Id, [f64; 2]);
|
||||
#[derive(Copy, Clone)]
|
||||
enum HoverState {
|
||||
Hovering(Hover),
|
||||
Fading(Instant, Hover, Option<(Instant, widget::Id)>),
|
||||
Start(Instant, widget::Id),
|
||||
None,
|
||||
}
|
||||
|
||||
// Spacing between the tooltip and mouse
|
||||
const MOUSE_PAD_Y: f64 = 15.0;
|
||||
|
||||
pub struct ItemTooltipManager {
|
||||
tooltip_id: widget::Id,
|
||||
state: HoverState,
|
||||
// How long before a tooltip is displayed when hovering
|
||||
hover_dur: Duration,
|
||||
// How long it takes a tooltip to disappear
|
||||
fade_dur: Duration,
|
||||
// Current scaling of the ui
|
||||
logical_scale_factor: f64,
|
||||
}
|
||||
impl ItemTooltipManager {
|
||||
pub fn new(
|
||||
mut generator: widget::id::Generator,
|
||||
hover_dur: Duration,
|
||||
fade_dur: Duration,
|
||||
logical_scale_factor: f64,
|
||||
) -> Self {
|
||||
Self {
|
||||
tooltip_id: generator.next(),
|
||||
state: HoverState::None,
|
||||
hover_dur,
|
||||
fade_dur,
|
||||
logical_scale_factor,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, input: &Global, logical_scale_factor: f64) {
|
||||
self.logical_scale_factor = logical_scale_factor;
|
||||
|
||||
let current = &input.current;
|
||||
|
||||
if let Some(um_id) = current.widget_under_mouse {
|
||||
match self.state {
|
||||
HoverState::Hovering(hover) if um_id == hover.0 => (),
|
||||
HoverState::Hovering(hover) => {
|
||||
self.state =
|
||||
HoverState::Fading(Instant::now(), hover, Some((Instant::now(), um_id)))
|
||||
},
|
||||
HoverState::Fading(_, _, Some((_, id))) if um_id == id => {},
|
||||
HoverState::Fading(start, hover, _) => {
|
||||
self.state = HoverState::Fading(start, hover, Some((Instant::now(), um_id)))
|
||||
},
|
||||
HoverState::Start(_, id) if um_id == id => (),
|
||||
HoverState::Start(_, _) | HoverState::None => {
|
||||
self.state = HoverState::Start(Instant::now(), um_id)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match self.state {
|
||||
HoverState::Hovering(hover) => {
|
||||
self.state = HoverState::Fading(Instant::now(), hover, None)
|
||||
},
|
||||
HoverState::Fading(start, hover, Some((_, _))) => {
|
||||
self.state = HoverState::Fading(start, hover, None)
|
||||
},
|
||||
HoverState::Start(_, _) => self.state = HoverState::None,
|
||||
HoverState::Fading(_, _, None) | HoverState::None => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Handle fade timing
|
||||
if let HoverState::Fading(start, _, maybe_hover) = self.state {
|
||||
if start.elapsed() > self.fade_dur {
|
||||
self.state = match maybe_hover {
|
||||
Some((start, hover)) => HoverState::Start(start, hover),
|
||||
None => HoverState::None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
fn set_tooltip(
|
||||
&mut self,
|
||||
tooltip: &ItemTooltip,
|
||||
item: &dyn ItemDesc,
|
||||
extra: Option<String>,
|
||||
img_id: Option<image::Id>,
|
||||
image_dims: Option<(f64, f64)>,
|
||||
src_id: widget::Id,
|
||||
ui: &mut UiCell,
|
||||
) {
|
||||
let tooltip_id = self.tooltip_id;
|
||||
let mp_h = MOUSE_PAD_Y / self.logical_scale_factor;
|
||||
|
||||
let tooltip = |transparency, mouse_pos: [f64; 2], ui: &mut UiCell| {
|
||||
// Fill in text and the potential image beforehand to get an accurate size for
|
||||
// spacing
|
||||
let tooltip = tooltip
|
||||
.clone()
|
||||
.item(item)
|
||||
.extra(extra)
|
||||
.image(img_id)
|
||||
.image_dims(image_dims);
|
||||
|
||||
let [t_w, t_h] = tooltip.get_wh(ui).unwrap_or([0.0, 0.0]);
|
||||
let [m_x, m_y] = [mouse_pos[0], mouse_pos[1]];
|
||||
let (w_w, w_h) = (ui.win_w, ui.win_h);
|
||||
|
||||
// Determine position based on size and mouse position
|
||||
// Flow to the top left of the mouse when there is space
|
||||
let x = if (m_x + w_w / 2.0) > t_w {
|
||||
m_x - t_w / 2.0
|
||||
} else {
|
||||
m_x + t_w / 2.0
|
||||
};
|
||||
let y = if w_h - (m_y + w_h / 2.0) > t_h + mp_h {
|
||||
m_y + mp_h + t_h / 2.0
|
||||
} else {
|
||||
m_y - mp_h - t_h / 2.0
|
||||
};
|
||||
tooltip
|
||||
.floating(true)
|
||||
.transparency(transparency)
|
||||
.x_y(x, y)
|
||||
.set(tooltip_id, ui);
|
||||
};
|
||||
|
||||
match self.state {
|
||||
HoverState::Hovering(Hover(id, xy)) if id == src_id => tooltip(1.0, xy, ui),
|
||||
HoverState::Fading(start, Hover(id, xy), _) if id == src_id => tooltip(
|
||||
(0.1f32 - start.elapsed().as_millis() as f32 / self.hover_dur.as_millis() as f32)
|
||||
.max(0.0),
|
||||
xy,
|
||||
ui,
|
||||
),
|
||||
HoverState::Start(start, id) if id == src_id && start.elapsed() > self.hover_dur => {
|
||||
let xy = ui.global_input().current.mouse.xy;
|
||||
self.state = HoverState::Hovering(Hover(id, xy));
|
||||
tooltip(1.0, xy, ui);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemTooltipped<'a, W> {
|
||||
inner: W,
|
||||
tooltip_manager: &'a mut ItemTooltipManager,
|
||||
|
||||
item: &'a dyn ItemDesc,
|
||||
extra: Option<String>,
|
||||
img_id: Option<image::Id>,
|
||||
image_dims: Option<(f64, f64)>,
|
||||
tooltip: &'a ItemTooltip<'a>,
|
||||
}
|
||||
impl<'a, W: Widget> ItemTooltipped<'a, W> {
|
||||
pub fn tooltip_image(mut self, img_id: image::Id) -> Self {
|
||||
self.img_id = Some(img_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tooltip_image_dims(mut self, dims: (f64, f64)) -> Self {
|
||||
self.image_dims = Some(dims);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set(self, id: widget::Id, ui: &mut UiCell) -> W::Event {
|
||||
let event = self.inner.set(id, ui);
|
||||
self.tooltip_manager.set_tooltip(
|
||||
self.tooltip,
|
||||
self.item,
|
||||
self.extra,
|
||||
self.img_id,
|
||||
self.image_dims,
|
||||
id,
|
||||
ui,
|
||||
);
|
||||
event
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ItemTooltipable {
|
||||
// If `Tooltip` is expensive to construct accept a closure here instead.
|
||||
fn with_item_tooltip<'a>(
|
||||
self,
|
||||
tooltip_manager: &'a mut ItemTooltipManager,
|
||||
|
||||
item: &'a dyn ItemDesc,
|
||||
|
||||
extra: Option<String>,
|
||||
|
||||
tooltip: &'a ItemTooltip<'a>,
|
||||
) -> ItemTooltipped<'a, Self>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
}
|
||||
impl<W: Widget> ItemTooltipable for W {
|
||||
fn with_item_tooltip<'a>(
|
||||
self,
|
||||
tooltip_manager: &'a mut ItemTooltipManager,
|
||||
item: &'a dyn ItemDesc,
|
||||
extra: Option<String>,
|
||||
tooltip: &'a ItemTooltip<'a>,
|
||||
) -> ItemTooltipped<'a, W> {
|
||||
ItemTooltipped {
|
||||
inner: self,
|
||||
tooltip_manager,
|
||||
item,
|
||||
extra,
|
||||
img_id: None,
|
||||
image_dims: None,
|
||||
tooltip,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Vertical spacing between elements of the tooltip
|
||||
const V_PAD: f64 = 10.0;
|
||||
/// Horizontal spacing between elements of the tooltip
|
||||
const H_PAD: f64 = 10.0;
|
||||
/// Vertical spacing between stats
|
||||
const V_PAD_STATS: f64 = 6.0;
|
||||
/// Default portion of inner width that goes to an image
|
||||
const IMAGE_W_FRAC: f64 = 0.3;
|
||||
// Item icon size
|
||||
const ICON_SIZE: [f64; 2] = [64.0, 64.0];
|
||||
|
||||
/// A widget for displaying tooltips
|
||||
#[derive(Clone, WidgetCommon)]
|
||||
pub struct ItemTooltip<'a> {
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
item: &'a dyn ItemDesc,
|
||||
msm: &'a MaterialStatManifest,
|
||||
extra: Option<String>,
|
||||
image: Option<image::Id>,
|
||||
image_dims: Option<(f64, f64)>,
|
||||
style: Style,
|
||||
transparency: f32,
|
||||
image_frame: ImageFrame,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, WidgetStyle)]
|
||||
pub struct Style {
|
||||
#[conrod(default = "Color::Rgba(1.0, 1.0, 1.0, 1.0)")]
|
||||
pub color: Option<Color>,
|
||||
title: widget::text::Style,
|
||||
desc: widget::text::Style,
|
||||
// add background imgs here
|
||||
}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
title,
|
||||
subtitle,
|
||||
desc,
|
||||
extra,
|
||||
main_stat,
|
||||
main_stat_text,
|
||||
stats[],
|
||||
diff_main_stat,
|
||||
diffs[],
|
||||
item_frame,
|
||||
item_render,
|
||||
image_frame,
|
||||
image,
|
||||
background,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref EMPTY_ITEM: Item = Item::new_from_asset_expect("common.items.weapons.empty.empty");
|
||||
}
|
||||
|
||||
impl<'a> ItemTooltip<'a> {
|
||||
builder_methods! {
|
||||
pub desc_text_color { style.desc.color = Some(Color) }
|
||||
pub title_font_size { style.title.font_size = Some(FontSize) }
|
||||
pub desc_font_size { style.desc.font_size = Some(FontSize) }
|
||||
pub title_justify { style.title.justify = Some(text::Justify) }
|
||||
pub desc_justify { style.desc.justify = Some(text::Justify) }
|
||||
pub title_line_spacing { style.title.line_spacing = Some(Scalar) }
|
||||
pub desc_line_spacing { style.desc.line_spacing = Some(Scalar) }
|
||||
image { image = Option<image::Id> }
|
||||
item { item = &'a dyn ItemDesc }
|
||||
extra { extra = Option<String> }
|
||||
msm { msm = &'a MaterialStatManifest }
|
||||
image_dims { image_dims = Option<(f64, f64)> }
|
||||
transparency { transparency = f32 }
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
image_frame: ImageFrame,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
item_imgs: &'a ItemImgs,
|
||||
pulse: f32,
|
||||
msm: &'a MaterialStatManifest,
|
||||
localized_strings: &'a Localization,
|
||||
) -> Self {
|
||||
ItemTooltip {
|
||||
common: widget::CommonBuilder::default(),
|
||||
style: Style::default(),
|
||||
item: &*EMPTY_ITEM,
|
||||
msm,
|
||||
extra: None,
|
||||
transparency: 1.0,
|
||||
image_frame,
|
||||
image: None,
|
||||
image_dims: None,
|
||||
client: &client,
|
||||
imgs: &imgs,
|
||||
item_imgs: &item_imgs,
|
||||
pulse,
|
||||
localized_strings,
|
||||
}
|
||||
}
|
||||
|
||||
/// Align the text to the left of its bounding **Rect**'s *x* axis range.
|
||||
//pub fn left_justify(self) -> Self {
|
||||
// self.justify(text::Justify::Left)
|
||||
//}
|
||||
|
||||
/// Align the text to the middle of its bounding **Rect**'s *x* axis range.
|
||||
//pub fn center_justify(self) -> Self {
|
||||
// self.justify(text::Justify::Center)
|
||||
//}
|
||||
|
||||
/// Align the text to the right of its bounding **Rect**'s *x* axis range.
|
||||
//pub fn right_justify(self) -> Self {
|
||||
// self.justify(text::Justify::Right)
|
||||
//}
|
||||
|
||||
fn text_image_width(&self, total_width: f64) -> (f64, f64) {
|
||||
let inner_width = (total_width - H_PAD * 2.0).max(0.0);
|
||||
// Image defaults to 30% of the width
|
||||
let image_w = if self.image.is_some() {
|
||||
match self.image_dims {
|
||||
Some((w, _)) => w,
|
||||
None => (inner_width - H_PAD).max(0.0) * IMAGE_W_FRAC,
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// Text gets the remaining width
|
||||
let text_w = (inner_width
|
||||
- if self.image.is_some() {
|
||||
image_w + H_PAD
|
||||
} else {
|
||||
0.0
|
||||
})
|
||||
.max(0.0);
|
||||
|
||||
(text_w, image_w)
|
||||
}
|
||||
|
||||
/// Specify the font used for displaying the text.
|
||||
pub fn font_id(mut self, font_id: text::font::Id) -> Self {
|
||||
self.style.title.font_id = Some(Some(font_id));
|
||||
self.style.desc.font_id = Some(Some(font_id));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for ItemTooltip<'a> {
|
||||
type Event = ();
|
||||
type State = State;
|
||||
type Style = Style;
|
||||
|
||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style { self.style.clone() }
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) {
|
||||
let widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
rect,
|
||||
ui,
|
||||
..
|
||||
} = args;
|
||||
|
||||
fn stats_count(item: &dyn ItemDesc) -> usize {
|
||||
let mut count = match item.kind() {
|
||||
ItemKind::Armor(_) => 1,
|
||||
ItemKind::Tool(_) => 5,
|
||||
ItemKind::Consumable { .. } => 1,
|
||||
_ => 0,
|
||||
};
|
||||
if item.num_slots() != 0 {
|
||||
count += 1
|
||||
}
|
||||
count as usize
|
||||
}
|
||||
|
||||
let i18n = &self.localized_strings;
|
||||
|
||||
let inventories = self.client.inventories();
|
||||
let inventory = match inventories.get(self.client.entity()) {
|
||||
Some(l) => l,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let item = self.item;
|
||||
|
||||
let quality = get_quality_col(item);
|
||||
|
||||
let equip_slot = inventory.equipped_items_of_kind(item.kind().clone());
|
||||
|
||||
let (title, desc) = (item.name().to_string(), item.description().to_string());
|
||||
|
||||
let subtitle = util::kind_text(item.kind(), i18n);
|
||||
|
||||
let text_color = conrod_core::color::WHITE;
|
||||
|
||||
// Widths
|
||||
let (text_w, image_w) = self.text_image_width(rect.w());
|
||||
|
||||
// Color quality
|
||||
let quality_col_img = match &item.quality() {
|
||||
Quality::Low => self.imgs.inv_slot_grey,
|
||||
Quality::Common => self.imgs.inv_slot,
|
||||
Quality::Moderate => self.imgs.inv_slot_green,
|
||||
Quality::High => self.imgs.inv_slot_blue,
|
||||
Quality::Epic => self.imgs.inv_slot_purple,
|
||||
Quality::Legendary => self.imgs.inv_slot_gold,
|
||||
Quality::Artifact => self.imgs.inv_slot_orange,
|
||||
_ => self.imgs.inv_slot_red,
|
||||
};
|
||||
|
||||
// Update windget array size
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.stats
|
||||
.resize(stats_count(item), &mut ui.widget_id_generator())
|
||||
});
|
||||
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.diffs
|
||||
.resize(stats_count(item), &mut ui.widget_id_generator())
|
||||
});
|
||||
|
||||
// Background image frame
|
||||
self.image_frame
|
||||
.wh(rect.dim())
|
||||
.xy(rect.xy())
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.color(quality)
|
||||
.set(state.ids.image_frame, ui);
|
||||
|
||||
// Image
|
||||
if let Some(img_id) = self.image {
|
||||
widget::Image::new(img_id)
|
||||
.w_h(image_w, self.image_dims.map_or(image_w, |(_, h)| h))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.color(Some(quality))
|
||||
.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
||||
.set(state.ids.image, ui);
|
||||
}
|
||||
|
||||
// Title
|
||||
widget::Text::new(&title)
|
||||
.w(text_w)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.title)
|
||||
.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
||||
.center_justify()
|
||||
.color(quality)
|
||||
.set(state.ids.title, ui);
|
||||
|
||||
// Item frame
|
||||
widget::Image::new(quality_col_img)
|
||||
.wh(ICON_SIZE)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.top_left_with_margins_on(state.ids.image_frame, V_PAD, H_PAD)
|
||||
.down_from(state.ids.title, V_PAD)
|
||||
.set(state.ids.item_frame, ui);
|
||||
|
||||
// Item render
|
||||
widget::Image::new(animate_by_pulse(
|
||||
&self
|
||||
.item_imgs
|
||||
.img_ids_or_not_found_img(ItemKey::from(&item)),
|
||||
self.pulse,
|
||||
))
|
||||
.color(Some(conrod_core::color::WHITE))
|
||||
.w_h(ICON_SIZE[0] * 0.8, ICON_SIZE[1] * 0.8)
|
||||
.middle_of(state.ids.item_frame)
|
||||
.set(state.ids.item_render, ui);
|
||||
|
||||
// Subtitle
|
||||
widget::Text::new(&subtitle)
|
||||
.w(text_w)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(conrod_core::color::GREY)
|
||||
.right_from(state.ids.item_frame, H_PAD)
|
||||
.set(state.ids.subtitle, ui);
|
||||
|
||||
// Stats
|
||||
match item.kind() {
|
||||
ItemKind::Tool(tool) => {
|
||||
let power = tool.base_power(self.msm, item.components()) * 10.0;
|
||||
let speed = tool.base_speed(self.msm, item.components());
|
||||
let poise_str = tool.base_poise_strength(self.msm, item.components()) * 10.0;
|
||||
let crit_chance = tool.base_crit_chance(self.msm, item.components()) * 100.0;
|
||||
let crit_mult = tool.base_crit_mult(self.msm, item.components());
|
||||
let dps = power * speed;
|
||||
|
||||
// DPS
|
||||
widget::Text::new(&format!("{:.1}", dps))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.font_size(34)
|
||||
.align_middle_y_of(state.ids.item_frame)
|
||||
.right_from(state.ids.item_frame, H_PAD)
|
||||
.set(state.ids.main_stat, ui);
|
||||
|
||||
widget::Text::new(i18n.get("common.stats.dps"))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.align_bottom_of(state.ids.main_stat)
|
||||
.right_from(state.ids.main_stat, H_PAD)
|
||||
.set(state.ids.main_stat_text, ui);
|
||||
|
||||
// Power
|
||||
widget::Text::new(&format!(
|
||||
"{} : {:.1}",
|
||||
i18n.get("common.stats.power"),
|
||||
power
|
||||
))
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.item_frame, V_PAD)
|
||||
.set(state.ids.stats[0], ui);
|
||||
|
||||
// Speed
|
||||
widget::Text::new(&format!(
|
||||
"{} : {:.1}",
|
||||
i18n.get("common.stats.speed"),
|
||||
speed
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.stats[0], V_PAD_STATS)
|
||||
.set(state.ids.stats[1], ui);
|
||||
|
||||
// Poise
|
||||
widget::Text::new(&format!(
|
||||
"{} : {:.1}",
|
||||
i18n.get("common.stats.poise"),
|
||||
poise_str
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.stats[1], V_PAD_STATS)
|
||||
.set(state.ids.stats[2], ui);
|
||||
|
||||
// Crit chance
|
||||
widget::Text::new(&format!(
|
||||
"{} : {:.1}%",
|
||||
i18n.get("common.stats.crit_chance"),
|
||||
crit_chance
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.stats[2], V_PAD_STATS)
|
||||
.set(state.ids.stats[3], ui);
|
||||
|
||||
// Crit mult
|
||||
widget::Text::new(&format!(
|
||||
"{} : x{:.1}",
|
||||
i18n.get("common.stats.crit_mult"),
|
||||
crit_mult
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.stats[3], V_PAD_STATS)
|
||||
.set(state.ids.stats[4], ui);
|
||||
if let Some(equipped_item) = equip_slot.cloned().next() {
|
||||
if let ItemKind::Tool(equipped_tool) = equipped_item.kind() {
|
||||
let tool_stats = tool
|
||||
.stats
|
||||
.resolve_stats(self.msm, item.components())
|
||||
.clamp_speed();
|
||||
let equipped_tool_stats = equipped_tool
|
||||
.stats
|
||||
.resolve_stats(self.msm, equipped_item.components())
|
||||
.clamp_speed();
|
||||
let diff = tool_stats - equipped_tool_stats;
|
||||
let power_diff =
|
||||
util::comparison(tool_stats.power, equipped_tool_stats.power);
|
||||
let speed_diff =
|
||||
util::comparison(tool_stats.speed, equipped_tool_stats.speed);
|
||||
let poise_strength_diff = util::comparison(
|
||||
tool_stats.poise_strength,
|
||||
equipped_tool_stats.poise_strength,
|
||||
);
|
||||
let crit_chance_diff = util::comparison(
|
||||
tool_stats.crit_chance,
|
||||
equipped_tool_stats.crit_chance,
|
||||
);
|
||||
let crit_mult_diff =
|
||||
util::comparison(tool_stats.crit_mult, equipped_tool_stats.crit_mult);
|
||||
let equipped_dps =
|
||||
equipped_tool_stats.power * equipped_tool_stats.speed * 10.0;
|
||||
let diff_main_stat = util::comparison(dps, equipped_dps);
|
||||
|
||||
if equipped_dps - dps != 0.0 {
|
||||
widget::Text::new(&diff_main_stat.0)
|
||||
.right_from(state.ids.main_stat_text, H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(diff_main_stat.1)
|
||||
.set(state.ids.diff_main_stat, ui);
|
||||
}
|
||||
|
||||
if diff.power != 0.0 {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&power_diff.0,
|
||||
&diff.power * 10.0
|
||||
))
|
||||
.align_middle_y_of(state.ids.stats[0])
|
||||
.right_from(state.ids.stats[0], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(power_diff.1)
|
||||
.set(state.ids.diffs[0], ui);
|
||||
}
|
||||
if diff.speed != 0.0 {
|
||||
widget::Text::new(&format!("{} {:.1}", &speed_diff.0, &diff.speed))
|
||||
.align_middle_y_of(state.ids.stats[1])
|
||||
.right_from(state.ids.stats[1], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(speed_diff.1)
|
||||
.set(state.ids.diffs[1], ui);
|
||||
}
|
||||
if diff.poise_strength != 0.0 {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&poise_strength_diff.0,
|
||||
&diff.poise_strength * 10.0
|
||||
))
|
||||
.align_middle_y_of(state.ids.stats[2])
|
||||
.right_from(state.ids.stats[2], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(poise_strength_diff.1)
|
||||
.set(state.ids.diffs[2], ui);
|
||||
}
|
||||
if diff.crit_chance != 0.0 {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}%",
|
||||
&crit_chance_diff.0,
|
||||
&diff.crit_chance * 100.0
|
||||
))
|
||||
.align_middle_y_of(state.ids.stats[3])
|
||||
.right_from(state.ids.stats[3], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(crit_chance_diff.1)
|
||||
.set(state.ids.diffs[3], ui);
|
||||
}
|
||||
if diff.crit_mult != 0.0 {
|
||||
widget::Text::new(&format!(
|
||||
"{} {:.1}",
|
||||
&crit_mult_diff.0, &diff.crit_mult
|
||||
))
|
||||
.align_middle_y_of(state.ids.stats[4])
|
||||
.right_from(state.ids.stats[4], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(crit_mult_diff.1)
|
||||
.set(state.ids.diffs[4], ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ItemKind::Armor(armor) => {
|
||||
let protection = armor.get_protection();
|
||||
let poise_res = armor.get_poise_resilience();
|
||||
|
||||
// Armour
|
||||
widget::Text::new(&util::protec2string(protection))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.font_size(34)
|
||||
.align_middle_y_of(state.ids.item_frame)
|
||||
.right_from(state.ids.item_frame, H_PAD)
|
||||
.set(state.ids.main_stat, ui);
|
||||
|
||||
widget::Text::new(i18n.get("common.stats.armor"))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.align_bottom_of(state.ids.main_stat)
|
||||
.right_from(state.ids.main_stat, H_PAD)
|
||||
.set(state.ids.main_stat_text, ui);
|
||||
|
||||
// Poise res
|
||||
widget::Text::new(&format!(
|
||||
"{} : {}",
|
||||
i18n.get("common.stats.poise_res"),
|
||||
util::protec2string(poise_res)
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.down_from(state.ids.item_frame, V_PAD)
|
||||
.set(state.ids.stats[0], ui);
|
||||
|
||||
// Slots
|
||||
if item.num_slots() > 0 {
|
||||
widget::Text::new(&format!(
|
||||
"{} : {}",
|
||||
i18n.get("common.stats.slots"),
|
||||
item.num_slots()
|
||||
))
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.down_from(state.ids.stats[0], V_PAD_STATS)
|
||||
.set(state.ids.stats[1], ui);
|
||||
}
|
||||
|
||||
if let Some(equipped_item) = equip_slot.cloned().next() {
|
||||
if let ItemKind::Armor(equipped_armor) = equipped_item.kind() {
|
||||
let diff = armor.stats - equipped_armor.stats;
|
||||
let protection_diff = util::comparison(
|
||||
&armor.get_protection(),
|
||||
&equipped_armor.get_protection(),
|
||||
);
|
||||
let poise_res_diff = util::comparison(
|
||||
&armor.get_poise_resilience(),
|
||||
&equipped_armor.get_poise_resilience(),
|
||||
);
|
||||
|
||||
if diff.get_protection() != Protection::Normal(0.0) {
|
||||
widget::Text::new(&protection_diff.0)
|
||||
.right_from(state.ids.main_stat_text, H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(protection_diff.1)
|
||||
.set(state.ids.diff_main_stat, ui);
|
||||
}
|
||||
|
||||
if diff.get_poise_resilience() != Protection::Normal(0.0) {
|
||||
widget::Text::new(&format!(
|
||||
"{} {}",
|
||||
&poise_res_diff.0,
|
||||
util::protec2string(diff.get_poise_resilience())
|
||||
))
|
||||
.align_middle_y_of(state.ids.stats[0])
|
||||
.right_from(state.ids.stats[0], H_PAD)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(poise_res_diff.1)
|
||||
.set(state.ids.diffs[0], ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ItemKind::Consumable { effect, .. } => {
|
||||
widget::Text::new(&util::consumable_desc(effect, i18n))
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.item_frame, V_PAD)
|
||||
.set(state.ids.stats[0], ui);
|
||||
},
|
||||
ItemKind::ModularComponent(mc) => {
|
||||
widget::Text::new(&util::modular_component_desc(
|
||||
mc,
|
||||
item.components(),
|
||||
&self.msm,
|
||||
item.description(),
|
||||
))
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(text_color)
|
||||
.down_from(state.ids.item_frame, V_PAD)
|
||||
.set(state.ids.stats[0], ui);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// Description
|
||||
if !desc.is_empty() {
|
||||
widget::Text::new(&format!("\"{}\"", &desc))
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.color(conrod_core::color::GREY)
|
||||
.down_from(
|
||||
if stats_count(item) > 0 {
|
||||
state.ids.stats[state.ids.stats.len() - 1]
|
||||
} else {
|
||||
state.ids.item_frame
|
||||
},
|
||||
V_PAD,
|
||||
)
|
||||
.w(text_w)
|
||||
.set(state.ids.desc, ui);
|
||||
}
|
||||
|
||||
// Extra text
|
||||
if let Some(extra) = self.extra {
|
||||
widget::Text::new(&extra)
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.with_style(self.style.desc)
|
||||
.down_from(
|
||||
if !desc.is_empty() {
|
||||
state.ids.desc
|
||||
} else if stats_count(item) > 0 {
|
||||
state.ids.stats[state.ids.stats.len() - 1]
|
||||
} else {
|
||||
state.ids.item_frame
|
||||
},
|
||||
V_PAD,
|
||||
)
|
||||
.w(text_w)
|
||||
.set(state.ids.extra, ui);
|
||||
}
|
||||
}
|
||||
|
||||
/// Default width is based on the description font size unless the text is
|
||||
/// small enough to fit on a single line
|
||||
fn default_x_dimension(&self, _ui: &Ui) -> Dimension { Dimension::Absolute(260.0) }
|
||||
|
||||
fn default_y_dimension(&self, ui: &Ui) -> Dimension {
|
||||
fn stats_count(item: &dyn ItemDesc) -> usize {
|
||||
let mut count = match item.kind() {
|
||||
ItemKind::Armor(_) => 1,
|
||||
ItemKind::Tool(_) => 5,
|
||||
ItemKind::Consumable { .. } => 1,
|
||||
ItemKind::ModularComponent { .. } => 1,
|
||||
_ => 0,
|
||||
};
|
||||
if item.num_slots() != 0 {
|
||||
count += 1
|
||||
}
|
||||
count as usize
|
||||
}
|
||||
|
||||
let item = &self.item;
|
||||
|
||||
let (title, desc) = (item.name().to_string(), item.description().to_string());
|
||||
|
||||
let (text_w, _image_w) = self.text_image_width(260.0);
|
||||
|
||||
// Title
|
||||
let title_h = widget::Text::new(&title)
|
||||
.w(text_w)
|
||||
.with_style(self.style.title)
|
||||
.get_h(ui)
|
||||
.unwrap_or(0.0)
|
||||
+ V_PAD;
|
||||
|
||||
// Item frame
|
||||
let frame_h = ICON_SIZE[1] + V_PAD;
|
||||
|
||||
// Stats
|
||||
let stat_h = if stats_count(self.item) > 0 {
|
||||
widget::Text::new(&"placeholder".to_string())
|
||||
.with_style(self.style.desc)
|
||||
.get_h(ui)
|
||||
.unwrap_or(0.0)
|
||||
* stats_count(self.item) as f64
|
||||
+ (stats_count(self.item) - 1) as f64 * V_PAD_STATS
|
||||
+ V_PAD
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// Description
|
||||
let desc_h: f64 = if !desc.is_empty() {
|
||||
widget::Text::new(&format!("\"{}\"", &desc))
|
||||
.with_style(self.style.desc)
|
||||
.w(text_w)
|
||||
.get_h(ui)
|
||||
.unwrap_or(0.0)
|
||||
+ V_PAD
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// Price
|
||||
let price_h: f64 = if let Some(extra) = &self.extra {
|
||||
widget::Text::new(&extra)
|
||||
.with_style(self.style.desc)
|
||||
.w(text_w)
|
||||
.get_h(ui)
|
||||
.unwrap_or(0.0)
|
||||
+ V_PAD
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let height = title_h + frame_h + stat_h + desc_h + price_h + V_PAD + 5.0; // extra padding to fit frame top padding
|
||||
Dimension::Absolute(height)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Colorable for ItemTooltip<'a> {
|
||||
builder_method!(color { style.color = Some(Color) });
|
||||
}
|
@ -2,6 +2,7 @@ pub mod ghost_image;
|
||||
pub mod image_frame;
|
||||
pub mod image_slider;
|
||||
pub mod ingame;
|
||||
pub mod item_tooltip;
|
||||
pub mod radio_list;
|
||||
pub mod slot;
|
||||
pub mod toggle_button;
|
||||
|
Loading…
Reference in New Issue
Block a user