Skip to content

Commit b7b484d

Browse files
Absolutionismerenkarakal
authored andcommitted
EffForceAttack Damage Entity By Amount (SkriptLang#7878)
* Update EffForceAttack.java * Update EffForceAttack.java * Create EffForceAttack.sk * Update EffForceAttack.java * Edge Cases * Use Runtime Error in test
1 parent 53cf505 commit b7b484d

2 files changed

Lines changed: 150 additions & 31 deletions

File tree

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,117 @@
11
package ch.njol.skript.effects;
22

3-
import org.bukkit.entity.Entity;
4-
import org.bukkit.entity.LivingEntity;
5-
import org.bukkit.event.Event;
6-
import org.jetbrains.annotations.Nullable;
7-
83
import ch.njol.skript.Skript;
9-
import ch.njol.skript.doc.Description;
10-
import ch.njol.skript.doc.Examples;
11-
import ch.njol.skript.doc.Name;
12-
import ch.njol.skript.doc.RequiredPlugins;
13-
import ch.njol.skript.doc.Since;
4+
import ch.njol.skript.config.Node;
5+
import ch.njol.skript.doc.*;
146
import ch.njol.skript.lang.Effect;
157
import ch.njol.skript.lang.Expression;
168
import ch.njol.skript.lang.SkriptParser.ParseResult;
9+
import ch.njol.skript.lang.SyntaxStringBuilder;
1710
import ch.njol.util.Kleenean;
11+
import org.bukkit.entity.Damageable;
12+
import org.bukkit.entity.Entity;
13+
import org.bukkit.entity.LivingEntity;
14+
import org.bukkit.event.Event;
15+
import org.jetbrains.annotations.Nullable;
16+
import org.skriptlang.skript.log.runtime.SyntaxRuntimeErrorProducer;
1817

1918
@Name("Force Attack")
20-
@Description("Makes a living entity attack an entity with a melee attack.")
19+
@Description({
20+
"Makes a living entity attack an entity with a melee attack.",
21+
"Using 'attack' will make the attacker use the item in their main hand "
22+
+ "and will apply extra data from the item, including enchantments and attributes.",
23+
"Using 'damage' with a number of hearts will not account for the item in the main hand "
24+
+ "and will always be the number provided."
25+
})
26+
@Example("""
27+
spawn a wolf at location(0, 0, 0)
28+
make last spawned wolf attack all players
29+
""")
30+
@Example("""
31+
spawn a zombie at location(0, 0, 0)
32+
make player damage last spawned zombie by 2
33+
""")
2134
@Examples({"spawn a wolf at player's location",
2235
"make last spawned wolf attack player"})
23-
@Since("2.5.1")
36+
@Since("2.5.1, INSERT VERSION (multiple, amount)")
2437
@RequiredPlugins("Minecraft 1.15.2+")
25-
public class EffForceAttack extends Effect {
38+
public class EffForceAttack extends Effect implements SyntaxRuntimeErrorProducer {
2639

2740
static {
2841
Skript.registerEffect(EffForceAttack.class,
29-
"make %livingentities% attack %entity%",
30-
"force %livingentities% to attack %entity%");
42+
"make %livingentities% attack %entities%",
43+
"force %livingentities% to attack %entities%",
44+
"make %livingentities% damage %entities% by %number% [heart[s]]",
45+
"force %livingentities% to damage %entities% by %number% [heart[s]]");
3146
}
47+
48+
private Expression<LivingEntity> attackers;
49+
private Expression<Entity> victims;
50+
private @Nullable Expression<Number> amount;
51+
private Node node;
3252

33-
@SuppressWarnings("null")
34-
private Expression<LivingEntity> entities;
35-
@SuppressWarnings("null")
36-
private Expression<Entity> target;
37-
38-
@Override
3953
@SuppressWarnings("unchecked")
54+
@Override
4055
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
41-
entities = (Expression<LivingEntity>) exprs[0];
42-
target = (Expression<Entity>) exprs[1];
56+
attackers = (Expression<LivingEntity>) exprs[0];
57+
victims = (Expression<Entity>) exprs[1];
58+
if (matchedPattern >= 2)
59+
amount = (Expression<Number>) exprs[2];
60+
node = getParser().getNode();
4361
return true;
4462
}
4563

4664
@Override
47-
protected void execute(Event e) {
48-
Entity target = this.target.getSingle(e);
49-
if (target != null) {
50-
for (LivingEntity entity : entities.getArray(e)) {
51-
entity.attack(target);
65+
protected void execute(Event event) {
66+
Double amount = null;
67+
if (this.amount != null) {
68+
Number number = this.amount.getSingle(event);
69+
if (number == null)
70+
return;
71+
Double preAmount = number.doubleValue();
72+
if (preAmount <= 0) {
73+
error("Cannot damage an entity by 0 or less. Consider healing instead.");
74+
return;
75+
} else if (!Double.isFinite(preAmount)) {
76+
return;
77+
}
78+
amount = preAmount * 2; // hearts
79+
}
80+
81+
LivingEntity[] attackers = this.attackers.getArray(event);
82+
Entity[] victims = this.victims.getArray(event);
83+
if (amount == null) {
84+
for (Entity victim : victims) {
85+
for (LivingEntity attacker : attackers) {
86+
attacker.attack(victim);
87+
}
88+
}
89+
} else {
90+
for (Entity victim : victims) {
91+
if (!(victim instanceof Damageable damageable))
92+
continue;
93+
for (LivingEntity attacker : attackers) {
94+
damageable.damage(amount, attacker);
95+
}
5296
}
5397
}
5498
}
55-
99+
56100
@Override
57-
public String toString(@Nullable Event e, boolean debug) {
58-
return "make " + entities.toString(e, debug) + " attack " + target.toString(e, debug);
101+
public Node getNode() {
102+
return node;
103+
}
104+
105+
@Override
106+
public String toString(Event event, boolean debug) {
107+
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);
108+
builder.append("make", attackers);
109+
if (amount == null) {
110+
builder.append("attack", victims);
111+
} else {
112+
builder.append("damage", victims, "by", amount);
113+
}
114+
return builder.toString();
59115
}
60116

61117
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
test "force attack":
3+
spawn a zombie at test-location:
4+
set {_attacker} to entity
5+
spawn a pig at test-location:
6+
set {_victim} to entity
7+
8+
set {_max} to the max health of {_victim}
9+
make {_attacker} attack {_victim}
10+
assert the health of {_victim} < {_max} with "Victim should have taken damage"
11+
assert the last damage of {_victim} is 1.5 with "Damage taken should be 1.5"
12+
13+
clear entity within {_attacker}
14+
clear entity within {_victim}
15+
16+
test "entity damage entity by amount":
17+
spawn a zombie at test-location:
18+
set {_attacker} to entity
19+
spawn a pig at test-location:
20+
set {_victim} to entity
21+
22+
set {_max} to the max health of {_victim}
23+
make {_attacker} damage {_victim} by 5
24+
assert the health of {_victim} < {_max} with "Victim should have taken damage"
25+
assert the last damage of {_victim} is 5 with "Damage taken should be 5"
26+
27+
clear entity within {_attacker}
28+
clear entity within {_victim}
29+
30+
using error catching
31+
32+
test "entity damage entity by negative":
33+
spawn a zombie at test-location:
34+
set {_attacker} to entity
35+
spawn a pig at test-location:
36+
set {_victim} to entity
37+
38+
set {_max} to the max health of {_victim}
39+
catch errors:
40+
make {_attacker} damage {_victim} by -2
41+
set {_error} to "Cannot damage an entity by 0 or less. Consider healing instead."
42+
assert last caught errors is {_error} with "Damaging by negative value did not throw error"
43+
44+
clear entity within {_attacker}
45+
clear entity within {_victim}
46+
47+
test "entity damage entity by infinity/NaN":
48+
spawn a zombie at test-location:
49+
set {_attacker} to entity
50+
spawn a pig at test-location:
51+
set {_victim} to entity
52+
53+
set {_max} to the max health of {_victim}
54+
make {_attacker} damage {_victim} by infinity value
55+
assert the health of {_victim} is {_max} with "Victim's health should be max - infinity value"
56+
assert the last damage of {_victim} is 0 with "Victim should not have taken damage - infinity value"
57+
58+
make {_attacker} damage {_victim} by NaN value
59+
assert the health of {_victim} is {_max} with "Victim's health should be max - NaN value"
60+
assert the last damage of {_victim} is 0 with "Victim should not have taken damage - NaN value"
61+
62+
clear entity within {_attacker}
63+
clear entity within {_victim}

0 commit comments

Comments
 (0)