diff --git a/assets/common/items/charms/burning_charm.ron b/assets/common/items/charms/burning_charm.ron new file mode 100644 index 0000000000..220d092304 --- /dev/null +++ b/assets/common/items/charms/burning_charm.ron @@ -0,0 +1,20 @@ +ItemDef( + name: "Blazing Charm", + description: "Flame is your ally, harness its power to burn your foes.", + kind: Consumable( + kind: Drink, + effects: All([ + Buff(( + kind: Flame, + data: ( + strength: 0.4, + duration: Some(20), + ), + cat_ids: [Natural], + )), + + ]) + ), + quality: Legendary, + tags: [], +) \ No newline at end of file diff --git a/assets/common/items/charms/frozen_charm.ron b/assets/common/items/charms/frozen_charm.ron new file mode 100644 index 0000000000..82c70063b3 --- /dev/null +++ b/assets/common/items/charms/frozen_charm.ron @@ -0,0 +1,20 @@ +ItemDef( + name: "Freezing Charm", + description: "Let your enemies feel the sting of cold as you freeze them in their tracks.", + kind: Consumable( + kind: Drink, + effects: All([ + Buff(( + kind: Frigid, + data: ( + strength: 0.4, + duration: Some(20), + ), + cat_ids: [Natural], + )), + + ]) + ), + quality: Legendary, + tags: [], +) \ No newline at end of file diff --git a/assets/common/items/charms/lifesteal_charm.ron b/assets/common/items/charms/lifesteal_charm.ron new file mode 100644 index 0000000000..7455489d82 --- /dev/null +++ b/assets/common/items/charms/lifesteal_charm.ron @@ -0,0 +1,20 @@ +ItemDef( + name: "Siphon Charm", + description: "Siphon your target life and use it for your own.", + kind: Consumable( + kind: Drink, + effects: All([ + Buff(( + kind: Lifesteal, + data: ( + strength: 0.4, + duration: Some(20), + ), + cat_ids: [Natural], + )), + + ]) + ), + quality: Legendary, + tags: [], +) \ No newline at end of file diff --git a/assets/voxygen/i18n/en/buff.ftl b/assets/voxygen/i18n/en/buff.ftl index a572deb87e..4b9c803dc4 100644 --- a/assets/voxygen/i18n/en/buff.ftl +++ b/assets/voxygen/i18n/en/buff.ftl @@ -79,6 +79,15 @@ buff-desc-reckless = Your attacks are more powerful, however you are leaving you ## Polymorped buff-title-polymorphed = Polymorphed buff-desc-polymorphed = Your body changes form. +## Flame +buff-title-flame = Flame +buff-desc-flame = Flame is your ally. +## Frigid +buff-title-frigid = Frigid +buff-desc-frigid = Freeze your foes. +## Lifesteal +buff-title-lifesteal = Lifesteal +buff-desc-lifesteal = Siphon your enemies life away. ## Util buff-text-over_seconds = over { $dur_secs } seconds buff-text-for_seconds = for { $dur_secs } seconds diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron index 40dd2f6f69..f35e7d5ddc 100644 --- a/assets/voxygen/item_image_manifest.ron +++ b/assets/voxygen/item_image_manifest.ron @@ -3154,6 +3154,18 @@ "voxel.object.curious_potion", (0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7, ), + Simple("common.items.charms.burning_charm"): VoxTrans( + "voxel.object.burning_charm", + (0.0, 0.0, 0.0), (-80.0, 15.0, 15.0), 1.0, + ), + Simple("common.items.charms.frozen_charm"): VoxTrans( + "voxel.object.frozen_charm", + (0.0, 0.0, 0.0), (-80.0, 15.0, 15.0), 1.0, + ), + Simple("common.items.charms.lifesteal_charm"): VoxTrans( + "voxel.object.lifesteal_charm", + (0.0, 0.0, 0.0), (-80.0, 15.0, 15.0), 1.0, + ), Simple("common.items.food.cheese"): VoxTrans( "voxel.object.cheese", (0.0, 0.0, 0.0), (-60.0, 27.0, 17.0), 0.7, diff --git a/assets/voxygen/voxel/item_drop_manifest.ron b/assets/voxygen/voxel/item_drop_manifest.ron index 09c0f7cead..1d6ac3f0d4 100644 --- a/assets/voxygen/voxel/item_drop_manifest.ron +++ b/assets/voxygen/voxel/item_drop_manifest.ron @@ -798,6 +798,9 @@ Simple("common.items.consumable.potion_minor"): "voxel.object.potion_red", Simple("common.items.consumable.potion_big"): "voxel.object.potion_red", Simple("common.items.consumable.curious_potion"): "voxel.object.curious_potion", + Simple("common.items.charms.burning_charm"): "voxel.object.burning_charm", + Simple("common.items.charms.frozen_charm"): "voxel.object.frozen_charm", + Simple("common.items.charms.lifesteal_charm"): "voxel.object.lifesteal_charm", Simple("common.items.boss_drops.potions"): "voxel.object.potion_red", Simple("common.items.food.cheese"): "voxel.object.cheese", Simple("common.items.food.blue_cheese"): "voxel.object.blue_cheese", diff --git a/assets/voxygen/voxel/object/burning_charm.vox b/assets/voxygen/voxel/object/burning_charm.vox new file mode 100644 index 0000000000..042664b1e6 --- /dev/null +++ b/assets/voxygen/voxel/object/burning_charm.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3789cbc24ad5ff295f3144348bed61704bdf2f90057925c30f16db2fccee06c +size 23192 diff --git a/assets/voxygen/voxel/object/frozen_charm.vox b/assets/voxygen/voxel/object/frozen_charm.vox new file mode 100644 index 0000000000..638355761d --- /dev/null +++ b/assets/voxygen/voxel/object/frozen_charm.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68207ba110cf30e97da5c004322f2b39b1434b894ca00d70dc2d06f1985db4dc +size 23192 diff --git a/assets/voxygen/voxel/object/lifesteal_charm.vox b/assets/voxygen/voxel/object/lifesteal_charm.vox new file mode 100644 index 0000000000..160156ae64 --- /dev/null +++ b/assets/voxygen/voxel/object/lifesteal_charm.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b59b8431632dd8331b880498edd804da4c328824f2303fdfb275d0720f7fd0d8 +size 23192 diff --git a/common/src/cmd.rs b/common/src/cmd.rs index 0e9c18bebd..528ed79474 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -158,6 +158,9 @@ lazy_static! { BuffKind::PotionSickness => "potion_sickness", BuffKind::Reckless => "reckless", BuffKind::Polymorphed(_) => "polymorphed", + BuffKind::Flame => "flame", + BuffKind::Frigid => "frigid", + BuffKind::Lifesteal => "lifesteal", }; let mut buff_parser = HashMap::new(); for kind in BuffKind::iter() { diff --git a/common/src/combat.rs b/common/src/combat.rs index 7026a14b4c..bec5f2a492 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -516,6 +516,12 @@ impl Attack { for effect in self .effects .iter() + .chain( + attacker + .and_then(|attacker| attacker.stats) + .iter() + .flat_map(|stats| stats.buffs_on_hit.iter()), + ) .filter(|e| e.target.map_or(true, |t| t == target_group)) .filter(|e| !avoid_effect(e)) { diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 5a29d122da..a138af295a 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -1,9 +1,11 @@ #![allow(clippy::nonstandard_macro_braces)] //tmp as of false positive !? use crate::{ + combat::{AttackEffect, CombatBuff, CombatBuffStrength, CombatEffect}, comp::{aura::AuraKey, Health, Stats}, resources::{Secs, Time}, uid::Uid, }; + use core::cmp::Ordering; #[cfg(not(target_arch = "wasm32"))] use hashbrown::HashMap; @@ -111,6 +113,12 @@ pub enum BuffKind { PotionSickness, // Changed into another body. Polymorphed(Body), + // Inflict burning on your attack + Flame, + // Inflict frost on your attack + Frigid, + // Gain Lifesteal on your attack + Lifesteal, } #[cfg(not(target_arch = "wasm32"))] @@ -130,7 +138,10 @@ impl BuffKind { | BuffKind::ProtectingWard | BuffKind::Hastened | BuffKind::Fortitude - | BuffKind::Reckless => true, + | BuffKind::Reckless + | BuffKind::Flame + | BuffKind::Frigid + | BuffKind::Lifesteal => true, BuffKind::Bleeding | BuffKind::Cursed | BuffKind::Burning @@ -285,6 +296,28 @@ impl BuffKind { BuffEffect::AttackDamage(1.0 + data.strength), ], BuffKind::Polymorphed(body) => vec![BuffEffect::BodyChange(*body)], + BuffKind::Flame => vec![BuffEffect::BuffOnHit(AttackEffect::new( + None, + CombatEffect::Buff(CombatBuff { + kind: BuffKind::Burning, + dur_secs: 5.0, + strength: CombatBuffStrength::DamageFraction(0.2), + chance: 1.0, + }), + ))], + BuffKind::Frigid => vec![BuffEffect::BuffOnHit(AttackEffect::new( + None, + CombatEffect::Buff(CombatBuff { + kind: BuffKind::Frozen, + dur_secs: 5.0, + strength: CombatBuffStrength::DamageFraction(0.2), + chance: 1.0, + }), + ))], + BuffKind::Lifesteal => vec![BuffEffect::BuffOnHit(AttackEffect::new( + None, + CombatEffect::Lifesteal(0.2), + ))], } } } @@ -373,6 +406,8 @@ pub enum BuffEffect { CriticalChance(f32), /// Changes body. BodyChange(Body), + /// Inflict buff to target + BuffOnHit(AttackEffect), } /// Actual de/buff. diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index c533dd7388..0c77109546 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize}; use specs::{Component, DerefFlaggedStorage}; use std::{error::Error, fmt}; +use crate::combat::AttackEffect; + use super::Body; #[derive(Debug)] @@ -62,6 +64,7 @@ pub struct Stats { pub poise_damage_modifier: f32, pub attack_damage_modifier: f32, pub crit_chance_modifier: f32, + pub buffs_on_hit: Vec, } impl Stats { @@ -80,6 +83,7 @@ impl Stats { poise_damage_modifier: 1.0, attack_damage_modifier: 1.0, crit_chance_modifier: 1.0, + buffs_on_hit: Vec::new(), } } diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 07463dbdd2..4b6e5f33f4 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -647,5 +647,6 @@ fn execute_effect( *body_override = Some(*b) } }, + BuffEffect::BuffOnHit(effect) => stat.buffs_on_hit.push(effect.clone()), }; } diff --git a/voxygen/i18n-helpers/src/lib.rs b/voxygen/i18n-helpers/src/lib.rs index 0218a57aef..5d6f1460b0 100644 --- a/voxygen/i18n-helpers/src/lib.rs +++ b/voxygen/i18n-helpers/src/lib.rs @@ -116,7 +116,10 @@ pub fn localize_chat_message( | BuffKind::Frenzied | BuffKind::Hastened | BuffKind::Fortitude - | BuffKind::Reckless => { + | BuffKind::Reckless + | BuffKind::Flame + | BuffKind::Frigid + | BuffKind::Lifesteal => { tracing::error!("Player was killed by a positive buff!"); "hud-outcome-mysterious" }, diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 937ca37f43..b8afcb2879 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -5062,6 +5062,9 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id { BuffKind::Hastened => imgs.buff_haste_0, BuffKind::Fortitude => imgs.buff_fortitude_0, BuffKind::Reckless => imgs.buff_reckless, + BuffKind::Flame => imgs.debuff_burning_0, + BuffKind::Frigid => imgs.debuff_frozen_0, + BuffKind::Lifesteal => imgs.buff_plus_0, // Debuffs BuffKind::Bleeding => imgs.debuff_bleed_0, BuffKind::Cursed => imgs.debuff_skull_0, @@ -5109,6 +5112,9 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> Cow localized_strings.get_msg("buff-title-parried"), BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-title-potionsickness"), BuffKind::Polymorphed { .. } => localized_strings.get_msg("buff-title-polymorphed"), + BuffKind::Flame => localized_strings.get_msg("buff-title-burn"), + BuffKind::Frigid => localized_strings.get_msg("buff-title-frigid"), + BuffKind::Lifesteal => localized_strings.get_msg("buff-title-lifesteal"), } } @@ -5148,6 +5154,9 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz BuffKind::Parried { .. } => localized_strings.get_msg("buff-desc-parried"), BuffKind::PotionSickness { .. } => localized_strings.get_msg("buff-desc-potionsickness"), BuffKind::Polymorphed { .. } => localized_strings.get_msg("buff-desc-polymorphed"), + BuffKind::Flame { .. } => localized_strings.get_msg("buff-desc-flame"), + BuffKind::Frigid { .. } => localized_strings.get_msg("buff-desc-frigid"), + BuffKind::Lifesteal { .. } => localized_strings.get_msg("buff-desc-lifesteal"), } } diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index f444e4b23a..5a521f46d6 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -204,7 +204,10 @@ pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec { | BuffKind::Fortitude | BuffKind::Parried | BuffKind::Reckless - | BuffKind::Polymorphed(_) => Cow::Borrowed(""), + | BuffKind::Polymorphed(_) + | BuffKind::Flame + | BuffKind::Frigid + | BuffKind::Lifesteal => Cow::Borrowed(""), }; write!(&mut description, "{}", buff_desc).unwrap(); @@ -242,7 +245,10 @@ pub fn consumable_desc(effects: &Effects, i18n: &Localization) -> Vec { | BuffKind::Hastened | BuffKind::Fortitude | BuffKind::Parried - | BuffKind::Reckless => Cow::Borrowed(""), + | BuffKind::Reckless + | BuffKind::Flame + | BuffKind::Frigid + | BuffKind::Lifesteal => Cow::Borrowed(""), } } else if let BuffKind::Saturation | BuffKind::Regeneration