Added spawning test dummy

This commit is contained in:
Forest Anderson 2020-07-02 17:53:01 -04:00
parent 05d4dd0556
commit e73ec7a4d2
4 changed files with 85 additions and 6 deletions

View File

@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ability to wield 2 × 1h weapons and shields (Note: 1h weapons & shields are not currently avaliable, see [!1095](https://gitlab.com/veloren/veloren/-/merge_requests/1095) for more info) - Ability to wield 2 × 1h weapons and shields (Note: 1h weapons & shields are not currently avaliable, see [!1095](https://gitlab.com/veloren/veloren/-/merge_requests/1095) for more info)
- Zoomable Map - Zoomable Map
- M2 attack for hammer - M2 attack for hammer
- Spawnable training dummies
### Changed ### Changed

View File

@ -32,6 +32,11 @@ impl TabComplete for ArgumentSpec {
.filter(|string| string.starts_with(part)) .filter(|string| string.starts_with(part))
.map(|c| c.to_string()) .map(|c| c.to_string())
.collect(), .collect(),
ArgumentSpec::Boolean(_, part, _) => vec!["true", "false"]
.iter()
.filter(|string| string.starts_with(part))
.map(|c| c.to_string())
.collect(),
} }
} }
} }

View File

@ -40,6 +40,7 @@ pub enum ChatCommand {
Build, Build,
Debug, Debug,
DebugColumn, DebugColumn,
Dummy,
Explosion, Explosion,
Faction, Faction,
GiveExp, GiveExp,
@ -81,6 +82,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Build, ChatCommand::Build,
ChatCommand::Debug, ChatCommand::Debug,
ChatCommand::DebugColumn, ChatCommand::DebugColumn,
ChatCommand::Dummy,
ChatCommand::Explosion, ChatCommand::Explosion,
ChatCommand::Faction, ChatCommand::Faction,
ChatCommand::GiveExp, ChatCommand::GiveExp,
@ -191,6 +193,7 @@ impl ChatCommand {
"Prints some debug information about a column", "Prints some debug information about a column",
NoAdmin, NoAdmin,
), ),
ChatCommand::Dummy => cmd(vec![], "Spawns a training dummy", NoAdmin),
ChatCommand::Explosion => cmd( ChatCommand::Explosion => cmd(
vec![Float("radius", 5.0, Required)], vec![Float("radius", 5.0, Required)],
"Explodes the ground around you", "Explodes the ground around you",
@ -321,6 +324,7 @@ impl ChatCommand {
Enum("alignment", ALIGNMENTS.clone(), Required), Enum("alignment", ALIGNMENTS.clone(), Required),
Enum("entity", ENTITIES.clone(), Required), Enum("entity", ENTITIES.clone(), Required),
Integer("amount", 1, Optional), Integer("amount", 1, Optional),
Boolean("ai", "true".to_string(), Optional),
], ],
"Spawn a test entity", "Spawn a test entity",
Admin, Admin,
@ -370,6 +374,7 @@ impl ChatCommand {
ChatCommand::Build => "build", ChatCommand::Build => "build",
ChatCommand::Debug => "debug", ChatCommand::Debug => "debug",
ChatCommand::DebugColumn => "debug_column", ChatCommand::DebugColumn => "debug_column",
ChatCommand::Dummy => "dummy",
ChatCommand::Explosion => "explosion", ChatCommand::Explosion => "explosion",
ChatCommand::Faction => "faction", ChatCommand::Faction => "faction",
ChatCommand::GiveExp => "give_exp", ChatCommand::GiveExp => "give_exp",
@ -433,6 +438,7 @@ impl ChatCommand {
ArgumentSpec::Message(_) => "{/.*/}", ArgumentSpec::Message(_) => "{/.*/}",
ArgumentSpec::SubCommand => "{} {/.*/}", ArgumentSpec::SubCommand => "{} {/.*/}",
ArgumentSpec::Enum(_, _, _) => "{}", ArgumentSpec::Enum(_, _, _) => "{}",
ArgumentSpec::Boolean(_, _, _) => "{}",
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" ") .join(" ")
@ -514,6 +520,11 @@ pub enum ArgumentSpec {
/// * Predefined string completions /// * Predefined string completions
/// * whether it's optional /// * whether it's optional
Enum(&'static str, Vec<String>, Requirement), Enum(&'static str, Vec<String>, Requirement),
/// The argument is likely a boolean. The associated values are
/// * label
/// * suggested tab-completion
/// * whether it's optional
Boolean(&'static str, String, Requirement),
} }
impl ArgumentSpec { impl ArgumentSpec {
@ -569,6 +580,13 @@ impl ArgumentSpec {
format! {"[{}]", label} format! {"[{}]", label}
} }
}, },
ArgumentSpec::Boolean(label, _, req) => {
if &Requirement::Required == req {
format!("<{}>", label)
} else {
format!("[{}]", label)
}
},
} }
} }
} }

