From c9e1e4e7c106cfbdbf39236304d56b3d4d9c55b9 Mon Sep 17 00:00:00 2001 From: wolf Date: Thu, 15 May 2025 15:21:35 -0500 Subject: [PATCH] Fixed stuff that madness needed --- .../server/commands/AdminCommand.java | 6 +- .../systems/abilities/trims/BoltAbility.java | 32 +++- .../systems/abilities/trims/DuneAbility.java | 2 + .../systems/abilities/trims/EyeAbility.java | 32 ++-- .../systems/abilities/trims/HostAbility.java | 20 +-- .../abilities/trims/SentryAbility.java | 16 +- .../abilities/trims/ShaperAbility.java | 68 ++++---- .../abilities/trims/SilenceAbility.java | 4 +- .../systems/abilities/trims/WardAbility.java | 32 ++-- .../trouper/trimserver/utils/PlayerUtils.java | 3 +- .../utils/visual/CustomDisplayRaytracer.java | 163 ++++++++++++++++-- .../trimserver/utils/visual/Point.java | 42 ----- 12 files changed, 275 insertions(+), 145 deletions(-) diff --git a/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java b/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java index fef2f88..535b18e 100644 --- a/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java +++ b/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java @@ -89,10 +89,10 @@ public class AdminCommand implements QuickCommand { switch (args.get(1).toString()) { case "vector" -> { if (!(commandSender instanceof Player p)) return; - CustomDisplayRaytracer.traceWithReflection(p.getEyeLocation(),p.getEyeLocation().getDirection(),60,0.1,6,point -> { + CustomDisplayRaytracer.traceWithReflection(p.getEyeLocation(),p.getEyeLocation().getDirection(),60,0.5,60,point -> { DisplayUtils.DUST_PARTICLE_FACTORY.apply(Color.AQUA,1F).accept(point.getLoc()); - return CustomDisplayRaytracer.hitBlockIf(block -> !block.isPassable()).test(point); + return false; },(point,block) -> { DisplayUtils.sphere(point.getLoc(),0.3,0.1,0.1,loc -> { DisplayUtils.DUST_PARTICLE_FACTORY.apply(Color.RED,1F).accept(loc); @@ -100,7 +100,7 @@ public class AdminCommand implements QuickCommand { return true; },(point,entity) -> { - return false; + return !p.equals(entity); }); } } diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/BoltAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/BoltAbility.java index 838daa2..db2995b 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/BoltAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/BoltAbility.java @@ -6,19 +6,19 @@ import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; +import me.trouper.trimserver.utils.Text; import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; import org.bukkit.entity.Player; import org.bukkit.inventory.meta.trim.TrimPattern; +import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; @PatternInfo(name = "Bolt", description = "Summon a bolt of lightning at enemies. Includes Variants.") public class BoltAbility extends AbstractAbility implements Main { @@ -31,6 +31,25 @@ public class BoltAbility extends AbstractAbility implements Main { return TargetingUtils.areaAffect(caster.getLocation(),range,target-> !main.man().trustBackend.trusts(caster,target),(target)->{ drawLightning(caster.getEyeLocation(),target.getEyeLocation(),innerBlock,outerBlock); target.damage(damage,DamageSource.builder(DamageType.LIGHTNING_BOLT).withDamageLocation(caster.getEyeLocation()).withDirectEntity(caster).build()); + if (target instanceof Player t) Text.sendMessage(Text.Pallet.INFO,t,"You have been stunned by {0}'s Bolt!",caster.name()); + + AtomicInteger counter = new AtomicInteger(0); + Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(task) -> { + if (counter.getAndIncrement() > 40) { + task.cancel(); + return; + } + int tick = target.getNoDamageTicks(); + int maxTick = target.getMaximumNoDamageTicks(); + + target.setNoDamageTicks(1); + target.setMaximumNoDamageTicks(2); + target.damage(0.01,DamageSource.builder(DamageType.LIGHTNING_BOLT).withDamageLocation(caster.getLocation()).withDirectEntity(caster).build()); + target.setNoDamageTicks(tick); + target.setMaximumNoDamageTicks(maxTick); + Location stunLoc = target.getLocation().clone(); + target.teleport(stunLoc); + },0,1); }); } @@ -48,7 +67,9 @@ public class BoltAbility extends AbstractAbility implements Main { direction.normalize().multiply(segmentLength); SoundPlayer bolt = new SoundPlayer(end, Sound.ENTITY_LIGHTNING_BOLT_THUNDER,10,1); SoundPlayer ring = new SoundPlayer(end, Sound.ITEM_TRIDENT_THUNDER,10,1); + SoundPlayer zip = new SoundPlayer(end, Sound.ENTITY_BEE_STING,10,1); + zip.playWithin(30 ); bolt.playWithin(50); ring.playWithin(30); @@ -59,8 +80,7 @@ public class BoltAbility extends AbstractAbility implements Main { (random.nextDouble() - 0.5) * maxOffset ); Location next = current.clone().add(direction).add(offset); - SoundPlayer zip = new SoundPlayer(next, Sound.ENTITY_BEE_STING,10,1); - zip.playWithin(10); + BlockDisplayRaytracer.trace(blockInner, current, next, thickness, stayTime, viewers); BlockDisplayRaytracer.trace(blockOuter, current, next, thicknessOut, stayTime, viewers); next.getWorld().spawnParticle(Particle.FLASH,next,0,0,0,0,0); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/DuneAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/DuneAbility.java index b24e72f..366f3c9 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/DuneAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/DuneAbility.java @@ -6,6 +6,7 @@ import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; import me.trouper.trimserver.server.systems.abilities.WormEvent; import me.trouper.trimserver.utils.TargetingUtils; +import me.trouper.trimserver.utils.Text; import me.trouper.trimserver.utils.visual.DisplayUtils; import org.bukkit.*; import org.bukkit.block.Block; @@ -116,6 +117,7 @@ public class DuneAbility extends AbstractAbility { if (e.getPlayer().getScoreboardTags().contains("$/TrimServer/ NoJumping")) { e.setCancelled(true); e.getPlayer().getVelocity().add(new Vector(0,-10,0)); + Text.sendMessage(Text.Pallet.INFO,e.getPlayer(),"You are stuck in unstable earth!"); } } diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/EyeAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/EyeAbility.java index 3f1756d..3b8cd08 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/EyeAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/EyeAbility.java @@ -10,12 +10,15 @@ import me.trouper.trimserver.utils.visual.CustomDisplayRaytracer; import org.bukkit.*; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @PatternInfo(name = "Eye of Power", description = "Allows you to see players hidden with the host trim. Includes variants.") @@ -32,26 +35,30 @@ public class EyeAbility extends AbstractAbility { task.cancel(); return; } - Location chestLocation = player.getLocation(); - chestLocation.setY(chestLocation.getY() + (player.getHeight() / 2) + 0.1); - double radians = Math.toRadians(player.getBodyYaw()); + Location headLocation = player.getEyeLocation().clone(); + Vector eyeCenter = headLocation.getDirection(); + Vector leftRight = new Vector(-eyeCenter.getZ(), eyeCenter.getY(), eyeCenter.getX()).normalize().multiply(0.2); + + // Two eye locations + Location leftEye = headLocation.clone().add(leftRight); + Location rightEye = headLocation.clone().subtract(leftRight); - double x = -Math.sin(radians); - double z = Math.cos(radians); + Location focus = laser(player,headLocation,eyeCenter,60); - Vector chestDirection = new Vector(x,0,z).normalize(); + BlockDisplayRaytracer.trace(beam,leftEye,focus,0.05,2); + BlockDisplayRaytracer.trace(glow,leftEye,focus,0.1,2); - Location focus = laser(player,chestLocation,chestDirection,60); - BlockDisplayRaytracer.trace(beam,chestLocation,focus,0.2,2); - BlockDisplayRaytracer.trace(glow,chestLocation,focus,0.4,2); + BlockDisplayRaytracer.trace(beam,rightEye,focus,0.05,2); + BlockDisplayRaytracer.trace(glow,rightEye,focus,0.1,2); },0,1); } public Location laser(Player owner, Location start, Vector direction, double distance) { return CustomDisplayRaytracer.trace(start,direction,distance,1,point ->{ SoundPlayer hissSound = new SoundPlayer(point.getLoc(), Sound.BLOCK_LAVA_EXTINGUISH, 1, 1); - - return TargetingUtils.areaAffect(point.getLoc(),1,target -> !target.isDead() && !main.man().trustBackend.trusts(owner,target), liv->{ + List targets = point.getNearbyEntities(owner,5,true,0.5, target -> target instanceof LivingEntity && !target.isDead() && !main.man().trustBackend.trusts(owner, (LivingEntity) target)); + targets.forEach(entity -> { + if (!(entity instanceof LivingEntity liv)) return; hissSound.playWithin(10); int tick = liv.getNoDamageTicks(); @@ -65,7 +72,8 @@ public class EyeAbility extends AbstractAbility { liv.setFireTicks(20); liv.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,20,1,true,false,false)); liv.getWorld().spawnParticle(Particle.LAVA, point.getLoc(), 1, 0.5, 0.5, 0.5, 0); - }) || !point.getBlock().isPassable(); + }); + return !point.getBlock().isPassable() || !targets.isEmpty(); }).getLoc(); } diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/HostAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/HostAbility.java index 72da2b4..432c7ac 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/HostAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/HostAbility.java @@ -49,7 +49,7 @@ public class HostAbility extends AbstractAbility { } } - @MaterialInfo(name = "Amethyst ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Amethyst ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean amethystAbility(Player player) { makeInvisible(player,20); @@ -57,7 +57,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Copper ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Copper ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean copperAbility(Player player) { makeInvisible(player,20); @@ -65,7 +65,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Diamond ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Diamond ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean diamondAbility(Player player) { makeInvisible(player,20); @@ -73,7 +73,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Emerald ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Emerald ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean emeraldAbility(Player player) { makeInvisible(player,20); @@ -81,7 +81,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Gold ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Gold ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean goldAbility(Player player) { makeInvisible(player,20); @@ -89,7 +89,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Iron ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Iron ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean ironAbility(Player player) { makeInvisible(player,20); @@ -97,7 +97,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Lapis ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Lapis ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean lapisAbility(Player player) { makeInvisible(player,20); @@ -113,7 +113,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Quartz ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Quartz ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean quartzAbility(Player player) { makeInvisible(player,20); @@ -121,7 +121,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Redstone ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Redstone ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean redstoneAbility(Player player) { makeInvisible(player,20); @@ -129,7 +129,7 @@ public class HostAbility extends AbstractAbility { return true; } - @MaterialInfo(name = "Resin ", description = "Grants true invisibility for 20 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) + @MaterialInfo(name = "Resin ", description = "Grants true invisibility for 6 seconds but makes your attacks weaker", cooldownTicks = 20 * 30) @Override public boolean resinAbility(Player player) { makeInvisible(player,20); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SentryAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SentryAbility.java index 21aa65f..7ee797e 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SentryAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SentryAbility.java @@ -54,12 +54,14 @@ public class SentryAbility extends AbstractAbility { turretParts.add(turret); - Bat dummy = w.spawn(turret.getLocation(),Bat.class,bat->{ - bat.setInvisible(true); - bat.setInvulnerable(true); - bat.customName(Text.color("%s's Sentry\n".formatted(owner.getName()))); - bat.setAI(false); - bat.addScoreboardTag("$/TrimServer/ Temp"); + Slime dummy = w.spawn(turret.getLocation(),Slime.class,slime->{ + slime.setInvisible(true); + slime.setSize(2); + slime.setHealth(10); + // TODO: Make this not a slime. + slime.customName(Text.color("%s's Sentry\n".formatted(owner.getName()))); + slime.setAI(false); + slime.addScoreboardTag("$/TrimServer/ Temp"); }); turretParts.add(dummy); @@ -103,7 +105,7 @@ public class SentryAbility extends AbstractAbility { @Override public void run() { - if (chamber <= 0 || turret.isDead() || meter.isDead()) { + if (chamber <= 0 || turret.isDead() || meter.isDead() || dummy.isDead()) { cancel(); return; } diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/ShaperAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/ShaperAbility.java index cd1d5af..769b83e 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/ShaperAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/ShaperAbility.java @@ -10,12 +10,10 @@ import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.Display; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.meta.trim.TrimPattern; @@ -40,9 +38,8 @@ public class ShaperAbility extends AbstractAbility implements Listener { private final Map originalFireTicks = new ConcurrentHashMap<>(); private static final int BASE_DURATION_TICKS = 8 * 20; - private static final double BASE_SHATTER_DAMAGE = 6.0; - private static final double BASE_SHATTER_RADIUS = 4.0; - private static final int RESISTANCE_AMPLIFIER = 2; + private static final double BASE_SHATTER_DAMAGE = 10.0; + private static final double BASE_SHATTER_RADIUS = 8.0; private static final int SLOWNESS_AMPLIFIER = 1; // Cooldowns @@ -53,7 +50,6 @@ public class ShaperAbility extends AbstractAbility implements Listener { // Netherite Modifiers private static final double NETHERITE_DURATION_MULTIPLIER = 1.3; private static final double NETHERITE_SHATTER_DAMAGE_MULTIPLIER = 1.5; - private static final int NETHERITE_RESISTANCE_AMPLIFIER_BONUS = 1; // Total Resistance IV private static final double NETHERITE_SHATTER_RADIUS_MULTIPLIER = 1.2; public ShaperAbility() { @@ -79,7 +75,7 @@ public class ShaperAbility extends AbstractAbility implements Listener { for (int i = 0; i < numShellParts; i++) { double angle = ((double) i / numShellParts) * 2 * Math.PI; - double yInitialOffset = (Math.random() * 0.8) + 0.5; // Start around player's mid-section + double yInitialOffset = (Math.random() * 0.8) + 0.5; Vector offset = new Vector(Math.cos(angle) * orbitRadius, yInitialOffset, Math.sin(angle) * orbitRadius); Location partLoc = player.getLocation().add(offset); @@ -91,8 +87,8 @@ public class ShaperAbility extends AbstractAbility implements Listener { new Vector3f(shellPartScale, shellPartScale, shellPartScale), new Quaternionf() )); - display.setInterpolationDelay(-1); // Start interpolating immediately - display.setInterpolationDuration(2); // Smooth movement over 2 ticks + display.setInterpolationDelay(-1); + display.setInterpolationDuration(2); display.setTeleportDuration(2); display.setBrightness(new Display.Brightness(world.getBlockAt(partLoc).getLightFromSky(), world.getBlockAt(partLoc).getLightFromBlocks())); display.setGravity(false); @@ -104,23 +100,17 @@ public class ShaperAbility extends AbstractAbility implements Listener { int duration = BASE_DURATION_TICKS; double shatterDamage = BASE_SHATTER_DAMAGE; double shatterRadius = BASE_SHATTER_RADIUS; - int resistanceAmplifier = RESISTANCE_AMPLIFIER; int slownessAmplifier = SLOWNESS_AMPLIFIER; if (blockMaterialForShell == Material.NETHERITE_BLOCK) { duration = (int) (duration * NETHERITE_DURATION_MULTIPLIER); shatterDamage *= NETHERITE_SHATTER_DAMAGE_MULTIPLIER; shatterRadius *= NETHERITE_SHATTER_RADIUS_MULTIPLIER; - resistanceAmplifier += NETHERITE_RESISTANCE_AMPLIFIER_BONUS; } else if (blockMaterialForShell == Material.RESIN_BLOCK) { slownessAmplifier = 0; - if (slownessAmplifier < 0) slownessAmplifier = -1; } - player.addPotionEffect(new PotionEffect(PotionEffectType.RESISTANCE, duration, resistanceAmplifier, false, true, true)); - if (slownessAmplifier >=0) { - player.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, duration, slownessAmplifier, false, false, true)); - } + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, duration, slownessAmplifier, false, false, true)); originalFireTicks.put(playerUUID, player.getFireTicks()); if (player.getFireTicks() > 0) player.setFireTicks(0); @@ -227,22 +217,34 @@ public class ShaperAbility extends AbstractAbility implements Listener { } @EventHandler - public void onPlayerDamageInShell(EntityDamageEvent event) { - if (event.getEntity() instanceof Player player) { - UUID playerUUID = player.getUniqueId(); - if (activeShellTasks.containsKey(playerUUID)) { - new SoundPlayer(player.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 0.7f + (float)Math.random()*0.5f).playWithin(5); - if (player.getFireTicks() > 0 && ( - event.getCause() == EntityDamageEvent.DamageCause.FIRE || - event.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK || - event.getCause() == EntityDamageEvent.DamageCause.LAVA) - ) { - player.setFireTicks(0); - event.setCancelled(true); - new SoundPlayer(player.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 1.0f, 1.0f).playWithin(5); - } - } + public void onPlayerDamage(EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + UUID playerUUID = player.getUniqueId(); + if (!activeShellTasks.containsKey(playerUUID)) return; + + new SoundPlayer(player.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 0.7f + (float)Math.random()*0.5f).playWithin(5); + if (player.getFireTicks() > 0 && ( + event.getCause() == EntityDamageEvent.DamageCause.FIRE || + event.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK || + event.getCause() == EntityDamageEvent.DamageCause.LAVA + )) { + player.setFireTicks(0); + new SoundPlayer(player.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 1.0f, 1.0f).playWithin(5); } + event.setCancelled(true); + } + + @EventHandler + public void onEntityDamagePlayer(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + if (!(event.getDamager() instanceof LivingEntity a)) return; + + UUID playerUUID = player.getUniqueId(); + if (!activeShellTasks.containsKey(playerUUID)) return; + + new SoundPlayer(player.getLocation(), Sound.ITEM_TRIDENT_RETURN, 1.0f, 2f + (float)Math.random()*0.5f).playWithin(5); + event.setCancelled(true); + a.damage(event.getDamage()); } @MaterialInfo(name = "Amethyst Terra Shell", description = "Protective Amethyst shell, shatters on expiry.", cooldownTicks = DEFAULT_COOLDOWN) diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SilenceAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SilenceAbility.java index 9c8a3bc..410cd36 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SilenceAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SilenceAbility.java @@ -29,7 +29,7 @@ public class SilenceAbility extends AbstractAbility { public SilenceAbility() { super(TrimPattern.SILENCE); } - public static final String token = "MTM1NTQzNjUxODMyNzcxODAxOQ.GIcTck.Ervj3lOfh8xii6SsYjOqLYrcMtoPrpXLLbYpu8 "; + public void shootSonicBoom(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; @@ -51,7 +51,7 @@ public class SilenceAbility extends AbstractAbility { CustomDisplayRaytracer.traceWithReflection(chestLocation,direction,30,0.5,4,point->{ point.getWorld().spawnParticle(Particle.SONIC_BOOM, point.getLoc(), 1, 0, 0, 0, 0); - Optional target = TargetingUtils.getClosestPlayer(point.getLoc(),1,entity -> !entity.equals(player) && !entity.isDead() && !main.man().trustBackend.trusts(player,entity) && !shaper.activeShellTasks.containsKey(entity.getUniqueId())); + Optional target = TargetingUtils.getClosestLivingEntity(point.getLoc(),1,entity -> !entity.equals(player) && !entity.isDead() && !main.man().trustBackend.trusts(player,entity) && !shaper.activeShellTasks.containsKey(entity.getUniqueId())); target.ifPresent(value -> PlayerUtils.dealTrueDamage(value, DamageSource.builder(DamageType.SONIC_BOOM).withDirectEntity(player).build(), 10)); Verbose.send("Traced warden beam:"); return target.isPresent(); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WardAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WardAbility.java index b265200..8f0b736 100644 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WardAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WardAbility.java @@ -92,6 +92,8 @@ public class WardAbility extends AbstractAbility { if (stepsTaken.getAndIncrement() >= 20*4) { player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,20 * 30, 0, true,false,false)); player.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION,20 * 30, 9,true,false,false)); + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED,20 * 30, 2,true,false,false)); + player.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,20 * 30, 3,true,false,false)); activeDisguises.put(player.getUniqueId(), new DisguiseData(warden, expiration)); task.cancel(); return; @@ -132,21 +134,21 @@ public class WardAbility extends AbstractAbility { private void updateDisguisePosition(Player player) { DisguiseData data = activeDisguises.get(player.getUniqueId()); - if (data != null) { - data.disguise.teleport(player.getLocation()); - Verbose.send( "Teleported disguise %s to %s for player %s", - data.disguise.getUniqueId(), - player.getLocation().toVector(), - player.getName()); - } + if (data == null) return; + + data.disguise.teleport(player.getLocation()); + Verbose.send( "Teleported disguise %s to %s for player %s", + data.disguise.getUniqueId(), + player.getLocation().toVector(), + player.getName()); } private Player getPlayerByDisguise(Entity disguise) { for (Map.Entry e : activeDisguises.entrySet()) { - if (e.getValue().disguise.equals(disguise)) { - Verbose.send( "Mapped disguise %s → player %s", disguise.getUniqueId(), e.getKey()); - return Bukkit.getPlayer(e.getKey()); - } + if (!e.getValue().disguise.equals(disguise)) continue; + + Verbose.send( "Mapped disguise %s → player %s", disguise.getUniqueId(), e.getKey()); + return Bukkit.getPlayer(e.getKey()); } return null; } @@ -175,10 +177,10 @@ public class WardAbility extends AbstractAbility { @EventHandler public void onPlayerQuit(PlayerQuitEvent e) { Verbose.send( "onPlayerQuit: %s", e.getPlayer().getName()); - if (activeDisguises.containsKey(e.getPlayer().getUniqueId())) { - Verbose.send( "Player %s quit while disguised; removing disguise", e.getPlayer().getName()); - removeDisguise(e.getPlayer()); - } + if (!activeDisguises.containsKey(e.getPlayer().getUniqueId())) return; + + Verbose.send( "Player %s quit while disguised; removing disguise", e.getPlayer().getName()); + removeDisguise(e.getPlayer()); } @EventHandler diff --git a/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java b/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java index 5aa738a..b9a523b 100644 --- a/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java +++ b/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java @@ -79,10 +79,9 @@ public class PlayerUtils implements Main { .orElse(null); } - @SuppressWarnings("deprecation") public static void dealTrueDamage(LivingEntity target, DamageSource source, double amount) { double newHealth = target.getHealth() - amount; - target.damage(0.1, source); + target.damage(1, source); if (newHealth <= 0) { target.setHealth(0); } else { diff --git a/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java b/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java index 1b638a6..0df23ad 100644 --- a/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java +++ b/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java @@ -1,6 +1,7 @@ package me.trouper.trimserver.utils.visual; import me.trouper.trimserver.utils.Verbose; +import me.trouper.trimserver.utils.misc.Randomizer; import org.bukkit.FluidCollisionMode; import org.bukkit.Location; import org.bukkit.block.Block; @@ -17,6 +18,7 @@ import org.bukkit.util.VoxelShape; import java.util.ArrayList; import java.util.List; +import java.util.Random; import java.util.function.BiPredicate; import java.util.function.Predicate; @@ -164,6 +166,129 @@ public class CustomDisplayRaytracer { return traceDelayed(plugin, start, direction, distance, 0.5, tickDelay,1, hitCondition); } + public static Point traceWithReflection(Location start, Vector direction, double distance, double interval, + int maxReflections, Predicate hitCondition, + BiPredicate blockReflectCondition, + BiPredicate entityReflectCondition) { + + /* + Raytrace exactly like the non-reflecting methods. + However, every point (in addition to the hit condition) have a broad check if both a block, or an entity is hit. + If a block is hit, test it and its point against the blockReflectCondition + if it should hit, step a point back and use the traceBlockFace method to determine the face to reflect off. + get the BlockFace's normal with the getFaceNormal function + get the reflection ray's vector with calculateReflection + + + If an entity is hit, test it and its point against the entityReflectCondition. + if it should hit, then step a point back and calculate a glancing reflection with the glanceReflect method. + + Apply the new direction to the raytracer, then skip a point to prevent Immediately reflecting off the same point. + + repeat until running out of distance, running out of max reflections, until the hit condition is satisfied. + return the final point processed. + + */ + + if (interval <= 0) throw new IllegalArgumentException("interval cannot be zero or negative!"); + if (distance <= 0) throw new IllegalArgumentException("distance cannot be zero or negative!"); + + Vector normalizedDir = direction.clone().normalize(); + Location currentLocation = start.clone(); + Vector currentDirection = normalizedDir.clone(); + double remainingDistance = distance; + int reflections = 0; + + while (remainingDistance > 0 && reflections <= maxReflections) { + // Trace along the current ray direction + for (double i = 0.0; i < remainingDistance; i += interval) { + Point point = blocksInFrontOf(currentLocation, currentDirection, i, false); + + // Check if the hit condition is satisfied + if (hitCondition.test(point)) { + return point; // Hit condition met, return the hit point + } + + // Check for potential reflection + boolean shouldReflect = false; + Vector newDirection = null; + + // Check if point hits a block for reflection + if (HIT_BLOCK.test(point) && point.getBlock() != null) { + Block hitBlock = point.getBlock(); + if (blockReflectCondition.test(point, hitBlock)) { + // Step back slightly to get accurate reflection + Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false); + + // Determine which face was hit + BlockFace hitFace = traceBlockFace(previousPoint.getLoc(), currentDirection, interval * 2); + + if (hitFace != null) { + Vector faceNormal = getFaceNormal(hitFace); + newDirection = calculateReflection(currentDirection, faceNormal); + shouldReflect = true; + } + } + } + + // Check if point hits an entity for reflection + List nearbyEntities = point.getNearbyEntities(null, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()); + if (!nearbyEntities.isEmpty()) { + for (Entity entity : nearbyEntities) { + if (entityReflectCondition.test(point, entity)) { + // Step back slightly for glancing reflection + Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false); + + newDirection = glanceReflect(currentDirection); + shouldReflect = true; + break; + } + } + } + + if (shouldReflect) { + // Update current location to point before collision + double backStep = Math.max(0, i - interval); + currentLocation = blocksInFrontOf(currentLocation, currentDirection, backStep, false).getLoc(); + + // Update direction to reflection direction + currentDirection = newDirection; + + // Update remaining distance + remainingDistance -= backStep; + + // Increment reflection counter + reflections++; + + // Skip a small amount to prevent immediate reflection off the same object + currentLocation = currentLocation.add(currentDirection.clone().multiply(interval * 0.1)); + remainingDistance -= interval * 0.1; + + break; // Exit the inner loop to restart with new direction + } + + // If we reached the end without reflecting + if (i + interval >= remainingDistance) { + Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true); + return finalPoint; + } + } + + // If we've used all reflections but didn't reach the hit condition + if (reflections > maxReflections) { + Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true); + return finalPoint; + } + } + + // Should only reach here if we've exhausted all distance + return blocksInFrontOf(start, normalizedDir, distance, true); + } + + private static Vector glanceReflect(Vector incident) { + return offsetVector(incident,4).multiply(-1); + } + private static BlockFace traceBlockFace(Location startLocation, Vector direction, double maxDistance) { Predicate blockPredicate = block -> true; Predicate entityPredicate = entity -> false; @@ -177,20 +302,7 @@ public class CustomDisplayRaytracer { return null; } - private static Vector calculateReflection(Vector incident, BlockFace face) { - Verbose.send("Calculating vector reflection for face %s".formatted(face)); - Vector normal = getFaceNormal(face); - - return calculateReflection(incident,normal); - } - private static Vector calculateReflection(Vector incident, Vector normal) { - Verbose.send("Calculating entity reflection"); - - if (normal.lengthSquared() < 0.001) { - return incident.clone().multiply(-1).normalize(); - } - // r = i - 2(i dot n)n double dot = incident.dot(normal); Vector reflection = incident.clone().subtract(normal.clone().multiply(2 * dot)); @@ -213,4 +325,29 @@ public class CustomDisplayRaytracer { public static Point blocksInFrontOf(Location loc, Vector dir, double blocks, boolean missed) { return new Point(loc.clone().add(dir.getX() * blocks, dir.getY() * blocks, dir.getZ() * blocks), blocks, missed); } + + public static Vector offsetVector(Vector original, double angleDegrees) { + Random random = new Random(); + original = original.clone().normalize(); + + double yaw = Math.toDegrees(Math.atan2(-original.getX(), original.getZ())); + double pitch = Math.toDegrees(Math.asin(-original.getY())); + + double yawOffset = (random.nextDouble() * 2 - 1) * angleDegrees; + double pitchOffset = (random.nextDouble() * 2 - 1) * angleDegrees; + + yaw += yawOffset; + pitch += pitchOffset; + + pitch = Math.max(-90, Math.min(90, pitch)); + + double pitchRad = Math.toRadians(pitch); + double yawRad = Math.toRadians(yaw); + + double x = -Math.sin(yawRad) * Math.cos(pitchRad); + double y = -Math.sin(pitchRad); + double z = Math.cos(yawRad) * Math.cos(pitchRad); + + return new Vector(x, y, z); + } } diff --git a/src/main/java/me/trouper/trimserver/utils/visual/Point.java b/src/main/java/me/trouper/trimserver/utils/visual/Point.java index ec994ca..dc369ea 100644 --- a/src/main/java/me/trouper/trimserver/utils/visual/Point.java +++ b/src/main/java/me/trouper/trimserver/utils/visual/Point.java @@ -54,48 +54,6 @@ public class Point { return getNearbyEntities(exclude, range, false, filter); } - public BlockFace getBlockFace(Vector vector) { - if (block == null || block.isPassable()) { - return null; - } - - double x = vector.getX() - block.getX(); - double y = vector.getY() - block.getY(); - double z = vector.getZ() - block.getZ(); - - double min = 0; - BlockFace face = null; - - if (x < min) { - min = x; - face = BlockFace.WEST; - } - if (1 - x < min) { - min = 1 - x; - face = BlockFace.EAST; - } - if (y < min) { - min = y; - face = BlockFace.DOWN; - } - if (1 - y < min) { - min = 1 - y; - face = BlockFace.UP; - } - if (z < min) { - min = z; - face = BlockFace.NORTH; - } - if (1 - z < min) { - face = BlockFace.SOUTH; - } - - Verbose.send("Block face was %s. X: %s, Y: %s, Z: %s.", Text.formatEnum(face),x,y,z); - - return face; - } - - public double getTraveledDist() { return traveledDist; }