feat: BlackKnife DeltaMine v1.0.0 - Paper 1.21.1 SWOON/Stars/Sword/Diamond/Lunge/Snipe/Tri/Overhead + Magic 4commons Parry chat 400words +12h updates
This commit is contained in:
@@ -0,0 +1,488 @@
|
||||
package me.sashegdev.blackknife;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.BlockDisplay;
|
||||
import org.bukkit.entity.Display;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class LungeAttack {
|
||||
public static boolean tryUse(Player p, TensionManager tension, LivingEntity target) {
|
||||
if (target == null || !target.isValid() || target.isDead()) {
|
||||
p.sendActionBar(Component.text("No target! Look at entity within 120 blocks").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (!canSeeTarget(p, target)) {
|
||||
p.sendActionBar(Component.text("Target blocked by wall!").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (tension.getTP(p) < 225f) {
|
||||
p.sendActionBar(Component.text("Need 90% TP").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
tension.setTP(p, tension.getTP(p) - 225f);
|
||||
tension.startBattle(p, target);
|
||||
Location start = p.getEyeLocation().clone();
|
||||
BlackKnifePlugin plugin = BlackKnifePlugin.getPlugin(BlackKnifePlugin.class);
|
||||
|
||||
BlockDisplay catalyst = p.getWorld().spawn(start, BlockDisplay.class, d -> {
|
||||
d.setBlock(Material.SCULK_CATALYST.createBlockData());
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
});
|
||||
p.getWorld().playSound(start, Sound.BLOCK_SCULK_CATALYST_BLOOM, 1f, 0.7f);
|
||||
double catSpeed = 3.0;
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
if (!target.isValid() || target.isDead()) { if (catalyst.isValid()) catalyst.remove(); cancel(); return; }
|
||||
if (!catalyst.isValid()) { cancel(); return; }
|
||||
Location cur = catalyst.getLocation();
|
||||
Location tpos = target.getLocation().clone().add(0, 1, 0);
|
||||
Vector catDir = tpos.clone().subtract(cur).toVector().normalize();
|
||||
Location nl = cur.clone().add(catDir.clone().multiply(catSpeed));
|
||||
catalyst.teleport(nl);
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl, 2, 0.15, 0.15, 0.15, 0.02);
|
||||
nl.getWorld().spawnParticle(Particle.DUST, nl, 1, 0, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(20, 60, 80), 1f));
|
||||
if (nl.distanceSquared(tpos) < 4) {
|
||||
catalyst.teleport(tpos);
|
||||
catalyst.remove();
|
||||
cancel();
|
||||
tpos.getWorld().spawnParticle(Particle.EXPLOSION, tpos, 1);
|
||||
tpos.getWorld().playSound(tpos, Sound.BLOCK_SCULK_CATALYST_BLOOM, 1f, 0.5f);
|
||||
tpos.getWorld().playSound(tpos, Sound.ENTITY_WARDEN_SONIC_BOOM, 1f, 0.6f);
|
||||
startPhase1(p, tpos, target, plugin);
|
||||
}
|
||||
if (catalyst.getTicksLived() > 80) { catalyst.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean canSeeTarget(Player p, LivingEntity target) {
|
||||
if (!p.hasLineOfSight(target)) return false;
|
||||
var ray = p.getWorld().rayTraceBlocks(p.getEyeLocation(), p.getEyeLocation().getDirection().normalize(), 120);
|
||||
if (ray != null && ray.getHitBlock() != null) {
|
||||
double blockDist = ray.getHitBlock().getLocation().distanceSquared(p.getEyeLocation());
|
||||
double entDist = target.getLocation().add(0, 1, 0).distanceSquared(p.getEyeLocation());
|
||||
if (blockDist + 1 < entDist) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean trySnipe(Player p, TensionManager tension, LivingEntity target) {
|
||||
if (target == null || !target.isValid() || target.isDead()) {
|
||||
p.sendActionBar(Component.text("No target! Look at entity within 120 blocks").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (!canSeeTarget(p, target)) {
|
||||
p.sendActionBar(Component.text("Target blocked by wall!").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (tension.getTP(p) < 62.5f) {
|
||||
p.sendActionBar(Component.text("Need 25% TP").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
tension.setTP(p, tension.getTP(p) - 62.5f);
|
||||
tension.startBattle(p, target);
|
||||
spawnLungeSword(p, target, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean tryTri(Player p, TensionManager tension, LivingEntity target) {
|
||||
if (target == null || !target.isValid() || target.isDead()) {
|
||||
p.sendActionBar(Component.text("No target! Look at entity within 120 blocks").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (!canSeeTarget(p, target)) {
|
||||
p.sendActionBar(Component.text("Target blocked by wall!").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (tension.getTP(p) < 87.5f) {
|
||||
p.sendActionBar(Component.text("Need 35% TP").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
tension.setTP(p, tension.getTP(p) - 87.5f);
|
||||
tension.startBattle(p, target);
|
||||
BlackKnifePlugin plugin = BlackKnifePlugin.getPlugin(BlackKnifePlugin.class);
|
||||
double baseAngle = Math.random() * 360;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int idx = i;
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
if (!target.isValid() || target.isDead()) return;
|
||||
double angle = (baseAngle + idx * 120) % 360 * Math.PI / 180;
|
||||
spawnLungeSwordAt(p, target, angle, 7 + Math.random() * 2, 20);
|
||||
if (idx == 0) p.getWorld().playSound(p.getLocation(), Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1f, 0.6f);
|
||||
}, idx * 12L);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void spawnLungeSword(Player p, LivingEntity target, double damage) {
|
||||
double angle = Math.random() * Math.PI * 2;
|
||||
spawnLungeSwordAt(p, target, angle, 7 + Math.random() * 2, damage);
|
||||
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1f, 0.7f);
|
||||
}
|
||||
|
||||
private static void spawnLungeSwordAt(Player p, LivingEntity target, double angleRad, double r, double damage) {
|
||||
BlackKnifePlugin plugin = BlackKnifePlugin.getPlugin(BlackKnifePlugin.class);
|
||||
Location curTargetPos = target.getLocation().clone().add(0, 1, 0);
|
||||
Vector offset = new Vector(Math.cos(angleRad), 0, Math.sin(angleRad));
|
||||
Location spawn = curTargetPos.clone().add(offset.clone().multiply(r)).add(0, (Math.random() - 0.5) * 2, 0);
|
||||
Vector aim = curTargetPos.clone().subtract(spawn).toVector().normalize().multiply(3.0);
|
||||
BlockDisplay sword = spawn.getWorld().spawn(spawn, BlockDisplay.class, d -> {
|
||||
d.setBlock(Material.DEEPSLATE_TILES.createBlockData());
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
d.setTransformation(new org.bukkit.util.Transformation(
|
||||
new org.joml.Vector3f(-0.75f, -0.4f, -0.75f),
|
||||
new org.joml.AxisAngle4f(),
|
||||
new org.joml.Vector3f(1.5f, 1.5f, 1.5f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
new BukkitRunnable() {
|
||||
long hold = 5;
|
||||
boolean launched = false;
|
||||
@Override public void run() {
|
||||
if (!sword.isValid()) { cancel(); return; }
|
||||
Location cur = sword.getLocation();
|
||||
if (!launched) {
|
||||
cur.getWorld().spawnParticle(Particle.DUST, cur.clone().add(0, 0.5, 0), 3, 0.15, 0.15, 0.15, 0, new Particle.DustOptions(Color.fromRGB(10, 30, 50), 1.5f));
|
||||
cur.getWorld().spawnParticle(Particle.SCULK_SOUL, cur, 1, 0.1, 0.1, 0.1, 0);
|
||||
hold--;
|
||||
if (hold <= 0) launched = true;
|
||||
return;
|
||||
}
|
||||
Location nl = cur.clone().add(aim);
|
||||
int points = Math.max(1, (int) (aim.length() * 3));
|
||||
for (int j = 0; j <= points; j++) {
|
||||
Location pp = cur.clone().add(aim.clone().multiply((double) j / points));
|
||||
pp.getWorld().spawnParticle(Particle.DUST, pp, 1, 0, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(0, 0, 0), 2.0f));
|
||||
pp.getWorld().spawnParticle(Particle.SCULK_SOUL, pp, 1, 0.05, 0.05, 0.05, 0);
|
||||
}
|
||||
int steps = Math.max(1, (int) Math.ceil(aim.length() / 0.5));
|
||||
for (int s = 0; s <= steps; s++) {
|
||||
Location check = cur.clone().add(aim.clone().multiply((double) s / steps));
|
||||
if (check.getBlock().isSolid()) { sword.remove(); cancel(); return; }
|
||||
}
|
||||
sword.teleport(nl);
|
||||
for (LivingEntity le : nl.getWorld().getNearbyLivingEntities(nl, 1.0)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 10, 0.4, 0.4, 0.4, 0.1);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
for (Player pl : nl.getWorld().getNearbyPlayers(nl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
}
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
}
|
||||
|
||||
public static boolean tryOverhead(Player p, TensionManager tension, Location gazePoint) {
|
||||
if (gazePoint == null) {
|
||||
p.sendActionBar(Component.text("Look at ground within 120 blocks!").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
if (tension.getTP(p) < 50f) {
|
||||
p.sendActionBar(Component.text("Need 20% TP").color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
tension.setTP(p, tension.getTP(p) - 50f);
|
||||
BlackKnifePlugin plugin = BlackKnifePlugin.getPlugin(BlackKnifePlugin.class);
|
||||
Location above = gazePoint.clone().add(0, 10, 0);
|
||||
BlockDisplay sword = p.getWorld().spawn(above, BlockDisplay.class, d -> {
|
||||
d.setBlock(Material.DEEPSLATE_TILES.createBlockData());
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
d.setTransformation(new org.bukkit.util.Transformation(
|
||||
new org.joml.Vector3f(-0.75f, -0.4f, -0.75f),
|
||||
new org.joml.AxisAngle4f(),
|
||||
new org.joml.Vector3f(1.5f, 1.5f, 1.5f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
p.getWorld().playSound(gazePoint, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1f, 0.5f);
|
||||
p.getWorld().playSound(gazePoint, Sound.BLOCK_ANVIL_LAND, 0.6f, 1.4f);
|
||||
Vector vel = new Vector(0, -1.8, 0);
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
if (!sword.isValid()) { cancel(); return; }
|
||||
Location cur = sword.getLocation();
|
||||
Location nl = cur.clone().add(vel);
|
||||
sword.teleport(nl);
|
||||
nl.getWorld().spawnParticle(Particle.DUST, nl, 2, 0.15, 0.15, 0.15, 0, new Particle.DustOptions(Color.fromRGB(0, 0, 0), 1.5f));
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl, 1, 0.05, 0.05, 0.05, 0);
|
||||
if (nl.getY() <= gazePoint.getY() + 0.5 || nl.getBlock().isSolid()) {
|
||||
Location expl = gazePoint.clone();
|
||||
sword.remove(); cancel();
|
||||
expl.getWorld().spawnParticle(Particle.EXPLOSION, expl, 1);
|
||||
expl.getWorld().spawnParticle(Particle.SMOKE, expl, 10, 0.3, 0.1, 0.3, 0.02);
|
||||
for (int k = 0; k < 16; k++) {
|
||||
double a = (double) k / 16 * Math.PI * 2;
|
||||
Location r = expl.clone().add(Math.cos(a) * 2, 0.1, Math.sin(a) * 2);
|
||||
r.getWorld().spawnParticle(Particle.ASH, r, 1, 0, 0, 0, 0);
|
||||
r.getWorld().spawnParticle(Particle.SOUL, r, 1, 0.02, 0.02, 0.02, 0);
|
||||
}
|
||||
for (LivingEntity le : expl.getWorld().getNearbyLivingEntities(expl, 2.2)) {
|
||||
if (le == p) continue;
|
||||
double d = le.getLocation().distanceSquared(expl);
|
||||
if (d > 4.84) continue;
|
||||
applyLungeDamage(le, p, 20);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 10, 0.4, 0.4, 0.4, 0.1);
|
||||
}
|
||||
for (Player pl : expl.getWorld().getNearbyPlayers(expl, 2.5)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(expl);
|
||||
if (d2 > 0.25 && d2 < 6.5) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
}
|
||||
expl.getWorld().playSound(expl, Sound.ENTITY_GENERIC_EXPLODE, 0.8f, 1.2f);
|
||||
return;
|
||||
}
|
||||
for (LivingEntity le : nl.getWorld().getNearbyLivingEntities(nl, 1.0)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, 20);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
if (sword.getTicksLived() > 60) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void applyLungeDamage(LivingEntity ent, Player attacker, double amount) {
|
||||
if (ent instanceof Player pl && pl.isBlocking()) amount /= 2.5;
|
||||
ent.getPersistentDataContainer().set(SwoonHandler.MAGIC_DAMAGE, PersistentDataType.BYTE, (byte) 1);
|
||||
ent.damage(amount, attacker);
|
||||
}
|
||||
|
||||
private static void startPhase1(Player p, Location epicenter, LivingEntity target, BlackKnifePlugin plugin) {
|
||||
epicenter = epicenter.clone();
|
||||
Location ground = epicenter.clone();
|
||||
ground.setY(epicenter.getWorld().getHighestBlockYAt(epicenter) + 1);
|
||||
if (ground.getY() > epicenter.getY() + 0.5) ground = epicenter.clone();
|
||||
Location finalEpicenter = ground.clone();
|
||||
new BukkitRunnable() {
|
||||
int wave = 0;
|
||||
@Override public void run() {
|
||||
if (wave >= 5) { cancel(); startPhase2(p, finalEpicenter, target, plugin); return; }
|
||||
spawnShockwave(p, finalEpicenter.clone(), 20, plugin);
|
||||
wave++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 10L);
|
||||
}
|
||||
|
||||
private static void spawnShockwave(Player p, Location center, double damage, BlackKnifePlugin plugin) {
|
||||
center.getWorld().playSound(center, Sound.BLOCK_SCULK_SHRIEKER_SHRIEK, 1f, 0.6f);
|
||||
double maxRadius = 40;
|
||||
double expandSpeed = 2.0;
|
||||
new BukkitRunnable() {
|
||||
double radius = 1;
|
||||
@Override public void run() {
|
||||
if (radius > maxRadius) { cancel(); return; }
|
||||
int points = (int) (radius * 6);
|
||||
for (int i = 0; i < points; i++) {
|
||||
double angle = (double) i / points * Math.PI * 2;
|
||||
double x = Math.cos(angle) * radius;
|
||||
double z = Math.sin(angle) * radius;
|
||||
Location ring = center.clone().add(x, 0.3, z);
|
||||
ring.getWorld().spawnParticle(Particle.ASH, ring, 1, 0, 0, 0, 0);
|
||||
ring.getWorld().spawnParticle(Particle.SOUL, ring, 1, 0.05, 0.05, 0.05, 0);
|
||||
ring.getWorld().spawnParticle(Particle.SCULK_SOUL, ring, 1, 0.05, 0.05, 0.05, 0);
|
||||
}
|
||||
if (radius > 3 && radius < maxRadius - 1) {
|
||||
double thinRadius = radius;
|
||||
for (LivingEntity le : center.getWorld().getNearbyLivingEntities(center, maxRadius + 2)) {
|
||||
if (le == p) continue;
|
||||
if (le.getLocation().getY() > center.getY() + 2.5) continue;
|
||||
double dist = Math.sqrt(Math.pow(le.getLocation().getX() - center.getX(), 2) + Math.pow(le.getLocation().getZ() - center.getZ(), 2));
|
||||
if (Math.abs(dist - thinRadius) < 1.2) {
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 8, 0.3, 0.3, 0.3, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
radius += expandSpeed;
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
}
|
||||
|
||||
private static void startPhase2(Player p, Location epicenter, LivingEntity target, BlackKnifePlugin plugin) {
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
new BukkitRunnable() {
|
||||
int idx = 0;
|
||||
@Override public void run() {
|
||||
if (idx >= 8) { cancel(); return; }
|
||||
Location above = epicenter.clone().add((Math.random() - 0.5) * 10, 10 + Math.random() * 3, (Math.random() - 0.5) * 10);
|
||||
spawnFallingSword(p, above, epicenter, 10, 0.7, plugin);
|
||||
idx++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 3L);
|
||||
spawnShockwave(p, epicenter.clone(), 20, plugin);
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> spawnShockwave(p, epicenter.clone(), 20, plugin), 12L);
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> spawnShockwave(p, epicenter.clone(), 20, plugin), 24L);
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> startPhase3(p, epicenter, target, plugin), 36L);
|
||||
}, 10L);
|
||||
}
|
||||
|
||||
private static void spawnFallingSword(Player p, Location spawn, Location target, double damage, double fallSpeed, BlackKnifePlugin plugin) {
|
||||
BlockDisplay sword = p.getWorld().spawn(spawn, BlockDisplay.class, d -> {
|
||||
d.setBlock(Material.DEEPSLATE_TILES.createBlockData());
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
d.setTransformation(new org.bukkit.util.Transformation(
|
||||
new org.joml.Vector3f(-0.35f, -0.18f, -0.35f),
|
||||
new org.joml.AxisAngle4f(),
|
||||
new org.joml.Vector3f(0.7f, 0.7f, 0.7f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
Vector vel = new Vector(0, -fallSpeed, 0);
|
||||
p.getWorld().playSound(spawn, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.6f, 0.7f);
|
||||
new BukkitRunnable() {
|
||||
@Override public void run() {
|
||||
if (!sword.isValid()) { cancel(); return; }
|
||||
Location cur = sword.getLocation();
|
||||
Location nl = cur.clone().add(vel);
|
||||
sword.teleport(nl);
|
||||
nl.getWorld().spawnParticle(Particle.DUST, nl, 1, 0, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(0, 0, 0), 1.0f));
|
||||
nl.getWorld().spawnParticle(Particle.SCULK_SOUL, nl, 1, 0.05, 0.05, 0.05, 0);
|
||||
if (nl.getY() <= target.getY() + 0.5 || nl.getBlock().isSolid()) {
|
||||
Location expl = nl.clone();
|
||||
sword.remove();
|
||||
cancel();
|
||||
expl.getWorld().spawnParticle(Particle.SMOKE, expl, 6, 0.2, 0.1, 0.2, 0.02);
|
||||
expl.getWorld().spawnParticle(Particle.SCULK_SOUL, expl, 4, 0.2, 0.1, 0.2, 0.02);
|
||||
for (int k = 0; k < 12; k++) {
|
||||
double a = (double) k / 12 * Math.PI * 2;
|
||||
Location r = expl.clone().add(Math.cos(a) * 1.5, 0.1, Math.sin(a) * 1.5);
|
||||
r.getWorld().spawnParticle(Particle.ASH, r, 1, 0, 0, 0, 0);
|
||||
r.getWorld().spawnParticle(Particle.SOUL, r, 1, 0.02, 0.02, 0.02, 0);
|
||||
}
|
||||
for (LivingEntity le : expl.getWorld().getNearbyLivingEntities(expl, 1.5)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 6, 0.3, 0.3, 0.3, 0.1);
|
||||
}
|
||||
for (Player pl : expl.getWorld().getNearbyPlayers(expl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(expl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (LivingEntity le : nl.getWorld().getNearbyLivingEntities(nl, 0.7)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, damage);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 8, 0.3, 0.3, 0.3, 0.1);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
}
|
||||
|
||||
private static void startPhase3(Player p, Location epicenter, LivingEntity target, BlackKnifePlugin plugin) {
|
||||
new BukkitRunnable() {
|
||||
int idx = 0;
|
||||
@Override public void run() {
|
||||
if (idx >= 20) { cancel(); startPhase4(p, target, plugin); return; }
|
||||
Location above = epicenter.clone().add((Math.random() - 0.5) * 12, 10 + Math.random() * 4, (Math.random() - 0.5) * 12);
|
||||
spawnFallingSword(p, above, epicenter, 10, 0.7, plugin);
|
||||
idx++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 2L, 4L);
|
||||
}
|
||||
|
||||
private static void startPhase4(Player p, LivingEntity target, BlackKnifePlugin plugin) {
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
new BukkitRunnable() {
|
||||
int swordIdx = 0;
|
||||
long nextDelay = 30;
|
||||
long delayCounter = 0;
|
||||
@Override public void run() {
|
||||
if (swordIdx >= 30 || !target.isValid() || target.isDead()) { cancel(); return; }
|
||||
if (delayCounter < nextDelay) { delayCounter++; return; }
|
||||
delayCounter = 0;
|
||||
double frac = (double) swordIdx / 29;
|
||||
long holdTicks = Math.round(15 - frac * 10);
|
||||
long gapTicks = Math.round(20 - frac * 5);
|
||||
nextDelay = gapTicks;
|
||||
|
||||
double angle = (swordIdx * 137.5) % 360 * Math.PI / 180;
|
||||
double r = 7 + Math.random() * 3;
|
||||
Vector offset = new Vector(Math.cos(angle), 0, Math.sin(angle));
|
||||
Location curTargetPos = target.getLocation().clone().add(0, 1, 0);
|
||||
Location spawn = curTargetPos.clone().add(offset.clone().multiply(r)).add(0, (Math.random() - 0.5) * 2, 0);
|
||||
Vector aim = curTargetPos.clone().subtract(spawn).toVector().normalize().multiply(3.0);
|
||||
|
||||
BlockDisplay sword = spawn.getWorld().spawn(spawn, BlockDisplay.class, d -> {
|
||||
d.setBlock(Material.DEEPSLATE_TILES.createBlockData());
|
||||
d.setBrightness(new Display.Brightness(15, 15));
|
||||
d.setViewRange(64);
|
||||
d.setTransformation(new org.bukkit.util.Transformation(
|
||||
new org.joml.Vector3f(-0.75f, -0.4f, -0.75f),
|
||||
new org.joml.AxisAngle4f(),
|
||||
new org.joml.Vector3f(1.5f, 1.5f, 1.5f),
|
||||
new org.joml.AxisAngle4f()));
|
||||
});
|
||||
spawn.getWorld().playSound(spawn, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 0.8f, 0.5f);
|
||||
|
||||
new BukkitRunnable() {
|
||||
long hold = holdTicks;
|
||||
boolean launched = false;
|
||||
@Override public void run() {
|
||||
if (!sword.isValid()) { cancel(); return; }
|
||||
Location cur = sword.getLocation();
|
||||
if (!launched) {
|
||||
cur.getWorld().spawnParticle(Particle.DUST, cur.clone().add(0, 0.5, 0), 3, 0.15, 0.15, 0.15, 0, new Particle.DustOptions(Color.fromRGB(10, 30, 50), 1.5f));
|
||||
cur.getWorld().spawnParticle(Particle.SCULK_SOUL, cur, 1, 0.1, 0.1, 0.1, 0);
|
||||
hold--;
|
||||
if (hold <= 0) launched = true;
|
||||
return;
|
||||
}
|
||||
Location nl = cur.clone().add(aim);
|
||||
int points = Math.max(1, (int) (aim.length() * 3));
|
||||
Vector step = aim.clone();
|
||||
for (int j = 0; j <= points; j++) {
|
||||
Location pp = cur.clone().add(step.clone().multiply((double) j / points));
|
||||
pp.getWorld().spawnParticle(Particle.DUST, pp, 1, 0, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(0, 0, 0), 2.0f));
|
||||
pp.getWorld().spawnParticle(Particle.SCULK_SOUL, pp, 1, 0.05, 0.05, 0.05, 0);
|
||||
}
|
||||
int steps = Math.max(1, (int) Math.ceil(aim.length() / 0.5));
|
||||
for (int s = 0; s <= steps; s++) {
|
||||
Location check = cur.clone().add(aim.clone().multiply((double) s / steps));
|
||||
if (check.getBlock().isSolid()) { sword.remove(); cancel(); return; }
|
||||
}
|
||||
sword.teleport(nl);
|
||||
for (LivingEntity le : nl.getWorld().getNearbyLivingEntities(nl, 1.0)) {
|
||||
if (le == p) continue;
|
||||
applyLungeDamage(le, p, 20);
|
||||
le.getWorld().spawnParticle(Particle.CRIT, le.getLocation().add(0, 1, 0), 10, 0.4, 0.4, 0.4, 0.1);
|
||||
sword.remove(); cancel(); return;
|
||||
}
|
||||
for (Player pl : nl.getWorld().getNearbyPlayers(nl, 0.9)) {
|
||||
if (pl == p) continue;
|
||||
double d2 = pl.getLocation().add(0, 1, 0).distanceSquared(nl);
|
||||
if (d2 > 0.25 && d2 < 0.81) plugin.getTension().addTP(pl, 2.5f, "DODGE +1%");
|
||||
}
|
||||
if (sword.getTicksLived() > 80) { sword.remove(); cancel(); }
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
|
||||
swordIdx++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 1L);
|
||||
}, 10L);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user