steel_core/command/builtins/
damage.rs1use super::super::{
4 brigadier::{ArgumentType, CommandNodeBuilder, CommandSyntaxError},
5 execution::{
6 CommandSource, SteelArgumentType, SteelCommandContext, SteelCommandRuntime, argument,
7 literal,
8 },
9 registration::CommandRegistration,
10};
11use crate::entity::damage::DamageSource;
12use steel_registry::vanilla_damage_types;
13use steel_utils::Identifier;
14use steel_utils::translations::{COMMANDS_DAMAGE_INVULNERABLE, COMMANDS_DAMAGE_SUCCESS};
15use text_components::TextComponent;
16
17pub(super) fn registration() -> CommandRegistration<CommandSource> {
18 CommandRegistration::new(Identifier::vanilla_static("damage"), |_| command())
19}
20
21fn command() -> CommandNodeBuilder<CommandSource, SteelCommandRuntime> {
22 literal("damage").then(
23 argument("target", SteelArgumentType::entity()).then(
24 argument("amount", ArgumentType::float(0.0, f32::MAX))
25 .executes(damage)
26 .then(
27 argument("damageType", SteelArgumentType::damage_type())
28 .executes(damage)
29 .then(literal("at").then(
30 argument("location", SteelArgumentType::vec3(true)).executes(damage),
31 ))
32 .then(
33 literal("by").then(
34 argument("entity", SteelArgumentType::entity())
35 .executes(damage)
36 .then(
37 literal("from").then(
38 argument("cause", SteelArgumentType::entity())
39 .executes(damage),
40 ),
41 ),
42 ),
43 ),
44 ),
45 ),
46 )
47}
48
49fn damage(context: &SteelCommandContext<CommandSource>) -> Result<i32, CommandSyntaxError> {
50 let target = context.entity("target")?;
51 let Some(amount) = context.float("amount") else {
52 return Err(CommandSyntaxError::dynamic(
53 "Parsed value for amount is missing from the command context",
54 ));
55 };
56
57 let damage_type = context
59 .damage_type("damageType")
60 .unwrap_or(&vanilla_damage_types::GENERIC);
61
62 let mut damage_source = DamageSource::environment(damage_type);
64
65 if let Some(coordinates) = context.coordinates("location") {
67 damage_source.source_position = Some(coordinates.position(context.source()));
68 }
69
70 if let Ok(entity) = context.entity("entity") {
72 damage_source.direct_entity_id = Some(entity.id());
73
74 if let Ok(cause) = context.entity("cause") {
76 damage_source.causing_entity_id = Some(cause.id());
77 }
78 }
79
80 let Some(target_world) = target.level() else {
81 return Err(CommandSyntaxError::dynamic(
82 "The entity is not in a world or the world was dropped.",
83 ));
84 };
85
86 if target.hurt(&target_world, &damage_source, amount) {
87 context.source().send_success(
88 &COMMANDS_DAMAGE_SUCCESS
89 .message([
90 TextComponent::plain(format!("{amount:?}")),
91 target.display_name(),
92 ])
93 .component(),
94 true,
95 );
96 Ok(1)
97 } else {
98 context
99 .source()
100 .send_failure(COMMANDS_DAMAGE_INVULNERABLE.msg().component());
101 Ok(0)
102 }
103}