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 8f571a8..e6de3fd 100755 --- a/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java +++ b/src/main/java/me/trouper/trimserver/server/commands/AdminCommand.java @@ -84,6 +84,14 @@ public class AdminCommand implements QuickCommand { b.arg("test") .then( b.arg("vector") + ).then( + b.arg("sphere") + .then( + b.argPosDecimal("radius") + .then( + b.argPosDecimal("pointDistance") + ) + ) ) ); } @@ -97,7 +105,7 @@ public class AdminCommand implements QuickCommand { return false; },(point,block) -> { - DisplayUtils.sphere(point.getLoc(),0.3,0.1,0.1,loc -> { + DisplayUtils.sphere(point.getLoc(),0.3,0.1,loc -> { DisplayUtils.DUST_PARTICLE_FACTORY.apply(Color.RED,1F).accept(loc); }); @@ -106,6 +114,16 @@ public class AdminCommand implements QuickCommand { return !p.equals(entity); }); } + case "sphere" -> { + if (!(commandSender instanceof Player p)) return; + + double radius = args.get(2).toDouble(); + double pointDistance = args.get(3).toDouble(); + + DisplayUtils.sphere(p.getLocation(),radius,pointDistance,loc->{ + DisplayUtils.DUST_PARTICLE_FACTORY.apply(Color.AQUA,1F).accept(loc); + }); + } } } diff --git a/src/main/java/me/trouper/trimserver/server/systems/AbilityBackend.java b/src/main/java/me/trouper/trimserver/server/systems/AbilityBackend.java index 452fecd..a2be1ab 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/AbilityBackend.java +++ b/src/main/java/me/trouper/trimserver/server/systems/AbilityBackend.java @@ -85,7 +85,9 @@ public class AbilityBackend implements Main { } public AbstractAbility getAbility(Player player) { - return getArmorInfo(player).getAbility(); + ArmorInfo info = getArmorInfo(player); + if (info == null) return null; + return info.getAbility(); } public TrimMaterial getMaterial(Player player) { @@ -249,7 +251,7 @@ public class AbilityBackend implements Main { } /** - * Force-removes the cooldown for a player's specific trim ability. + * Force removes the cooldown for a player's specific trim ability. * Useful for admin commands or testing. * * @param player The player whose cooldown to reset @@ -270,7 +272,7 @@ public class AbilityBackend implements Main { * Checks the ability flag at the useLocation * @param player the player to check * @param useLocation the Bukkit location to check at - * @return + * @return true if the ability is allowed, false otherwise */ public boolean abilityAllowed(Player player, Location useLocation) { LocalPlayer user = WorldGuardPlugin.inst().wrapPlayer(player); 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 0e25657..56ad809 100755 --- 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 @@ -31,7 +31,9 @@ public class BoltAbility extends AbstractAbility implements Main { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(caster.getLocation(),range,target-> !main.man().trustBackend.trusts(caster,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()),(target) ->{ + return TargetingUtils.areaAffect(caster.getLocation(),range,target-> !main.man().trustBackend.trusts(caster,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(caster,target.getLocation()),(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()); @@ -72,7 +74,7 @@ public class BoltAbility extends AbstractAbility implements Main { 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 ); + zip.playWithin(30); bolt.playWithin(50); ring.playWithin(30); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/CoastAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/CoastAbility.java index 016d04e..609df3a 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/CoastAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/CoastAbility.java @@ -68,6 +68,7 @@ public class CoastAbility extends AbstractAbility { } Location centerLocation = TargetingUtils.findGroundLocation(castLocation); + if (!main.man().abilityBackend.abilityAllowed(player,centerLocation)) return; World world = centerLocation.getWorld(); if (world == null) return; 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 366f3c9..a83fb54 100755 --- 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 @@ -5,6 +5,7 @@ import me.trouper.trimserver.server.systems.abilities.MaterialInfo; 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.PlayerUtils; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.Text; import me.trouper.trimserver.utils.visual.DisplayUtils; @@ -33,6 +34,7 @@ public class DuneAbility extends AbstractAbility { } private void spawnWormSign(Player owner, Location loc) { + if (!main.man().abilityBackend.abilityAllowed(owner,loc)) return; AtomicInteger t = new AtomicInteger(0); Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(wave)->{ if (t.getAndIncrement() >= 25) { @@ -44,7 +46,10 @@ public class DuneAbility extends AbstractAbility { block.getWorld().playSound(block.getLocation(), Sound.BLOCK_ROOTED_DIRT_BREAK,0.1F,1); block.getWorld().spawnParticle(Particle.BLOCK_CRUMBLE,block.getLocation().add(0,1,0),1,0.5,0,0.5, data); - TargetingUtils.areaAffect(block.getLocation(),2, target -> !target.isDead() && !main.man().trustBackend.trusts(owner,target), liv->{ + TargetingUtils.areaAffect(block.getLocation(),2, target -> !target.isDead() && + !main.man().trustBackend.trusts(owner,target) && + main.man().abilityBackend.abilityAllowed(owner,target.getLocation()) && + PlayerUtils.combatAllowed(target,owner), liv->{ liv.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS,20,4,true,false,false)); Vector pullDirection = loc.toVector().subtract(liv.getLocation().toVector()).normalize(); Vector pullVelocity = pullDirection.multiply(0.0015); 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 b85cf36..147ea60 100755 --- 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 @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer; @@ -58,9 +59,16 @@ public class EyeAbility extends AbstractAbility { public Location laser(Player owner, Location start, Vector direction, double distance) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; + return CustomDisplayRaytracer.trace(start,direction,distance,1,point ->{ SoundPlayer hissSound = new SoundPlayer(point.getLoc(), Sound.BLOCK_LAVA_EXTINGUISH, 1, 1); - List targets = point.getNearbyEntities(owner,5,true,0.5, target -> target instanceof LivingEntity && !target.isDead() && !main.man().trustBackend.trusts(owner, (LivingEntity) target)); + List targets = point.getNearbyEntities(owner,5,true,0.5, target -> + target instanceof LivingEntity && + !target.isDead() && + !main.man().trustBackend.trusts(owner, (LivingEntity) target) && + PlayerUtils.combatAllowed(target, owner) && + main.man().abilityBackend.abilityAllowed(owner,target.getLocation()) + ); targets.forEach(entity -> { if (!(entity instanceof LivingEntity liv) || shaper.activeShellTasks.containsKey(liv.getUniqueId())) return; hissSound.playWithin(30); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/FlowAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/FlowAbility.java index c8d5cfc..b5bfc6e 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/FlowAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/FlowAbility.java @@ -70,7 +70,7 @@ public class FlowAbility extends AbstractAbility { @Override public void run() { if (System.currentTimeMillis() > endTime || !player.isOnline() || - breeze.isDead() || breeze.getPassengers().isEmpty()) { + breeze.isDead() || breeze.getPassengers().isEmpty() || !main.man().abilityBackend.abilityAllowed(player,player.getLocation())) { endBreezeRide(player, breeze); cancel(); return; diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RaiserAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RaiserAbility.java index d39de88..19a225c 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RaiserAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RaiserAbility.java @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.Text; import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer; @@ -30,8 +31,8 @@ public class RaiserAbility extends AbstractAbility { private final Map levitationTasks = new HashMap<>(); - public void raiseEntity(LivingEntity target) { - if (target == null) return; + public void raiseEntity(Player caster, LivingEntity target) { + if (target == null || !PlayerUtils.combatAllowed(target,caster)) return; UUID uuid = target.getUniqueId(); @@ -45,21 +46,17 @@ public class RaiserAbility extends AbstractAbility { int frequency = 2; int duration = 20 * 7; - // --- Start Up Effects --- target.getWorld().playSound(target.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.8f, 1.0f); BlockDisplay hook = BlockDisplayRaytracer.trace(Material.IRON_BLOCK,target.getEyeLocation(),target.getLocation().add(0,128,0),0.3,60); DisplayUtils.wave(target.getLocation(),2,Color.WHITE,1,0.1); - // Give an initial upward push target.setVelocity(new Vector(0, 0.4, 0)); - // --- The Main Repeating Task (Holding, Checking, Effects) --- BukkitTask task = new BukkitRunnable() { int ticksElapsed = 0; final int durationTicks = duration / frequency; @Override public void run() { - // Check if player is still valid and online if (target.isDead()) { endLevitation(uuid); return; @@ -68,20 +65,17 @@ public class RaiserAbility extends AbstractAbility { Location currentLocation = target.getLocation(); double currentHealth = target.getHealth(); - // --- Check Conditions to End --- - // 1. Health threshold reached + if (currentHealth <= healthThreshold) { endLevitation(uuid); return; } - // 2. Time limit reached if (ticksElapsed >= durationTicks) { endLevitation(uuid); return; } - // --- Hold Player at Target Height --- if (currentLocation.getY() >= targetY) { Vector currentVelocity = target.getVelocity(); target.setVelocity(new Vector(currentVelocity.getX(), 0, currentVelocity.getZ())); @@ -144,7 +138,12 @@ public class RaiserAbility extends AbstractAbility { public boolean amethystAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Copper ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -152,7 +151,12 @@ public class RaiserAbility extends AbstractAbility { public boolean copperAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Diamond ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -160,7 +164,12 @@ public class RaiserAbility extends AbstractAbility { public boolean diamondAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Emerald ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -168,7 +177,12 @@ public class RaiserAbility extends AbstractAbility { public boolean emeraldAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Gold ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -176,7 +190,12 @@ public class RaiserAbility extends AbstractAbility { public boolean goldAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Iron ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -184,7 +203,12 @@ public class RaiserAbility extends AbstractAbility { public boolean ironAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Lapis ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -192,13 +216,22 @@ public class RaiserAbility extends AbstractAbility { public boolean lapisAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Netherite ", description = "Pins your enemy 4 blocks into the air for 6 seconds. Can raise those with Shaper ability activated too.", cooldownTicks = 20 * 30) @Override public boolean netheriteAbility(Player player) { - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Quartz ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -206,7 +239,12 @@ public class RaiserAbility extends AbstractAbility { public boolean quartzAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Redstone ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -214,7 +252,12 @@ public class RaiserAbility extends AbstractAbility { public boolean redstoneAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } @MaterialInfo(name = "Resin ", description = "Pins your enemy 4 blocks into the air for 6 seconds, or until they loose half their current health", cooldownTicks = 20 * 45) @@ -222,6 +265,11 @@ public class RaiserAbility extends AbstractAbility { public boolean resinAbility(Player player) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - return TargetingUtils.areaAffect(player.getLocation(),15,target -> !main.man().trustBackend.trusts(player,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()), this::raiseEntity); + return TargetingUtils.areaAffect(player.getLocation(),15,target -> + !main.man().trustBackend.trusts(player,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + main.man().abilityBackend.abilityAllowed(player,target.getLocation()), ent->{ + raiseEntity(player,ent); + }); } } diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RibAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RibAbility.java index 430de56..c094bed 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RibAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/RibAbility.java @@ -15,14 +15,11 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.BoundingBox; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.joml.Vector3f; -import org.joml.Quaternionf; -import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -36,7 +33,7 @@ public class RibAbility extends AbstractAbility { super(TrimPattern.RIB); } - private void executeResinEruption(Player caster, Material activatingTrimMaterial, int spikeCount, double areaRadius, int activeDurationTicks, Material groundParticleMaterial) { + private void executeEruption(Player caster, Material activatingTrimMaterial, int spikeCount, double areaRadius, int activeDurationTicks, Material groundParticleMaterial) { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; @@ -49,11 +46,16 @@ public class RibAbility extends AbstractAbility { caster.addPotionEffect(new PotionEffect(PotionEffectType.STRENGTH,10*20,1,true)); caster.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION,5*20,2,true)); - DisplayUtils.sphereWave(caster.getEyeLocation(),10,0.5,2,2,(point)->{ + DisplayUtils.sphereWave(caster.getEyeLocation(),10,0.5,2,(point)->{ point.getWorld().spawnParticle(Particle.FLAME,point,1,0.1,0.1,0.1,0.01); point.getWorld().spawnParticle(Particle.SMOKE,point,1,0.1,0.1,0.1,0.1); point.getWorld().spawnParticle(Particle.CAMPFIRE_COSY_SMOKE,point,1,0.1,0.1,0.1,0.1); - TargetingUtils.areaAffect(point,1, liv->!liv.equals(caster) && !liv.isDead() && !main.man().trustBackend.trusts(caster,liv) && !shaper.activeShellTasks.containsKey(liv.getUniqueId()), target->{ + TargetingUtils.areaAffect(point,1, liv-> !liv.equals(caster) && + !liv.isDead() && + !main.man().trustBackend.trusts(caster,liv) && + !shaper.activeShellTasks.containsKey(liv.getUniqueId()) + && main.man().abilityBackend.abilityAllowed(caster, liv.getLocation()), + target->{ target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,20*20,1,true,false,false)); target.setFireTicks(20*20); }); @@ -103,8 +105,10 @@ public class RibAbility extends AbstractAbility { } - final Location finalSpikeBase = groundSurfaceLoc.clone(); - final Location spikeTipLoc = finalSpikeBase.clone().add(0, spikeVisualHeight, 0); + final Location finalSpikeBase = groundSurfaceLoc.clone(); // BOTTOM + final Location spikeTipLoc = finalSpikeBase.clone().add(0, spikeVisualHeight, 0); // TOP + + if (!main.man().abilityBackend.abilityAllowed(caster,finalSpikeBase)) continue; BlockDisplay spikeDisplay = world.spawn(finalSpikeBase, BlockDisplay.class, bd -> { bd.setBlock(spikeBlockData); @@ -204,77 +208,77 @@ public class RibAbility extends AbstractAbility { @MaterialInfo(name = "Eruption (Amethyst)", description = "Erupts spikes of amethyst", cooldownTicks = 20 * 30) @Override public boolean amethystAbility(Player player) { - executeResinEruption(player, Material.AMETHYST_BLOCK, 10, 5.5, 20 * 5, Material.SMOOTH_BASALT); + executeEruption(player, Material.AMETHYST_BLOCK, 10, 5.5, 20 * 5, Material.SMOOTH_BASALT); return true; } @MaterialInfo(name = "Eruption (Copper)", description = "Erupts spikes of oxidized copper", cooldownTicks = 20 * 30) @Override public boolean copperAbility(Player player) { - executeResinEruption(player, Material.RAW_COPPER, 10, 5.0, 20 * 5, Material.TUFF); + executeEruption(player, Material.RAW_COPPER, 10, 5.0, 20 * 5, Material.TUFF); return true; } @MaterialInfo(name = "Eruption (Diamond)", description = "Erupts spikes of diamond", cooldownTicks = 20 * 30) @Override public boolean diamondAbility(Player player) { - executeResinEruption(player, Material.DEEPSLATE_DIAMOND_ORE, 12, 6.0, 20 * 6, Material.DEEPSLATE); + executeEruption(player, Material.DEEPSLATE_DIAMOND_ORE, 12, 6.0, 20 * 6, Material.DEEPSLATE); return true; } @MaterialInfo(name = "Eruption (Emerald)", description = "Erupts spikes of emerald", cooldownTicks = 20 * 30) @Override public boolean emeraldAbility(Player player) { - executeResinEruption(player, Material.DEEPSLATE_EMERALD_ORE, 12, 6.0, 20 * 6, Material.MOSS_BLOCK); + executeEruption(player, Material.DEEPSLATE_EMERALD_ORE, 12, 6.0, 20 * 6, Material.MOSS_BLOCK); return true; } @MaterialInfo(name = "Eruption (Gold)", description = "Erupts spikes of gold", cooldownTicks = 20 * 30) @Override public boolean goldAbility(Player player) { - executeResinEruption(player, Material.DEEPSLATE_GOLD_ORE, 10, 5.0, 20 * 5, Material.NETHER_GOLD_ORE); + executeEruption(player, Material.DEEPSLATE_GOLD_ORE, 10, 5.0, 20 * 5, Material.NETHER_GOLD_ORE); return true; } @MaterialInfo(name = "Eruption (Iron)", description = "Erupts spikes of iron", cooldownTicks = 20 * 30) @Override public boolean ironAbility(Player player) { - executeResinEruption(player, Material.RAW_IRON_BLOCK, 11, 5.5, 20 * 5, Material.RAW_IRON_BLOCK); + executeEruption(player, Material.RAW_IRON_BLOCK, 11, 5.5, 20 * 5, Material.RAW_IRON_BLOCK); return true; } @MaterialInfo(name = "Eruption (Lapis)", description = "Erupts spikes of lapis", cooldownTicks = 20 * 30) @Override public boolean lapisAbility(Player player) { - executeResinEruption(player, Material.LAPIS_BLOCK, 10, 5.0, 20 * 5, Material.CLAY); + executeEruption(player, Material.LAPIS_BLOCK, 10, 5.0, 20 * 5, Material.CLAY); return true; } @MaterialInfo(name = "Eruption (Netherite)", description = "Erupts deadly blackstone spikes", cooldownTicks = 20 * 20) @Override public boolean netheriteAbility(Player player) { - executeResinEruption(player, Material.BLACKSTONE, 20, 10.0, 20 * 8, Material.BLACKSTONE); + executeEruption(player, Material.BLACKSTONE, 20, 10.0, 20 * 8, Material.BLACKSTONE); return true; } @MaterialInfo(name = "Eruption (Quartz)", description = "Erupts spikes of quartz", cooldownTicks = 20 * 30) @Override public boolean quartzAbility(Player player) { - executeResinEruption(player, Material.QUARTZ_BLOCK, 11, 5.5, 20 * 5, Material.NETHER_QUARTZ_ORE); + executeEruption(player, Material.QUARTZ_BLOCK, 11, 5.5, 20 * 5, Material.NETHER_QUARTZ_ORE); return true; } @MaterialInfo(name = "Eruption (Redstone)", description = "Erupts energized redstone spikes", cooldownTicks = 20 * 30) @Override public boolean redstoneAbility(Player player) { - executeResinEruption(player, Material.REDSTONE_BLOCK, 11, 5.5, 20 * 5, Material.REDSTONE_ORE); + executeEruption(player, Material.REDSTONE_BLOCK, 11, 5.5, 20 * 5, Material.REDSTONE_ORE); return true; } @MaterialInfo(name = "Eruption (Resin)", description = "Erupts spikes of hardened resin from the ground", cooldownTicks = 20 * 30) @Override public boolean resinAbility(Player player) { - executeResinEruption(player, Material.RESIN_BLOCK, 12, 6.0, 20 * 6, Material.NETHERRACK); + executeEruption(player, Material.RESIN_BLOCK, 12, 6.0, 20 * 6, Material.NETHERRACK); return true; } } \ No newline at end of file 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 3985452..c38d800 100755 --- 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 @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.Text; @@ -41,7 +42,6 @@ public class SentryAbility extends AbstractAbility { Location spawn = loc.clone().subtract(0,2,0); List turretParts = new ArrayList<>(); - // 1) Spawn the rotating turret (dispenser model) BlockDisplay turret = w.spawn(spawn.clone().add(0.5, 1.5, 0.5), BlockDisplay.class, display -> { display.setBlock(turretMat.createBlockData()); display.setBrightness(new Display.Brightness(15, 15)); @@ -49,11 +49,8 @@ public class SentryAbility extends AbstractAbility { display.setInterpolationDuration(2); display.addScoreboardTag("$/TrimServer/ Temp"); - // Get the current transformation Transformation transformation = display.getTransformation(); - // Set the translation to center the pivot point transformation.getTranslation().set(-0.5f, -0.5f, -0.5f); - // Apply the modified transformation back to the display display.setTransformation(transformation); }); @@ -69,9 +66,8 @@ public class SentryAbility extends AbstractAbility { turretParts.add(dummy); - // 2) Legs: four converging from a 1×1 square around base up to head-pole double legHeight = 1.5; - double halfSize = 0.6; // distance from center + double halfSize = 0.6; List stand = new ArrayList<>(); for (double dx : new double[]{ -halfSize, +halfSize }) { for (double dz : new double[]{ -halfSize, +halfSize }) { @@ -90,7 +86,6 @@ public class SentryAbility extends AbstractAbility { turretParts.addAll(stand); - // 3) Ammo display above head TextDisplay meter = w.spawn(spawn.clone().add(0.5, 2.5, 0.5), TextDisplay.class, t -> { t.setBillboard(Display.Billboard.CENTER); t.setRotation(0, 90); @@ -116,7 +111,11 @@ public class SentryAbility extends AbstractAbility { String bar = Text.generateProgressBar(10, maxAmmo, chamber); meter.text(Text.color("%s's Sentry\n".formatted(owner.getName()) + "Ammo " + bar)); - Optional target = TargetingUtils.getClosestPlayer(finalLoc,15,p -> !p.isDead() && !p.equals(owner) && !main.man().trustBackend.trusts(owner,p) && !shaper.activeShellTasks.containsKey(p.getUniqueId())); + Optional target = TargetingUtils.getClosestPlayer(finalLoc,15,p -> !p.isDead() && + !p.equals(owner) && + !main.man().trustBackend.trusts(owner,p) && + !shaper.activeShellTasks.containsKey(p.getUniqueId()) && + PlayerUtils.combatAllowed(p,owner)); if (target.isPresent()) { Player tracked = target.get(); 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 de39eef..5755056 100755 --- 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 @@ -53,7 +53,14 @@ 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); - List targets = point.getNearbyEntities(player,5,true,0.5, entity -> entity instanceof LivingEntity && !entity.equals(player) && !entity.isDead() && !main.man().trustBackend.trusts(player.getUniqueId(),entity.getUniqueId()) && !shaper.activeShellTasks.containsKey(entity.getUniqueId())); + List targets = point.getNearbyEntities(player,5,true,0.5, entity -> + entity instanceof LivingEntity && + !entity.equals(player) && + !entity.isDead() && + !main.man().trustBackend.trusts(player.getUniqueId(),entity.getUniqueId()) && + !shaper.activeShellTasks.containsKey(entity.getUniqueId()) && + PlayerUtils.combatAllowed(entity,player) + ); targets.forEach(target -> { PlayerUtils.dealTrueDamage((LivingEntity) target, DamageSource.builder(DamageType.SONIC_BOOM).withDirectEntity(player).build(), 10); }); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SpireAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SpireAbility.java index 1f596c4..c3c9b91 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SpireAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/SpireAbility.java @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.PatternInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.visual.DisplayUtils; @@ -30,7 +31,7 @@ public class SpireAbility extends AbstractAbility { private final Map> activeSpires = new HashMap<>(); private final Map activeTasks = new HashMap<>(); - private final Set activeProjectiles = new HashSet<>(); + private final Map activeProjectiles = new HashMap<>(); public SpireAbility() { super(TrimPattern.SPIRE); @@ -40,7 +41,6 @@ public class SpireAbility extends AbstractAbility { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - // Cancel any existing spire for this player if (activeTasks.containsKey(player.getUniqueId())) { activeTasks.get(player.getUniqueId()).cancel(); activeTasks.remove(player.getUniqueId()); @@ -57,18 +57,14 @@ public class SpireAbility extends AbstractAbility { Location baseLoc = player.getLocation().clone(); Location topLoc = baseLoc.clone().add(0, spireHeight, 0); - // Store entities for cleanup List entities = new ArrayList<>(); activeSpires.put(player.getUniqueId(), entities); - // Start with initial effects SoundPlayer startSound = new SoundPlayer(baseLoc, Sound.BLOCK_END_PORTAL_SPAWN, 1.0f, 0.8f); startSound.playWithin(10); - // Create the blocks for the spire (cone shape) createSpireStructure(player, baseLoc, spireHeight, material, entities); - // Teleport player to the top Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> { Bat dummy = world.spawn(topLoc.clone().add(0.5,0,0.5),Bat.class,(bat)->{ bat.setAI(false); @@ -80,18 +76,14 @@ public class SpireAbility extends AbstractAbility { dummy.addPassenger(player); }, 10L); - // Create the barrier sphere - double sphereRadius = spireHeight * 0.75; + double sphereRadius = spireHeight * 1.25; - // Create initial sphere particle effect Color sphereColor = getColor(material); Consumer particleAction = DisplayUtils.DUST_PARTICLE_FACTORY.apply(sphereColor, 1.2f); - - // Create expanding sphere effect + DisplayUtils.sphereWave(baseLoc.clone().add(0, sphereRadius/2, 0), - sphereRadius, 0.5, 0.5, 0.5, particleAction); + sphereRadius, 1, 1, particleAction); - // Start the main task for the ability BukkitTask task = new BukkitRunnable() { final long endTime = System.currentTimeMillis() + (duration * 1000L); int tickCounter = 0; @@ -99,7 +91,6 @@ public class SpireAbility extends AbstractAbility { @Override public void run() { - // Check if ability should end if (System.currentTimeMillis() > endTime || !player.isOnline()) { endEnderStorm(player); cancel(); @@ -108,15 +99,16 @@ public class SpireAbility extends AbstractAbility { tickCounter++; - // Every 10 ticks, refresh the sphere particles if (tickCounter % 10 == 0) { - DisplayUtils.sphere(sphereCenter, sphereRadius, 1.0, 1.0, loc -> - world.spawnParticle(Particle.PORTAL, loc, 1, 0, 0, 0, 0)); + DisplayUtils.sphere(sphereCenter, sphereRadius, 2, loc -> { + world.spawnParticle(Particle.PORTAL, loc, 1, 0, 0, 0, 0); + world.spawnParticle(Particle.BLOCK, loc, 1, 0, 0, 0, 0,Material.NETHER_PORTAL.createBlockData()); + }); } - // Every 5 ticks, check for players in the sphere and push them inward if they're near the edge + // check for players in the sphere and push them inward if they're near the edge if (tickCounter % 5 == 0) { - TargetingUtils.areaAffect(sphereCenter,sphereRadius,target -> !main.man().trustBackend.trusts(player,target),target -> { + TargetingUtils.areaAffect(sphereCenter,sphereRadius,target -> !main.man().trustBackend.trusts(player,target) && PlayerUtils.combatAllowed(target,player),target -> { double distanceFromCenter = target.getLocation().distance(sphereCenter); if (distanceFromCenter > sphereRadius * 0.8) { Vector pushDirection = sphereCenter.clone() @@ -129,10 +121,13 @@ public class SpireAbility extends AbstractAbility { }); } - // Fire shulker bullets every 15 ticks (0.75 seconds) if (tickCounter % 15 == 0) { List targets = world.getNearbyEntities(sphereCenter, sphereRadius, sphereRadius, sphereRadius).stream() - .filter(entity -> entity instanceof Player && !entity.equals(player) && !main.man().trustBackend.trusts(player.getUniqueId(), entity.getUniqueId()) && !shaper.activeShellTasks.containsKey(entity.getUniqueId())) + .filter(entity -> entity instanceof Player && + !entity.equals(player) && + !main.man().trustBackend.trusts(player.getUniqueId(), entity.getUniqueId()) && + !shaper.activeShellTasks.containsKey(entity.getUniqueId()) && + PlayerUtils.combatAllowed(entity,player)) .map(entity -> (Player) entity) .toList(); @@ -144,17 +139,19 @@ public class SpireAbility extends AbstractAbility { ShulkerBullet bullet = (ShulkerBullet) world.spawnEntity(fireLocation, EntityType.SHULKER_BULLET); bullet.setTarget(target); - activeProjectiles.add(bullet.getUniqueId()); + bullet.setShooter(player); + activeProjectiles.put(bullet.getUniqueId(),player.getUniqueId()); world.spawnParticle(Particle.END_ROD, fireLocation, 10, 0.2, 0.2, 0.2, 0.1); SoundPlayer bulletSound = new SoundPlayer(fireLocation, Sound.ENTITY_SHULKER_SHOOT, 1.0f, 1.0f); + SoundPlayer bulletSound2 = new SoundPlayer(fireLocation, Sound.ENTITY_EVOKER_CAST_SPELL, 1.0f, 1.0f); bulletSound.playWithin(20); + bulletSound2.playWithin(20); entities.add(bullet); } } - // Every 20 ticks, create some ambient particles around the spire if (tickCounter % 10 == 0) { for (int y = 0; y < spireHeight; y += 2) { Location particleLoc = baseLoc.clone().add(0, y, 0); @@ -187,12 +184,10 @@ public class SpireAbility extends AbstractAbility { World world = player.getWorld(); BlockData blockData = material.createBlockData(); - // Create the main spire body (cone shape) + // Spire Cone for (int y = 0; y < height; y++) { - // Calculate radius at this height (decreasing as y increases) double radius = 2.0 * (1 - y / (double) height); - // Create circle of blocks if (radius > 0.1) { int blocks = Math.max(4, (int) (2 * Math.PI * radius / 0.5)); double angleStep = 360.0 / blocks; @@ -204,7 +199,6 @@ public class SpireAbility extends AbstractAbility { Location blockLoc = baseLoc.clone().add(x, y, z); - // Create Block Display BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> { b.setBlock(blockData); b.setBrightness(new Display.Brightness(15, 15)); @@ -222,7 +216,7 @@ public class SpireAbility extends AbstractAbility { } } - // Create a platform at the top + // Platform double topRadius = 1; int platformBlocks = 12; double angleStep = 360.0 / platformBlocks; @@ -233,8 +227,7 @@ public class SpireAbility extends AbstractAbility { double z = Math.sin(Math.toRadians(angle)) * topRadius; Location blockLoc = baseLoc.clone().add(x-1, height, z); - - // Create Block Display for platform + BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> { b.setBlock(blockData); b.setBrightness(new Display.Brightness(15, 15)); @@ -244,8 +237,7 @@ public class SpireAbility extends AbstractAbility { entities.add(display); } - - // Create center block for platform + BlockDisplay centerDisplay = world.spawn(baseLoc.clone().add(0, height, 0), BlockDisplay.class, b -> { b.setBlock(blockData); b.setBrightness(new Display.Brightness(15, 15)); @@ -254,28 +246,6 @@ public class SpireAbility extends AbstractAbility { entities.add(centerDisplay); - // Add some decorative elements - crystal-like structures on top - for (int i = 0; i < 4; i++) { - double angle = i * 90; - double x = Math.cos(Math.toRadians(angle)) * 1.5; - double z = Math.sin(Math.toRadians(angle)) * 1.5; - - Location crystalBase = baseLoc.clone().add(x, height + 0.5, z); - - // Add a crystal spike using tracing - BlockDisplay crystal = BlockDisplayRaytracer.trace( - Material.WHITE_STAINED_GLASS, - crystalBase, - new Vector(0, 2, 0), - 0.2, - 2.0, - 20 * 60 - ); - - entities.add(crystal); - } - - // Rising animation for the spire AtomicInteger animStep = new AtomicInteger(0); BukkitTask animTask = new BukkitRunnable() { @Override @@ -286,7 +256,6 @@ public class SpireAbility extends AbstractAbility { return; } - // Rising particles for (int y = 0; y < step * height / 10; y++) { Location particleLoc = baseLoc.clone().add(0, y, 0); world.spawnParticle(Particle.END_ROD, particleLoc, @@ -299,8 +268,6 @@ public class SpireAbility extends AbstractAbility { } } }.runTaskTimer(main.getPlugin(), 0L, 2L); - - entities.add(null); // Placeholder to ensure the task is recognized as an entity for cleanup } private void endEnderStorm(Player player) { @@ -312,12 +279,10 @@ public class SpireAbility extends AbstractAbility { if (activeSpires.containsKey(player.getUniqueId())) { List entities = activeSpires.get(player.getUniqueId()); - // Create disintegration effect if (!entities.isEmpty()) { Location baseLoc = entities.get(0).getLocation(); World world = baseLoc.getWorld(); - // Disintegration particles for (Entity entity : entities) { if (entity instanceof Display) { Location loc = entity.getLocation(); @@ -340,35 +305,37 @@ public class SpireAbility extends AbstractAbility { private Color getColor(Material material) { return switch (material) { - case AMETHYST_BLOCK -> Color.fromRGB(137, 0, 201); - case COPPER_BLOCK -> Color.fromRGB(184, 115, 51); - case DIAMOND_BLOCK -> Color.fromRGB(51, 235, 203); - case EMERALD_BLOCK -> Color.fromRGB(0, 217, 58); - case GOLD_BLOCK -> Color.fromRGB(255, 230, 0); - case IRON_BLOCK -> Color.fromRGB(216, 216, 216); - case LAPIS_BLOCK -> Color.fromRGB(0, 85, 255); - case NETHERITE_BLOCK -> Color.fromRGB(66, 66, 76); - case QUARTZ_BLOCK -> Color.fromRGB(225, 225, 225); - case REDSTONE_BLOCK -> Color.fromRGB(255, 0, 0); - case RESIN_BLOCK -> Color.fromRGB(239, 195, 134); - default -> Color.fromRGB(128, 0, 128); + case AMETHYST_BLOCK -> Color.fromRGB(0x8900C9); + case COPPER_BLOCK -> Color.fromRGB(0xB87333); + case DIAMOND_BLOCK -> Color.fromRGB(0x33EBCB); + case EMERALD_BLOCK -> Color.fromRGB(0x00D93A); + case GOLD_BLOCK -> Color.fromRGB(0xFFE600); + case IRON_BLOCK -> Color.fromRGB(0xD8D8D8); + case LAPIS_BLOCK -> Color.fromRGB(0x0055FF); + case NETHERITE_BLOCK -> Color.fromRGB(0x42424C); + case QUARTZ_BLOCK -> Color.fromRGB(0xE1E1E1); + case REDSTONE_BLOCK -> Color.fromRGB(0xFF0000); + case RESIN_BLOCK -> Color.fromRGB(0xEFC386); + default -> Color.fromRGB(0x800080); + }; } @EventHandler public void onProjectileHit(ProjectileHitEvent event) { - if (event.getEntity() instanceof ShulkerBullet bullet) { - if (activeProjectiles.contains(bullet.getUniqueId())) { - activeProjectiles.remove(bullet.getUniqueId()); - - Location hitLoc = bullet.getLocation(); - hitLoc.getWorld().spawnParticle(Particle.DRAGON_BREATH, hitLoc, - 15, 0.2, 0.2, 0.2, 0.1); - - SoundPlayer impactSound = new SoundPlayer(hitLoc, Sound.ENTITY_SHULKER_BULLET_HIT, 1.0f, 1.2f); - impactSound.playWithin(5); - } + if (!(event.getEntity() instanceof ShulkerBullet bullet)) return; + if (!activeProjectiles.containsKey(bullet.getUniqueId())) return; + if (event.getHitEntity() != null && PlayerUtils.combatAllowed(event.getHitEntity(),Bukkit.getPlayer(activeProjectiles.get(bullet.getUniqueId())))) { + event.setCancelled(true); } + activeProjectiles.remove(bullet.getUniqueId()); + + Location hitLoc = bullet.getLocation(); + hitLoc.getWorld().spawnParticle(Particle.DRAGON_BREATH, hitLoc, + 15, 0.2, 0.2, 0.2, 0.1); + + SoundPlayer impactSound = new SoundPlayer(hitLoc, Sound.ENTITY_SHULKER_BULLET_HIT, 1.0f, 1.2f); + impactSound.playWithin(5); } @MaterialInfo(name = "Amethyst Ender Storm", description = "Summon a spire that traps players and fires shulker bullets", cooldownTicks = 20*90) diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/TideAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/TideAbility.java index a10768f..140b91c 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/TideAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/TideAbility.java @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.visual.DisplayUtils; @@ -38,7 +39,10 @@ public class TideAbility extends AbstractAbility { DisplayUtils.waveFan(caster.getLocation().add(0, 2,0),10,direction,90,0.1, point->{ point.getWorld().spawnParticle(Particle.BLOCK_CRUMBLE,point,8,0.1,0.1,0.1,0.1, Material.BLUE_STAINED_GLASS.createBlockData()); - TargetingUtils.areaAffect(point,0.3,5,0.3,target -> !main.man().trustBackend.trusts(caster,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()),target -> { + TargetingUtils.areaAffect(point,0.3,5,0.3,target -> !main.man().trustBackend.trusts(caster,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + PlayerUtils.combatAllowed(target,caster) + ,target -> { SoundPlayer blockSound = new SoundPlayer(target.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 0.5F); Vector dir = target.getLocation().toVector().subtract(caster.getLocation().toVector()).normalize(); double strength = 0.5; 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 8f0b736..3c58eec 100755 --- 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 @@ -62,7 +62,6 @@ public class WardAbility extends AbstractAbility { return; } - // spawn and configure warden Warden warden = (Warden) player.getWorld().spawnEntity(player.getLocation().subtract(0,3,0), EntityType.WARDEN, CreatureSpawnEvent.SpawnReason.NATURAL); Verbose.send( "Spawned Warden entity %s for %s", warden.getUniqueId(), player.getName()); warden.setAI(false); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WayfinderAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WayfinderAbility.java index 950a5a5..2bb4bbb 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WayfinderAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WayfinderAbility.java @@ -3,6 +3,7 @@ package me.trouper.trimserver.server.systems.abilities.trims; import me.trouper.trimserver.server.systems.abilities.MaterialInfo; import me.trouper.trimserver.server.systems.abilities.AbstractAbility; import me.trouper.trimserver.server.systems.abilities.PatternInfo; +import me.trouper.trimserver.utils.PlayerUtils; import me.trouper.trimserver.utils.SoundPlayer; import me.trouper.trimserver.utils.TargetingUtils; import me.trouper.trimserver.utils.visual.DisplayUtils; @@ -63,7 +64,11 @@ public class WayfinderAbility extends AbstractAbility { block.setCancelDrop(true); }); - TargetingUtils.areaAffect(caster.getLocation(),10,target -> !target.isDead() && !target.equals(caster) && !main.man().trustBackend.trusts(caster,target) && !shaper.activeShellTasks.containsKey(target.getUniqueId()),target->{ + TargetingUtils.areaAffect(caster.getLocation(),10,target -> !target.isDead() && + !target.equals(caster) && + !main.man().trustBackend.trusts(caster,target) && + !shaper.activeShellTasks.containsKey(target.getUniqueId()) && + PlayerUtils.combatAllowed(target,caster), target->{ SoundPlayer hit = new SoundPlayer(target.getLocation(), Sound.ENTITY_EVOKER_FANGS_ATTACK, 1, 2); Vector direction = target.getLocation().toVector().subtract(caster.getEyeLocation().toVector()).normalize(); target.setVelocity(direction.multiply(0.5).setY(0.3)); diff --git a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WildAbility.java b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WildAbility.java index de0f4d2..051ffe5 100755 --- a/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WildAbility.java +++ b/src/main/java/me/trouper/trimserver/server/systems/abilities/trims/WildAbility.java @@ -32,7 +32,7 @@ public class WildAbility extends AbstractAbility { AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER); ShaperAbility shaper = (ShaperAbility) shaperInstance; - if (caster == null || !caster.isOnline() || target == null || !target.isOnline() || caster.equals(target)) return; + if (caster == null || !caster.isOnline() || target == null || !target.isOnline() || caster.equals(target) || !PlayerUtils.combatAllowed(target,caster)) return; if (shaper.activeShellTasks.containsKey(target.getUniqueId())) return; if (caster.getWorld() != target.getWorld()) return; diff --git a/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java b/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java index 40542c8..b8a417c 100755 --- a/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java +++ b/src/main/java/me/trouper/trimserver/utils/PlayerUtils.java @@ -1,5 +1,6 @@ package me.trouper.trimserver.utils; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; @@ -9,6 +10,7 @@ import com.sk89q.worldguard.protection.regions.RegionQuery; import me.trouper.trimserver.server.Main; import org.bukkit.Location; import org.bukkit.damage.DamageSource; +import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -85,15 +87,32 @@ public class PlayerUtils implements Main { public static void dealTrueDamage(LivingEntity target, DamageSource source, double amount) { if (source.getDirectEntity() instanceof Player a && target instanceof Player t && !combatAllowed(t,a)) return; - double newHealth = target.getHealth() - amount; + target.damage(1, source); + + double newHealth = target.getHealth() - amount; if (newHealth <= 0) { target.setHealth(0); } else { target.setHealth(newHealth); } + + Entity attacker = source.getDirectEntity(); + if (attacker instanceof LivingEntity) { + double dx = target.getX() - attacker.getX(); + double dz = target.getZ() - attacker.getZ(); + double magnitude = Math.sqrt(dx * dx + dz * dz); + + if (magnitude > 0) { + double strength = 0.4; + dx /= magnitude; + dz /= magnitude; + target.setVelocity(target.getVelocity().add(new Vector(dx * strength, 0.1, dz * strength))); + } + } } - + + public static boolean combatAllowed(Player v, Player a) { LocalPlayer victim = WorldGuardPlugin.inst().wrapPlayer(v); LocalPlayer attacker = WorldGuardPlugin.inst().wrapPlayer(a); @@ -101,10 +120,31 @@ public class PlayerUtils implements Main { RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); RegionQuery query = container.createQuery(); - if (!query.testState(victim.getLocation(),victim, Flags.PVP) || !query.testState(attacker.getLocation(),attacker, Flags.PVP)) { + if (!query.testState(victim.getLocation(),victim, Flags.PVP)) { main.warning(a,"You cannot attack players protected by regions."); return false; } + if (!query.testState(attacker.getLocation(),attacker, Flags.PVP)) { + main.warning(a,"You cannot attack players while you are protected by a region."); + return false; + } + return true; + } + + public static boolean combatAllowed(Entity v, Player a) { + LocalPlayer attacker = WorldGuardPlugin.inst().wrapPlayer(a); + + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + RegionQuery query = container.createQuery(); + + if (!query.testState(BukkitAdapter.adapt(v.getLocation()),attacker, Flags.PVP)) { + main.warning(a,"You cannot attack entities protected by regions."); + return false; + } + if (!query.testState(attacker.getLocation(),attacker, Flags.PVP)) { + main.warning(a,"You cannot attack players while you are protected by a region."); + return false; + } return true; } } 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 0df23ad..c0efa34 100755 --- a/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java +++ b/src/main/java/me/trouper/trimserver/utils/visual/CustomDisplayRaytracer.java @@ -171,24 +171,6 @@ public class CustomDisplayRaytracer { 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!"); @@ -200,27 +182,21 @@ public class CustomDisplayRaytracer { 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 + return 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) { @@ -231,12 +207,10 @@ public class CustomDisplayRaytracer { } } - // 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); @@ -247,41 +221,33 @@ public class CustomDisplayRaytracer { } 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 + break; } - // 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); } diff --git a/src/main/java/me/trouper/trimserver/utils/visual/DisplayUtils.java b/src/main/java/me/trouper/trimserver/utils/visual/DisplayUtils.java index c5593e0..aa7f637 100755 --- a/src/main/java/me/trouper/trimserver/utils/visual/DisplayUtils.java +++ b/src/main/java/me/trouper/trimserver/utils/visual/DisplayUtils.java @@ -19,38 +19,38 @@ import java.util.function.Function; public class DisplayUtils implements Main { - public static void sphere(Location center, double radius, double verticalStep, double maxDistanceBetweenPoints, Consumer action) { - for (double yOffset = -radius; yOffset <= radius; yOffset += verticalStep) { - double horizontalRadius = Math.sqrt(radius * radius - yOffset * yOffset); + public static void sphere(Location center, double radius, double pointDistance, Consumer action) { + double dPhi = pointDistance / radius; - if (horizontalRadius < 0.01) { - Location point = center.clone().add(0, yOffset, 0); - action.accept(point); - continue; - } + for (double phi = 0.0; phi <= Math.PI; phi += dPhi) { + double yOffset = radius * Math.cos(phi); + double ringRadius = radius * Math.sin(phi); - double circumference = 2 * Math.PI * horizontalRadius; - int points = Math.max(4, (int) (circumference / maxDistanceBetweenPoints)); - double angleStep = 360.0 / points; + if (ringRadius < 1e-6) { + Location loc = center.clone().add(0, yOffset, 0); + action.accept(loc); + } else { + double dTheta = pointDistance / ringRadius; - for (int i = 0; i < points; i++) { - double theta = i * angleStep; - double x = Math.cos(Math.toRadians(theta)) * horizontalRadius; - double z = Math.sin(Math.toRadians(theta)) * horizontalRadius; - Location point = center.clone().add(x, yOffset, z); - action.accept(point); + for (double theta = 0.0; theta < 2 * Math.PI; theta += dTheta) { + double xOffset = ringRadius * Math.cos(theta); + double zOffset = ringRadius * Math.sin(theta); + + Location loc = center.clone().add(xOffset, yOffset, zOffset); + action.accept(loc); + } } } } - public static void sphereWave(Location center, double maxRadius, double radialStep, double verticalStep, double maxDistanceBetweenPoints, Consumer action) { + public static void sphereWave(Location center, double maxRadius, double radialStep, double maxDistanceBetweenPoints, Consumer action) { AtomicReference currentRadius = new AtomicReference<>(radialStep); Bukkit.getScheduler().scheduleSyncRepeatingTask(main.getPlugin(), () -> { double r = currentRadius.get(); if (r > maxRadius) return; - sphere(center, r, verticalStep, maxDistanceBetweenPoints, action); + sphere(center, r, maxDistanceBetweenPoints, action); currentRadius.set(r + radialStep); }, 0L, 1L); }