mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch veloren:master into jcoxeye/price-entries
This commit is contained in:
commit
941e953348
@ -96,6 +96,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Fixed Perforate icon not displaying
|
- Fixed Perforate icon not displaying
|
||||||
- Make cave entrances easier to follow
|
- Make cave entrances easier to follow
|
||||||
- Renamed Twiggy Shoulders to match the Twig Armor set
|
- Renamed Twiggy Shoulders to match the Twig Armor set
|
||||||
|
- No longer stack buffs of the same kind with equal attributes, this could lead to a DoS if ie. an entity stayed long enough in lava.
|
||||||
|
|
||||||
## [0.15.0] - 2023-07-01
|
## [0.15.0] - 2023-07-01
|
||||||
|
|
||||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7088,6 +7088,7 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
"vek 0.15.8",
|
"vek 0.15.8",
|
||||||
"veloren-common",
|
"veloren-common",
|
||||||
|
"veloren-common-assets",
|
||||||
"veloren-common-base",
|
"veloren-common-base",
|
||||||
"veloren-common-ecs",
|
"veloren-common-ecs",
|
||||||
"veloren-common-net",
|
"veloren-common-net",
|
||||||
|
@ -48,7 +48,6 @@ Most Veloren servers require you to register with the official authentication se
|
|||||||
- [Website](https://veloren.net)
|
- [Website](https://veloren.net)
|
||||||
- [Discord](https://discord.gg/veloren-community-449602562165833758)
|
- [Discord](https://discord.gg/veloren-community-449602562165833758)
|
||||||
- [Matrix](https://matrix.to/#/#veloren-space:fachschaften.org)
|
- [Matrix](https://matrix.to/#/#veloren-space:fachschaften.org)
|
||||||
- [Twitter](https://twitter.com/velorenproject)
|
|
||||||
- [Mastodon](https://floss.social/@veloren)
|
- [Mastodon](https://floss.social/@veloren)
|
||||||
- [Reddit](https://www.reddit.com/r/Veloren)
|
- [Reddit](https://www.reddit.com/r/Veloren)
|
||||||
- [YouTube](https://youtube.com/@Veloren)
|
- [YouTube](https://youtube.com/@Veloren)
|
||||||
|
@ -64,6 +64,8 @@ command-battlemode-available-modes = Available modes: pvp, pve
|
|||||||
command-battlemode-same = Attempted to set the same battlemode
|
command-battlemode-same = Attempted to set the same battlemode
|
||||||
command-battlemode-updated = New battlemode: { $battlemode }
|
command-battlemode-updated = New battlemode: { $battlemode }
|
||||||
command-buff-unknown = Unknown buff: { $buff }
|
command-buff-unknown = Unknown buff: { $buff }
|
||||||
|
command-buff-data = Buff argument '{ $buff }' requires additional data
|
||||||
|
command-buff-body-unknown = Unknown body spec: { $spec }
|
||||||
command-skillpreset-load-error = Error while loading presets
|
command-skillpreset-load-error = Error while loading presets
|
||||||
command-skillpreset-broken = Skill preset is broken
|
command-skillpreset-broken = Skill preset is broken
|
||||||
command-skillpreset-missing = Preset does not exist: { $preset }
|
command-skillpreset-missing = Preset does not exist: { $preset }
|
||||||
|
@ -201,9 +201,10 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static ref BUFFS: Vec<String> = {
|
static ref BUFFS: Vec<String> = {
|
||||||
let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect();
|
let mut buff_pack: Vec<String> = BUFF_PARSER.keys().cloned().collect();
|
||||||
// Add all as valid command
|
|
||||||
buff_pack.push("all".to_string());
|
// Add `all` as valid command
|
||||||
|
buff_pack.push("all".to_owned());
|
||||||
buff_pack
|
buff_pack
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -429,6 +430,7 @@ impl ServerChatCommand {
|
|||||||
Enum("buff", BUFFS.clone(), Required),
|
Enum("buff", BUFFS.clone(), Required),
|
||||||
Float("strength", 0.01, Optional),
|
Float("strength", 0.01, Optional),
|
||||||
Float("duration", 10.0, Optional),
|
Float("duration", 10.0, Optional),
|
||||||
|
Any("buff data spec", Optional),
|
||||||
],
|
],
|
||||||
"Cast a buff on player",
|
"Cast a buff on player",
|
||||||
Some(Admin),
|
Some(Admin),
|
||||||
|
@ -791,7 +791,7 @@ impl AttackDamage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct AttackEffect {
|
pub struct AttackEffect {
|
||||||
target: Option<GroupTarget>,
|
target: Option<GroupTarget>,
|
||||||
effect: CombatEffect,
|
effect: CombatEffect,
|
||||||
@ -890,7 +890,7 @@ impl CombatEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum CombatRequirement {
|
pub enum CombatRequirement {
|
||||||
AnyDamage,
|
AnyDamage,
|
||||||
Energy(f32),
|
Energy(f32),
|
||||||
@ -898,7 +898,7 @@ pub enum CombatRequirement {
|
|||||||
TargetHasBuff(BuffKind),
|
TargetHasBuff(BuffKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum DamagedEffect {
|
pub enum DamagedEffect {
|
||||||
Combo(i32),
|
Combo(i32),
|
||||||
}
|
}
|
||||||
|
@ -165,19 +165,38 @@ pub enum BuffKind {
|
|||||||
/// Results from drinking a potion.
|
/// Results from drinking a potion.
|
||||||
/// Decreases the health gained from subsequent potions.
|
/// Decreases the health gained from subsequent potions.
|
||||||
PotionSickness,
|
PotionSickness,
|
||||||
/// Changed into another body.
|
|
||||||
Polymorphed,
|
|
||||||
/// Slows movement speed and reduces energy reward.
|
/// Slows movement speed and reduces energy reward.
|
||||||
/// Both scales non-linearly to strength, 0.5 lead to movespeed reduction
|
/// Both scales non-linearly to strength, 0.5 lead to movespeed reduction
|
||||||
/// by 25% and energy reward reduced by 150%, 1.0 lead to MS reduction by
|
/// by 25% and energy reward reduced by 150%, 1.0 lead to MS reduction by
|
||||||
/// 33.3% and energy reward reduced by 200%. Energy reward can't be
|
/// 33.3% and energy reward reduced by 200%. Energy reward can't be
|
||||||
/// reduced by more than 200%, to a minimum value of -100%.
|
/// reduced by more than 200%, to a minimum value of -100%.
|
||||||
Heatstroke,
|
Heatstroke,
|
||||||
|
// Complex, non-obvious buffs
|
||||||
|
/// Changed into another body.
|
||||||
|
Polymorphed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tells a little more about the buff kind than simple buff/debuff
|
||||||
|
pub enum BuffDescriptor {
|
||||||
|
/// Simple positive buffs, like `BuffKind::Saturation`
|
||||||
|
SimplePositive,
|
||||||
|
/// Simple negative buffs, like `BuffKind::Bleeding`
|
||||||
|
SimpleNegative,
|
||||||
|
/// Buffs that require unusual data that can't be governed just by strength
|
||||||
|
/// and duration, like `BuffKind::Polymorhped`
|
||||||
|
Complex,
|
||||||
|
// For future additions, we may want to tell about non-obvious buffs,
|
||||||
|
// like Agility.
|
||||||
|
// Also maybe extend Complex to differentiate between Positive, Negative
|
||||||
|
// and Neutral buffs?
|
||||||
|
// For now, Complex is assumed to be neutral/non-obvious.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuffKind {
|
impl BuffKind {
|
||||||
/// Checks if buff is buff or debuff.
|
/// Tells a little more about buff kind than simple buff/debuff
|
||||||
pub fn is_buff(self) -> bool {
|
///
|
||||||
|
/// Read more in [BuffDescriptor].
|
||||||
|
pub fn differentiate(self) -> BuffDescriptor {
|
||||||
match self {
|
match self {
|
||||||
BuffKind::Regeneration
|
BuffKind::Regeneration
|
||||||
| BuffKind::Saturation
|
| BuffKind::Saturation
|
||||||
@ -202,7 +221,7 @@ impl BuffKind {
|
|||||||
| BuffKind::Sunderer
|
| BuffKind::Sunderer
|
||||||
| BuffKind::Defiance
|
| BuffKind::Defiance
|
||||||
| BuffKind::Bloodfeast
|
| BuffKind::Bloodfeast
|
||||||
| BuffKind::Berserk => true,
|
| BuffKind::Berserk => BuffDescriptor::SimplePositive,
|
||||||
BuffKind::Bleeding
|
BuffKind::Bleeding
|
||||||
| BuffKind::Cursed
|
| BuffKind::Cursed
|
||||||
| BuffKind::Burning
|
| BuffKind::Burning
|
||||||
@ -213,8 +232,23 @@ impl BuffKind {
|
|||||||
| BuffKind::Poisoned
|
| BuffKind::Poisoned
|
||||||
| BuffKind::Parried
|
| BuffKind::Parried
|
||||||
| BuffKind::PotionSickness
|
| BuffKind::PotionSickness
|
||||||
| BuffKind::Polymorphed
|
| BuffKind::Heatstroke => BuffDescriptor::SimpleNegative,
|
||||||
| BuffKind::Heatstroke => false,
|
BuffKind::Polymorphed => BuffDescriptor::Complex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if buff is buff or debuff.
|
||||||
|
pub fn is_buff(self) -> bool {
|
||||||
|
match self.differentiate() {
|
||||||
|
BuffDescriptor::SimplePositive => true,
|
||||||
|
BuffDescriptor::SimpleNegative | BuffDescriptor::Complex => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_simple(self) -> bool {
|
||||||
|
match self.differentiate() {
|
||||||
|
BuffDescriptor::SimplePositive | BuffDescriptor::SimpleNegative => true,
|
||||||
|
BuffDescriptor::Complex => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,9 +494,6 @@ pub struct BuffData {
|
|||||||
pub strength: f32,
|
pub strength: f32,
|
||||||
pub duration: Option<Secs>,
|
pub duration: Option<Secs>,
|
||||||
pub delay: Option<Secs>,
|
pub delay: Option<Secs>,
|
||||||
/// Force the buff effects to be applied each tick, ignoring num_ticks
|
|
||||||
#[serde(default)]
|
|
||||||
pub force_immediate: bool,
|
|
||||||
/// Used for buffs that have rider buffs (e.g. Flame, Frigid)
|
/// Used for buffs that have rider buffs (e.g. Flame, Frigid)
|
||||||
pub secondary_duration: Option<Secs>,
|
pub secondary_duration: Option<Secs>,
|
||||||
/// Used to add random data to buffs if needed (e.g. polymorphed)
|
/// Used to add random data to buffs if needed (e.g. polymorphed)
|
||||||
@ -479,7 +510,6 @@ impl BuffData {
|
|||||||
Self {
|
Self {
|
||||||
strength,
|
strength,
|
||||||
duration,
|
duration,
|
||||||
force_immediate: false,
|
|
||||||
delay: None,
|
delay: None,
|
||||||
secondary_duration: None,
|
secondary_duration: None,
|
||||||
misc_data: None,
|
misc_data: None,
|
||||||
@ -496,12 +526,6 @@ impl BuffData {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Force the buff effects to be applied each tick, ignoring num_ticks
|
|
||||||
pub fn with_force_immediate(mut self, force_immediate: bool) -> Self {
|
|
||||||
self.force_immediate = force_immediate;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_misc_data(mut self, misc_data: MiscBuffData) -> Self {
|
pub fn with_misc_data(mut self, misc_data: MiscBuffData) -> Self {
|
||||||
self.misc_data = Some(misc_data);
|
self.misc_data = Some(misc_data);
|
||||||
self
|
self
|
||||||
@ -524,14 +548,14 @@ pub enum BuffCategory {
|
|||||||
SelfBuff,
|
SelfBuff,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum ModifierKind {
|
pub enum ModifierKind {
|
||||||
Additive,
|
Additive,
|
||||||
Multiplicative,
|
Multiplicative,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data indicating and configuring behaviour of a de/buff.
|
/// Data indicating and configuring behaviour of a de/buff.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum BuffEffect {
|
pub enum BuffEffect {
|
||||||
/// Periodically damages or heals entity
|
/// Periodically damages or heals entity
|
||||||
HealthChangeOverTime {
|
HealthChangeOverTime {
|
||||||
@ -782,11 +806,44 @@ impl Buffs {
|
|||||||
|
|
||||||
pub fn insert(&mut self, buff: Buff, current_time: Time) -> BuffKey {
|
pub fn insert(&mut self, buff: Buff, current_time: Time) -> BuffKey {
|
||||||
let kind = buff.kind;
|
let kind = buff.kind;
|
||||||
|
// Try to find another overlaping non-queueable buff with same data, cat_ids and
|
||||||
|
// source.
|
||||||
|
let other_key = if kind.queues() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.kinds[kind].as_ref().and_then(|(keys, _)| {
|
||||||
|
keys.iter()
|
||||||
|
.find(|key| {
|
||||||
|
self.buffs.get(**key).map_or(false, |other_buff| {
|
||||||
|
other_buff.data == buff.data
|
||||||
|
&& other_buff.cat_ids == buff.cat_ids
|
||||||
|
&& other_buff.source == buff.source
|
||||||
|
&& other_buff
|
||||||
|
.end_time
|
||||||
|
.map_or(true, |end_time| end_time.0 >= buff.start_time.0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.copied()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// If another buff with the same fields is found, update end_time and effects
|
||||||
|
let key = if let Some((other_buff, key)) =
|
||||||
|
other_key.and_then(|key| Some((self.buffs.get_mut(key)?, key)))
|
||||||
|
{
|
||||||
|
other_buff.end_time = buff.end_time;
|
||||||
|
other_buff.effects = buff.effects;
|
||||||
|
key
|
||||||
|
// Otherwise, insert a new buff
|
||||||
|
} else {
|
||||||
let key = self.buffs.insert(buff);
|
let key = self.buffs.insert(buff);
|
||||||
self.kinds[kind]
|
self.kinds[kind]
|
||||||
.get_or_insert_with(|| (Vec::new(), current_time))
|
.get_or_insert_with(|| (Vec::new(), current_time))
|
||||||
.0
|
.0
|
||||||
.push(key);
|
.push(key);
|
||||||
|
key
|
||||||
|
};
|
||||||
|
|
||||||
self.sort_kind(kind);
|
self.sort_kind(kind);
|
||||||
if kind.queues() {
|
if kind.queues() {
|
||||||
self.delay_queueable_buffs(kind, current_time);
|
self.delay_queueable_buffs(kind, current_time);
|
||||||
|
@ -6,7 +6,7 @@ version = "0.10.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
simd = ["vek/platform_intrinsics"]
|
simd = ["vek/platform_intrinsics"]
|
||||||
plugins = ["toml", "tar", "wasmer", "wasmer-wasix-types", "bincode", "plugin-api", "serde"]
|
plugins = ["common-assets/plugins", "toml", "tar", "wasmer", "wasmer-wasix-types", "bincode", "plugin-api", "serde"]
|
||||||
|
|
||||||
default = ["simd"]
|
default = ["simd"]
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ common = { package = "veloren-common", path = ".." }
|
|||||||
common-net = { package = "veloren-common-net", path = "../net" }
|
common-net = { package = "veloren-common-net", path = "../net" }
|
||||||
common-ecs = { package = "veloren-common-ecs", path = "../ecs" }
|
common-ecs = { package = "veloren-common-ecs", path = "../ecs" }
|
||||||
common-base = { package = "veloren-common-base", path = "../base" }
|
common-base = { package = "veloren-common-base", path = "../base" }
|
||||||
|
common-assets = { package = "veloren-common-assets", path = "../assets", optional = true}
|
||||||
|
|
||||||
rayon = { workspace = true }
|
rayon = { workspace = true }
|
||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
|
@ -161,7 +161,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
entity,
|
entity,
|
||||||
buff_change: BuffChange::Add(Buff::new(
|
buff_change: BuffChange::Add(Buff::new(
|
||||||
BuffKind::Bleeding,
|
BuffKind::Bleeding,
|
||||||
BuffData::new(1.0, Some(Secs(6.0))).with_force_immediate(true),
|
BuffData::new(1.0, Some(Secs(6.0))),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
BuffSource::World,
|
BuffSource::World,
|
||||||
*read_data.time,
|
*read_data.time,
|
||||||
@ -179,7 +179,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
entity,
|
entity,
|
||||||
buff_change: BuffChange::Add(Buff::new(
|
buff_change: BuffChange::Add(Buff::new(
|
||||||
BuffKind::Bleeding,
|
BuffKind::Bleeding,
|
||||||
BuffData::new(5.0, Some(Secs(3.0))).with_force_immediate(true),
|
BuffData::new(5.0, Some(Secs(3.0))),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
BuffSource::World,
|
BuffSource::World,
|
||||||
*read_data.time,
|
*read_data.time,
|
||||||
@ -215,7 +215,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
entity,
|
entity,
|
||||||
buff_change: BuffChange::Add(Buff::new(
|
buff_change: BuffChange::Add(Buff::new(
|
||||||
BuffKind::Bleeding,
|
BuffKind::Bleeding,
|
||||||
BuffData::new(15.0, Some(Secs(0.1))).with_force_immediate(true),
|
BuffData::new(15.0, Some(Secs(0.1))),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
BuffSource::World,
|
BuffSource::World,
|
||||||
*read_data.time,
|
*read_data.time,
|
||||||
@ -420,7 +420,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
execute_effect(
|
execute_effect(
|
||||||
effect,
|
effect,
|
||||||
buff.kind,
|
buff.kind,
|
||||||
&buff.data,
|
|
||||||
buff.start_time,
|
buff.start_time,
|
||||||
kind_start_time,
|
kind_start_time,
|
||||||
&read_data,
|
&read_data,
|
||||||
@ -478,7 +477,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
fn execute_effect(
|
fn execute_effect(
|
||||||
effect: &BuffEffect,
|
effect: &BuffEffect,
|
||||||
buff_kind: BuffKind,
|
buff_kind: BuffKind,
|
||||||
buff_data: &BuffData,
|
|
||||||
buff_start_time: Time,
|
buff_start_time: Time,
|
||||||
buff_kind_start_time: Time,
|
buff_kind_start_time: Time,
|
||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
@ -516,9 +514,7 @@ fn execute_effect(
|
|||||||
let prev_tick = ((time_passed - dt).max(0.0) / tick_dur.0).floor();
|
let prev_tick = ((time_passed - dt).max(0.0) / tick_dur.0).floor();
|
||||||
let whole_ticks = curr_tick - prev_tick;
|
let whole_ticks = curr_tick - prev_tick;
|
||||||
|
|
||||||
if buff_data.force_immediate {
|
if buff_will_expire {
|
||||||
Some((1.0 / tick_dur.0 * dt) as f32)
|
|
||||||
} else if buff_will_expire {
|
|
||||||
// If the buff is ending, include the fraction of progress towards the next
|
// If the buff is ending, include the fraction of progress towards the next
|
||||||
// tick.
|
// tick.
|
||||||
let fractional_tick = (time_passed % tick_dur.0) / tick_dur.0;
|
let fractional_tick = (time_passed % tick_dur.0) / tick_dur.0;
|
||||||
|
@ -26,7 +26,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self,
|
||||||
buff::{Buff, BuffData, BuffKind, BuffSource},
|
buff::{Buff, BuffData, BuffKind, BuffSource, MiscBuffData},
|
||||||
inventory::{
|
inventory::{
|
||||||
item::{tool::AbilityMap, MaterialStatManifest, Quality},
|
item::{tool::AbilityMap, MaterialStatManifest, Quality},
|
||||||
slot::Slot,
|
slot::Slot,
|
||||||
@ -4140,25 +4140,110 @@ fn handle_buff(
|
|||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
action: &ServerChatCommand,
|
action: &ServerChatCommand,
|
||||||
) -> CmdResult<()> {
|
) -> CmdResult<()> {
|
||||||
if let (Some(buff), strength, duration) = parse_cmd_args!(args, String, f32, f64) {
|
let (Some(buff), strength, duration, misc_data_spec) =
|
||||||
|
parse_cmd_args!(args, String, f32, f64, String)
|
||||||
|
else {
|
||||||
|
return Err(Content::Plain(action.help_string()));
|
||||||
|
};
|
||||||
|
|
||||||
let strength = strength.unwrap_or(0.01);
|
let strength = strength.unwrap_or(0.01);
|
||||||
let duration = duration.unwrap_or(1.0);
|
|
||||||
|
if buff == "all" {
|
||||||
|
let duration = duration.unwrap_or(5.0);
|
||||||
let buffdata = BuffData::new(strength, Some(Secs(duration)));
|
let buffdata = BuffData::new(strength, Some(Secs(duration)));
|
||||||
if buff != "all" {
|
|
||||||
cast_buff(&buff, buffdata, server, target)
|
// apply every(*) non-complex buff
|
||||||
} else {
|
//
|
||||||
for kind in BUFF_PACK.iter() {
|
// (*) BUFF_PACK contains all buffs except
|
||||||
cast_buff(kind, buffdata, server, target)?;
|
// invulnerability
|
||||||
}
|
BUFF_PACK
|
||||||
|
.iter()
|
||||||
|
.filter_map(|kind_key| parse_buffkind(kind_key))
|
||||||
|
.filter(|buffkind| buffkind.is_simple())
|
||||||
|
.for_each(|buffkind| cast_buff(buffkind, buffdata, server, target));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(Content::Plain(action.help_string()))
|
let buffkind = parse_buffkind(&buff).ok_or_else(|| {
|
||||||
|
Content::localized_with_args("command-buff-unknown", [("buff", buff.clone())])
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if buffkind.is_simple() {
|
||||||
|
let duration = duration.unwrap_or(10.0);
|
||||||
|
let buffdata = BuffData::new(strength, Some(Secs(duration)));
|
||||||
|
cast_buff(buffkind, buffdata, server, target);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// default duration is longer for complex buffs
|
||||||
|
let duration = duration.unwrap_or(20.0);
|
||||||
|
let spec = misc_data_spec.ok_or_else(|| {
|
||||||
|
Content::localized_with_args("command-buff-data", [("buff", buff.clone())])
|
||||||
|
})?;
|
||||||
|
cast_buff_complex(buffkind, server, target, spec, strength, duration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity) -> CmdResult<()> {
|
fn cast_buff_complex(
|
||||||
if let Some(buffkind) = parse_buffkind(kind) {
|
buffkind: BuffKind,
|
||||||
|
server: &mut Server,
|
||||||
|
target: EcsEntity,
|
||||||
|
spec: String,
|
||||||
|
strength: f32,
|
||||||
|
duration: f64,
|
||||||
|
) -> CmdResult<()> {
|
||||||
|
// explicit match to remember that this function exists
|
||||||
|
let misc_data = match buffkind {
|
||||||
|
BuffKind::Polymorphed => {
|
||||||
|
let Ok(npc::NpcBody(_id, mut body)) = spec.parse() else {
|
||||||
|
return Err(Content::localized_with_args("command-buff-body-unknown", [
|
||||||
|
("spec", spec.clone()),
|
||||||
|
]));
|
||||||
|
};
|
||||||
|
MiscBuffData::Body(body())
|
||||||
|
},
|
||||||
|
BuffKind::Regeneration
|
||||||
|
| BuffKind::Saturation
|
||||||
|
| BuffKind::Potion
|
||||||
|
| BuffKind::Agility
|
||||||
|
| BuffKind::CampfireHeal
|
||||||
|
| BuffKind::Frenzied
|
||||||
|
| BuffKind::EnergyRegen
|
||||||
|
| BuffKind::IncreaseMaxEnergy
|
||||||
|
| BuffKind::IncreaseMaxHealth
|
||||||
|
| BuffKind::Invulnerability
|
||||||
|
| BuffKind::ProtectingWard
|
||||||
|
| BuffKind::Hastened
|
||||||
|
| BuffKind::Fortitude
|
||||||
|
| BuffKind::Reckless
|
||||||
|
| BuffKind::Flame
|
||||||
|
| BuffKind::Frigid
|
||||||
|
| BuffKind::Lifesteal
|
||||||
|
| BuffKind::ImminentCritical
|
||||||
|
| BuffKind::Fury
|
||||||
|
| BuffKind::Sunderer
|
||||||
|
| BuffKind::Defiance
|
||||||
|
| BuffKind::Bloodfeast
|
||||||
|
| BuffKind::Berserk
|
||||||
|
| BuffKind::Bleeding
|
||||||
|
| BuffKind::Cursed
|
||||||
|
| BuffKind::Burning
|
||||||
|
| BuffKind::Crippled
|
||||||
|
| BuffKind::Frozen
|
||||||
|
| BuffKind::Wet
|
||||||
|
| BuffKind::Ensnared
|
||||||
|
| BuffKind::Poisoned
|
||||||
|
| BuffKind::Parried
|
||||||
|
| BuffKind::PotionSickness
|
||||||
|
| BuffKind::Heatstroke => unreachable!("is_simple() above"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let buffdata = BuffData::new(strength, Some(Secs(duration))).with_misc_data(misc_data);
|
||||||
|
|
||||||
|
cast_buff(buffkind, buffdata, server, target);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast_buff(buffkind: BuffKind, data: BuffData, server: &mut Server, target: EcsEntity) {
|
||||||
let ecs = &server.state.ecs();
|
let ecs = &server.state.ecs();
|
||||||
let mut buffs_all = ecs.write_storage::<comp::Buffs>();
|
let mut buffs_all = ecs.write_storage::<comp::Buffs>();
|
||||||
let stats = ecs.read_storage::<comp::Stats>();
|
let stats = ecs.read_storage::<comp::Stats>();
|
||||||
@ -4178,12 +4263,6 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity)
|
|||||||
*time,
|
*time,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Content::localized_with_args("command-buff-unknown", [(
|
|
||||||
"buff", kind,
|
|
||||||
)]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() }
|
fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() }
|
||||||
|
Loading…
Reference in New Issue
Block a user