-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathCombatFeature.java
More file actions
115 lines (94 loc) · 5 KB
/
CombatFeature.java
File metadata and controls
115 lines (94 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package net.minestom.arena.feature;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityProjectile;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.hologram.Hologram;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToLongFunction;
/**
* @param playerCombat Allow player combat
* @param damageFunction Uses the return value as damage to apply (in lambda arg 1 is attacker, arg 2 is victim)
* @param invulnerabilityFunction Uses the return value as time an entity is invulnerable after getting attacked (in lambda arg 1 is victim)
*/
record CombatFeature(boolean playerCombat, ToDoubleBiFunction<Entity, Entity> damageFunction,
ToLongFunction<Entity> invulnerabilityFunction) implements Feature {
private static final Tag<Long> INVULNERABLE_UNTIL_TAG = Tag.Long("invulnerable_until").defaultValue(0L);
private void takeKnockback(Entity target, Entity source) {
target.takeKnockback(
0.5f,
Math.sin(source.getPosition().yaw() * (Math.PI / 180)),
-Math.cos(source.getPosition().yaw() * (Math.PI / 180))
);
}
private void spawnHologram(Entity target, Entity source, float damage) {
damage = MathUtils.round(damage, 2);
new DamageHologram(
target.getInstance(),
target.getPosition().add(0, target.getEyeHeight(), 0),
Component.text(damage, NamedTextColor.RED)
);
}
@Override
public void hook(@NotNull EventNode<InstanceEvent> node) {
node.addListener(ProjectileCollideWithEntityEvent.class, event -> {
if (!(event.getTarget() instanceof LivingEntity target)) return;
if (!(event.getEntity() instanceof EntityProjectile projectile)) return;
// Don't apply damage if entity is invulnerable
final long now = System.currentTimeMillis();
final long invulnerableUntil = target.getTag(INVULNERABLE_UNTIL_TAG);
if (invulnerableUntil > now) return;
float damage = (float) damageFunction.applyAsDouble(projectile, target);
target.damage(DamageType.fromProjectile(projectile.getShooter(), projectile), damage);
target.setTag(INVULNERABLE_UNTIL_TAG, now + invulnerabilityFunction.applyAsLong(target));
takeKnockback(target, projectile);
spawnHologram(target, projectile, damage);
projectile.remove();
}).addListener(EntityAttackEvent.class, event -> {
if (!(event.getTarget() instanceof LivingEntity target)) return;
// PVP is disabled and two players have attempted to hit each other
if (!playerCombat && target instanceof Player && event.getEntity() instanceof Player) return;
// Can't have dead sources attacking things
if (((LivingEntity) event.getEntity()).isDead()) return;
// Don't apply damage if entity is invulnerable
final long now = System.currentTimeMillis();
final long invulnerableUntil = target.getTag(INVULNERABLE_UNTIL_TAG);
if (invulnerableUntil > now) return;
float damage = (float) damageFunction.applyAsDouble(event.getEntity(), target);
target.damage(DamageType.fromEntity(event.getEntity()), damage);
target.setTag(INVULNERABLE_UNTIL_TAG, now + invulnerabilityFunction.applyAsLong(target));
takeKnockback(target, event.getEntity());
spawnHologram(target, event.getEntity(), damage);
});
}
private static class DamageHologram extends Hologram {
public DamageHologram(Instance instance, Pos spawnPosition, Component text) {
super(instance, spawnPosition, text, true, true);
getEntity().getEntityMeta().setHasNoGravity(false);
Random random = ThreadLocalRandom.current();
getEntity().setVelocity(getPosition()
.direction()
.withX(random.nextDouble(2))
.withY(3)
.withZ(random.nextDouble(2))
.normalize().mul(3));
getEntity().scheduleRemove(Duration.of(15, TimeUnit.SERVER_TICK));
}
}
}