From 54c48c71128a5983c5b13ed2b084c9cb1207743c Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Mon, 5 Sep 2022 15:48:23 +0300 Subject: [PATCH 1/3] Extract buff executor into own function --- common/systems/src/buff.rs | 349 ++++++++++++++++++++----------------- 1 file changed, 186 insertions(+), 163 deletions(-) diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index caf755edb0..56d47e933c 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -11,10 +11,10 @@ use common::{ Energy, Group, Health, HealthChange, Inventory, LightEmitter, ModifierKind, PhysicsState, Stats, }, - event::{EventBus, ServerEvent}, + event::{Emitter, EventBus, ServerEvent}, resources::{DeltaTime, Time}, terrain::SpriteKind, - uid::UidAllocator, + uid::{Uid, UidAllocator}, Damage, DamageSource, }; use common_base::prof_span; @@ -22,8 +22,8 @@ use common_ecs::{Job, Origin, ParMode, Phase, System}; use hashbrown::HashMap; use rayon::iter::ParallelIterator; use specs::{ - saveload::MarkerAllocator, shred::ResourceId, Entities, Join, ParJoin, Read, ReadExpect, - ReadStorage, SystemData, World, WriteStorage, + saveload::MarkerAllocator, shred::ResourceId, Entities, Entity, Join, ParJoin, Read, + ReadExpect, ReadStorage, SystemData, World, WriteStorage, }; use std::time::Duration; @@ -257,165 +257,19 @@ impl<'a> System<'a> for Sys { // Now, execute the buff, based on it's delta for effect in &mut buff.effects { - match effect { - BuffEffect::HealthChangeOverTime { - rate, - accumulated, - kind, - instance, - } => { - *accumulated += *rate * dt; - // Apply health change only once per second, per health, or - // when a buff is removed - if accumulated.abs() > rate.abs().min(1.0) - || buff.time.map_or(false, |dur| dur == Duration::default()) - { - let (cause, by) = if *accumulated != 0.0 { - (Some(DamageSource::Buff(buff.kind)), buff_owner) - } else { - (None, None) - }; - let amount = match *kind { - ModifierKind::Additive => *accumulated, - ModifierKind::Fractional => health.maximum() * *accumulated, - }; - let damage_contributor = by.and_then(|uid| { - read_data.uid_allocator.retrieve_entity_internal(uid.0).map( - |entity| { - DamageContributor::new( - uid, - read_data.groups.get(entity).cloned(), - ) - }, - ) - }); - server_emitter.emit(ServerEvent::HealthChange { - entity, - change: HealthChange { - amount, - by: damage_contributor, - cause, - time: *read_data.time, - crit: false, - instance: *instance, - }, - }); - *accumulated = 0.0; - }; - }, - BuffEffect::EnergyChangeOverTime { - rate, - accumulated, - kind, - } => { - *accumulated += *rate * dt; - // Apply energy change only once per second, per energy, or - // when a buff is removed - if accumulated.abs() > rate.abs().min(10.0) - || buff.time.map_or(false, |dur| dur == Duration::default()) - { - let amount = match *kind { - ModifierKind::Additive => *accumulated, - ModifierKind::Fractional => { - energy.maximum() as f32 * *accumulated - }, - }; - server_emitter.emit(ServerEvent::EnergyChange { - entity, - change: amount, - }); - *accumulated = 0.0; - }; - }, - BuffEffect::MaxHealthModifier { value, kind } => match kind { - ModifierKind::Additive => { - stat.max_health_modifiers.add_mod += *value; - }, - ModifierKind::Fractional => { - stat.max_health_modifiers.mult_mod *= *value; - }, - }, - BuffEffect::MaxEnergyModifier { value, kind } => match kind { - ModifierKind::Additive => { - stat.max_energy_modifiers.add_mod += *value; - }, - ModifierKind::Fractional => { - stat.max_energy_modifiers.mult_mod *= *value; - }, - }, - BuffEffect::DamageReduction(dr) => { - stat.damage_reduction = stat.damage_reduction.max(*dr).min(1.0); - }, - BuffEffect::MaxHealthChangeOverTime { - rate, - kind, - target_fraction, - achieved_fraction, - } => { - // Current fraction uses information from last tick, which is - // necessary as buffs from this tick are not guaranteed to have - // finished applying - let current_fraction = health.maximum() / health.base_max(); - - // If achieved_fraction not initialized, initialize it to health - // fraction - if achieved_fraction.is_none() { - *achieved_fraction = Some(current_fraction) - } - - if let Some(achieved_fraction) = achieved_fraction { - // Percentage change that should be applied to max_health - let health_tick = match kind { - ModifierKind::Additive => { - // `rate * dt` is amount of health, dividing by base max - // creates fraction - *rate * dt / health.base_max() as f32 - }, - ModifierKind::Fractional => { - // `rate * dt` is the fraction - *rate * dt - }, - }; - - let potential_fraction = *achieved_fraction + health_tick; - - // Potential progress towards target fraction, if - // target_fraction ~ 1.0 then set progress to 1.0 to avoid - // divide by zero - let progress = if (1.0 - *target_fraction).abs() > f32::EPSILON - { - (1.0 - potential_fraction) / (1.0 - *target_fraction) - } else { - 1.0 - }; - - // Change achieved_fraction depending on what other buffs have - // occurred - if progress > 1.0 { - // If potential fraction already beyond target fraction, - // simply multiply max_health_modifier by the target - // fraction, and set achieved fraction to target_fraction - *achieved_fraction = *target_fraction; - } else { - // Else have not achieved target yet, update - // achieved_fraction - *achieved_fraction = potential_fraction; - } - - // Apply achieved_fraction to max_health_modifier - stat.max_health_modifiers.mult_mod *= *achieved_fraction; - } - }, - BuffEffect::MovementSpeed(speed) => { - stat.move_speed_modifier *= *speed; - }, - BuffEffect::AttackSpeed(speed) => { - stat.attack_speed_modifier *= *speed; - }, - BuffEffect::GroundFriction(gf) => { - stat.friction_modifier *= *gf; - }, - }; + execute_effect( + effect, + buff.kind, + buff.time, + &read_data, + &mut *stat, + health, + energy, + entity, + buff_owner, + &mut server_emitter, + dt, + ); } } } @@ -446,6 +300,175 @@ impl<'a> System<'a> for Sys { } } +fn execute_effect( + effect: &mut BuffEffect, + buff_kind: BuffKind, + buff_time: Option, + read_data: &ReadData, + stat: &mut Stats, + health: &Health, + energy: &Energy, + entity: Entity, + buff_owner: Option, + server_emitter: &mut Emitter, + dt: f32, +) { + match effect { + BuffEffect::HealthChangeOverTime { + rate, + accumulated, + kind, + instance, + } => { + *accumulated += *rate * dt; + // Apply health change only once per second, per health, or + // when a buff is removed + if accumulated.abs() > rate.abs().min(1.0) + || buff_time.map_or(false, |dur| dur == Duration::default()) + { + let (cause, by) = if *accumulated != 0.0 { + (Some(DamageSource::Buff(buff_kind)), buff_owner) + } else { + (None, None) + }; + let amount = match *kind { + ModifierKind::Additive => *accumulated, + ModifierKind::Fractional => health.maximum() * *accumulated, + }; + let damage_contributor = by.and_then(|uid| { + read_data + .uid_allocator + .retrieve_entity_internal(uid.0) + .map(|entity| { + DamageContributor::new(uid, read_data.groups.get(entity).cloned()) + }) + }); + server_emitter.emit(ServerEvent::HealthChange { + entity, + change: HealthChange { + amount, + by: damage_contributor, + cause, + time: *read_data.time, + crit: false, + instance: *instance, + }, + }); + *accumulated = 0.0; + }; + }, + BuffEffect::EnergyChangeOverTime { + rate, + accumulated, + kind, + } => { + *accumulated += *rate * dt; + // Apply energy change only once per second, per energy, or + // when a buff is removed + if accumulated.abs() > rate.abs().min(10.0) + || buff_time.map_or(false, |dur| dur == Duration::default()) + { + let amount = match *kind { + ModifierKind::Additive => *accumulated, + ModifierKind::Fractional => energy.maximum() as f32 * *accumulated, + }; + server_emitter.emit(ServerEvent::EnergyChange { + entity, + change: amount, + }); + *accumulated = 0.0; + }; + }, + BuffEffect::MaxHealthModifier { value, kind } => match kind { + ModifierKind::Additive => { + stat.max_health_modifiers.add_mod += *value; + }, + ModifierKind::Fractional => { + stat.max_health_modifiers.mult_mod *= *value; + }, + }, + BuffEffect::MaxEnergyModifier { value, kind } => match kind { + ModifierKind::Additive => { + stat.max_energy_modifiers.add_mod += *value; + }, + ModifierKind::Fractional => { + stat.max_energy_modifiers.mult_mod *= *value; + }, + }, + BuffEffect::DamageReduction(dr) => { + stat.damage_reduction = stat.damage_reduction.max(*dr).min(1.0); + }, + BuffEffect::MaxHealthChangeOverTime { + rate, + kind, + target_fraction, + achieved_fraction, + } => { + // Current fraction uses information from last tick, which is + // necessary as buffs from this tick are not guaranteed to have + // finished applying + let current_fraction = health.maximum() / health.base_max(); + + // If achieved_fraction not initialized, initialize it to health + // fraction + if achieved_fraction.is_none() { + *achieved_fraction = Some(current_fraction) + } + + if let Some(achieved_fraction) = achieved_fraction { + // Percentage change that should be applied to max_health + let health_tick = match kind { + ModifierKind::Additive => { + // `rate * dt` is amount of health, dividing by base max + // creates fraction + *rate * dt / health.base_max() as f32 + }, + ModifierKind::Fractional => { + // `rate * dt` is the fraction + *rate * dt + }, + }; + + let potential_fraction = *achieved_fraction + health_tick; + + // Potential progress towards target fraction, if + // target_fraction ~ 1.0 then set progress to 1.0 to avoid + // divide by zero + let progress = if (1.0 - *target_fraction).abs() > f32::EPSILON { + (1.0 - potential_fraction) / (1.0 - *target_fraction) + } else { + 1.0 + }; + + // Change achieved_fraction depending on what other buffs have + // occurred + if progress > 1.0 { + // If potential fraction already beyond target fraction, + // simply multiply max_health_modifier by the target + // fraction, and set achieved fraction to target_fraction + *achieved_fraction = *target_fraction; + } else { + // Else have not achieved target yet, update + // achieved_fraction + *achieved_fraction = potential_fraction; + } + + // Apply achieved_fraction to max_health_modifier + stat.max_health_modifiers.mult_mod *= *achieved_fraction; + } + }, + BuffEffect::MovementSpeed(speed) => { + stat.move_speed_modifier *= *speed; + }, + BuffEffect::AttackSpeed(speed) => { + stat.attack_speed_modifier *= *speed; + }, + BuffEffect::GroundFriction(gf) => { + stat.friction_modifier *= *gf; + }, + }; +} + fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64)) { // If a buff is recently applied from an aura, do not tick duration if buff From 34c5e95d8a3e779639608d686edd776016be9c11 Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Mon, 5 Sep 2022 17:16:18 +0300 Subject: [PATCH 2/3] Add Energy regen buff * Fix broken i18n keys for health and energy increases * Better handle buff descriptions Calculate infobox lines for item stats to set correct infobox frame dimensions --- assets/voxygen/i18n/en/buff.ftl | 44 ++++++++-- assets/voxygen/i18n/uk_UA/buff.ftl | 43 ++++++++-- common/src/cmd.rs | 5 +- common/src/comp/buff.rs | 18 ++++- voxygen/src/hud/chat.rs | 1 + voxygen/src/hud/mod.rs | 13 ++- voxygen/src/hud/util.rs | 107 ++++++++++++++----------- voxygen/src/ui/widgets/item_tooltip.rs | 5 +- 8 files changed, 163 insertions(+), 73 deletions(-) diff --git a/assets/voxygen/i18n/en/buff.ftl b/assets/voxygen/i18n/en/buff.ftl index 8aefd0a07d..3cd5c8464d 100644 --- a/assets/voxygen/i18n/en/buff.ftl +++ b/assets/voxygen/i18n/en/buff.ftl @@ -1,39 +1,67 @@ -buff-remove = Click to remove -buff-title-missing = Missing Title -buff-desc-missing = Missing Description +## Regeneration buff-title-heal = Heal buff-desc-heal = Gain health over time. +buff-stat-health = Restores { $str_total } Health +## Potion buff-title-potion = Potion buff-desc-potion = Drinking... +## Saturation buff-title-saturation = Saturation buff-desc-saturation = Gain health over time from consumables. +## Campfire buff-title-campfire_heal = Campfire Heal buff-desc-campfire_heal = Resting at a campfire heals { $rate }% per second. +## Energy Regen +buff-title-energy_regen = Energy Regeneration +buff-desc-energy_regen = Faster energy regeneration +buff-stat-energy_regen = Restores { $str_total } Energy +## Health Increase +buff-title-increase_max_health = Increase Max Health +buff-desc-increase_max_health = Raise your max health cap +buff-stat-increase_max_health = + Raises maximum health + by { $strength } +## Energy Increase +buff-title-increase_max_energy = Increase Max Energy +buff-desc-increase_max_energy = Raise your max energy cap +buff-stat-increase_max_energy = + Raises maximum energy + by { $strength } +## Invulnerability buff-title-invulnerability = Invulnerability buff-desc-invulnerability = You cannot be damaged by any attack. +buff-stat-invulnerability = Grants invulnerability +## Protection Ward buff-title-protectingward = Protecting Ward buff-desc-protectingward = You are protected, somewhat, from attacks. +## Frenzied buff-title-frenzied = Frenzied buff-desc-frenzied = You are imbued with unnatural speed and can ignore minor injuries. +## Haste buff-title-hastened = Hastened buff-desc-hastened = Your movements and attacks are faster. +## Bleeding buff-title-bleed = Bleeding buff-desc-bleed = Inflicts regular damage. +## Curse buff-title-cursed = Cursed buff-desc-cursed = You are cursed. +## Burning buff-title-burn = On Fire buff-desc-burn = You are burning alive +## Crippled buff-title-crippled = Crippled buff-desc-crippled = Your movement is crippled as your legs are heavily injured. +## Freeze buff-title-frozen = Frozen buff-desc-frozen = Your movements and attacks are slowed. +## Wet buff-title-wet = Wet buff-desc-wet = The ground rejects your feet, making it hard to stop. +## Ensnared buff-title-ensnared = Ensnared buff-desc-ensnared = Vines grasp at your legs, impeding your movement. -buff-stat-health = Restores { $str_total } Health -buff-stat-increase_max_energy = Raises Maximum Energy by { $strength } -buff-stat-increase_max_health = Raises Maximum Health by { $strength } -buff-stat-invulnerability = Grants invulnerability +## Util buff-text-over_seconds = over { $dur_secs } seconds -buff-text-for_seconds = for { $dur_secs } seconds \ No newline at end of file +buff-text-for_seconds = for { $dur_secs } seconds +buff-remove = Click to remove diff --git a/assets/voxygen/i18n/uk_UA/buff.ftl b/assets/voxygen/i18n/uk_UA/buff.ftl index 103fbb6ff6..a80c6d9ba9 100644 --- a/assets/voxygen/i18n/uk_UA/buff.ftl +++ b/assets/voxygen/i18n/uk_UA/buff.ftl @@ -1,37 +1,64 @@ -buff-remove = Клікніть, щоб видалити -buff-title-missing = Назва відсутня -buff-desc-missing = Опис відсутній +## Regeneration buff-title-heal = Зцілення buff-desc-heal = Поступово відновлює Здоров'я. +buff-stat-health = Відновлює { $str_total } ОЗ +## Potion buff-title-potion = Зілля buff-desc-potion = Пиття... +## Saturation buff-title-saturation = Насичення buff-desc-saturation = Поступово відновлює Здоров'я з їжі. +## Campfire buff-title-campfire_heal = Відновлення біля ватри buff-desc-campfire_heal = Відпочинок біля ватри лікує на { $rate }% за секунду. +## Energy Regen +buff-title-energy_regen = Відновлення Енергії +buff-desc-energy_regen = Поступово відновляє Eнергію +buff-stat-energy-regen = Відновлює { $str_total } енергії +## Health Increase +buff-title-increase_max_health = Підвищення Максимального Здоров'я +buff-desc-increase_max_health = Піднімає ліміт вашого здоров'я +buff-stat-increase_max_health = + Підвищує максимальне здоров'я + на { $strength } +## Energy Increase +buff-title-increase_max_energy = Підвищення Максимальної Енергії +buff-desc-increase_max_energy = Піднімає ліміт вашої енергії +buff-stat-increase_max_energy = + Підвищує максимальну енергію + на { $strength } +## Invulnerability buff-title-invulnerability = Невразливість buff-desc-invulnerability = Ви невразливий, тільки тримайтесь подалі від омели. +buff-stat-invulnerability = Дає невразливість +## Protection Ward buff-title-protectingward = Захисна Аура buff-desc-protectingward = Ви захищені від атак, у якомусь сенсі. +## Frenized buff-title-frenzied = Манія buff-desc-frenzied = Кров тече швидше, прискоруючи ваш рух та помалу зцілюючи вас. +## Cursed buff-title-cursed = Проклін buff-desc-cursed = Вас прокляли. +## Bleeding buff-title-bleed = Кровотеча buff-desc-bleed = Завдає регулярних пошкодженнь. +## Burning buff-title-burn = У Вогні buff-desc-burn = Ви згораєте заживо. +## Crippled buff-title-crippled = Калічення buff-desc-crippled = Ваші рухи дуже скуті через отримані травми. +## Freeze buff-title-frozen = Обмороження buff-desc-frozen = Швидкість пересування та атак знижена. +## Wet buff-title-wet = Волога buff-desc-wet = Земля плутає ваші ноги ускладнючи пересування. +## Ensnared buff-title-ensnared = Пастка buff-desc-ensnared = Ліани опутують ваші ноги, перешкоджаючи ходьбі. -buff-stat-health = Відновлює { $str_total } ОЗ -buff-stat-increase_max_health = Підвищує Максимальне Здоров'я на { $strength } -buff-stat-increase_max_energy = Підвищує Максимальну Енергію на { $strength } -buff-stat-invulnerability = Дає невразливість +## Util buff-text-for_seconds = протягом { $dur_secs } сек. -buff-text-over_seconds = впродовж { $dur_secs } сек. \ No newline at end of file +buff-text-over_seconds = впродовж { $dur_secs } сек. +buff-remove = Клікніть, щоб видалити diff --git a/common/src/cmd.rs b/common/src/cmd.rs index ed8c986797..c0a4e330e8 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -141,6 +141,7 @@ lazy_static! { BuffKind::Cursed => "cursed", BuffKind::Potion => "potion", BuffKind::CampfireHeal => "campfire_heal", + BuffKind::EnergyRegen => "energy_regen", BuffKind::IncreaseMaxEnergy => "increase_max_energy", BuffKind::IncreaseMaxHealth => "increase_max_health", BuffKind::Invulnerability => "invulnerability", @@ -154,7 +155,9 @@ lazy_static! { BuffKind::Hastened => "hastened", }; let mut buff_parser = HashMap::new(); - BuffKind::iter().for_each(|kind| {buff_parser.insert(string_from_buff(kind).to_string(), kind);}); + for kind in BuffKind::iter() { + buff_parser.insert(string_from_buff(kind).to_string(), kind); + } buff_parser }; diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index db2b4c32dc..572b5e8af3 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -27,6 +27,9 @@ pub enum BuffKind { /// Applied when sitting at a campfire /// Strength is fraction of health restored per second CampfireHeal, + /// Restores energy/time for some period + /// Strength should be the healing per second + EnergyRegen, /// Raises maximum energy /// Strength should be 10x the effect to max energy IncreaseMaxEnergy, @@ -91,6 +94,7 @@ impl BuffKind { | BuffKind::Potion | BuffKind::CampfireHeal | BuffKind::Frenzied + | BuffKind::EnergyRegen | BuffKind::IncreaseMaxEnergy | BuffKind::IncreaseMaxHealth | BuffKind::Invulnerability @@ -279,6 +283,14 @@ impl Buff { ], data.duration, ), + BuffKind::EnergyRegen => ( + vec![BuffEffect::EnergyChangeOverTime { + rate: data.strength, + accumulated: 0.0, + kind: ModifierKind::Additive, + }], + data.duration, + ), BuffKind::IncreaseMaxEnergy => ( vec![BuffEffect::MaxEnergyModifier { value: data.strength, @@ -296,9 +308,9 @@ impl Buff { BuffKind::Invulnerability => (vec![BuffEffect::DamageReduction(1.0)], data.duration), BuffKind::ProtectingWard => ( vec![BuffEffect::DamageReduction( - // Causes non-linearity in effect strength, but necessary to allow for tool - // power and other things to affect the strength. 0.5 also still provides 50% - // damage reduction. + // Causes non-linearity in effect strength, but necessary + // to allow for tool power and other things to affect the + // strength. 0.5 also still provides 50% damage reduction. nn_scaling(data.strength), )], data.duration, diff --git a/voxygen/src/hud/chat.rs b/voxygen/src/hud/chat.rs index 6ec3d2c32b..3c4896a4fc 100644 --- a/voxygen/src/hud/chat.rs +++ b/voxygen/src/hud/chat.rs @@ -788,6 +788,7 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat | BuffKind::Saturation | BuffKind::Potion | BuffKind::CampfireHeal + | BuffKind::EnergyRegen | BuffKind::IncreaseMaxEnergy | BuffKind::IncreaseMaxHealth | BuffKind::Invulnerability diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 5d950626d1..23c1e8d970 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -4564,6 +4564,7 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id { BuffKind::Saturation { .. } => imgs.buff_saturation_0, BuffKind::Potion { .. } => imgs.buff_potion_0, BuffKind::CampfireHeal { .. } => imgs.buff_campfire_heal_0, + BuffKind::EnergyRegen { .. } => imgs.buff_energyplus_0, BuffKind::IncreaseMaxEnergy { .. } => imgs.buff_energyplus_0, BuffKind::IncreaseMaxHealth { .. } => imgs.buff_healthplus_0, BuffKind::Invulnerability => imgs.buff_invincibility_0, @@ -4589,10 +4590,13 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> Cow localized_strings.get_msg("buff-title-saturation"), BuffKind::Potion { .. } => localized_strings.get_msg("buff-title-potion"), BuffKind::CampfireHeal { .. } => localized_strings.get_msg("buff-title-campfire_heal"), + BuffKind::EnergyRegen { .. } => localized_strings.get_msg("buff-title-energy_regen"), BuffKind::IncreaseMaxHealth { .. } => { - localized_strings.get_msg("buff-title-IncreaseMaxHealth") + localized_strings.get_msg("buff-title-increase_max_health") + }, + BuffKind::IncreaseMaxEnergy { .. } => { + localized_strings.get_msg("buff-title-increase_max_energy") }, - BuffKind::IncreaseMaxEnergy { .. } => localized_strings.get_msg("buff-title-energyup"), BuffKind::Invulnerability => localized_strings.get_msg("buff-title-invulnerability"), BuffKind::ProtectingWard => localized_strings.get_msg("buff-title-protectingward"), BuffKind::Frenzied => localized_strings.get_msg("buff-title-frenzied"), @@ -4620,11 +4624,12 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz "rate" => data.strength * 100.0 }) }, + BuffKind::EnergyRegen { .. } => localized_strings.get_msg("buff-desc-energy_regen"), BuffKind::IncreaseMaxHealth { .. } => { - localized_strings.get_msg("buff-desc-IncreaseMaxHealth") + localized_strings.get_msg("buff-desc-increase_max_health") }, BuffKind::IncreaseMaxEnergy { .. } => { - localized_strings.get_msg("buff-desc-IncreaseMaxEnergy") + localized_strings.get_msg("buff-desc-increase_max_energy") }, BuffKind::Invulnerability => localized_strings.get_msg("buff-desc-invulnerability"), BuffKind::ProtectingWard => localized_strings.get_msg("buff-desc-protectingward"), diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index 774ce0f63f..5c4eff6369 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -21,51 +21,43 @@ pub fn price_desc<'a>( item_definition_id: ItemDefinitionId<'_>, i18n: &'a Localization, ) -> Option<(Cow<'a, str>, Cow<'a, str>, f32)> { - if let Some(prices) = prices { - if let Some(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 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::() - / prices.values.get(&Good::Coin).cloned().unwrap_or(1.0) - / (materials.len() as f32); - let deal_goodness = deal_goodness.log(2.0); + let deal_goodness: f32 = materials + .iter() + .map(|e| prices.values.get(&e.1).cloned().unwrap_or(0.0)) + .sum::() + / 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 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)) - } else { - None - } - } else { - None - } + 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> { @@ -126,6 +118,21 @@ pub fn stats_count(item: &dyn ItemDesc, msm: &MaterialStatManifest) -> usize { } } +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 /// @@ -149,6 +156,11 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec { .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), + }) + }, BuffKind::IncreaseMaxEnergy => { i18n.get_msg_ctx("buff-stat-increase_max_energy", &i18n::fluent_args! { "strength" => format_float(strength), @@ -178,11 +190,10 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec { let dur_desc = if let Some(dur_secs) = dur_secs { match buff.kind { - BuffKind::Saturation | BuffKind::Regeneration => { - i18n.get_msg_ctx("buff-text-over_seconds", &i18n::fluent_args! { + BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen => i18n + .get_msg_ctx("buff-text-over_seconds", &i18n::fluent_args! { "dur_secs" => dur_secs - }) - }, + }), BuffKind::IncreaseMaxEnergy | BuffKind::IncreaseMaxHealth | BuffKind::Invulnerability => { @@ -204,7 +215,9 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> Vec { | BuffKind::Poisoned | BuffKind::Hastened => Cow::Borrowed(""), } - } else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind { + } else if let BuffKind::Saturation | BuffKind::Regeneration | BuffKind::EnergyRegen = + buff.kind + { i18n.get_msg("buff-text-every_second") } else { Cow::Borrowed("") diff --git a/voxygen/src/ui/widgets/item_tooltip.rs b/voxygen/src/ui/widgets/item_tooltip.rs index ba86d89af7..e8d06bf9a4 100644 --- a/voxygen/src/ui/widgets/item_tooltip.rs +++ b/voxygen/src/ui/widgets/item_tooltip.rs @@ -1248,7 +1248,7 @@ impl<'a> Widget for ItemTooltip<'a> { let frame_h = ICON_SIZE[1] + V_PAD; // Stats - let stats_count = util::stats_count(self.item, self.msm); + let stats_count = util::line_count(self.item, self.msm, self.localized_strings); let stat_h = if stats_count > 0 { widget::Text::new("placeholder") .with_style(self.style.desc) @@ -1294,7 +1294,8 @@ impl<'a> Widget for ItemTooltip<'a> { 0.0 }; - let height = frame_h + stat_h + desc_h + price_h + V_PAD + 5.0; // extra padding to fit frame top padding + // extra padding to fit frame top padding + let height = frame_h + stat_h + desc_h + price_h + V_PAD + 5.0; Dimension::Absolute(height) } } From 3cbfe02a8e1a687ee50b4564f680df3571727243 Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Mon, 5 Sep 2022 21:57:45 +0300 Subject: [PATCH 3/3] Add Golden Cheese debug item --- assets/common/items/debug/golden_cheese.ron | 55 +++++++++++++++++++++ assets/server/manifests/kits.ron | 1 + assets/voxygen/item_image_manifest.ron | 5 ++ 3 files changed, 61 insertions(+) create mode 100644 assets/common/items/debug/golden_cheese.ron diff --git a/assets/common/items/debug/golden_cheese.ron b/assets/common/items/debug/golden_cheese.ron new file mode 100644 index 0000000000..37d23c0fa0 --- /dev/null +++ b/assets/common/items/debug/golden_cheese.ron @@ -0,0 +1,55 @@ +ItemDef( + name: "Golden Cheese", + description: "They say gods eat it to get eternal youth.", + kind: Consumable( + kind: Drink, + effects: [ + Buff(( + kind: Regeneration, + data: ( + strength: 1000, + duration: Some(( + secs: 999, + nanos: 0, + )), + ), + cat_ids: [Natural], + )), + Buff(( + kind: EnergyRegen, + data: ( + strength: 1000, + duration: Some(( + secs: 999, + nanos: 0, + )), + ), + cat_ids: [Natural], + )), + Buff(( + kind: IncreaseMaxHealth, + data: ( + strength: 50000, + duration: Some(( + secs: 999, + nanos: 0, + )), + ), + cat_ids: [Natural], + )), + Buff(( + kind: IncreaseMaxEnergy, + data: ( + strength: 50000, + duration: Some(( + secs: 999, + nanos: 0, + )), + ), + cat_ids: [Natural], + )), + ] + ), + quality: Debug, + tags: [Food], +) diff --git a/assets/server/manifests/kits.ron b/assets/server/manifests/kits.ron index 0cbbde29bc..e6b2bd4bcf 100644 --- a/assets/server/manifests/kits.ron +++ b/assets/server/manifests/kits.ron @@ -5,6 +5,7 @@ (Item("common.items.debug.admin_sword"),1), (Item("common.items.debug.velorite_bow_debug"), 1), (Item("common.items.debug.admin"),1), + (Item("common.items.debug.golden_cheese"),100), ], "consumables": [ (Item("common.items.consumable.potion_big"), 100), diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron index 7dd0e4a4c0..8e341d120c 100644 --- a/assets/voxygen/item_image_manifest.ron +++ b/assets/voxygen/item_image_manifest.ron @@ -3189,6 +3189,11 @@ "voxel.sprite.food.salad_tomato", (0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.8, ), + // Admin consumables + Simple("common.items.debug.golden_cheese"): VoxTrans( + "voxel.object.item_cheese", + (0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7, + ), // Throwables Simple("common.items.utility.bomb"): VoxTrans( "voxel.object.bomb",