mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'srpapinha/new-potion-and-some-buffs' into 'master'
Freezing potion and debuff immunity See merge request veloren/veloren!4517
This commit is contained in:
commit
2c5bff33fe
@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Protocol to query game server information (player count, version, etc.) and make ping tests.
|
||||
- Unlockable recipes
|
||||
- Localization support for prompt dialogs, diary sections, trade and group invitations.
|
||||
- Added Freezing Potion
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -3183,6 +3183,9 @@
|
||||
Simple(
|
||||
"common.items.consumable.potion_minor",
|
||||
): "object-potion_minor",
|
||||
Simple(
|
||||
"common.items.consumable.potion_freezing",
|
||||
): "object-potion_freezing",
|
||||
Simple(
|
||||
"common.items.lantern.black_0",
|
||||
): "lantern-black",
|
||||
|
@ -11,7 +11,15 @@ ItemDef(
|
||||
duration: Some(10)
|
||||
),
|
||||
cat_ids: [Natural],
|
||||
))
|
||||
)),
|
||||
Buff((
|
||||
kind: PotionSickness,
|
||||
data: (
|
||||
strength: 0.15,
|
||||
duration: Some(30),
|
||||
),
|
||||
cat_ids: [Natural],
|
||||
)),
|
||||
])
|
||||
),
|
||||
quality: Moderate,
|
||||
|
27
assets/common/items/consumable/potion_freezing.ron
Normal file
27
assets/common/items/consumable/potion_freezing.ron
Normal file
@ -0,0 +1,27 @@
|
||||
ItemDef(
|
||||
legacy_name: "Freezing Potion",
|
||||
legacy_description: "Freezes the user's brain",
|
||||
kind: Consumable(
|
||||
kind: Drink,
|
||||
effects: All([
|
||||
Buff((
|
||||
kind: Frozen,
|
||||
data: (
|
||||
strength: 0.1,
|
||||
duration: Some(30)
|
||||
),
|
||||
cat_ids: [Natural],
|
||||
)),
|
||||
Buff((
|
||||
kind: PotionSickness,
|
||||
data: (
|
||||
strength: 0.15,
|
||||
duration: Some(30),
|
||||
),
|
||||
cat_ids: [Natural],
|
||||
)),
|
||||
])
|
||||
),
|
||||
quality: Moderate,
|
||||
tags: [Potion],
|
||||
)
|
@ -4,6 +4,7 @@ ItemDef(
|
||||
kind: RecipeGroup(
|
||||
recipes: [
|
||||
"potion_combustion",
|
||||
"potion_freezing",
|
||||
"potion_agility",
|
||||
"potion_minor",
|
||||
"potion_medium",
|
||||
|
@ -31,6 +31,15 @@
|
||||
],
|
||||
craft_sprite: Some(Anvil),
|
||||
),
|
||||
"potion_freezing": (
|
||||
output: ("common.items.consumable.potion_freezing", 1),
|
||||
inputs: [
|
||||
(Item("common.items.crafting_ing.empty_vial"), 1, false),
|
||||
(Item("common.items.crafting_ing.animal_misc.icy_fang"), 3, false),
|
||||
(Item("common.items.crafting_ing.animal_misc.viscous_ooze"), 1, false),
|
||||
],
|
||||
craft_sprite: Some(Cauldron),
|
||||
),
|
||||
"potion_combustion": (
|
||||
output: ("common.items.consumable.potion_combustion", 1),
|
||||
inputs: [
|
||||
|
@ -19,6 +19,9 @@ object-potion_med = Medium Potion
|
||||
object-potion_minor = Minor Potion
|
||||
.desc = A small potion concocted from apples and honey.
|
||||
|
||||
object-potion_freezing = Freezing Potion
|
||||
.desc = Freezes the user's brain.
|
||||
|
||||
object-burning_charm = Blazing Charm
|
||||
.desc = Flame is your ally, harness its power to burn your foes.
|
||||
|
||||
|
@ -3411,6 +3411,10 @@
|
||||
"voxel.object.potion_combustion",
|
||||
(0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7,
|
||||
),
|
||||
Simple("common.items.consumable.potion_freezing"): VoxTrans(
|
||||
"voxel.object.potion_blue_1",
|
||||
(0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7,
|
||||
),
|
||||
Simple("common.items.consumable.potion_agility"): VoxTrans(
|
||||
"voxel.object.potion_agility",
|
||||
(0.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.7,
|
||||
|
@ -862,6 +862,7 @@
|
||||
Simple("common.items.consumable.potion_big"): "voxel.object.potion_red",
|
||||
Simple("common.items.consumable.potion_curious"): "voxel.object.potion_curious",
|
||||
Simple("common.items.consumable.potion_combustion"): "voxel.object.potion_combustion",
|
||||
Simple("common.items.consumable.potion_freezing"): "voxel.object.potion_blue_1",
|
||||
Simple("common.items.consumable.potion_agility"): "voxel.object.potion_agility",
|
||||
Simple("common.items.charms.burning_charm"): "voxel.object.burning_charm",
|
||||
Simple("common.items.charms.frozen_charm"): "voxel.object.frozen_charm",
|
||||
|
BIN
assets/voxygen/voxel/object/potion_blue_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/potion_blue_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -152,6 +152,7 @@ pub enum BuffKind {
|
||||
// =================
|
||||
/// Does damage to a creature over time.
|
||||
/// Strength should be the DPS of the debuff.
|
||||
/// Provides immunity against Frozen.
|
||||
Burning,
|
||||
/// Lowers health over time for some duration.
|
||||
/// Strength should be the DPS of the debuff.
|
||||
@ -168,10 +169,12 @@ pub enum BuffKind {
|
||||
/// Strength scales the attack speed debuff non-linearly. 0.5 is ~50%
|
||||
/// speed, 1.0 is 33% speed. Movement speed debuff is scaled to be slightly
|
||||
/// smaller than attack speed debuff.
|
||||
/// Provides immunity against Heatstroke.
|
||||
Frozen,
|
||||
/// Makes you wet and causes you to have reduced friction on the ground.
|
||||
/// Strength scales the friction you ignore non-linearly. 0.5 is 50% ground
|
||||
/// friction, 1.0 is 33% ground friction.
|
||||
/// Provides immunity against Burning.
|
||||
Wet,
|
||||
/// Makes you move slower.
|
||||
/// Strength scales the movement speed debuff non-linearly. 0.5 is 50%
|
||||
@ -319,7 +322,7 @@ impl BuffKind {
|
||||
/// only the strongest.
|
||||
pub fn stacks(self) -> bool { matches!(self, BuffKind::PotionSickness | BuffKind::Resilience) }
|
||||
|
||||
pub fn effects(&self, data: &BuffData, stats: Option<&Stats>) -> Vec<BuffEffect> {
|
||||
pub fn effects(&self, data: &BuffData) -> Vec<BuffEffect> {
|
||||
// Normalized nonlinear scaling
|
||||
// TODO: Do we want to make denominator term parameterized. Come back to if we
|
||||
// add nn_scaling3.
|
||||
@ -347,16 +350,14 @@ impl BuffKind {
|
||||
}],
|
||||
BuffKind::Potion => {
|
||||
vec![BuffEffect::HealthChangeOverTime {
|
||||
rate: data.strength * stats.map_or(1.0, |s| s.heal_multiplier),
|
||||
rate: data.strength,
|
||||
kind: ModifierKind::Additive,
|
||||
instance,
|
||||
tick_dur: Secs(0.1),
|
||||
}]
|
||||
},
|
||||
BuffKind::Agility => vec![
|
||||
BuffEffect::MovementSpeed(
|
||||
1.0 + data.strength * stats.map_or(1.0, |s| s.move_speed_multiplier),
|
||||
),
|
||||
BuffEffect::MovementSpeed(1.0 + data.strength),
|
||||
BuffEffect::DamageReduction(-1.0),
|
||||
BuffEffect::AttackDamage(0.0),
|
||||
],
|
||||
@ -399,12 +400,15 @@ impl BuffKind {
|
||||
// strength. 0.5 also still provides 50% damage reduction.
|
||||
nn_scaling(data.strength),
|
||||
)],
|
||||
BuffKind::Burning => vec![BuffEffect::HealthChangeOverTime {
|
||||
BuffKind::Burning => vec![
|
||||
BuffEffect::HealthChangeOverTime {
|
||||
rate: -data.strength,
|
||||
kind: ModifierKind::Additive,
|
||||
instance,
|
||||
tick_dur: Secs(0.25),
|
||||
}],
|
||||
},
|
||||
BuffEffect::BuffImmunity(BuffKind::Frozen),
|
||||
],
|
||||
BuffKind::Poisoned => vec![BuffEffect::EnergyChangeOverTime {
|
||||
rate: -data.strength,
|
||||
kind: ModifierKind::Additive,
|
||||
@ -431,8 +435,12 @@ impl BuffKind {
|
||||
BuffKind::Frozen => vec![
|
||||
BuffEffect::MovementSpeed(f32::powf(1.0 - nn_scaling(data.strength), 1.1)),
|
||||
BuffEffect::AttackSpeed(1.0 - nn_scaling(data.strength)),
|
||||
BuffEffect::BuffImmunity(BuffKind::Heatstroke),
|
||||
],
|
||||
BuffKind::Wet => vec![
|
||||
BuffEffect::GroundFriction(1.0 - nn_scaling(data.strength)),
|
||||
BuffEffect::BuffImmunity(BuffKind::Burning),
|
||||
],
|
||||
BuffKind::Wet => vec![BuffEffect::GroundFriction(1.0 - nn_scaling(data.strength))],
|
||||
BuffKind::Ensnared => vec![BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength))],
|
||||
BuffKind::Hastened => vec![
|
||||
BuffEffect::MovementSpeed(1.0 + data.strength),
|
||||
@ -447,11 +455,7 @@ impl BuffKind {
|
||||
BuffEffect::RecoverySpeed(0.25),
|
||||
BuffEffect::PrecisionVulnerabilityOverride(1.0),
|
||||
],
|
||||
//TODO: Handle potion sickness in a more general way.
|
||||
BuffKind::PotionSickness => vec![
|
||||
BuffEffect::HealReduction(data.strength),
|
||||
BuffEffect::MoveSpeedReduction(data.strength),
|
||||
],
|
||||
BuffKind::PotionSickness => vec![BuffEffect::ItemEffectReduction(data.strength)],
|
||||
BuffKind::Reckless => vec![
|
||||
BuffEffect::DamageReduction(-data.strength),
|
||||
BuffEffect::AttackDamage(1.0 + data.strength),
|
||||
@ -562,6 +566,7 @@ impl BuffKind {
|
||||
mut data: BuffData,
|
||||
source_mass: Option<&Mass>,
|
||||
dest_info: DestInfo,
|
||||
source: BuffSource,
|
||||
) -> BuffData {
|
||||
// TODO: Remove clippy allow after another buff needs this
|
||||
#[allow(clippy::single_match)]
|
||||
@ -580,6 +585,7 @@ impl BuffKind {
|
||||
.map_or(1.0, |s| (1.0 - s.crowd_control_resistance).max(0.0));
|
||||
data.duration = data.duration.map(|dur| dur * dur_mult as f64);
|
||||
}
|
||||
self.apply_item_effect_reduction(&mut data, source, dest_info);
|
||||
data
|
||||
}
|
||||
|
||||
@ -592,6 +598,27 @@ impl BuffKind {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_item_effect_reduction(
|
||||
&self,
|
||||
data: &mut BuffData,
|
||||
source: BuffSource,
|
||||
dest_info: DestInfo,
|
||||
) {
|
||||
if !matches!(source, BuffSource::Item) {
|
||||
return;
|
||||
}
|
||||
let item_effect_reduction = dest_info.stats.map_or(1.0, |s| s.item_effect_reduction);
|
||||
match self {
|
||||
BuffKind::Potion | BuffKind::Agility => {
|
||||
data.strength *= item_effect_reduction;
|
||||
},
|
||||
BuffKind::Burning | BuffKind::Frozen | BuffKind::Resilience => {
|
||||
data.duration = data.duration.map(|dur| dur * item_effect_reduction as f64);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Struct used to store data relevant to a buff
|
||||
@ -705,10 +732,6 @@ pub enum BuffEffect {
|
||||
GroundFriction(f32),
|
||||
/// Reduces poise damage taken after armor is accounted for by this fraction
|
||||
PoiseReduction(f32),
|
||||
/// Reduces amount healed by consumables
|
||||
HealReduction(f32),
|
||||
/// Reduces amount of speed increase by consumables
|
||||
MoveSpeedReduction(f32),
|
||||
/// Increases poise damage dealt when health is lost
|
||||
PoiseDamageFromLostHealth(f32),
|
||||
/// Modifier to the amount of damage dealt with attacks
|
||||
@ -737,6 +760,8 @@ pub enum BuffEffect {
|
||||
DisableAuxiliaryAbilities,
|
||||
/// Reduces duration of crowd control debuffs
|
||||
CrowdControlResistance(f32),
|
||||
/// Reduces the strength or duration of item buff
|
||||
ItemEffectReduction(f32),
|
||||
}
|
||||
|
||||
/// Actual de/buff.
|
||||
@ -796,8 +821,8 @@ impl Buff {
|
||||
// Create source_info if we need more parameters from source
|
||||
source_mass: Option<&Mass>,
|
||||
) -> Self {
|
||||
let data = kind.modify_data(data, source_mass, dest_info);
|
||||
let effects = kind.effects(&data, dest_info.stats);
|
||||
let data = kind.modify_data(data, source_mass, dest_info, source);
|
||||
let effects = kind.effects(&data);
|
||||
let cat_ids = kind.extend_cat_ids(cat_ids);
|
||||
let start_time = Time(time.0 + data.delay.map_or(0.0, |delay| delay.0));
|
||||
let end_time = if cat_ids
|
||||
|
@ -74,10 +74,6 @@ pub struct Stats {
|
||||
pub original_body: Body,
|
||||
pub damage_reduction: StatsSplit,
|
||||
pub poise_reduction: StatsSplit,
|
||||
pub heal_multiplier: f32,
|
||||
// Note: This is used to counteract agility as a "potion sickness" right now, and otherwise
|
||||
// does not impact movement speed
|
||||
pub move_speed_multiplier: f32,
|
||||
pub max_health_modifiers: StatsModifier,
|
||||
pub move_speed_modifier: f32,
|
||||
pub jump_modifier: f32,
|
||||
@ -102,6 +98,7 @@ pub struct Stats {
|
||||
pub effects_on_death: Vec<DeathEffect>,
|
||||
pub disable_auxiliary_abilities: bool,
|
||||
pub crowd_control_resistance: f32,
|
||||
pub item_effect_reduction: f32,
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
@ -111,8 +108,6 @@ impl Stats {
|
||||
original_body: body,
|
||||
damage_reduction: StatsSplit::default(),
|
||||
poise_reduction: StatsSplit::default(),
|
||||
heal_multiplier: 1.0,
|
||||
move_speed_multiplier: 1.0,
|
||||
max_health_modifiers: StatsModifier::default(),
|
||||
move_speed_modifier: 1.0,
|
||||
jump_modifier: 1.0,
|
||||
@ -132,6 +127,7 @@ impl Stats {
|
||||
effects_on_death: Vec::new(),
|
||||
disable_auxiliary_abilities: false,
|
||||
crowd_control_resistance: 0.0,
|
||||
item_effect_reduction: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,12 +790,6 @@ fn execute_effect(
|
||||
stat.poise_reduction.neg_mod += pr;
|
||||
}
|
||||
},
|
||||
BuffEffect::HealReduction(red) => {
|
||||
stat.heal_multiplier *= 1.0 - *red;
|
||||
},
|
||||
BuffEffect::MoveSpeedReduction(red) => {
|
||||
stat.move_speed_multiplier *= 1.0 - *red;
|
||||
},
|
||||
BuffEffect::PoiseDamageFromLostHealth(strength) => {
|
||||
stat.poise_damage_modifier *= 1.0 + (1.0 - health.fraction()) * *strength;
|
||||
},
|
||||
@ -855,5 +849,8 @@ fn execute_effect(
|
||||
BuffEffect::CrowdControlResistance(ccr) => {
|
||||
stat.crowd_control_resistance += ccr;
|
||||
},
|
||||
BuffEffect::ItemEffectReduction(ier) => {
|
||||
stat.item_effect_reduction *= 1.0 - ier;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -740,7 +740,7 @@ impl<'a> AgentData<'a> {
|
||||
relaxed: bool,
|
||||
) -> bool {
|
||||
// Wait for potion sickness to wear off if potions are less than 50% effective.
|
||||
let heal_multiplier = self.stats.map_or(1.0, |s| s.heal_multiplier);
|
||||
let heal_multiplier = self.stats.map_or(1.0, |s| s.item_effect_reduction);
|
||||
if heal_multiplier < 0.5 {
|
||||
return false;
|
||||
}
|
||||
@ -754,7 +754,7 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
Effect::Buff(BuffEffect { kind, data, .. }) => {
|
||||
if let Some(duration) = data.duration {
|
||||
for effect in kind.effects(data, self.stats) {
|
||||
for effect in kind.effects(data) {
|
||||
match effect {
|
||||
comp::BuffEffect::HealthChangeOverTime { rate, kind, .. } => {
|
||||
let amount = match kind {
|
||||
@ -766,7 +766,7 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
value += amount;
|
||||
},
|
||||
comp::BuffEffect::HealReduction(amount) => {
|
||||
comp::BuffEffect::ItemEffectReduction(amount) => {
|
||||
heal_reduction =
|
||||
heal_reduction + amount - heal_reduction * amount;
|
||||
},
|
||||
|
@ -27,9 +27,9 @@ use common::{
|
||||
inventory::item::{AbilityMap, MaterialStatManifest},
|
||||
item::flatten_counted_items,
|
||||
loot_owner::LootOwnerKind,
|
||||
Alignment, Auras, Body, CharacterState, Energy, Group, Health, Inventory, Object,
|
||||
PickupItem, Player, Poise, PoiseChange, Pos, Presence, PresenceKind, SkillSet, Stats,
|
||||
BASE_ABILITY_LIMIT,
|
||||
Alignment, Auras, Body, BuffEffect, CharacterState, Energy, Group, Health, Inventory,
|
||||
Object, PickupItem, Player, Poise, PoiseChange, Pos, Presence, PresenceKind, SkillSet,
|
||||
Stats, BASE_ABILITY_LIMIT,
|
||||
},
|
||||
consts::TELEPORTER_RADIUS,
|
||||
event::{
|
||||
@ -1630,9 +1630,19 @@ impl ServerEvent for BuffEvent {
|
||||
use buff::BuffChange;
|
||||
match ev.buff_change {
|
||||
BuffChange::Add(new_buff) => {
|
||||
let immunity_by_buff = buffs
|
||||
.buffs
|
||||
.values_mut()
|
||||
.flat_map(|b| b.kind.effects(&b.data))
|
||||
.find(|b| match b {
|
||||
BuffEffect::BuffImmunity(kind) => new_buff.kind == *kind,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
if !bodies
|
||||
.get(ev.entity)
|
||||
.map_or(false, |body| body.immune_to(new_buff.kind))
|
||||
&& immunity_by_buff.is_none()
|
||||
&& healths.get(ev.entity).map_or(true, |h| !h.is_dead)
|
||||
{
|
||||
if let Some(strength) =
|
||||
|
Loading…
Reference in New Issue
Block a user