Add /buff_complex command

This commit is contained in:
juliancoffee 2024-01-06 18:00:03 +02:00
parent 5aa30b0175
commit 2746a98f40
3 changed files with 132 additions and 42 deletions

View File

@ -64,7 +64,9 @@ 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-complex = /buff doesn't work with this buff, use /buff_complex command-buff-complex = /buff doesn't work with [{ $buff }], use /buff_complex
command-buff-simple = /buff_complex doesn't work with [{ $buff }], use /buff
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 }

View File

@ -200,13 +200,23 @@ lazy_static! {
buff_pack buff_pack
}; };
static ref BUFFS: Vec<String> = { static ref BUFFS_SIMPLE: Vec<String> = {
let mut buff_pack: Vec<_> = BUFF_PARSER.keys().cloned().collect(); let mut buff_pack: Vec<String> = BUFF_PARSER
// Add all as valid command .iter()
.filter_map(|(key, kind)| kind.is_simple().then_some(key.clone()))
.collect();
// Add `all` as valid command
buff_pack.push("all".to_string()); buff_pack.push("all".to_string());
buff_pack buff_pack
}; };
static ref BUFFS_COMPLEX: Vec<String> =
BUFF_PARSER
.iter()
.filter_map(|(key, kind)| (!kind.is_simple()).then_some(key.clone()))
.collect();
static ref BLOCK_KINDS: Vec<String> = terrain::block::BlockKind::iter() static ref BLOCK_KINDS: Vec<String> = terrain::block::BlockKind::iter()
.map(|bk| bk.to_string()) .map(|bk| bk.to_string())
.collect(); .collect();
@ -312,6 +322,7 @@ pub enum ServerChatCommand {
BattleModeForce, BattleModeForce,
Body, Body,
Buff, Buff,
BuffComplex,
Build, Build,
Campfire, Campfire,
CreateLocation, CreateLocation,
@ -426,13 +437,23 @@ impl ServerChatCommand {
), ),
ServerChatCommand::Buff => cmd( ServerChatCommand::Buff => cmd(
vec![ vec![
Enum("buff", BUFFS.clone(), Required), Enum("buff", BUFFS_SIMPLE.clone(), Required),
Float("strength", 0.01, Optional), Float("strength", 0.01, Optional),
Float("duration", 10.0, Optional), Float("duration", 10.0, Optional),
], ],
"Cast a buff on player", "Cast a buff on player",
Some(Admin), Some(Admin),
), ),
ServerChatCommand::BuffComplex => cmd(
vec![
Enum("buff", BUFFS_COMPLEX.clone(), Required),
Any("buff data spec", Required),
Float("strength", 0.01, Optional),
Float("duration", 10.0, Optional),
],
"Cast a complex buff on player",
Some(Admin),
),
ServerChatCommand::Ban => cmd( ServerChatCommand::Ban => cmd(
vec![ vec![
PlayerName(Required), PlayerName(Required),
@ -934,6 +955,7 @@ impl ServerChatCommand {
ServerChatCommand::BattleModeForce => "battlemode_force", ServerChatCommand::BattleModeForce => "battlemode_force",
ServerChatCommand::Body => "body", ServerChatCommand::Body => "body",
ServerChatCommand::Buff => "buff", ServerChatCommand::Buff => "buff",
ServerChatCommand::BuffComplex => "buff_complex",
ServerChatCommand::Build => "build", ServerChatCommand::Build => "build",
ServerChatCommand::AreaAdd => "area_add", ServerChatCommand::AreaAdd => "area_add",
ServerChatCommand::AreaList => "area_list", ServerChatCommand::AreaList => "area_list",

View File

@ -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,
@ -131,6 +131,7 @@ fn do_command(
ServerChatCommand::BattleModeForce => handle_battlemode_force, ServerChatCommand::BattleModeForce => handle_battlemode_force,
ServerChatCommand::Body => handle_body, ServerChatCommand::Body => handle_body,
ServerChatCommand::Buff => handle_buff, ServerChatCommand::Buff => handle_buff,
ServerChatCommand::BuffComplex => handle_buff_complex,
ServerChatCommand::Build => handle_build, ServerChatCommand::Build => handle_build,
ServerChatCommand::AreaAdd => handle_area_add, ServerChatCommand::AreaAdd => handle_area_add,
ServerChatCommand::AreaList => handle_area_list, ServerChatCommand::AreaList => handle_area_list,
@ -4140,49 +4141,116 @@ 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) = parse_cmd_args!(args, String, f32, f64) else {
let strength = strength.unwrap_or(0.01); return Err(Content::Plain(action.help_string()));
let duration = duration.unwrap_or(1.0); };
let buffdata = BuffData::new(strength, Some(Secs(duration)));
if buff != "all" {
let buffkind = parse_buffkind(&buff).ok_or_else(|| {
Content::localized_with_args("command-buff-unknown", [("buff", buff.clone())])
})?;
if buffkind.is_simple() { let strength = strength.unwrap_or(0.01);
cast_buff(buffkind, buffdata, server, target) let duration = duration.unwrap_or(1.0);
} else { let buffdata = BuffData::new(strength, Some(Secs(duration)));
return Err(Content::localized_with_args("command-buff-complex", [(
"buff", buff,
)]));
}
} else {
for kind_key in BUFF_PACK.iter() {
let buffkind = parse_buffkind(kind_key).ok_or_else(|| {
Content::localized_with_args("command-buff-unknown", [(
"buff",
kind_key.to_owned(),
)])
})?;
// Execute only simple buffs, ignore complex if buff == "all" {
if buffkind.is_simple() { BUFF_PACK
cast_buff(buffkind, buffdata, server, target)?; .iter()
} .filter_map(|kind_key| parse_buffkind(kind_key))
} .filter(|buffkind| buffkind.is_simple())
Ok(()) .for_each(|buffkind| cast_buff(buffkind, buffdata, server, target));
}
} 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() {
return Err(Content::localized_with_args("command-buff-complex", [(
"buff", buff,
)]));
}
cast_buff(buffkind, buffdata, server, target);
} }
Ok(())
} }
fn cast_buff( fn handle_buff_complex(
buffkind: BuffKind,
data: BuffData,
server: &mut Server, server: &mut Server,
_client: EcsEntity,
target: EcsEntity, target: EcsEntity,
args: Vec<String>,
action: &ServerChatCommand,
) -> CmdResult<()> { ) -> CmdResult<()> {
let (Some(buff), Some(spec), strength, duration) =
parse_cmd_args!(args, String, String, f32, f64)
else {
return 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() {
return Err(Content::localized_with_args("command-buff-simple", [(
"buff", buff,
)]));
}
// 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 strength = strength.unwrap_or(0.01);
let duration = duration.unwrap_or(20.0);
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>();
@ -4202,8 +4270,6 @@ fn cast_buff(
*time, *time,
); );
} }
Ok(())
} }
fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() } fn parse_buffkind(buff: &str) -> Option<BuffKind> { BUFF_PARSER.get(buff).copied() }