Allow for an arbitrary array of effects and buffs for consumables

This commit is contained in:
Snowram 2020-10-27 22:27:19 +01:00
parent 121364821a
commit ce96af4363
26 changed files with 250 additions and 77 deletions

View File

@ -3,7 +3,11 @@ ItemDef(
description: "Increases Exp by 250\n\nTake with plenty of water\n\n<Right-Click to use>",
kind: Consumable(
kind: "PotionExp",
effect: Xp(250),
effect: Some(
[
Xp(250),
]
),
),
quality: High,
)

View File

@ -1,12 +1,16 @@
ItemDef(
name: "Potent Potion",
description: "A potent healing potion.\n\nRestores 100 health on use.\n\n<Right-Click to use>",
description: "A potent healing potion.\n\nRestores 100 health on use\n\n<Right-Click to use>",
kind: Consumable(
kind: "Potion",
effect: Health((
amount: 1000,
cause: Item,
)),
effect: Some(
[
Health((
amount: 1000,
cause: Item,
)),
]
),
),
quality: High,
)

View File

@ -3,7 +3,11 @@ ItemDef(
description: "Provides 250 XP to the drinker\n\n<Right-Click to use>",
kind: Consumable(
kind: "Potion",
effect: Xp(250),
),
effect: Some(
[
Xp(250),
]
),
),
quality: High,
)

View File

@ -3,10 +3,14 @@ ItemDef(
description: "Restores 100 Health",
kind: Consumable(
kind: "PotionLarge",
effect: Health((
amount: 1000,
cause: Item,
)),
effect: Some(
[
Health((
amount: 1000,
cause: Item,
)),
]
),
),
quality: Common,
)

View File

@ -3,10 +3,14 @@ ItemDef(
description: "Restores 70 Health",
kind: Consumable(
kind: "PotionMed",
effect: Health((
amount: 700,
cause: Item,
)),
effect: Some(
[
Health((
amount: 700,
cause: Item,
)),
]
),
),
quality: Common,
)

View File