View File

@ -66,6 +66,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::Build => handle_build, ChatCommand::Build => handle_build,
ChatCommand::Debug => handle_debug, ChatCommand::Debug => handle_debug,
ChatCommand::DebugColumn => handle_debug_column, ChatCommand::DebugColumn => handle_debug_column,
ChatCommand::Dummy => handle_spawn_training_dummy,
ChatCommand::Explosion => handle_explosion, ChatCommand::Explosion => handle_explosion,
ChatCommand::Faction => handle_faction, ChatCommand::Faction => handle_faction,
ChatCommand::GiveExp => handle_give_exp, ChatCommand::GiveExp => handle_give_exp,
@ -497,8 +498,15 @@ fn handle_spawn(
args: String, args: String,
action: &ChatCommand, action: &ChatCommand,
) { ) {
match scan_fmt_some!(&args, &action.arg_fmt(), String, npc::NpcBody, String) { match scan_fmt_some!(
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount) => { &args,
&action.arg_fmt(),
String,
npc::NpcBody,
String,
String
) {
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount, opt_ai) => {
if let Some(alignment) = parse_alignment(target, &opt_align) { if let Some(alignment) = parse_alignment(target, &opt_align) {
let amount = opt_amount let amount = opt_amount
.and_then(|a| a.parse().ok()) .and_then(|a| a.parse().ok())
@ -506,6 +514,8 @@ fn handle_spawn(
.unwrap_or(1) .unwrap_or(1)
.min(10); .min(10);
let ai = opt_ai.unwrap_or("true".to_string());
match server.state.read_component_cloned::<comp::Pos>(target) { match server.state.read_component_cloned::<comp::Pos>(target) {
Some(pos) => { Some(pos) => {
let agent = let agent =
@ -524,7 +534,7 @@ fn handle_spawn(
let body = body(); let body = body();
let new_entity = server let mut entity_base = server
.state .state
.create_npc( .create_npc(
pos, pos,
@ -534,9 +544,13 @@ fn handle_spawn(
) )
.with(comp::Vel(vel)) .with(comp::Vel(vel))
.with(comp::MountState::Unmounted) .with(comp::MountState::Unmounted)
.with(agent.clone()) .with(alignment);
.with(alignment)
.build(); if ai == "true".to_string() {
entity_base = entity_base.with(agent.clone());
}
let new_entity = entity_base.build();
if let Some(uid) = server.state.ecs().uid_from_entity(new_entity) { if let Some(uid) = server.state.ecs().uid_from_entity(new_entity) {
server.notify_client( server.notify_client(
@ -568,6 +582,47 @@ fn handle_spawn(
} }
} }
fn handle_spawn_training_dummy(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(pos) => {
let vel = Vec3::new(
rand::thread_rng().gen_range(-2.0, 3.0),
rand::thread_rng().gen_range(-2.0, 3.0),
10.0,
);
let body = comp::Body::Object(comp::object::Body::Scarecrow);
server
.state
.create_npc(
pos,
comp::Stats::new("Training Dummy".to_string(), body),
comp::Loadout::default(),
body,
)
.with(comp::Vel(vel))
.with(comp::MountState::Unmounted)
.build();
server.notify_client(
client,
ChatType::CommandInfo.server_msg(format!("Spawned a training dummy")),
);
},
None => server.notify_client(
client,
ChatType::CommandError.server_msg("You have no position!"),
),
}
}
fn handle_players( fn handle_players(
server: &mut Server, server: &mut Server,
client: EcsEntity, client: EcsEntity,