-
Notifications
You must be signed in to change notification settings - Fork 755
/
SweepWeaponAttack.java
65 lines (58 loc) · 3.46 KB
/
SweepWeaponAttack.java
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
package slimeknights.tconstruct.library.tools.definition.module.weapon;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.player.Player;
import slimeknights.mantle.data.loadable.primitive.FloatLoadable;
import slimeknights.mantle.data.loadable.record.RecordLoadable;
import slimeknights.tconstruct.library.module.ModuleHook;
import slimeknights.tconstruct.library.module.HookProvider;
import slimeknights.tconstruct.library.tools.context.ToolAttackContext;
import slimeknights.tconstruct.library.tools.definition.module.ToolHooks;
import slimeknights.tconstruct.library.tools.definition.module.ToolModule;
import slimeknights.tconstruct.library.tools.helper.ToolAttackUtil;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.tools.TinkerModifiers;
import java.util.List;
/** Attack logic for a sweep attack, similar to a sword */
public record SweepWeaponAttack(float range) implements MeleeHitToolHook, ToolModule {
public static final RecordLoadable<SweepWeaponAttack> LOADER = RecordLoadable.create(FloatLoadable.FROM_ZERO.defaultField("range", 0f, true, SweepWeaponAttack::range), SweepWeaponAttack::new);
private static final List<ModuleHook<?>> DEFAULT_HOOKS = HookProvider.<SweepWeaponAttack>defaultHooks(ToolHooks.MELEE_HIT);
@Override
public List<ModuleHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}
@Override
public RecordLoadable<SweepWeaponAttack> getLoader() {
return LOADER;
}
@Override
public void afterMeleeHit(IToolStackView tool, ToolAttackContext context, float damage) {
// sweep code from Player#attack(Entity)
// basically: no crit, no sprinting and has to stand on the ground for sweep. Also has to move regularly slowly
LivingEntity attacker = context.getAttacker();
if (context.isFullyCharged() && !attacker.isSprinting() && !context.isCritical() && attacker.isOnGround() && (attacker.walkDist - attacker.walkDistO) < attacker.getSpeed()) {
// loop through all nearby entities
double range = this.range + tool.getModifierLevel(TinkerModifiers.expanded.getId());
double rangeSq = (2 + range); // TODO: why do we add 2 here? should that not be defined in the datagen?
rangeSq *= rangeSq;
// if the modifier is missing, sweeping damage will be 0, so easiest to let it fully control this
float sweepDamage = TinkerModifiers.sweeping.get().getSweepingDamage(tool, damage);
Entity target = context.getTarget();
for (LivingEntity aoeTarget : attacker.level.getEntitiesOfClass(LivingEntity.class, target.getBoundingBox().inflate(range, 0.25D, range))) {
if (aoeTarget != attacker && aoeTarget != target && !attacker.isAlliedTo(aoeTarget)
&& !(aoeTarget instanceof ArmorStand armorStand && armorStand.isMarker()) && attacker.distanceToSqr(aoeTarget) < rangeSq) {
float angle = attacker.getYRot() * ((float) Math.PI / 180F);
aoeTarget.knockback(0.4F, Mth.sin(angle), -Mth.cos(angle));
ToolAttackUtil.dealDefaultDamage(attacker, aoeTarget, sweepDamage);
}
}
attacker.level.playSound(null, attacker.getX(), attacker.getY(), attacker.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, attacker.getSoundSource(), 1.0F, 1.0F);
if (attacker instanceof Player player) {
player.sweepAttack();
}
}
}
}