mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'juliancoffee/buff-misc-cmd' into 'master'
Add /buff_complex command See merge request veloren/veloren!4243
This commit is contained in:
commit
dc215ace34
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7088,6 +7088,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"vek 0.15.8",
|
||||
"veloren-common",
|
||||
"veloren-common-assets",
|
||||
"veloren-common-base",
|
||||
"veloren-common-ecs",
|
||||
"veloren-common-net",
|
||||
|
@ -64,6 +64,8 @@ command-battlemode-available-modes = Available modes: pvp, pve
|
||||
command-battlemode-same = Attempted to set the same battlemode
|
||||
command-battlemode-updated = New battlemode: { $battlemode }
|
||||
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-broken = Skill preset is broken
|
||||
command-skillpreset-missing = Preset does not exist: { $preset }
|
||||
@ -95,4 +97,4 @@ command-you-dont-exist = You do not exist, so you cannot use this command
|
||||
command-destroyed-tethers = All tethers destroyed! You are now free
|
||||
command-destroyed-no-tethers = You're not connected to any tethers
|
||||
command-dismounted = Dismounted
|
||||
command-no-dismount = You're not riding or being ridden
|
||||
command-no-dismount = You're not riding or being ridden
|
||||
|
@ -31,14 +31,14 @@ pub use walk::{walk_tree, Walk};
|
||||
|
||||
#[cfg(feature = "plugins")]
|
||||
lazy_static! {
|
||||
/// The HashMap where all loaded assets are stored in.
|
||||
static ref ASSETS: plugin_cache::CombinedCache = plugin_cache::CombinedCache::new().unwrap();
|
||||
/// The HashMap where all loaded assets are stored in.
|
||||
static ref ASSETS: plugin_cache::CombinedCache = plugin_cache::CombinedCache::new().unwrap();
|
||||
}
|
||||
#[cfg(not(feature = "plugins"))]
|
||||
lazy_static! {
|
||||
/// The HashMap where all loaded assets are stored in.
|
||||
static ref ASSETS: AssetCache<fs::FileSystem> =
|
||||
AssetCache::with_source(fs::FileSystem::new().unwrap());
|
||||
/// The HashMap where all loaded assets are stored in.
|
||||
static ref ASSETS: AssetCache<fs::FileSystem> =
|
||||
AssetCache::with_source(fs::FileSystem::new().unwrap());
|
||||
}
|
||||
|
||||
#[cfg(feature = "hot-reloading")]
|
||||
|
@ -201,9 +201,10 @@ lazy_static! {
|
||||
};
|
||||
|
||||
static ref BUFFS: Vec<String> = {
|
||||
let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect();
|
||||
// Add all as valid command
|
||||
buff_pack.push("all".to_string());
|
||||
let mut buff_pack: Vec<String> = BUFF_PARSER.keys().cloned().collect();
|
||||
|
||||
// Add `all` as valid command
|
||||
buff_pack.push("all".to_owned());
|
||||
buff_pack
|
||||
};
|
||||
|
||||
@ -429,6 +430,7 @@ impl ServerChatCommand {
|
||||
Enum("buff", BUFFS.clone(), Required),
|
||||
Float("strength", 0.01, Optional),
|
||||
Float("duration", 10.0, Optional),
|
||||
Any("buff data spec", Optional),
|
||||
],
|
||||
"Cast a buff on player",
|
||||
Some(Admin),
|
||||
|
@ -165,19 +165,38 @@ pub enum BuffKind {
|
||||
/// Results from drinking a potion.
|
||||
/// Decreases the health gained from subsequent potions.
|
||||
PotionSickness,
|
||||
/// Changed into another body.
|
||||
Polymorphed,
|
||||
/// Slows movement speed and reduces energy reward.
|
||||
/// 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
|
||||
/// 33.3% and energy reward reduced by 200%. Energy reward can't be
|
||||
/// reduced by more than 200%, to a minimum value of -100%.
|
||||
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 {
|
||||
/// Checks if buff is buff or debuff.
|
||||
pub fn is_buff(self) -> bool {
|
||||
/// Tells a little more about buff kind than simple buff/debuff
|
||||
///
|
||||
/// Read more in [BuffDescriptor].
|
||||
pub fn differentiate(self) -> BuffDescriptor {
|
||||
match self {
|
||||
BuffKind::Regeneration
|
||||
| BuffKind::Saturation
|
||||
@ -202,7 +221,7 @@ impl BuffKind {
|
||||
| BuffKind::Sunderer
|
||||
| BuffKind::Defiance
|
||||
| BuffKind::Bloodfeast
|
||||
| BuffKind::Berserk => true,
|
||||
| BuffKind::Berserk => BuffDescriptor::SimplePositive,
|
||||
BuffKind::Bleeding
|
||||
| BuffKind::Cursed
|
||||
| BuffKind::Burning
|
||||
@ -213,8 +232,23 @@ impl BuffKind {
|
||||
| BuffKind::Poisoned
|
||||
| BuffKind::Parried
|
||||
| BuffKind::PotionSickness
|
||||
| BuffKind::Polymorphed
|
||||
| BuffKind::Heatstroke => false,
|
||||
| BuffKind::Heatstroke => BuffDescriptor::SimpleNegative,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ version = "0.10.0"
|
||||
|
||||
[features]
|
||||
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"]
|
||||
|
||||
@ -15,6 +15,7 @@ common = { package = "veloren-common", path = ".." }
|
||||
common-net = { package = "veloren-common-net", path = "../net" }
|
||||
common-ecs = { package = "veloren-common-ecs", path = "../ecs" }
|
||||
common-base = { package = "veloren-common-base", path = "../base" }
|
||||
common-assets = { package = "veloren-common-assets", path = "../assets", optional = true}
|
||||
|
||||
rayon = { workspace = true }
|
||||
num_cpus = "1.0"
|
||||
|
@ -26,7 +26,7 @@ use common::{
|
||||
},
|
||||
comp::{
|
||||
self,
|
||||
buff::{Buff, BuffData, BuffKind, BuffSource},
|
||||
buff::{Buff, BuffData, BuffKind, BuffSource, MiscBuffData},
|
||||
inventory::{
|
||||
item::{tool::AbilityMap, MaterialStatManifest, Quality},
|
||||
slot::Slot,
|
||||
@ -4140,49 +4140,128 @@ fn handle_buff(
|
||||
args: Vec<String>,
|
||||
action: &ServerChatCommand,
|
||||
) -> CmdResult<()> {
|
||||
if let (Some(buff), strength, duration) = parse_cmd_args!(args, String, f32, f64) {
|
||||
let strength = strength.unwrap_or(0.01);
|
||||
let duration = duration.unwrap_or(1.0);
|
||||
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);
|
||||
|
||||
if buff == "all" {
|
||||
let duration = duration.unwrap_or(5.0);
|
||||
let buffdata = BuffData::new(strength, Some(Secs(duration)));
|
||||
if buff != "all" {
|
||||
cast_buff(&buff, buffdata, server, target)
|
||||
} else {
|
||||
for kind in BUFF_PACK.iter() {
|
||||
cast_buff(kind, buffdata, server, target)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// apply every(*) non-complex buff
|
||||
//
|
||||
// (*) BUFF_PACK contains all buffs except
|
||||
// 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(())
|
||||
} 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<()> {
|
||||
if let Some(buffkind) = parse_buffkind(kind) {
|
||||
let ecs = &server.state.ecs();
|
||||
let mut buffs_all = ecs.write_storage::<comp::Buffs>();
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let healths = ecs.read_storage::<comp::Health>();
|
||||
let time = ecs.read_resource::<Time>();
|
||||
if let Some(mut buffs) = buffs_all.get_mut(target) {
|
||||
buffs.insert(
|
||||
Buff::new(
|
||||
buffkind,
|
||||
data,
|
||||
vec![],
|
||||
BuffSource::Command,
|
||||
*time,
|
||||
stats.get(target),
|
||||
healths.get(target),
|
||||
),
|
||||
fn cast_buff_complex(
|
||||
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 mut buffs_all = ecs.write_storage::<comp::Buffs>();
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let healths = ecs.read_storage::<comp::Health>();
|
||||
let time = ecs.read_resource::<Time>();
|
||||
if let Some(mut buffs) = buffs_all.get_mut(target) {
|
||||
buffs.insert(
|
||||
Buff::new(
|
||||
buffkind,
|
||||
data,
|
||||
vec![],
|
||||
BuffSource::Command,
|
||||
*time,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Content::localized_with_args("command-buff-unknown", [(
|
||||
"buff", kind,
|
||||
)]))
|
||||
stats.get(target),
|
||||
healths.get(target),
|
||||
),
|
||||
*time,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user