veloren/voxygen/src/hud/util.rs

418 lines
18 KiB
Rust
Raw Normal View History

use super::img_ids;
2021-02-25 16:25:39 +00:00
use common::{
comp::{
inventory::trade_pricing::TradePricing,
2021-02-25 16:25:39 +00:00
item::{
armor::{Armor, ArmorKind, Protection},
2022-03-19 19:18:38 +00:00
tool::{Hands, Tool, ToolKind},
2022-07-02 16:20:10 +00:00
ItemDefinitionId, ItemDesc, ItemKind, MaterialKind, MaterialStatManifest,
2021-02-25 16:25:39 +00:00
},
BuffKind,
},
effect::Effect,
trade::{Good, SitePrices},
};
use conrod_core::image;
2022-08-26 14:56:32 +00:00
use i18n::{fluent_args, Localization};
2021-03-28 12:27:59 +00:00
use std::{borrow::Cow, fmt::Write};
2022-08-26 14:56:32 +00:00
pub fn price_desc<'a>(
2021-03-24 22:17:25 +00:00
prices: &Option<SitePrices>,
2022-07-02 16:20:10 +00:00
item_definition_id: ItemDefinitionId<'_>,
2022-08-26 14:56:32 +00:00
i18n: &'a Localization,
) -> Option<(Cow<'a, str>, Cow<'a, str>, f32)> {
let prices = prices.as_ref()?;
let materials = TradePricing::get_materials(&item_definition_id)?;
let coinprice = prices.values.get(&Good::Coin).cloned().unwrap_or(1.0);
let buyprice: f32 = materials
.iter()
.map(|e| prices.values.get(&e.1).cloned().unwrap_or_default() * e.0)
.sum();
let sellprice: f32 = materials
.iter()
.map(|e| prices.values.get(&e.1).cloned().unwrap_or_default() * e.0 * e.1.trade_margin())
.sum();
let deal_goodness: f32 = materials
.iter()
.map(|e| prices.values.get(&e.1).cloned().unwrap_or(0.0))
.sum::<f32>()
/ prices.values.get(&Good::Coin).cloned().unwrap_or(1.0)
/ (materials.len() as f32);
let deal_goodness = deal_goodness.log(2.0);
let buy_string = i18n.get_msg_ctx("hud-trade-buy", &fluent_args! {
"coin_num" => buyprice / coinprice,
"coin_formatted" => format!("{:0.1}", buyprice / coinprice),
});
let sell_string = i18n.get_msg_ctx("hud-trade-sell", &fluent_args! {
"coin_num" => sellprice / coinprice,
"coin_formatted" => format!("{:0.1}", sellprice / coinprice),
});
let deal_goodness = match deal_goodness {
x if x < -2.5 => 0.0,
x if x < -1.05 => 0.25,
x if x < -0.95 => 0.5,
x if x < 0.0 => 0.75,
_ => 1.0,
};
Some((buy_string, sell_string, deal_goodness))
}
pub fn kind_text<'a>(kind: &ItemKind, i18n: &'a Localization) -> Cow<'a, str> {
match kind {
2022-08-06 17:47:45 +00:00
ItemKind::Armor(armor) => armor_kind(armor, i18n),
2021-03-28 12:27:59 +00:00
ItemKind::Tool(tool) => Cow::Owned(format!(
"{} ({})",
2021-07-11 18:41:52 +00:00
tool_kind(tool, i18n),
tool_hands(tool, i18n)
2021-03-28 12:27:59 +00:00
)),
2022-03-19 19:18:38 +00:00
ItemKind::ModularComponent(mc) => {
if let Some(toolkind) = mc.toolkind() {
Cow::Owned(format!(
"{} {}",
2022-08-23 09:17:21 +00:00
i18n.get_msg(&format!("common-weapons-{}", toolkind.identifier_name())),
i18n.get_msg("common-kind-modular_component_partial")
2022-03-19 19:18:38 +00:00
))
} else {
2022-08-23 09:17:21 +00:00
i18n.get_msg("common-kind-modular_component")
2022-03-19 19:18:38 +00:00
}
},
2022-08-23 09:17:21 +00:00
ItemKind::Glider => i18n.get_msg("common-kind-glider"),
ItemKind::Consumable { .. } => i18n.get_msg("common-kind-consumable"),
ItemKind::Throwable { .. } => i18n.get_msg("common-kind-throwable"),
ItemKind::Utility { .. } => i18n.get_msg("common-kind-utility"),
ItemKind::Ingredient { .. } => i18n.get_msg("common-kind-ingredient"),
ItemKind::Lantern { .. } => i18n.get_msg("common-kind-lantern"),
2021-03-28 12:27:59 +00:00
ItemKind::TagExamples { .. } => Cow::Borrowed(""),
2021-03-02 00:45:02 +00:00
}
}
2022-08-06 17:47:45 +00:00
pub fn material_kind_text<'a>(kind: &MaterialKind, i18n: &'a Localization) -> Cow<'a, str> {
2021-05-26 00:12:43 +00:00
match kind {
2022-08-23 09:17:21 +00:00
MaterialKind::Metal { .. } => i18n.get_msg("common-material-metal"),
MaterialKind::Wood { .. } => i18n.get_msg("common-material-wood"),
MaterialKind::Stone { .. } => i18n.get_msg("common-material-stone"),
MaterialKind::Cloth { .. } => i18n.get_msg("common-material-cloth"),
MaterialKind::Hide { .. } => i18n.get_msg("common-material-hide"),
2021-05-26 00:12:43 +00:00
}
}
2022-05-28 23:41:31 +00:00
pub fn stats_count(item: &dyn ItemDesc, msm: &MaterialStatManifest) -> usize {
match &*item.kind() {
ItemKind::Armor(armor) => {
let armor_stats = armor.stats(msm);
armor_stats.energy_reward.is_some() as usize
+ armor_stats.energy_max.is_some() as usize
+ armor_stats.stealth.is_some() as usize
+ armor_stats.crit_power.is_some() as usize
+ armor_stats.poise_resilience.is_some() as usize
+ armor_stats.protection.is_some() as usize
+ (item.num_slots() > 0) as usize
},
2022-03-19 20:22:12 +00:00
ItemKind::Tool(_) => 7,
ItemKind::Consumable { effects, .. } => effects.len(),
2022-03-19 19:18:38 +00:00
ItemKind::ModularComponent { .. } => 7,
_ => 0,
}
}
pub fn line_count(item: &dyn ItemDesc, msm: &MaterialStatManifest, i18n: &Localization) -> usize {
match &*item.kind() {
ItemKind::Consumable { effects, .. } => {
let descs = consumable_desc(effects, i18n);
let mut lines = 0;
for desc in descs {
lines += desc.matches('\n').count() + 1;
}
lines
},
_ => stats_count(item, msm),
}
}
/// Takes N `effects` and returns N effect descriptions
/// If effect isn't intended to have description, returns empty string
///
/// FIXME: handle which effects should have description in `stats_count`
/// to not waste space in item box
pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec<String> {
let mut descriptions = Vec::new();
2021-02-25 16:25:39 +00:00
2021-03-02 23:53:21 +00:00
for effect in effects {
let mut description = String::new();
2021-03-02 23:53:21 +00:00
if let Effect::Buff(buff) = effect {
let strength = buff.data.strength;
let dur_secs = buff.data.duration.map(|d| d.as_secs_f32());
let str_total = dur_secs.map_or(strength, |secs| strength * secs);
2021-03-02 23:53:21 +00:00
let format_float =
|input: f32| format!("{:.1}", input).trim_end_matches(".0").to_string();
2021-03-02 23:53:21 +00:00
let buff_desc = match buff.kind {
2021-03-24 01:05:14 +00:00
BuffKind::Saturation | BuffKind::Regeneration | BuffKind::Potion => i18n
2022-08-06 17:47:45 +00:00
.get_msg_ctx("buff-stat-health", &i18n::fluent_args! {
"str_total" => format_float(str_total),
}),
BuffKind::EnergyRegen => {
i18n.get_msg_ctx("buff-stat-energy_regen", &i18n::fluent_args! {
"str_total" => format_float(str_total),
})
},
2022-08-06 17:47:45 +00:00
BuffKind::IncreaseMaxEnergy => {
i18n.get_msg_ctx("buff-stat-increase_max_energy", &i18n::fluent_args! {
"strength" => format_float(strength),
})
},
BuffKind::IncreaseMaxHealth => {
i18n.get_msg_ctx("buff-stat-increase_max_health", &i18n::fluent_args! {
"strength" => format_float(strength),
})
},
2022-08-23 09:17:21 +00:00
BuffKind::Invulnerability => i18n.get_msg("buff-stat-invulnerability"),
2021-03-05 10:12:44 +00:00
BuffKind::Bleeding
2021-04-15 20:32:38 +00:00
| BuffKind::Burning
2021-03-05 10:12:44 +00:00
| BuffKind::CampfireHeal
| BuffKind::Cursed
| BuffKind::ProtectingWard
| BuffKind::Crippled
2021-05-30 15:51:47 +00:00
| BuffKind::Frenzied
| BuffKind::Frozen
| BuffKind::Wet
| BuffKind::Ensnared
2022-02-09 01:23:23 +00:00
| BuffKind::Poisoned
2022-03-05 20:51:41 +00:00
| BuffKind::Hastened
| BuffKind::Fortitude => Cow::Borrowed(""),
2021-03-02 23:53:21 +00:00
};
2021-03-16 12:19:31 +00:00
write!(&mut description, "{}", buff_desc).unwrap();
2021-03-02 23:31:47 +00:00
2021-03-24 01:05:14 +00:00
let dur_desc = if let Some(dur_secs) = dur_secs {
match buff.kind {
BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen => i18n
.get_msg_ctx("buff-text-over_seconds", &i18n::fluent_args! {
2022-08-06 17:47:45 +00:00
"dur_secs" => dur_secs
}),
BuffKind::IncreaseMaxEnergy
| BuffKind::IncreaseMaxHealth
2022-08-06 17:47:45 +00:00
| BuffKind::Invulnerability => {
i18n.get_msg_ctx("buff-text-for_seconds", &i18n::fluent_args! {
"dur_secs" => dur_secs
})
},
BuffKind::Bleeding
2021-04-15 20:32:38 +00:00
| BuffKind::Burning
| BuffKind::Potion
| BuffKind::CampfireHeal
2021-03-05 10:12:44 +00:00
| BuffKind::Cursed
| BuffKind::ProtectingWard
| BuffKind::Crippled
2021-05-30 15:51:47 +00:00
| BuffKind::Frenzied
| BuffKind::Frozen
| BuffKind::Wet
| BuffKind::Ensnared
2022-02-09 01:23:23 +00:00
| BuffKind::Poisoned
2022-03-05 20:51:41 +00:00
| BuffKind::Hastened
| BuffKind::Fortitude => Cow::Borrowed(""),
}
} else if let BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen =
buff.kind
{
2022-08-23 09:17:21 +00:00
i18n.get_msg("buff-text-every_second")
} else {
2022-08-06 17:47:45 +00:00
Cow::Borrowed("")
2021-03-02 23:53:21 +00:00
};
write!(&mut description, " {}", dur_desc).unwrap();
2021-02-25 16:25:39 +00:00
}
descriptions.push(description);
2021-02-25 16:25:39 +00:00
}
descriptions
2020-10-07 02:23:20 +00:00
}
2021-03-02 00:45:02 +00:00
// Armor
2022-08-06 17:47:45 +00:00
fn armor_kind<'a>(armor: &Armor, i18n: &'a Localization) -> Cow<'a, str> {
let kind = match armor.kind {
2022-08-23 09:17:21 +00:00
ArmorKind::Shoulder => i18n.get_msg("hud-bag-shoulders"),
ArmorKind::Chest => i18n.get_msg("hud-bag-chest"),
ArmorKind::Belt => i18n.get_msg("hud-bag-belt"),
ArmorKind::Hand => i18n.get_msg("hud-bag-hands"),
ArmorKind::Pants => i18n.get_msg("hud-bag-legs"),
ArmorKind::Foot => i18n.get_msg("hud-bag-feet"),
ArmorKind::Back => i18n.get_msg("hud-bag-back"),
ArmorKind::Ring => i18n.get_msg("hud-bag-ring"),
ArmorKind::Neck => i18n.get_msg("hud-bag-neck"),
ArmorKind::Head => i18n.get_msg("hud-bag-head"),
ArmorKind::Tabard => i18n.get_msg("hud-bag-tabard"),
ArmorKind::Bag => i18n.get_msg("hud-bag-bag"),
};
2021-03-28 12:27:59 +00:00
kind
2021-03-02 00:45:02 +00:00
}
// Tool
2022-08-06 17:47:45 +00:00
fn tool_kind<'a>(tool: &Tool, i18n: &'a Localization) -> Cow<'a, str> {
let kind = match tool.kind {
2022-08-23 09:17:21 +00:00
ToolKind::Sword => i18n.get_msg("common-weapons-sword"),
ToolKind::Axe => i18n.get_msg("common-weapons-axe"),
ToolKind::Hammer => i18n.get_msg("common-weapons-hammer"),
ToolKind::Bow => i18n.get_msg("common-weapons-bow"),
ToolKind::Dagger => i18n.get_msg("common-weapons-dagger"),
ToolKind::Staff => i18n.get_msg("common-weapons-staff"),
ToolKind::Sceptre => i18n.get_msg("common-weapons-sceptre"),
ToolKind::Shield => i18n.get_msg("common-weapons-shield"),
ToolKind::Spear => i18n.get_msg("common-weapons-spear"),
ToolKind::Blowgun => i18n.get_msg("common-weapons-blowgun"),
ToolKind::Natural => i18n.get_msg("common-weapons-natural"),
ToolKind::Debug => i18n.get_msg("common-tool-debug"),
ToolKind::Farming => i18n.get_msg("common-tool-farming"),
2022-08-28 18:48:18 +00:00
ToolKind::Instrument => i18n.get_msg("common-tool-instrument"),
2022-08-23 09:17:21 +00:00
ToolKind::Pick => i18n.get_msg("common-tool-pick"),
ToolKind::Empty => i18n.get_msg("common-empty"),
};
2021-03-28 12:27:59 +00:00
kind
2021-03-02 00:45:02 +00:00
}
2021-01-13 03:26:51 +00:00
/// Output the number of hands needed to hold a tool
2022-08-06 17:47:45 +00:00
pub fn tool_hands<'a>(tool: &Tool, i18n: &'a Localization) -> Cow<'a, str> {
let hands = match tool.hands {
2022-08-23 09:17:21 +00:00
Hands::One => i18n.get_msg("common-hands-one"),
Hands::Two => i18n.get_msg("common-hands-two"),
2021-02-13 00:57:52 +00:00
};
2021-03-28 12:27:59 +00:00
hands
2021-03-02 00:45:02 +00:00
}
/// Compare two type, output a colored character to show comparison
2021-03-28 12:27:59 +00:00
pub fn comparison<T: PartialOrd>(first: T, other: T) -> (&'static str, conrod_core::Color) {
2021-03-02 00:45:02 +00:00
if first == other {
2021-03-28 12:27:59 +00:00
("", conrod_core::color::GREY)
2021-03-02 00:45:02 +00:00
} else if other < first {
2021-03-28 12:27:59 +00:00
("", conrod_core::color::GREEN)
2021-03-02 00:45:02 +00:00
} else {
2021-03-28 12:27:59 +00:00
("", conrod_core::color::RED)
2021-03-02 00:45:02 +00:00
}
}
2021-12-12 00:25:35 +00:00
/// Compare two Option type, output a colored character to show comparison
pub fn option_comparison<T: PartialOrd>(
first: &Option<T>,
other: &Option<T>,
) -> (&'static str, conrod_core::Color) {
if let Some(first) = first {
if let Some(other) = other {
if first == other {
("", conrod_core::color::GREY)
} else if other < first {
("", conrod_core::color::GREEN)
} else {
("", conrod_core::color::RED)
}
} else {
("", conrod_core::color::GREEN)
}
} else if other.is_some() {
("", conrod_core::color::RED)
} else {
("", conrod_core::color::GREY)
}
}
/// Output protection as a string
2021-03-02 00:45:02 +00:00
pub fn protec2string(stat: Protection) -> String {
match stat {
Protection::Normal(a) => format!("{:.1}", a),
2021-03-20 20:24:26 +00:00
Protection::Invincible => "Inf".to_string(),
2021-03-02 00:45:02 +00:00
}
}
pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
match ability_id {
// Debug stick
"common.abilities.debug.forwardboost" => imgs.flyingrod_m1,
"common.abilities.debug.upboost" => imgs.flyingrod_m2,
"common.abilities.debug.possess" => imgs.snake_arrow_0,
// Sword
2022-09-01 02:23:32 +00:00
"common.abilities.sword.balanced_combo" => imgs.sword_balanced_combo,
// "common.abilities.sword.balanced_thrust" => imgs.sword_balanced_thrust,
// "common.abilities.sword.balanced_finisher" => imgs.sword_balanced_finisher,
"common.abilities.sword.offensive_combo" => imgs.sword_offensive_combo,
// "common.abilities.sword.offensive_finisher" => imgs.sword_offensive_finisher,
// "common.abilities.sword.offensive_advance" => imgs.sword_offensive_advance,
"common.abilities.sword.crippling_combo" => imgs.sword_crippling_combo,
// "common.abilities.sword.crippling_finisher" => imgs.sword_crippling_finisher,
// "common.abilities.sword.crippling_strike" => imgs.sword_crippling_strike,
// "common.abilities.sword.crippling_gouge" => imgs.sword_crippling_gouge,
"common.abilities.sword.cleaving_combo" => imgs.sword_cleaving_combo,
// "common.abilities.sword.cleaving_finisher" => imgs.sword_cleaving_finisher,
// "common.abilities.sword.cleaving_spin" => imgs.sword_cleaving_spin,
// "common.abilities.sword.cleaving_dive" => imgs.sword_cleaving_dive,
"common.abilities.sword.defensive_combo" => imgs.sword_defensive_combo,
// "common.abilities.sword.defensive_bulwark" => imgs.sword_defensive_bulwark,
// "common.abilities.sword.defensive_retreat" => imgs.sword_defensive_retreat,
"common.abilities.sword.parrying_combo" => imgs.sword_parrying_combo,
// "common.abilities.sword.parrying_parry" => imgs.sword_parrying_parry,
// "common.abilities.sword.parrying_riposte" => imgs.sword_parrying_riposte,
// "common.abilities.sword.parrying_counter" => imgs.sword_parrying_counter,
"common.abilities.sword.heavy_combo" => imgs.sword_heavy_combo,
// "common.abilities.sword.heavy_finisher" => imgs.sword_heavy_finisher,
// "common.abilities.sword.heavy_pommelstrike" => imgs.sword_heavy_pommelstrike,
// "common.abilities.sword.heavy_fortitude" => imgs.sword_heavy_fortitude,
"common.abilities.sword.mobility_combo" => imgs.sword_mobility_combo,
// "common.abilities.sword.mobility_feint" => imgs.sword_mobility_feint,
// "common.abilities.sword.mobility_agility" => imgs.sword_mobility_agility,
"common.abilities.sword.reaching_combo" => imgs.sword_reaching_combo,
// "common.abilities.sword.reaching_charge" => imgs.sword_reaching_charge,
// "common.abilities.sword.reaching_flurry" => imgs.sword_reaching_flurry,
// "common.abilities.sword.reaching_skewer" => imgs.sword_reaching_skewer,
// Axe
"common.abilities.axe.doublestrike" => imgs.twohaxe_m1,
"common.abilities.axe.spin" => imgs.axespin,
"common.abilities.axe.leap" => imgs.skill_axe_leap_slash,
// Hammer
"common.abilities.hammer.singlestrike" => imgs.twohhammer_m1,
"common.abilities.hammer.charged" => imgs.hammergolf,
"common.abilities.hammer.leap" => imgs.hammerleap,
// Bow
"common.abilities.bow.charged" => imgs.bow_m1,
"common.abilities.bow.repeater" => imgs.bow_m2,
"common.abilities.bow.shotgun" => imgs.skill_bow_jump_burst,
// Staff
"common.abilities.staff.firebomb" => imgs.fireball,
"common.abilities.staff.flamethrower" => imgs.flamethrower,
"common.abilities.staff.fireshockwave" => imgs.fire_aoe,
// Sceptre
"common.abilities.sceptre.lifestealbeam" => imgs.skill_sceptre_lifesteal,
"common.abilities.sceptre.healingaura" => imgs.skill_sceptre_heal,
"common.abilities.sceptre.wardingaura" => imgs.skill_sceptre_aura,
// Shield
"common.abilities.shield.tempbasic" => imgs.onehshield_m1,
"common.abilities.shield.block" => imgs.onehshield_m2,
// Dagger
"common.abilities.dagger.tempbasic" => imgs.onehdagger_m1,
// Pickaxe
"common.abilities.pick.swing" => imgs.mining,
2022-08-28 18:48:18 +00:00
// Instruments
"common.abilities.music.bass" => imgs.instrument,
"common.abilities.music.flute" => imgs.instrument,
"common.abilities.music.harp" => imgs.instrument,
"common.abilities.music.perc" => imgs.instrument,
"common.abilities.music.kalimba" => imgs.instrument,
"common.abilities.music.melodica" => imgs.instrument,
"common.abilities.music.lute" => imgs.instrument,
2022-09-10 17:23:38 +00:00
"common.abilities.music.guitar" => imgs.instrument,
2022-08-28 18:48:18 +00:00
"common.abilities.music.sitar" => imgs.instrument,
2021-11-12 04:41:01 +00:00
_ => imgs.not_found,
}
}
pub fn ability_description<'a>(
2022-08-06 17:47:45 +00:00
ability_id: &str,
2022-07-15 12:08:04 +00:00
loc: &'a Localization,
2022-08-06 17:47:45 +00:00
) -> (Cow<'a, str>, Cow<'a, str>) {
let ability = ability_id.replace('.', "-");
2022-08-06 17:47:45 +00:00
(loc.get_msg(&ability), loc.get_attr(&ability, "desc"))
}