@ -3,10 +3,14 @@ ItemDef(
description: "Restores 50 Health",
kind: Consumable(
kind: "PotionMinor",
effect: Health((
amount: 500,
cause: Item,
)),
effect: Some(
[
Health((
amount: 500,
cause: Item,
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Apple",
description: "Restores 10 Health\n\nRed and juicy",
description: "Restores 10 Health over 10 seconds\n\nRed and juicy",
kind: Consumable(
kind: "Apple",
effect: Health((
amount: 100,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 10.0,
duration: Some((
secs: 10,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Mushroom Curry",
description: "Restores 120 Health\n\nWho could say no to that?",
description: "Restores 120 Health over 5 seconds\n\nWho could say no to that?",
kind: Consumable(
kind: "AppleShroomCurry",
effect: Health((
amount: 1200,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 120.0,
duration: Some((
secs: 5,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Moderate,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Apple Stick",
description: "Restores 25 Health\n\nThe stick makes it easier to carry!",
description: "Restores 25 Health over 5 seconds\n\nThe stick makes it easier to carry!",
kind: Consumable(
kind: "AppleStick",
effect: Health((
amount: 250,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 25.0,
duration: Some((
secs: 5,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Dwarven Cheese",
description: "Restores 15 Health\n\nAromatic and nutritious",
description: "Restores 15 Health over 10 seconds\n\nAromatic and nutritious",
kind: Consumable(
kind: "Cheese",
effect: Health((
amount: 150,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 15.0,
duration: Some((
secs: 10,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Coconut",
description: "Restores 20 health\n\nReliable source of water and fat",
description: "Restores 20 health over 10 seconds\n\nReliable source of water and fat",
kind: Consumable(
kind: "Coconut",
effect: Health((
amount: 200,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 20.0,
duration: Some((
secs: 10,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Mushroom",
description: "Restores 5 Health\n\nHopefully this one is not poisonous",
description: "Restores 5 Health over 10 seconds\n\nHopefully this one is not poisonous",
kind: Consumable(
kind: "Mushroom",
effect: Health((
amount: 50,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 5.0,
duration: Some((
secs: 10,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Mushroom Stick",
description: "Restores 20 Health\n\nRoasted mushrooms on a stick for easy carrying.",
description: "Restores 20 Health over 5 seconds\n\nRoasted mushrooms on a stick for easy carrying.",
kind: Consumable(
kind: "MushroomStick",
effect: Health((
amount: 200,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 20.0,
duration: Some((
secs: 5,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Common,
)

View File

@ -1,12 +1,23 @@
ItemDef(
name: "Sunflower Ice Tea",
description: "Restores 50 Health\n\nBrewed from freshly shelled sunflower seeds.",
description: "Restores 50 Health over 5 seconds\n\nBrewed from freshly shelled sunflower seeds.",
kind: Consumable(
kind: "SunflowerTea",
effect: Health((
amount: 500,
cause: Item,
)),
effect: Some(
[
Buff((
kind: Saturation,
data: (
strength: 50.0,
duration: Some((
secs: 5,
nanos: 0,
)),
),
cat_ids: [Natural],
)),
]
),
),
quality: Moderate,
)

View File

@ -3,7 +3,11 @@ ItemDef(
description: "Increases Exp by 20\n\nJust a slight touch makes you feel the knowledge of ancient times",
kind: Consumable(
kind: "Velorite",
effect: Xp(20),
),
quality: High,
effect: Some(
[
Xp(20),
]
),
),
quality: High,
)

View File

@ -3,7 +3,11 @@ ItemDef(
description: "Increases Exp by 10\n\nSmall runes sparkle on its surface",
kind: Consumable(
kind: "VeloriteFrag",
effect: Xp(10),
effect: Some(
[
Xp(10),
]
),
),
quality: Moderate,
quality: Moderate,
)

View File

@ -184,7 +184,7 @@ https://account.veloren.net."#,
"hud.chat.pvp_ranged_kill_msg": "[{attacker}] shot [{victim}]",
"hud.chat.pvp_explosion_kill_msg": "[{attacker}] blew up [{victim}]",
"hud.chat.pvp_energy_kill_msg": "[{attacker}] killed [{victim}] with magic",
"hud.chat.pvp_other_kill_msg": "[{attacker}] killed [{victim}]",
"hud.chat.pvp_buff_kill_msg": "[{attacker}] killed [{victim}]",
"hud.chat.npc_melee_kill_msg": "{attacker} killed [{victim}]",
@ -522,6 +522,8 @@ Protection
// Buffs
"buff.title.heal_test": "Heal Test",
"buff.desc.heal_test": "This is a test buff to test healing.",
"buff.title.saturation_test": "Saturation",
"buff.desc.saturation_test": "This is a test buff to test saturation.",
// Debuffs
"debuff.title.bleed_test": "Bleeding",
"debuff.desc.bleed_test": "Inflicts regular damage.",

View File

@ -10,6 +10,8 @@ use std::{cmp::Ordering, collections::HashMap, time::Duration};
pub enum BuffKind {
/// Restores health/time for some period
Regeneration,
/// Restores health/time for some period for consumables
Saturation,
/// Lowers health over time for some duration
Bleeding,
/// Lower a creature's max health
@ -22,6 +24,7 @@ impl BuffKind {
pub fn is_buff(self) -> bool {
match self {
BuffKind::Regeneration { .. } => true,
BuffKind::Saturation { .. } => true,
BuffKind::Bleeding { .. } => false,
BuffKind::Cursed { .. } => false,
}
@ -29,7 +32,7 @@ impl BuffKind {
}
// Struct used to store data relevant to a buff
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct BuffData {
pub strength: f32,
pub duration: Option<Duration>,
@ -97,7 +100,7 @@ pub enum BuffChange {
RemoveById(Vec<BuffId>),
/// Removes buffs of these categories (first vec is of categories of which
/// all are required, second vec is of categories of which at least one is
/// required, third vec is of categories that will not be removed)
/// required, third vec is of categories that will not be removed)
RemoveByCategory {
all_required: Vec<BuffCategory>,
any_required: Vec<BuffCategory>,
@ -121,7 +124,7 @@ impl Buff {
}],
data.duration,
),
BuffKind::Regeneration => (
BuffKind::Regeneration | BuffKind::Saturation => (
vec![BuffEffect::HealthChangeOverTime {
rate: data.strength,
accumulated: 0.0,

View File

@ -83,7 +83,7 @@ pub enum ItemKind {
Glider(Glider),
Consumable {
kind: String,
effect: Effect,
effect: Option<Vec<Effect>>,
},
Throwable {
kind: Throwable,

View File

@ -2,11 +2,20 @@ use crate::{combat, comp};
use serde::{Deserialize, Serialize};
/// An effect that may be applied to an entity
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Effect {
Health(comp::HealthChange),
Xp(i64),
Damage(combat::Damage),
Buff(BuffEffect),
}
/// A buff that may be applied to an entity
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct BuffEffect {
pub kind: comp::BuffKind,
pub data: comp::BuffData,
pub cat_ids: Vec<comp::BuffCategory>,
}
impl Effect {
@ -15,6 +24,7 @@ impl Effect {
Effect::Health(c) => format!("{:+} health", c.amount),
Effect::Xp(n) => format!("{:+} exp", n),
Effect::Damage(d) => format!("{:+}", d.value),
Effect::Buff(e) => format!("{:?} buff", e),
}
}
@ -29,6 +39,7 @@ impl Effect {
Effect::Damage(damage) => {
damage.interpolate_damage(modifier, 0.0);
},
_ => {},
}
}
}

View File

@ -649,7 +649,7 @@ pub fn handle_explosion(
if is_alive {
effect.modify_strength(strength);
server.state().apply_effect(entity_b, effect, owner);
server.state().apply_effect(entity_b, effect.clone(), owner);
// Apply energy change
if let Some(owner) = owner_entity {
if let Some(energy) =

View File

@ -211,7 +211,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
} else if let Some(item) = inventory.take(slot) {
match item.kind() {
ItemKind::Consumable { kind, effect, .. } => {
maybe_effect = Some(*effect);
maybe_effect = Some(effect.clone());
Some(comp::InventoryUpdateEvent::Consumed(kind.clone()))
},
ItemKind::Throwable { kind, .. } => {
@ -348,8 +348,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
};
drop(inventories);
if let Some(effect) = maybe_effect {
state.apply_effect(entity, effect, None);
if let Some(effects) = maybe_effect {
for effect in effects {
state.apply_effect(entity, effect, None);
}
}
if let Some(event) = event {
state.write_component(entity, comp::InventoryUpdate::new(event));

View File

@ -71,8 +71,8 @@ pub trait StateExt {
}
impl StateExt for State {
fn apply_effect(&self, entity: EcsEntity, effect: Effect, source: Option<Uid>) {
match effect {
fn apply_effect(&self, entity: EcsEntity, effects: Effect, source: Option<Uid>) {
match effects {
Effect::Health(change) => {
self.ecs()
.write_storage::<comp::Health>()
@ -93,6 +93,19 @@ impl StateExt for State {
.get_mut(entity)
.map(|health| health.change_by(change));
},
Effect::Buff(buff) => {
self.ecs()
.write_storage::<comp::Buffs>()
.get_mut(entity)
.map(|buffs| {
buffs.insert(comp::Buff::new(
buff.kind,
buff.data,
buff.cat_ids,
comp::BuffSource::Item,
))
});
},
}
}

View File

@ -182,6 +182,7 @@ impl<'a> Widget for BuffsBar<'a> {
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = match buff.kind {
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
BuffKind::Saturation { .. } => self.imgs.buff_plus_0,
_ => self.imgs.missing_icon,
};
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
@ -207,6 +208,9 @@ impl<'a> Widget for BuffsBar<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.title.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.title.saturation_test")
},
_ => localized_strings.get("buff.title.missing"),
};
let remaining_time = if current_duration.is_none() {
@ -219,6 +223,9 @@ impl<'a> Widget for BuffsBar<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.desc.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.desc.saturation_test")
},
_ => localized_strings.get("buff.desc.missing"),
};
let desc = format!("{}\n\n{}\n\n{}", desc_txt, remaining_time, click_to_remove);
@ -379,6 +386,7 @@ impl<'a> Widget for BuffsBar<'a> {
}) as u32;
let buff_img = match buff.kind {
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
BuffKind::Saturation { .. } => self.imgs.buff_plus_0,
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
};
@ -405,6 +413,9 @@ impl<'a> Widget for BuffsBar<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.title.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.title.saturation_test")
},
BuffKind::Bleeding { .. } => {
localized_strings.get("debuff.title.bleed_test")
},
@ -420,6 +431,9 @@ impl<'a> Widget for BuffsBar<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.desc.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.desc.saturation_test")
},
BuffKind::Bleeding { .. } => {
localized_strings.get("debuff.desc.bleed_test")
},

View File

@ -482,6 +482,7 @@ impl<'a> Widget for Group<'a> {
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = match buff.kind {
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
BuffKind::Saturation { .. } => self.imgs.buff_plus_0,
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
};
@ -512,6 +513,9 @@ impl<'a> Widget for Group<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.title.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.title.saturation_test")
},
BuffKind::Bleeding { .. } => {
localized_strings.get("debuff.title.bleed_test")
},
@ -529,6 +533,9 @@ impl<'a> Widget for Group<'a> {
BuffKind::Regeneration { .. } => {
localized_strings.get("buff.desc.heal_test")
},
BuffKind::Saturation { .. } => {
localized_strings.get("buff.desc.saturation_test")
},
BuffKind::Bleeding { .. } => {
localized_strings.get("debuff.desc.bleed_test")
},

View File

@ -243,6 +243,7 @@ impl<'a> Widget for Overhead<'a> {
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
let buff_img = match buff.kind {
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
BuffKind::Saturation { .. } => self.imgs.buff_plus_0,
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
};