1use super::img_ids;
2use common::{
3 comp::{
4 BuffData, BuffKind,
5 inventory::trade_pricing::TradePricing,
6 item::{
7 Effects, Item, ItemDefinitionId, ItemDesc, ItemI18n, ItemKind, MaterialKind,
8 MaterialStatManifest, Quality,
9 armor::{Armor, ArmorKind, Protection},
10 tool::{Hands, Tool, ToolKind},
11 },
12 },
13 effect::Effect,
14 trade::{Good, SitePrices},
15};
16use conrod_core::image;
17use i18n::{FluentValue, Localization, fluent_args};
18use std::{
19 borrow::Cow,
20 fmt::{Display, Write},
21};
22use vek::num_traits;
23
24pub fn formatted_float<F: num_traits::Float + Display>(f: F, dec: usize) -> String {
29 format!("{:.dec$}", f)
30 .trim_end_matches('0')
31 .trim_end_matches('.')
32 .to_string()
33}
34
35pub fn formatted_float_signed<F: num_traits::Float + Display>(f: F, dec: usize) -> String {
37 format!("{:+.dec$}", f)
38 .trim_end_matches('0')
39 .trim_end_matches('.')
40 .to_string()
41}
42
43pub fn price_desc<'a>(
44 prices: &Option<SitePrices>,
45 item_definition_id: ItemDefinitionId<'_>,
46 quality: Quality,
47 i18n: &'a Localization,
48) -> Option<(Cow<'a, str>, Cow<'a, str>, f32)> {
49 let prices = prices.as_ref()?;
50 let materials = TradePricing::get_materials(&item_definition_id)?;
51 let coinprice = prices.values.get(&Good::Coin).cloned().unwrap_or(1.0);
52 let buyprice: f32 = materials
53 .iter()
54 .map(|e| prices.values.get(&e.1).cloned().unwrap_or_default() * e.0)
55 .sum();
56 let sellprice = materials
57 .iter()
58 .map(|e| prices.values.get(&e.1).cloned().unwrap_or_default() * e.0)
59 .sum::<f32>()
60 * TradePricing::good_from_itemdef_id(item_definition_id).sell_discount(quality);
61
62 let deal_goodness: f32 = materials
63 .iter()
64 .map(|e| prices.values.get(&e.1).cloned().unwrap_or(0.0))
65 .sum::<f32>()
66 / prices.values.get(&Good::Coin).cloned().unwrap_or(1.0)
67 / (materials.len() as f32);
68 let deal_goodness = deal_goodness.log(2.0);
69
70 let buy_string = i18n.get_msg_ctx("hud-trade-buy", &fluent_args! {
71 "coin_num" => buyprice / coinprice,
72 "coin_formatted" => format!("{:0.1}", buyprice / coinprice),
73 });
74 let sell_string = i18n.get_msg_ctx("hud-trade-sell", &fluent_args! {
75 "coin_num" => sellprice / coinprice,
76 "coin_formatted" => format!("{:0.1}", sellprice / coinprice),
77 });
78
79 let deal_goodness = match deal_goodness {
80 x if x < -2.5 => 0.0,
81 x if x < -1.05 => 0.25,
82 x if x < -0.95 => 0.5,
83 x if x < 0.0 => 0.75,
84 _ => 1.0,
85 };
86 Some((buy_string, sell_string, deal_goodness))
87}
88
89pub fn item_text<'a, I: ItemDesc + ?Sized>(
90 item: &I,
91 i18n: &'a Localization,
92 i18n_spec: &'a ItemI18n,
93) -> (String, String) {
94 let (title, desc) = item.i18n(i18n_spec);
95
96 (i18n.get_content(&title), i18n.get_content(&desc))
97}
98
99pub fn describe<'a, I: ItemDesc + ?Sized>(
100 item: &I,
101 i18n: &'a Localization,
102 i18n_spec: &'a ItemI18n,
103) -> String {
104 let (title, _) = item_text(item, i18n, i18n_spec);
105 let amount = item.amount();
106
107 if amount.get() > 1 {
108 format!("{amount} x {title}")
109 } else {
110 title
111 }
112}
113
114pub fn kind_text<'a>(kind: &ItemKind, i18n: &'a Localization) -> Cow<'a, str> {
115 match kind {
116 ItemKind::Armor(armor) => armor_kind(armor, i18n),
117 ItemKind::Tool(tool) => Cow::Owned(format!(
118 "{} ({})",
119 tool_kind(tool, i18n),
120 tool_hands(tool, i18n)
121 )),
122 ItemKind::ModularComponent(mc) => {
123 if let Some(toolkind) = mc.toolkind() {
124 i18n.get_attr("common-kind-modular_component", toolkind.identifier_name())
125 } else {
126 i18n.get_msg("common-kind-modular_component")
127 }
128 },
129 ItemKind::Glider => i18n.get_msg("common-kind-glider"),
130 ItemKind::Consumable { .. } => i18n.get_msg("common-kind-consumable"),
131 ItemKind::Utility { .. } => i18n.get_msg("common-kind-utility"),
132 ItemKind::Ingredient { .. } => i18n.get_msg("common-kind-ingredient"),
133 ItemKind::Lantern { .. } => i18n.get_msg("common-kind-lantern"),
134 ItemKind::TagExamples { .. } => Cow::Borrowed(""),
135 ItemKind::RecipeGroup { .. } => i18n.get_msg("common-kind-recipegroup"),
136 ItemKind::Quest => i18n.get_msg("common-kind-quest"),
137 }
138}
139
140pub fn material_kind_text<'a>(kind: &MaterialKind, i18n: &'a Localization) -> Cow<'a, str> {
141 match kind {
142 MaterialKind::Metal => i18n.get_msg("common-material-metal"),
143 MaterialKind::Gem => i18n.get_msg("common-material-gem"),
144 MaterialKind::Wood => i18n.get_msg("common-material-wood"),
145 MaterialKind::Stone => i18n.get_msg("common-material-stone"),
146 MaterialKind::Cloth => i18n.get_msg("common-material-cloth"),
147 MaterialKind::Hide => i18n.get_msg("common-material-hide"),
148 }
149}
150
151pub fn stats_count(item: &dyn ItemDesc, msm: &MaterialStatManifest) -> usize {
152 let mut count = match &*item.kind() {
153 ItemKind::Armor(armor) => {
154 let armor_stats = armor.stats(msm, item.stats_durability_multiplier());
155 armor_stats.energy_reward.is_some() as usize
156 + armor_stats.energy_max.is_some() as usize
157 + armor_stats.stealth.is_some() as usize
158 + armor_stats.precision_power.is_some() as usize
159 + armor_stats.poise_resilience.is_some() as usize
160 + armor_stats.protection.is_some() as usize
161 + (item.num_slots() > 0) as usize
162 },
163 ItemKind::Tool(_) => 6,
164 ItemKind::Consumable { effects, .. } => match effects {
165 Effects::Any(_) | Effects::One(_) => 1,
166 Effects::All(effects) => effects.len(),
167 },
168 ItemKind::RecipeGroup { recipes } => {
169 recipes.len() + 1
171 },
172 ItemKind::ModularComponent { .. } => 6,
173 _ => 0,
174 };
175 if item.has_durability() {
176 count += 1;
177 }
178 count
179}
180
181pub fn line_count(item: &dyn ItemDesc, msm: &MaterialStatManifest, i18n: &Localization) -> usize {
182 match &*item.kind() {
183 ItemKind::Consumable { effects, .. } => {
184 let descs = consumable_desc(effects, i18n);
185 let mut lines = 0;
186 for desc in descs {
187 lines += desc.matches('\n').count() + 1;
188 }
189
190 lines
191 },
192 _ => stats_count(item, msm),
193 }
194}
195
196fn buff_key(buff: BuffKind) -> &'static str {
200 match buff {
201 BuffKind::Regeneration => "buff-heal",
203 BuffKind::Saturation => "buff-saturation",
204 BuffKind::Potion => "buff-potion",
205 BuffKind::Agility => "buff-agility",
206 BuffKind::RestingHeal => "buff-resting_heal",
207 BuffKind::EnergyRegen => "buff-energy_regen",
208 BuffKind::ComboGeneration => "buff-combo_generation",
209 BuffKind::IncreaseMaxHealth => "buff-increase_max_health",
210 BuffKind::IncreaseMaxEnergy => "buff-increase_max_energy",
211 BuffKind::Invulnerability => "buff-invulnerability",
212 BuffKind::ProtectingWard => "buff-protectingward",
213 BuffKind::Frenzied => "buff-frenzied",
214 BuffKind::Hastened => "buff-hastened",
215 BuffKind::Fortitude => "buff-fortitude",
216 BuffKind::Reckless => "buff-reckless",
217 BuffKind::Flame => "buff-burn",
219 BuffKind::Frigid => "buff-frigid",
220 BuffKind::Lifesteal => "buff-lifesteal",
221 BuffKind::ImminentCritical => "buff-imminentcritical",
222 BuffKind::Fury => "buff-fury",
223 BuffKind::Sunderer => "buff-sunderer",
224 BuffKind::Defiance => "buff-defiance",
225 BuffKind::Bloodfeast => "buff-bloodfeast",
226 BuffKind::Berserk => "buff-berserk",
227 BuffKind::ScornfulTaunt => "buff-scornfultaunt",
228 BuffKind::Tenacity => "buff-tenacity",
229 BuffKind::Resilience => "buff-resilience",
230 BuffKind::StormChaser => "buff-stormchaser",
231 BuffKind::EagleEye => "buff-eagleeye",
232 BuffKind::ArdentHunt => "buff-ardenthunt",
233 BuffKind::IgniteArrow => "buff-ignitearrow",
234 BuffKind::FreezeArrow => "buff-freezearrow",
235 BuffKind::DrenchArrow => "buff-drencharrow",
236 BuffKind::JoltArrow => "buff-joltarrow",
237 BuffKind::Bleeding => "buff-bleed",
239 BuffKind::Cursed => "buff-cursed",
240 BuffKind::Burning => "buff-burn",
241 BuffKind::Crippled => "buff-crippled",
242 BuffKind::Frozen => "buff-frozen",
243 BuffKind::Wet => "buff-wet",
244 BuffKind::Ensnared => "buff-ensnared",
245 BuffKind::Poisoned => "buff-poisoned",
246 BuffKind::Parried => "buff-parried",
247 BuffKind::PotionSickness => "buff-potionsickness",
248 BuffKind::Heatstroke => "buff-heatstroke",
249 BuffKind::Rooted => "buff-rooted",
250 BuffKind::Winded => "buff-winded",
251 BuffKind::Amnesia => "buff-amnesia",
252 BuffKind::OffBalance => "buff-offbalance",
253 BuffKind::Chilled => "buff-chilled",
254 BuffKind::Polymorphed => "buff-polymorphed",
256 }
257}
258
259pub fn get_buff_title(buff: BuffKind, i18n: &Localization) -> Cow<'_, str> {
261 let key = buff_key(buff);
262
263 i18n.get_msg(key)
264}
265
266pub fn get_buff_desc(buff: BuffKind, data: BuffData, i18n: &Localization) -> Cow<'_, str> {
268 let key = buff_key(buff);
269 if let BuffKind::RestingHeal = buff {
270 i18n.get_attr_ctx(key, "desc", &i18n::fluent_args! {
271 "rate" => data.strength * 100.0
272 })
273 } else {
274 i18n.get_attr(key, "desc")
275 }
276}
277
278fn almost_integer(number: &f32) -> FluentValue<'_> {
279 let epsilon = 0.001;
280 if number.fract() < epsilon {
281 FluentValue::from(number.round() as usize)
282 } else {
283 FluentValue::from(format!("{:.<3}", number))
284 }
285}
286pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec<String> {
292 let mut descriptions = Vec::new();
293 match effects {
294 Effects::Any(_) => {
295 descriptions.push(i18n.get_msg("buff-mysterious").into_owned());
296 },
297 Effects::All(_) | Effects::One(_) => {
298 for effect in effects.effects() {
299 let mut description = String::new();
300 if let Effect::Buff(buff) = effect {
301 let strength = buff.data.strength;
302 let duration = buff.data.duration.map(|d| d.0 as f32);
303 let str_total = duration.map_or(strength, |secs| strength * secs);
304 let str_duration = duration.unwrap_or(0.0);
305 let fluent_duration = almost_integer(&str_duration);
306
307 let format_float =
308 |input: f32| format!("{:.1}", input).trim_end_matches(".0").to_string();
309
310 let buff_desc = match buff.kind {
311 BuffKind::Saturation | BuffKind::Regeneration | BuffKind::Potion => {
313 let key = "buff-heal";
314 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
315 "str_total" => format_float(str_total),
316 "duration" => fluent_duration,
317 })
318 },
319 BuffKind::EnergyRegen => {
321 let key = buff_key(buff.kind);
322 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
323 "str_total" => format_float(str_total),
324 "duration" => fluent_duration,
325 })
326 },
327 BuffKind::ComboGeneration => {
328 let key = buff_key(buff.kind);
329 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
330 "str_total" => format_float(str_total),
331 "duration" => fluent_duration,
332 })
333 },
334 BuffKind::IncreaseMaxEnergy
336 | BuffKind::IncreaseMaxHealth => {
337 let key = buff_key(buff.kind);
338 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
339 "strength" => format_float(strength),
340 "duration" => fluent_duration,
341 })
342 },
343 BuffKind::PotionSickness
345 | BuffKind::Agility => {
346 let key = buff_key(buff.kind);
347 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
348 "strength" => format_float(strength * 100.0),
349 "duration" => fluent_duration,
350 })
351 },
352 BuffKind::Invulnerability => {
354 let key = buff_key(buff.kind);
355 i18n.get_attr_ctx(key, "stat", &i18n::fluent_args! {
356 "duration" => fluent_duration,
357 })
358 },
359 BuffKind::Bleeding
361 | BuffKind::Burning
362 | BuffKind::RestingHeal
363 | BuffKind::Cursed
364 | BuffKind::ProtectingWard
365 | BuffKind::Crippled
366 | BuffKind::Frenzied
367 | BuffKind::Frozen
368 | BuffKind::Wet
369 | BuffKind::Ensnared
370 | BuffKind::Poisoned
371 | BuffKind::Hastened
372 | BuffKind::Fortitude
373 | BuffKind::Parried
374 | BuffKind::Reckless
375 | BuffKind::Polymorphed
376 | BuffKind::Flame
377 | BuffKind::Frigid
378 | BuffKind::Lifesteal
379 | BuffKind::ImminentCritical
381 | BuffKind::Fury
382 | BuffKind::Sunderer
383 | BuffKind::Defiance
384 | BuffKind::Bloodfeast
385 | BuffKind::Berserk
386 | BuffKind::Heatstroke
387 | BuffKind::ScornfulTaunt
388 | BuffKind::Rooted
389 | BuffKind::Winded
390 | BuffKind::Amnesia
391 | BuffKind::OffBalance
392 | BuffKind::Tenacity
393 | BuffKind::Resilience
394 | BuffKind::StormChaser
395 | BuffKind::EagleEye
396 | BuffKind::Chilled
397 | BuffKind::ArdentHunt
398 | BuffKind::IgniteArrow
399 | BuffKind::FreezeArrow
400 | BuffKind::DrenchArrow
401 | BuffKind::JoltArrow => Cow::Borrowed(""),
402 };
403
404 write!(&mut description, "{}", buff_desc).unwrap();
405 }
406 descriptions.push(description);
407 }
408 },
409 }
410 descriptions
411}
412
413fn armor_kind<'a>(armor: &Armor, i18n: &'a Localization) -> Cow<'a, str> {
415 match armor.kind {
416 ArmorKind::Shoulder => i18n.get_msg("hud-bag-shoulders"),
417 ArmorKind::Chest => i18n.get_msg("hud-bag-chest"),
418 ArmorKind::Belt => i18n.get_msg("hud-bag-belt"),
419 ArmorKind::Hand => i18n.get_msg("hud-bag-hands"),
420 ArmorKind::Pants => i18n.get_msg("hud-bag-legs"),
421 ArmorKind::Foot => i18n.get_msg("hud-bag-feet"),
422 ArmorKind::Back => i18n.get_msg("hud-bag-back"),
423 ArmorKind::Backpack => i18n.get_msg("hud-bag-backpack"),
424 ArmorKind::Ring => i18n.get_msg("hud-bag-ring"),
425 ArmorKind::Neck => i18n.get_msg("hud-bag-neck"),
426 ArmorKind::Head => i18n.get_msg("hud-bag-head"),
427 ArmorKind::Tabard => i18n.get_msg("hud-bag-tabard"),
428 ArmorKind::Bag => i18n.get_msg("hud-bag-bag"),
429 }
430}
431
432fn tool_kind<'a>(tool: &Tool, i18n: &'a Localization) -> Cow<'a, str> {
434 match tool.kind {
435 ToolKind::Sword => i18n.get_msg("common-weapons-sword"),
436 ToolKind::Axe => i18n.get_msg("common-weapons-axe"),
437 ToolKind::Hammer => i18n.get_msg("common-weapons-hammer"),
438 ToolKind::Bow => i18n.get_msg("common-weapons-bow"),
439 ToolKind::Dagger => i18n.get_msg("common-weapons-dagger"),
440 ToolKind::Staff => i18n.get_msg("common-weapons-staff"),
441 ToolKind::Sceptre => i18n.get_msg("common-weapons-sceptre"),
442 ToolKind::Shield => i18n.get_msg("common-weapons-shield"),
443 ToolKind::Spear => i18n.get_msg("common-weapons-spear"),
444 ToolKind::Blowgun => i18n.get_msg("common-weapons-blowgun"),
445 ToolKind::Natural => i18n.get_msg("common-weapons-natural"),
446 ToolKind::Debug => i18n.get_msg("common-tool-debug"),
447 ToolKind::Farming => i18n.get_msg("common-tool-farming"),
448 ToolKind::Instrument => i18n.get_msg("common-tool-instrument"),
449 ToolKind::Throwable => i18n.get_msg("common-tool-throwable"),
450 ToolKind::Pick => i18n.get_msg("common-tool-pick"),
451 ToolKind::Shovel => i18n.get_msg("common-tool-shovel"),
452 ToolKind::Empty => i18n.get_msg("common-empty"),
453 }
454}
455
456pub fn tool_hands<'a>(tool: &Tool, i18n: &'a Localization) -> Cow<'a, str> {
458 match tool.hands {
459 Hands::One => i18n.get_msg("common-hands-one"),
460 Hands::Two => i18n.get_msg("common-hands-two"),
461 }
462}
463
464pub fn comparison<T: PartialOrd>(first: T, other: T) -> (&'static str, conrod_core::Color) {
466 if first == other {
467 ("•", conrod_core::color::GREY)
468 } else if other < first {
469 ("▲", conrod_core::color::GREEN)
470 } else {
471 ("▼", conrod_core::color::RED)
472 }
473}
474
475pub fn option_comparison<T: PartialOrd>(
477 first: &Option<T>,
478 other: &Option<T>,
479) -> (&'static str, conrod_core::Color) {
480 if let Some(first) = first {
481 if let Some(other) = other {
482 if first == other {
483 ("•", conrod_core::color::GREY)
484 } else if other < first {
485 ("▲", conrod_core::color::GREEN)
486 } else {
487 ("▼", conrod_core::color::RED)
488 }
489 } else {
490 ("▲", conrod_core::color::GREEN)
491 }
492 } else if other.is_some() {
493 ("▼", conrod_core::color::RED)
494 } else {
495 ("•", conrod_core::color::GREY)
496 }
497}
498
499pub fn protec2string(stat: Protection) -> String {
501 match stat {
502 Protection::Normal(a) => format!("{:.1}", a),
503 Protection::Invincible => "Inf".to_string(),
504 }
505}
506
507pub fn item_durability(item: &dyn ItemDesc) -> Option<u32> {
509 let durability = item
510 .durability_lost()
511 .or_else(|| item.has_durability().then_some(0));
512 durability.map(|d| Item::MAX_DURABILITY - d)
513}
514
515pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
516 match ability_id {
517 "common.abilities.debug.forwardboost" => imgs.flyingrod_m1,
519 "common.abilities.debug.upboost" => imgs.flyingrod_m2,
520 "common.abilities.debug.possess" => imgs.snake_arrow_0,
521 "veloren.core.pseudo_abilities.sword.heavy_stance" => imgs.sword_heavy_stance,
523 "veloren.core.pseudo_abilities.sword.agile_stance" => imgs.sword_agile_stance,
524 "veloren.core.pseudo_abilities.sword.defensive_stance" => imgs.sword_defensive_stance,
525 "veloren.core.pseudo_abilities.sword.crippling_stance" => imgs.sword_crippling_stance,
526 "veloren.core.pseudo_abilities.sword.cleaving_stance" => imgs.sword_cleaving_stance,
527 "veloren.core.pseudo_abilities.sword.double_slash" => imgs.sword_double_slash,
528 "common.abilities.sword.basic_double_slash" => imgs.sword_basic_double_slash,
529 "common.abilities.sword.heavy_double_slash" => imgs.sword_heavy_double_slash,
530 "common.abilities.sword.agile_double_slash" => imgs.sword_agile_double_slash,
531 "common.abilities.sword.defensive_double_slash" => imgs.sword_defensive_double_slash,
532 "common.abilities.sword.crippling_double_slash" => imgs.sword_crippling_double_slash,
533 "common.abilities.sword.cleaving_double_slash" => imgs.sword_cleaving_double_slash,
534 "veloren.core.pseudo_abilities.sword.secondary_ability" => imgs.sword_secondary_ability,
535 "common.abilities.sword.basic_thrust" => imgs.sword_basic_thrust,
536 "common.abilities.sword.heavy_slam" => imgs.sword_heavy_slam,
537 "common.abilities.sword.agile_perforate" => imgs.sword_agile_perforate,
538 "common.abilities.sword.agile_dual_perforate" => imgs.sword_agile_perforate,
539 "common.abilities.sword.defensive_vital_jab" => imgs.sword_defensive_vital_jab,
540 "common.abilities.sword.crippling_deep_rend" => imgs.sword_crippling_deep_rend,
541 "common.abilities.sword.cleaving_spiral_slash" => imgs.sword_cleaving_spiral_slash,
542 "common.abilities.sword.cleaving_dual_spiral_slash" => imgs.sword_cleaving_spiral_slash,
543 "veloren.core.pseudo_abilities.sword.crescent_slash" => imgs.sword_crescent_slash,
544 "common.abilities.sword.basic_crescent_slash" => imgs.sword_basic_crescent_slash,
545 "common.abilities.sword.heavy_crescent_slash" => imgs.sword_heavy_crescent_slash,
546 "common.abilities.sword.agile_crescent_slash" => imgs.sword_agile_crescent_slash,
547 "common.abilities.sword.defensive_crescent_slash" => imgs.sword_defensive_crescent_slash,
548 "common.abilities.sword.crippling_crescent_slash" => imgs.sword_crippling_crescent_slash,
549 "common.abilities.sword.cleaving_crescent_slash" => imgs.sword_cleaving_crescent_slash,
550 "veloren.core.pseudo_abilities.sword.fell_strike" => imgs.sword_fell_strike,
551 "common.abilities.sword.basic_fell_strike" => imgs.sword_basic_fell_strike,
552 "common.abilities.sword.heavy_fell_strike" => imgs.sword_heavy_fell_strike,
553 "common.abilities.sword.agile_fell_strike" => imgs.sword_agile_fell_strike,
554 "common.abilities.sword.defensive_fell_strike" => imgs.sword_defensive_fell_strike,
555 "common.abilities.sword.crippling_fell_strike" => imgs.sword_crippling_fell_strike,
556 "common.abilities.sword.cleaving_fell_strike" => imgs.sword_cleaving_fell_strike,
557 "veloren.core.pseudo_abilities.sword.skewer" => imgs.sword_skewer,
558 "common.abilities.sword.basic_skewer" => imgs.sword_basic_skewer,
559 "common.abilities.sword.heavy_skewer" => imgs.sword_heavy_skewer,
560 "common.abilities.sword.agile_skewer" => imgs.sword_agile_skewer,
561 "common.abilities.sword.defensive_skewer" => imgs.sword_defensive_skewer,
562 "common.abilities.sword.crippling_skewer" => imgs.sword_crippling_skewer,
563 "common.abilities.sword.cleaving_skewer" => imgs.sword_cleaving_skewer,
564 "veloren.core.pseudo_abilities.sword.cascade" => imgs.sword_cascade,
565 "common.abilities.sword.basic_cascade" => imgs.sword_basic_cascade,
566 "common.abilities.sword.heavy_cascade" => imgs.sword_heavy_cascade,
567 "common.abilities.sword.agile_cascade" => imgs.sword_agile_cascade,
568 "common.abilities.sword.defensive_cascade" => imgs.sword_defensive_cascade,
569 "common.abilities.sword.crippling_cascade" => imgs.sword_crippling_cascade,
570 "common.abilities.sword.cleaving_cascade" => imgs.sword_cleaving_cascade,
571 "veloren.core.pseudo_abilities.sword.cross_cut" => imgs.sword_cross_cut,
572 "common.abilities.sword.basic_cross_cut" => imgs.sword_basic_cross_cut,
573 "common.abilities.sword.heavy_cross_cut" => imgs.sword_heavy_cross_cut,
574 "common.abilities.sword.agile_cross_cut" => imgs.sword_agile_cross_cut,
575 "common.abilities.sword.defensive_cross_cut" => imgs.sword_defensive_cross_cut,
576 "common.abilities.sword.crippling_cross_cut" => imgs.sword_crippling_cross_cut,
577 "common.abilities.sword.cleaving_cross_cut" => imgs.sword_cleaving_cross_cut,
578 "common.abilities.sword.basic_dual_cross_cut" => imgs.sword_basic_cross_cut,
579 "common.abilities.sword.heavy_dual_cross_cut" => imgs.sword_heavy_cross_cut,
580 "common.abilities.sword.agile_dual_cross_cut" => imgs.sword_agile_cross_cut,
581 "common.abilities.sword.defensive_dual_cross_cut" => imgs.sword_defensive_cross_cut,
582 "common.abilities.sword.crippling_dual_cross_cut" => imgs.sword_crippling_cross_cut,
583 "common.abilities.sword.cleaving_dual_cross_cut" => imgs.sword_cleaving_cross_cut,
584 "veloren.core.pseudo_abilities.sword.finisher" => imgs.sword_finisher,
585 "common.abilities.sword.basic_mighty_strike" => imgs.sword_basic_mighty_strike,
586 "common.abilities.sword.heavy_guillotine" => imgs.sword_heavy_guillotine,
587 "common.abilities.sword.agile_hundred_cuts" => imgs.sword_agile_hundred_cuts,
588 "common.abilities.sword.defensive_counter" => imgs.sword_defensive_counter,
589 "common.abilities.sword.crippling_mutilate" => imgs.sword_crippling_mutilate,
590 "common.abilities.sword.cleaving_bladestorm" => imgs.sword_cleaving_bladestorm,
591 "common.abilities.sword.cleaving_dual_bladestorm" => imgs.sword_cleaving_bladestorm,
592 "common.abilities.sword.heavy_sweep" => imgs.sword_heavy_sweep,
593 "common.abilities.sword.heavy_pommel_strike" => imgs.sword_heavy_pommel_strike,
594 "common.abilities.sword.agile_quick_draw" => imgs.sword_agile_quick_draw,
595 "common.abilities.sword.agile_feint" => imgs.sword_agile_feint,
596 "common.abilities.sword.defensive_riposte" => imgs.sword_defensive_riposte,
597 "common.abilities.sword.defensive_disengage" => imgs.sword_defensive_disengage,
598 "common.abilities.sword.crippling_gouge" => imgs.sword_crippling_gouge,
599 "common.abilities.sword.crippling_hamstring" => imgs.sword_crippling_hamstring,
600 "common.abilities.sword.cleaving_whirlwind_slice" => imgs.sword_cleaving_whirlwind_slice,
601 "common.abilities.sword.cleaving_dual_whirlwind_slice" => {
602 imgs.sword_cleaving_whirlwind_slice
603 },
604 "common.abilities.sword.cleaving_earth_splitter" => imgs.sword_cleaving_earth_splitter,
605 "common.abilities.sword.heavy_fortitude" => imgs.sword_heavy_fortitude,
606 "common.abilities.sword.heavy_pillar_thrust" => imgs.sword_heavy_pillar_thrust,
607 "common.abilities.sword.agile_dancing_edge" => imgs.sword_agile_dancing_edge,
608 "common.abilities.sword.agile_flurry" => imgs.sword_agile_flurry,
609 "common.abilities.sword.agile_dual_flurry" => imgs.sword_agile_flurry,
610 "common.abilities.sword.defensive_stalwart_sword" => imgs.sword_defensive_stalwart_sword,
611 "common.abilities.sword.defensive_deflect" => imgs.sword_defensive_deflect,
612 "common.abilities.sword.crippling_eviscerate" => imgs.sword_crippling_eviscerate,
613 "common.abilities.sword.crippling_bloody_gash" => imgs.sword_crippling_bloody_gash,
614 "common.abilities.sword.cleaving_blade_fever" => imgs.sword_cleaving_blade_fever,
615 "common.abilities.sword.cleaving_sky_splitter" => imgs.sword_cleaving_sky_splitter,
616 "common.abilities.axe.triple_chop" => imgs.axe_triple_chop,
618 "common.abilities.axe.cleave" => imgs.axe_cleave,
619 "common.abilities.axe.brutal_swing" => imgs.axe_brutal_swing,
620 "common.abilities.axe.berserk" => imgs.axe_berserk,
621 "common.abilities.axe.rising_tide" => imgs.axe_rising_tide,
622 "common.abilities.axe.savage_sense" => imgs.axe_savage_sense,
623 "common.abilities.axe.adrenaline_rush" => imgs.axe_adrenaline_rush,
624 "common.abilities.axe.execute" => imgs.axe_execute,
625 "common.abilities.axe.maelstrom" => imgs.axe_maelstrom,
626 "common.abilities.axe.rake" => imgs.axe_rake,
627 "common.abilities.axe.bloodfeast" => imgs.axe_bloodfeast,
628 "common.abilities.axe.fierce_raze" => imgs.axe_fierce_raze,
629 "common.abilities.axe.dual_fierce_raze" => imgs.axe_fierce_raze,
630 "common.abilities.axe.furor" => imgs.axe_furor,
631 "common.abilities.axe.fracture" => imgs.axe_fracture,
632 "common.abilities.axe.lacerate" => imgs.axe_lacerate,
633 "common.abilities.axe.riptide" => imgs.axe_riptide,
634 "common.abilities.axe.skull_bash" => imgs.axe_skull_bash,
635 "common.abilities.axe.sunder" => imgs.axe_sunder,
636 "common.abilities.axe.plunder" => imgs.axe_plunder,
637 "common.abilities.axe.defiance" => imgs.axe_defiance,
638 "common.abilities.axe.keelhaul" => imgs.axe_keelhaul,
639 "common.abilities.axe.bulkhead" => imgs.axe_bulkhead,
640 "common.abilities.axe.capsize" => imgs.axe_capsize,
641 "common.abilities.hammer.solid_smash" => imgs.hammer_solid_smash,
643 "common.abilities.hammer.wide_wallop" => imgs.hammer_wide_wallop,
644 "common.abilities.hammer.scornful_swipe" => imgs.hammer_scornful_swipe,
645 "common.abilities.hammer.tremor" => imgs.hammer_tremor,
646 "common.abilities.hammer.vigorous_bash" => imgs.hammer_vigorous_bash,
647 "common.abilities.hammer.heavy_whorl" => imgs.hammer_heavy_whorl,
648 "common.abilities.hammer.dual_heavy_whorl" => imgs.hammer_heavy_whorl,
649 "common.abilities.hammer.intercept" => imgs.hammer_intercept,
650 "common.abilities.hammer.dual_intercept" => imgs.hammer_intercept,
651 "common.abilities.hammer.retaliate" => imgs.hammer_retaliate,
652 "common.abilities.hammer.spine_cracker" => imgs.hammer_spine_cracker,
653 "common.abilities.hammer.breach" => imgs.hammer_breach,
654 "common.abilities.hammer.pile_driver" => imgs.hammer_pile_driver,
655 "common.abilities.hammer.lung_pummel" => imgs.hammer_lung_pummel,
656 "common.abilities.hammer.helm_crusher" => imgs.hammer_helm_crusher,
657 "common.abilities.hammer.iron_tempest" => imgs.hammer_iron_tempest,
658 "common.abilities.hammer.dual_iron_tempest" => imgs.hammer_iron_tempest,
659 "common.abilities.hammer.upheaval" => imgs.hammer_upheaval,
660 "common.abilities.hammer.dual_upheaval" => imgs.hammer_upheaval,
661 "common.abilities.hammer.rampart" => imgs.hammer_rampart,
662 "common.abilities.hammer.tenacity" => imgs.hammer_tenacity,
663 "common.abilities.hammer.thunderclap" => imgs.hammer_thunderclap,
664 "common.abilities.hammer.seismic_shock" => imgs.hammer_seismic_shock,
665 "common.abilities.hammer.earthshaker" => imgs.hammer_earthshaker,
666 "common.abilities.hammer.judgement" => imgs.hammer_judgement,
667 "common.abilities.bow.arrow_shot" => imgs.bow_arrow_shot,
669 "common.abilities.bow.broadhead" => imgs.bow_broadhead,
670 "common.abilities.bow.foothold" => imgs.bow_foothold,
671 "common.abilities.bow.heavy_nock" => imgs.bow_heavy_nock,
672 "common.abilities.bow.ardent_hunt" => imgs.bow_ardent_hunt,
673 "common.abilities.bow.ardent_hunt_clear" => imgs.bow_ardent_hunt,
674 "common.abilities.bow.storm_chaser" => imgs.bow_storm_chaser,
675 "common.abilities.bow.storm_chaser_clear" => imgs.bow_storm_chaser,
676 "common.abilities.bow.eagle_eye" => imgs.bow_eagle_eye,
677 "common.abilities.bow.heartseeker" => imgs.bow_heartseeker,
678 "common.abilities.bow.heartseeker_shot" => imgs.bow_heartseeker,
679 "common.abilities.bow.burning_heartseeker_shot" => imgs.bow_burning_heartseeker,
680 "common.abilities.bow.freezing_heartseeker_shot" => imgs.bow_freezing_heartseeker,
681 "common.abilities.bow.poison_heartseeker_shot" => imgs.bow_poison_heartseeker,
682 "common.abilities.bow.lightning_heartseeker_shot" => imgs.bow_lightning_heartseeker,
683 "common.abilities.bow.hawkstrike" => imgs.bow_hawkstrike,
684 "common.abilities.bow.hawkstrike_shot" => imgs.bow_hawkstrike,
685 "common.abilities.bow.burning_hawkstrike_shot" => imgs.bow_burning_hawkstrike,
686 "common.abilities.bow.freezing_hawkstrike_shot" => imgs.bow_freezing_hawkstrike,
687 "common.abilities.bow.poison_hawkstrike_shot" => imgs.bow_poison_hawkstrike,
688 "common.abilities.bow.lightning_hawkstrike_shot" => imgs.bow_lightning_hawkstrike,
689 "common.abilities.bow.septic_shot" => imgs.bow_septic_shot,
690 "common.abilities.bow.ignite_arrow" => imgs.bow_ignite_arrow,
691 "common.abilities.bow.burning_broadhead" => imgs.bow_burning_broadhead,
692 "common.abilities.bow.drench_arrow" => imgs.bow_drench_arrow,
693 "common.abilities.bow.poison_broadhead" => imgs.bow_poison_broadhead,
694 "common.abilities.bow.freeze_arrow" => imgs.bow_freeze_arrow,
695 "common.abilities.bow.freezing_broadhead" => imgs.bow_freezing_broadhead,
696 "common.abilities.bow.jolt_arrow" => imgs.bow_jolt_arrow,
697 "common.abilities.bow.lightning_broadhead" => imgs.bow_lightning_broadhead,
698 "common.abilities.bow.barrage" => imgs.bow_barrage,
699 "common.abilities.bow.barrage_shot" => imgs.bow_barrage,
700 "common.abilities.bow.piercing_gale" => imgs.bow_piercing_gale,
701 "common.abilities.bow.fusillade" => imgs.bow_fusillade,
702 "common.abilities.bow.death_volley" => imgs.bow_death_volley,
703 "common.abilities.bow.thorn_stake" => imgs.bow_thorn_stake,
704 "common.abilities.bow.burning_thorn_stake" => imgs.bow_burning_thorn_stake,
705 "common.abilities.bow.freezing_thorn_stake" => imgs.bow_freezing_thorn_stake,
706 "common.abilities.bow.poison_thorn_stake" => imgs.bow_poison_thorn_stake,
707 "common.abilities.bow.lightning_thorn_stake" => imgs.bow_lightning_thorn_stake,
708 "common.abilities.staff.firebomb" => imgs.fireball,
710 "common.abilities.staff.flamethrower" => imgs.flamethrower,
711 "common.abilities.staff.fireshockwave" => imgs.fire_aoe,
712 "common.abilities.staff.napalm_strike" => imgs.staff_napalm_strike,
713 "common.abilities.staff.flame_cloak" => imgs.staff_flame_cloak,
714 "common.abilities.staff.fire_dash" => imgs.staff_fire_dash,
715 "common.abilities.staff.fire_breath" => imgs.staff_fire_breath,
716 "common.abilities.staff.pyroclasm" => imgs.staff_pyroclasm,
717 "common.abilities.sceptre.lifestealbeam" => imgs.skill_sceptre_lifesteal,
719 "common.abilities.sceptre.healingaura" => imgs.skill_sceptre_heal,
720 "common.abilities.sceptre.wardingaura" => imgs.skill_sceptre_aura,
721 "common.abilities.shield.singlestrike" => imgs.onehshield_m1,
723 "common.abilities.shield.power_guard" => imgs.onehshield_m1,
724 "common.abilities.dagger.tempbasic" => imgs.onehdagger_m1,
726 "common.abilities.pick.swing" => imgs.mining,
728 "common.abilities.shovel.dig" => imgs.dig,
730 "common.abilities.music.bass" => imgs.instrument,
732 "common.abilities.music.flute" => imgs.instrument,
733 "common.abilities.music.harp" => imgs.instrument,
734 "common.abilities.music.perc" => imgs.instrument,
735 "common.abilities.music.kalimba" => imgs.instrument,
736 "common.abilities.music.melodica" => imgs.instrument,
737 "common.abilities.music.lute" => imgs.instrument,
738 "common.abilities.music.oud" => imgs.instrument,
739 "common.abilities.music.guitar" => imgs.instrument,
740 "common.abilities.music.dark_guitar" => imgs.instrument,
741 "common.abilities.music.sitar" => imgs.instrument,
742 "common.abilities.music.double_bass" => imgs.instrument,
743 "common.abilities.music.glass_flute" => imgs.instrument,
744 "common.abilities.music.lyre" => imgs.instrument,
745 "common.abilities.music.wildskin_drum" => imgs.instrument,
746 "common.abilities.music.icy_talharpa" => imgs.instrument,
747 "common.abilities.music.washboard" => imgs.instrument,
748 "common.abilities.music.steeltonguedrum" => imgs.instrument,
749 "common.abilities.music.shamisen" => imgs.instrument,
750 "common.abilities.music.kora" => imgs.instrument,
751 "common.abilities.music.banjo" => imgs.instrument,
752 "common.abilities.music.viola_pizzicato" => imgs.instrument,
753 "common.abilities.music.starlight_conch" => imgs.instrument,
754 "common.abilities.music.timbrel_of_chaos" => imgs.instrument,
755 "common.abilities.music.rhythmo" => imgs.instrument,
756 "common.abilities.debug.glide_boost" => imgs.flyingrod_m2,
758 "common.abilities.debug.glide_speeder" => imgs.flyingrod_m1,
759 _ => imgs.not_found,
760 }
761}
762
763pub fn ability_description<'a>(
764 ability_id: &str,
765 loc: &'a Localization,
766) -> (Cow<'a, str>, Cow<'a, str>) {
767 let ability_i18n_key = ability_id.replace('.', "-");
768 match ability_i18n_key.as_str() {
769 "common-abilities-axe-execute"
770 | "common-abilities-axe-maelstrom"
771 | "common-abilities-axe-lacerate"
772 | "common-abilities-axe-riptide"
773 | "common-abilities-axe-bulkhead"
774 | "common-abilities-axe-capsize" => (
775 loc.get_msg(&ability_i18n_key),
776 loc.get_attr_ctx(&ability_i18n_key, "desc", &i18n::fluent_args! {
777 "min_combo" => 20,
778 "min_combo_upg" => 30,
779 }),
780 ),
781 "common-abilities-hammer-earthshaker"
782 | "common-abilities-hammer-judgement"
783 | "common-abilities-hammer-seismic_shock"
784 | "common-abilities-hammer-thunderclap" => (
785 loc.get_msg(&ability_i18n_key),
786 loc.get_attr_ctx(&ability_i18n_key, "desc", &i18n::fluent_args! {
787 "min_combo" => 20,
788 }),
789 ),
790 "common-abilities-hammer-lung_pummel" | "common-abilities-hammer-spine_cracker" => (
791 loc.get_msg(&ability_i18n_key),
792 loc.get_attr_ctx(&ability_i18n_key, "desc", &i18n::fluent_args! {
793 "min_combo" => 5,
794 }),
795 ),
796 "common-abilities-hammer-helm_crusher" => (
797 loc.get_msg(&ability_i18n_key),
798 loc.get_attr_ctx(&ability_i18n_key, "desc", &i18n::fluent_args! {
799 "min_combo" => 12,
800 }),
801 ),
802 ability_i18n_key => (
804 loc.get_msg(ability_i18n_key),
805 loc.get_attr(ability_i18n_key, "desc"),
806 ),
807 }
808}