Made it follow combat and region restrictions
This commit is contained in:
@@ -84,6 +84,14 @@ public class AdminCommand implements QuickCommand {
|
|||||||
b.arg("test")
|
b.arg("test")
|
||||||
.then(
|
.then(
|
||||||
b.arg("vector")
|
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;
|
return false;
|
||||||
},(point,block) -> {
|
},(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);
|
DisplayUtils.DUST_PARTICLE_FACTORY.apply(Color.RED,1F).accept(loc);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,6 +114,16 @@ public class AdminCommand implements QuickCommand {
|
|||||||
return !p.equals(entity);
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ public class AbilityBackend implements Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AbstractAbility getAbility(Player player) {
|
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) {
|
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.
|
* Useful for admin commands or testing.
|
||||||
*
|
*
|
||||||
* @param player The player whose cooldown to reset
|
* @param player The player whose cooldown to reset
|
||||||
@@ -270,7 +272,7 @@ public class AbilityBackend implements Main {
|
|||||||
* Checks the ability flag at the useLocation
|
* Checks the ability flag at the useLocation
|
||||||
* @param player the player to check
|
* @param player the player to check
|
||||||
* @param useLocation the Bukkit location to check at
|
* @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) {
|
public boolean abilityAllowed(Player player, Location useLocation) {
|
||||||
LocalPlayer user = WorldGuardPlugin.inst().wrapPlayer(player);
|
LocalPlayer user = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ public class BoltAbility extends AbstractAbility implements Main {
|
|||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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);
|
drawLightning(caster.getEyeLocation(),target.getEyeLocation(),innerBlock,outerBlock);
|
||||||
target.damage(damage,DamageSource.builder(DamageType.LIGHTNING_BOLT).withDamageLocation(caster.getEyeLocation()).withDirectEntity(caster).build());
|
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());
|
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 ring = new SoundPlayer(end, Sound.ITEM_TRIDENT_THUNDER,10,1);
|
||||||
SoundPlayer zip = new SoundPlayer(end, Sound.ENTITY_BEE_STING,10,1);
|
SoundPlayer zip = new SoundPlayer(end, Sound.ENTITY_BEE_STING,10,1);
|
||||||
|
|
||||||
zip.playWithin(30 );
|
zip.playWithin(30);
|
||||||
bolt.playWithin(50);
|
bolt.playWithin(50);
|
||||||
ring.playWithin(30);
|
ring.playWithin(30);
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class CoastAbility extends AbstractAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Location centerLocation = TargetingUtils.findGroundLocation(castLocation);
|
Location centerLocation = TargetingUtils.findGroundLocation(castLocation);
|
||||||
|
if (!main.man().abilityBackend.abilityAllowed(player,centerLocation)) return;
|
||||||
World world = centerLocation.getWorld();
|
World world = centerLocation.getWorld();
|
||||||
|
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
|
|||||||
@@ -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.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.WormEvent;
|
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.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.Text;
|
import me.trouper.trimserver.utils.Text;
|
||||||
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
||||||
@@ -33,6 +34,7 @@ public class DuneAbility extends AbstractAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void spawnWormSign(Player owner, Location loc) {
|
private void spawnWormSign(Player owner, Location loc) {
|
||||||
|
if (!main.man().abilityBackend.abilityAllowed(owner,loc)) return;
|
||||||
AtomicInteger t = new AtomicInteger(0);
|
AtomicInteger t = new AtomicInteger(0);
|
||||||
Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(wave)->{
|
Bukkit.getScheduler().runTaskTimer(main.getPlugin(),(wave)->{
|
||||||
if (t.getAndIncrement() >= 25) {
|
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().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);
|
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));
|
liv.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS,20,4,true,false,false));
|
||||||
Vector pullDirection = loc.toVector().subtract(liv.getLocation().toVector()).normalize();
|
Vector pullDirection = loc.toVector().subtract(liv.getLocation().toVector()).normalize();
|
||||||
Vector pullVelocity = pullDirection.multiply(0.0015);
|
Vector pullVelocity = pullDirection.multiply(0.0015);
|
||||||
|
|||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
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.SoundPlayer;
|
||||||
import me.trouper.trimserver.utils.TargetingUtils;
|
import me.trouper.trimserver.utils.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer;
|
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) {
|
public Location laser(Player owner, Location start, Vector direction, double distance) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
||||||
|
|
||||||
return CustomDisplayRaytracer.trace(start,direction,distance,1,point ->{
|
return CustomDisplayRaytracer.trace(start,direction,distance,1,point ->{
|
||||||
SoundPlayer hissSound = new SoundPlayer(point.getLoc(), Sound.BLOCK_LAVA_EXTINGUISH, 1, 1);
|
SoundPlayer hissSound = new SoundPlayer(point.getLoc(), Sound.BLOCK_LAVA_EXTINGUISH, 1, 1);
|
||||||
List<Entity> targets = point.getNearbyEntities(owner,5,true,0.5, target -> target instanceof LivingEntity && !target.isDead() && !main.man().trustBackend.trusts(owner, (LivingEntity) target));
|
List<Entity> 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 -> {
|
targets.forEach(entity -> {
|
||||||
if (!(entity instanceof LivingEntity liv) || shaper.activeShellTasks.containsKey(liv.getUniqueId())) return;
|
if (!(entity instanceof LivingEntity liv) || shaper.activeShellTasks.containsKey(liv.getUniqueId())) return;
|
||||||
hissSound.playWithin(30);
|
hissSound.playWithin(30);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class FlowAbility extends AbstractAbility {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (System.currentTimeMillis() > endTime || !player.isOnline() ||
|
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);
|
endBreezeRide(player, breeze);
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
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.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.Text;
|
import me.trouper.trimserver.utils.Text;
|
||||||
import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer;
|
import me.trouper.trimserver.utils.visual.BlockDisplayRaytracer;
|
||||||
@@ -30,8 +31,8 @@ public class RaiserAbility extends AbstractAbility {
|
|||||||
|
|
||||||
private final Map<UUID, BukkitTask> levitationTasks = new HashMap<>();
|
private final Map<UUID, BukkitTask> levitationTasks = new HashMap<>();
|
||||||
|
|
||||||
public void raiseEntity(LivingEntity target) {
|
public void raiseEntity(Player caster, LivingEntity target) {
|
||||||
if (target == null) return;
|
if (target == null || !PlayerUtils.combatAllowed(target,caster)) return;
|
||||||
|
|
||||||
UUID uuid = target.getUniqueId();
|
UUID uuid = target.getUniqueId();
|
||||||
|
|
||||||
@@ -45,21 +46,17 @@ public class RaiserAbility extends AbstractAbility {
|
|||||||
int frequency = 2;
|
int frequency = 2;
|
||||||
int duration = 20 * 7;
|
int duration = 20 * 7;
|
||||||
|
|
||||||
// --- Start Up Effects ---
|
|
||||||
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.8f, 1.0f);
|
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);
|
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);
|
DisplayUtils.wave(target.getLocation(),2,Color.WHITE,1,0.1);
|
||||||
// Give an initial upward push
|
|
||||||
target.setVelocity(new Vector(0, 0.4, 0));
|
target.setVelocity(new Vector(0, 0.4, 0));
|
||||||
|
|
||||||
// --- The Main Repeating Task (Holding, Checking, Effects) ---
|
|
||||||
BukkitTask task = new BukkitRunnable() {
|
BukkitTask task = new BukkitRunnable() {
|
||||||
int ticksElapsed = 0;
|
int ticksElapsed = 0;
|
||||||
final int durationTicks = duration / frequency;
|
final int durationTicks = duration / frequency;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Check if player is still valid and online
|
|
||||||
if (target.isDead()) {
|
if (target.isDead()) {
|
||||||
endLevitation(uuid);
|
endLevitation(uuid);
|
||||||
return;
|
return;
|
||||||
@@ -68,20 +65,17 @@ public class RaiserAbility extends AbstractAbility {
|
|||||||
Location currentLocation = target.getLocation();
|
Location currentLocation = target.getLocation();
|
||||||
double currentHealth = target.getHealth();
|
double currentHealth = target.getHealth();
|
||||||
|
|
||||||
// --- Check Conditions to End ---
|
|
||||||
// 1. Health threshold reached
|
|
||||||
if (currentHealth <= healthThreshold) {
|
if (currentHealth <= healthThreshold) {
|
||||||
endLevitation(uuid);
|
endLevitation(uuid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Time limit reached
|
|
||||||
if (ticksElapsed >= durationTicks) {
|
if (ticksElapsed >= durationTicks) {
|
||||||
endLevitation(uuid);
|
endLevitation(uuid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Hold Player at Target Height ---
|
|
||||||
if (currentLocation.getY() >= targetY) {
|
if (currentLocation.getY() >= targetY) {
|
||||||
Vector currentVelocity = target.getVelocity();
|
Vector currentVelocity = target.getVelocity();
|
||||||
target.setVelocity(new Vector(currentVelocity.getX(), 0, currentVelocity.getZ()));
|
target.setVelocity(new Vector(currentVelocity.getX(), 0, currentVelocity.getZ()));
|
||||||
@@ -144,7 +138,12 @@ public class RaiserAbility extends AbstractAbility {
|
|||||||
public boolean amethystAbility(Player player) {
|
public boolean amethystAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean copperAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean diamondAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean emeraldAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean goldAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean ironAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean lapisAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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
|
@Override
|
||||||
public boolean netheriteAbility(Player player) {
|
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)
|
@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) {
|
public boolean quartzAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean redstoneAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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)
|
@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) {
|
public boolean resinAbility(Player player) {
|
||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,11 @@ import org.bukkit.inventory.meta.trim.TrimPattern;
|
|||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.util.BoundingBox;
|
|
||||||
import org.bukkit.util.Transformation;
|
import org.bukkit.util.Transformation;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
import org.joml.Quaternionf;
|
|
||||||
|
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -36,7 +33,7 @@ public class RibAbility extends AbstractAbility {
|
|||||||
super(TrimPattern.RIB);
|
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);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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.STRENGTH,10*20,1,true));
|
||||||
caster.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION,5*20,2,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.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.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);
|
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.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,20*20,1,true,false,false));
|
||||||
target.setFireTicks(20*20);
|
target.setFireTicks(20*20);
|
||||||
});
|
});
|
||||||
@@ -103,8 +105,10 @@ public class RibAbility extends AbstractAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final Location finalSpikeBase = groundSurfaceLoc.clone();
|
final Location finalSpikeBase = groundSurfaceLoc.clone(); // BOTTOM
|
||||||
final Location spikeTipLoc = finalSpikeBase.clone().add(0, spikeVisualHeight, 0);
|
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 -> {
|
BlockDisplay spikeDisplay = world.spawn(finalSpikeBase, BlockDisplay.class, bd -> {
|
||||||
bd.setBlock(spikeBlockData);
|
bd.setBlock(spikeBlockData);
|
||||||
@@ -204,77 +208,77 @@ public class RibAbility extends AbstractAbility {
|
|||||||
@MaterialInfo(name = "Eruption (Amethyst)", description = "Erupts spikes of amethyst", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Amethyst)", description = "Erupts spikes of amethyst", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean amethystAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Copper)", description = "Erupts spikes of oxidized copper", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Copper)", description = "Erupts spikes of oxidized copper", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean copperAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Diamond)", description = "Erupts spikes of diamond", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Diamond)", description = "Erupts spikes of diamond", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean diamondAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Emerald)", description = "Erupts spikes of emerald", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Emerald)", description = "Erupts spikes of emerald", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean emeraldAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Gold)", description = "Erupts spikes of gold", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Gold)", description = "Erupts spikes of gold", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean goldAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Iron)", description = "Erupts spikes of iron", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Iron)", description = "Erupts spikes of iron", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean ironAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Lapis)", description = "Erupts spikes of lapis", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Lapis)", description = "Erupts spikes of lapis", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean lapisAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Netherite)", description = "Erupts deadly blackstone spikes", cooldownTicks = 20 * 20)
|
@MaterialInfo(name = "Eruption (Netherite)", description = "Erupts deadly blackstone spikes", cooldownTicks = 20 * 20)
|
||||||
@Override
|
@Override
|
||||||
public boolean netheriteAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Quartz)", description = "Erupts spikes of quartz", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Quartz)", description = "Erupts spikes of quartz", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean quartzAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Redstone)", description = "Erupts energized redstone spikes", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Redstone)", description = "Erupts energized redstone spikes", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean redstoneAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MaterialInfo(name = "Eruption (Resin)", description = "Erupts spikes of hardened resin from the ground", cooldownTicks = 20 * 30)
|
@MaterialInfo(name = "Eruption (Resin)", description = "Erupts spikes of hardened resin from the ground", cooldownTicks = 20 * 30)
|
||||||
@Override
|
@Override
|
||||||
public boolean resinAbility(Player player) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
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.SoundPlayer;
|
||||||
import me.trouper.trimserver.utils.TargetingUtils;
|
import me.trouper.trimserver.utils.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.Text;
|
import me.trouper.trimserver.utils.Text;
|
||||||
@@ -41,7 +42,6 @@ public class SentryAbility extends AbstractAbility {
|
|||||||
Location spawn = loc.clone().subtract(0,2,0);
|
Location spawn = loc.clone().subtract(0,2,0);
|
||||||
List<Entity> turretParts = new ArrayList<>();
|
List<Entity> 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 -> {
|
BlockDisplay turret = w.spawn(spawn.clone().add(0.5, 1.5, 0.5), BlockDisplay.class, display -> {
|
||||||
display.setBlock(turretMat.createBlockData());
|
display.setBlock(turretMat.createBlockData());
|
||||||
display.setBrightness(new Display.Brightness(15, 15));
|
display.setBrightness(new Display.Brightness(15, 15));
|
||||||
@@ -49,11 +49,8 @@ public class SentryAbility extends AbstractAbility {
|
|||||||
display.setInterpolationDuration(2);
|
display.setInterpolationDuration(2);
|
||||||
display.addScoreboardTag("$/TrimServer/ Temp");
|
display.addScoreboardTag("$/TrimServer/ Temp");
|
||||||
|
|
||||||
// Get the current transformation
|
|
||||||
Transformation transformation = display.getTransformation();
|
Transformation transformation = display.getTransformation();
|
||||||
// Set the translation to center the pivot point
|
|
||||||
transformation.getTranslation().set(-0.5f, -0.5f, -0.5f);
|
transformation.getTranslation().set(-0.5f, -0.5f, -0.5f);
|
||||||
// Apply the modified transformation back to the display
|
|
||||||
display.setTransformation(transformation);
|
display.setTransformation(transformation);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -69,9 +66,8 @@ public class SentryAbility extends AbstractAbility {
|
|||||||
|
|
||||||
turretParts.add(dummy);
|
turretParts.add(dummy);
|
||||||
|
|
||||||
// 2) Legs: four converging from a 1×1 square around base up to head-pole
|
|
||||||
double legHeight = 1.5;
|
double legHeight = 1.5;
|
||||||
double halfSize = 0.6; // distance from center
|
double halfSize = 0.6;
|
||||||
List<BlockDisplay> stand = new ArrayList<>();
|
List<BlockDisplay> stand = new ArrayList<>();
|
||||||
for (double dx : new double[]{ -halfSize, +halfSize }) {
|
for (double dx : new double[]{ -halfSize, +halfSize }) {
|
||||||
for (double dz : new double[]{ -halfSize, +halfSize }) {
|
for (double dz : new double[]{ -halfSize, +halfSize }) {
|
||||||
@@ -90,7 +86,6 @@ public class SentryAbility extends AbstractAbility {
|
|||||||
|
|
||||||
turretParts.addAll(stand);
|
turretParts.addAll(stand);
|
||||||
|
|
||||||
// 3) Ammo display above head
|
|
||||||
TextDisplay meter = w.spawn(spawn.clone().add(0.5, 2.5, 0.5), TextDisplay.class, t -> {
|
TextDisplay meter = w.spawn(spawn.clone().add(0.5, 2.5, 0.5), TextDisplay.class, t -> {
|
||||||
t.setBillboard(Display.Billboard.CENTER);
|
t.setBillboard(Display.Billboard.CENTER);
|
||||||
t.setRotation(0, 90);
|
t.setRotation(0, 90);
|
||||||
@@ -116,7 +111,11 @@ public class SentryAbility extends AbstractAbility {
|
|||||||
String bar = Text.generateProgressBar(10, maxAmmo, chamber);
|
String bar = Text.generateProgressBar(10, maxAmmo, chamber);
|
||||||
meter.text(Text.color("%s's Sentry\n".formatted(owner.getName()) + "Ammo " + bar));
|
meter.text(Text.color("%s's Sentry\n".formatted(owner.getName()) + "Ammo " + bar));
|
||||||
|
|
||||||
Optional<Player> target = TargetingUtils.getClosestPlayer(finalLoc,15,p -> !p.isDead() && !p.equals(owner) && !main.man().trustBackend.trusts(owner,p) && !shaper.activeShellTasks.containsKey(p.getUniqueId()));
|
Optional<Player> 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()) {
|
if (target.isPresent()) {
|
||||||
Player tracked = target.get();
|
Player tracked = target.get();
|
||||||
|
|||||||
@@ -53,7 +53,14 @@ public class SilenceAbility extends AbstractAbility {
|
|||||||
|
|
||||||
CustomDisplayRaytracer.traceWithReflection(chestLocation,direction,30,0.5,4,point->{
|
CustomDisplayRaytracer.traceWithReflection(chestLocation,direction,30,0.5,4,point->{
|
||||||
point.getWorld().spawnParticle(Particle.SONIC_BOOM, point.getLoc(), 1, 0, 0, 0, 0);
|
point.getWorld().spawnParticle(Particle.SONIC_BOOM, point.getLoc(), 1, 0, 0, 0, 0);
|
||||||
List<Entity> 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<Entity> 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 -> {
|
targets.forEach(target -> {
|
||||||
PlayerUtils.dealTrueDamage((LivingEntity) target, DamageSource.builder(DamageType.SONIC_BOOM).withDirectEntity(player).build(), 10);
|
PlayerUtils.dealTrueDamage((LivingEntity) target, DamageSource.builder(DamageType.SONIC_BOOM).withDirectEntity(player).build(), 10);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
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.SoundPlayer;
|
||||||
import me.trouper.trimserver.utils.TargetingUtils;
|
import me.trouper.trimserver.utils.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
||||||
@@ -30,7 +31,7 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
private final Map<UUID, List<Entity>> activeSpires = new HashMap<>();
|
private final Map<UUID, List<Entity>> activeSpires = new HashMap<>();
|
||||||
private final Map<UUID, BukkitTask> activeTasks = new HashMap<>();
|
private final Map<UUID, BukkitTask> activeTasks = new HashMap<>();
|
||||||
private final Set<UUID> activeProjectiles = new HashSet<>();
|
private final Map<UUID, UUID> activeProjectiles = new HashMap<>();
|
||||||
|
|
||||||
public SpireAbility() {
|
public SpireAbility() {
|
||||||
super(TrimPattern.SPIRE);
|
super(TrimPattern.SPIRE);
|
||||||
@@ -40,7 +41,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
||||||
|
|
||||||
// Cancel any existing spire for this player
|
|
||||||
if (activeTasks.containsKey(player.getUniqueId())) {
|
if (activeTasks.containsKey(player.getUniqueId())) {
|
||||||
activeTasks.get(player.getUniqueId()).cancel();
|
activeTasks.get(player.getUniqueId()).cancel();
|
||||||
activeTasks.remove(player.getUniqueId());
|
activeTasks.remove(player.getUniqueId());
|
||||||
@@ -57,18 +57,14 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
Location baseLoc = player.getLocation().clone();
|
Location baseLoc = player.getLocation().clone();
|
||||||
Location topLoc = baseLoc.clone().add(0, spireHeight, 0);
|
Location topLoc = baseLoc.clone().add(0, spireHeight, 0);
|
||||||
|
|
||||||
// Store entities for cleanup
|
|
||||||
List<Entity> entities = new ArrayList<>();
|
List<Entity> entities = new ArrayList<>();
|
||||||
activeSpires.put(player.getUniqueId(), entities);
|
activeSpires.put(player.getUniqueId(), entities);
|
||||||
|
|
||||||
// Start with initial effects
|
|
||||||
SoundPlayer startSound = new SoundPlayer(baseLoc, Sound.BLOCK_END_PORTAL_SPAWN, 1.0f, 0.8f);
|
SoundPlayer startSound = new SoundPlayer(baseLoc, Sound.BLOCK_END_PORTAL_SPAWN, 1.0f, 0.8f);
|
||||||
startSound.playWithin(10);
|
startSound.playWithin(10);
|
||||||
|
|
||||||
// Create the blocks for the spire (cone shape)
|
|
||||||
createSpireStructure(player, baseLoc, spireHeight, material, entities);
|
createSpireStructure(player, baseLoc, spireHeight, material, entities);
|
||||||
|
|
||||||
// Teleport player to the top
|
|
||||||
Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> {
|
Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> {
|
||||||
Bat dummy = world.spawn(topLoc.clone().add(0.5,0,0.5),Bat.class,(bat)->{
|
Bat dummy = world.spawn(topLoc.clone().add(0.5,0,0.5),Bat.class,(bat)->{
|
||||||
bat.setAI(false);
|
bat.setAI(false);
|
||||||
@@ -80,18 +76,14 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
dummy.addPassenger(player);
|
dummy.addPassenger(player);
|
||||||
}, 10L);
|
}, 10L);
|
||||||
|
|
||||||
// Create the barrier sphere
|
double sphereRadius = spireHeight * 1.25;
|
||||||
double sphereRadius = spireHeight * 0.75;
|
|
||||||
|
|
||||||
// Create initial sphere particle effect
|
|
||||||
Color sphereColor = getColor(material);
|
Color sphereColor = getColor(material);
|
||||||
Consumer<Location> particleAction = DisplayUtils.DUST_PARTICLE_FACTORY.apply(sphereColor, 1.2f);
|
Consumer<Location> particleAction = DisplayUtils.DUST_PARTICLE_FACTORY.apply(sphereColor, 1.2f);
|
||||||
|
|
||||||
// Create expanding sphere effect
|
|
||||||
DisplayUtils.sphereWave(baseLoc.clone().add(0, sphereRadius/2, 0),
|
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() {
|
BukkitTask task = new BukkitRunnable() {
|
||||||
final long endTime = System.currentTimeMillis() + (duration * 1000L);
|
final long endTime = System.currentTimeMillis() + (duration * 1000L);
|
||||||
int tickCounter = 0;
|
int tickCounter = 0;
|
||||||
@@ -99,7 +91,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Check if ability should end
|
|
||||||
if (System.currentTimeMillis() > endTime || !player.isOnline()) {
|
if (System.currentTimeMillis() > endTime || !player.isOnline()) {
|
||||||
endEnderStorm(player);
|
endEnderStorm(player);
|
||||||
cancel();
|
cancel();
|
||||||
@@ -108,15 +99,16 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
tickCounter++;
|
tickCounter++;
|
||||||
|
|
||||||
// Every 10 ticks, refresh the sphere particles
|
|
||||||
if (tickCounter % 10 == 0) {
|
if (tickCounter % 10 == 0) {
|
||||||
DisplayUtils.sphere(sphereCenter, sphereRadius, 1.0, 1.0, loc ->
|
DisplayUtils.sphere(sphereCenter, sphereRadius, 2, loc -> {
|
||||||
world.spawnParticle(Particle.PORTAL, loc, 1, 0, 0, 0, 0));
|
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) {
|
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);
|
double distanceFromCenter = target.getLocation().distance(sphereCenter);
|
||||||
if (distanceFromCenter > sphereRadius * 0.8) {
|
if (distanceFromCenter > sphereRadius * 0.8) {
|
||||||
Vector pushDirection = sphereCenter.clone()
|
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) {
|
if (tickCounter % 15 == 0) {
|
||||||
List<Player> targets = world.getNearbyEntities(sphereCenter, sphereRadius, sphereRadius, sphereRadius).stream()
|
List<Player> 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)
|
.map(entity -> (Player) entity)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@@ -144,17 +139,19 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
ShulkerBullet bullet = (ShulkerBullet) world.spawnEntity(fireLocation, EntityType.SHULKER_BULLET);
|
ShulkerBullet bullet = (ShulkerBullet) world.spawnEntity(fireLocation, EntityType.SHULKER_BULLET);
|
||||||
bullet.setTarget(target);
|
bullet.setTarget(target);
|
||||||
activeProjectiles.add(bullet.getUniqueId());
|
bullet.setShooter(player);
|
||||||
|
activeProjectiles.put(bullet.getUniqueId(),player.getUniqueId());
|
||||||
|
|
||||||
world.spawnParticle(Particle.END_ROD, fireLocation,
|
world.spawnParticle(Particle.END_ROD, fireLocation,
|
||||||
10, 0.2, 0.2, 0.2, 0.1);
|
10, 0.2, 0.2, 0.2, 0.1);
|
||||||
SoundPlayer bulletSound = new SoundPlayer(fireLocation, Sound.ENTITY_SHULKER_SHOOT, 1.0f, 1.0f);
|
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);
|
bulletSound.playWithin(20);
|
||||||
|
bulletSound2.playWithin(20);
|
||||||
entities.add(bullet);
|
entities.add(bullet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every 20 ticks, create some ambient particles around the spire
|
|
||||||
if (tickCounter % 10 == 0) {
|
if (tickCounter % 10 == 0) {
|
||||||
for (int y = 0; y < spireHeight; y += 2) {
|
for (int y = 0; y < spireHeight; y += 2) {
|
||||||
Location particleLoc = baseLoc.clone().add(0, y, 0);
|
Location particleLoc = baseLoc.clone().add(0, y, 0);
|
||||||
@@ -187,12 +184,10 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
World world = player.getWorld();
|
World world = player.getWorld();
|
||||||
BlockData blockData = material.createBlockData();
|
BlockData blockData = material.createBlockData();
|
||||||
|
|
||||||
// Create the main spire body (cone shape)
|
// Spire Cone
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
// Calculate radius at this height (decreasing as y increases)
|
|
||||||
double radius = 2.0 * (1 - y / (double) height);
|
double radius = 2.0 * (1 - y / (double) height);
|
||||||
|
|
||||||
// Create circle of blocks
|
|
||||||
if (radius > 0.1) {
|
if (radius > 0.1) {
|
||||||
int blocks = Math.max(4, (int) (2 * Math.PI * radius / 0.5));
|
int blocks = Math.max(4, (int) (2 * Math.PI * radius / 0.5));
|
||||||
double angleStep = 360.0 / blocks;
|
double angleStep = 360.0 / blocks;
|
||||||
@@ -204,7 +199,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
Location blockLoc = baseLoc.clone().add(x, y, z);
|
Location blockLoc = baseLoc.clone().add(x, y, z);
|
||||||
|
|
||||||
// Create Block Display
|
|
||||||
BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> {
|
BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> {
|
||||||
b.setBlock(blockData);
|
b.setBlock(blockData);
|
||||||
b.setBrightness(new Display.Brightness(15, 15));
|
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;
|
double topRadius = 1;
|
||||||
int platformBlocks = 12;
|
int platformBlocks = 12;
|
||||||
double angleStep = 360.0 / platformBlocks;
|
double angleStep = 360.0 / platformBlocks;
|
||||||
@@ -234,7 +228,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
Location blockLoc = baseLoc.clone().add(x-1, height, z);
|
Location blockLoc = baseLoc.clone().add(x-1, height, z);
|
||||||
|
|
||||||
// Create Block Display for platform
|
|
||||||
BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> {
|
BlockDisplay display = world.spawn(blockLoc, BlockDisplay.class, b -> {
|
||||||
b.setBlock(blockData);
|
b.setBlock(blockData);
|
||||||
b.setBrightness(new Display.Brightness(15, 15));
|
b.setBrightness(new Display.Brightness(15, 15));
|
||||||
@@ -245,7 +238,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
entities.add(display);
|
entities.add(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create center block for platform
|
|
||||||
BlockDisplay centerDisplay = world.spawn(baseLoc.clone().add(0, height, 0), BlockDisplay.class, b -> {
|
BlockDisplay centerDisplay = world.spawn(baseLoc.clone().add(0, height, 0), BlockDisplay.class, b -> {
|
||||||
b.setBlock(blockData);
|
b.setBlock(blockData);
|
||||||
b.setBrightness(new Display.Brightness(15, 15));
|
b.setBrightness(new Display.Brightness(15, 15));
|
||||||
@@ -254,28 +246,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
entities.add(centerDisplay);
|
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);
|
AtomicInteger animStep = new AtomicInteger(0);
|
||||||
BukkitTask animTask = new BukkitRunnable() {
|
BukkitTask animTask = new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -286,7 +256,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rising particles
|
|
||||||
for (int y = 0; y < step * height / 10; y++) {
|
for (int y = 0; y < step * height / 10; y++) {
|
||||||
Location particleLoc = baseLoc.clone().add(0, y, 0);
|
Location particleLoc = baseLoc.clone().add(0, y, 0);
|
||||||
world.spawnParticle(Particle.END_ROD, particleLoc,
|
world.spawnParticle(Particle.END_ROD, particleLoc,
|
||||||
@@ -299,8 +268,6 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTaskTimer(main.getPlugin(), 0L, 2L);
|
}.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) {
|
private void endEnderStorm(Player player) {
|
||||||
@@ -312,12 +279,10 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
if (activeSpires.containsKey(player.getUniqueId())) {
|
if (activeSpires.containsKey(player.getUniqueId())) {
|
||||||
List<Entity> entities = activeSpires.get(player.getUniqueId());
|
List<Entity> entities = activeSpires.get(player.getUniqueId());
|
||||||
|
|
||||||
// Create disintegration effect
|
|
||||||
if (!entities.isEmpty()) {
|
if (!entities.isEmpty()) {
|
||||||
Location baseLoc = entities.get(0).getLocation();
|
Location baseLoc = entities.get(0).getLocation();
|
||||||
World world = baseLoc.getWorld();
|
World world = baseLoc.getWorld();
|
||||||
|
|
||||||
// Disintegration particles
|
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
if (entity instanceof Display) {
|
if (entity instanceof Display) {
|
||||||
Location loc = entity.getLocation();
|
Location loc = entity.getLocation();
|
||||||
@@ -340,35 +305,37 @@ public class SpireAbility extends AbstractAbility {
|
|||||||
|
|
||||||
private Color getColor(Material material) {
|
private Color getColor(Material material) {
|
||||||
return switch (material) {
|
return switch (material) {
|
||||||
case AMETHYST_BLOCK -> Color.fromRGB(137, 0, 201);
|
case AMETHYST_BLOCK -> Color.fromRGB(0x8900C9);
|
||||||
case COPPER_BLOCK -> Color.fromRGB(184, 115, 51);
|
case COPPER_BLOCK -> Color.fromRGB(0xB87333);
|
||||||
case DIAMOND_BLOCK -> Color.fromRGB(51, 235, 203);
|
case DIAMOND_BLOCK -> Color.fromRGB(0x33EBCB);
|
||||||
case EMERALD_BLOCK -> Color.fromRGB(0, 217, 58);
|
case EMERALD_BLOCK -> Color.fromRGB(0x00D93A);
|
||||||
case GOLD_BLOCK -> Color.fromRGB(255, 230, 0);
|
case GOLD_BLOCK -> Color.fromRGB(0xFFE600);
|
||||||
case IRON_BLOCK -> Color.fromRGB(216, 216, 216);
|
case IRON_BLOCK -> Color.fromRGB(0xD8D8D8);
|
||||||
case LAPIS_BLOCK -> Color.fromRGB(0, 85, 255);
|
case LAPIS_BLOCK -> Color.fromRGB(0x0055FF);
|
||||||
case NETHERITE_BLOCK -> Color.fromRGB(66, 66, 76);
|
case NETHERITE_BLOCK -> Color.fromRGB(0x42424C);
|
||||||
case QUARTZ_BLOCK -> Color.fromRGB(225, 225, 225);
|
case QUARTZ_BLOCK -> Color.fromRGB(0xE1E1E1);
|
||||||
case REDSTONE_BLOCK -> Color.fromRGB(255, 0, 0);
|
case REDSTONE_BLOCK -> Color.fromRGB(0xFF0000);
|
||||||
case RESIN_BLOCK -> Color.fromRGB(239, 195, 134);
|
case RESIN_BLOCK -> Color.fromRGB(0xEFC386);
|
||||||
default -> Color.fromRGB(128, 0, 128);
|
default -> Color.fromRGB(0x800080);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onProjectileHit(ProjectileHitEvent event) {
|
public void onProjectileHit(ProjectileHitEvent event) {
|
||||||
if (event.getEntity() instanceof ShulkerBullet bullet) {
|
if (!(event.getEntity() instanceof ShulkerBullet bullet)) return;
|
||||||
if (activeProjectiles.contains(bullet.getUniqueId())) {
|
if (!activeProjectiles.containsKey(bullet.getUniqueId())) return;
|
||||||
activeProjectiles.remove(bullet.getUniqueId());
|
if (event.getHitEntity() != null && PlayerUtils.combatAllowed(event.getHitEntity(),Bukkit.getPlayer(activeProjectiles.get(bullet.getUniqueId())))) {
|
||||||
|
event.setCancelled(true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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)
|
@MaterialInfo(name = "Amethyst Ender Storm", description = "Summon a spire that traps players and fires shulker bullets", cooldownTicks = 20*90)
|
||||||
|
|||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
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.SoundPlayer;
|
||||||
import me.trouper.trimserver.utils.TargetingUtils;
|
import me.trouper.trimserver.utils.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
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->{
|
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());
|
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);
|
SoundPlayer blockSound = new SoundPlayer(target.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 0.5F);
|
||||||
Vector dir = target.getLocation().toVector().subtract(caster.getLocation().toVector()).normalize();
|
Vector dir = target.getLocation().toVector().subtract(caster.getLocation().toVector()).normalize();
|
||||||
double strength = 0.5;
|
double strength = 0.5;
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ public class WardAbility extends AbstractAbility {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// spawn and configure warden
|
|
||||||
Warden warden = (Warden) player.getWorld().spawnEntity(player.getLocation().subtract(0,3,0), EntityType.WARDEN, CreatureSpawnEvent.SpawnReason.NATURAL);
|
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());
|
Verbose.send( "Spawned Warden entity %s for %s", warden.getUniqueId(), player.getName());
|
||||||
warden.setAI(false);
|
warden.setAI(false);
|
||||||
|
|||||||
@@ -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.MaterialInfo;
|
||||||
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
import me.trouper.trimserver.server.systems.abilities.AbstractAbility;
|
||||||
import me.trouper.trimserver.server.systems.abilities.PatternInfo;
|
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.SoundPlayer;
|
||||||
import me.trouper.trimserver.utils.TargetingUtils;
|
import me.trouper.trimserver.utils.TargetingUtils;
|
||||||
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
import me.trouper.trimserver.utils.visual.DisplayUtils;
|
||||||
@@ -63,7 +64,11 @@ public class WayfinderAbility extends AbstractAbility {
|
|||||||
block.setCancelDrop(true);
|
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);
|
SoundPlayer hit = new SoundPlayer(target.getLocation(), Sound.ENTITY_EVOKER_FANGS_ATTACK, 1, 2);
|
||||||
Vector direction = target.getLocation().toVector().subtract(caster.getEyeLocation().toVector()).normalize();
|
Vector direction = target.getLocation().toVector().subtract(caster.getEyeLocation().toVector()).normalize();
|
||||||
target.setVelocity(direction.multiply(0.5).setY(0.3));
|
target.setVelocity(direction.multiply(0.5).setY(0.3));
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class WildAbility extends AbstractAbility {
|
|||||||
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
AbstractAbility shaperInstance = main.man().abilityBackend.getAbility(TrimPattern.SHAPER);
|
||||||
ShaperAbility shaper = (ShaperAbility) shaperInstance;
|
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 (shaper.activeShellTasks.containsKey(target.getUniqueId())) return;
|
||||||
if (caster.getWorld() != target.getWorld()) return;
|
if (caster.getWorld() != target.getWorld()) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package me.trouper.trimserver.utils;
|
package me.trouper.trimserver.utils;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldguard.LocalPlayer;
|
import com.sk89q.worldguard.LocalPlayer;
|
||||||
import com.sk89q.worldguard.WorldGuard;
|
import com.sk89q.worldguard.WorldGuard;
|
||||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||||
@@ -9,6 +10,7 @@ import com.sk89q.worldguard.protection.regions.RegionQuery;
|
|||||||
import me.trouper.trimserver.server.Main;
|
import me.trouper.trimserver.server.Main;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.damage.DamageSource;
|
import org.bukkit.damage.DamageSource;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
@@ -85,15 +87,32 @@ public class PlayerUtils implements Main {
|
|||||||
|
|
||||||
public static void dealTrueDamage(LivingEntity target, DamageSource source, double amount) {
|
public static void dealTrueDamage(LivingEntity target, DamageSource source, double amount) {
|
||||||
if (source.getDirectEntity() instanceof Player a && target instanceof Player t && !combatAllowed(t,a)) return;
|
if (source.getDirectEntity() instanceof Player a && target instanceof Player t && !combatAllowed(t,a)) return;
|
||||||
double newHealth = target.getHealth() - amount;
|
|
||||||
target.damage(1, source);
|
target.damage(1, source);
|
||||||
|
|
||||||
|
double newHealth = target.getHealth() - amount;
|
||||||
if (newHealth <= 0) {
|
if (newHealth <= 0) {
|
||||||
target.setHealth(0);
|
target.setHealth(0);
|
||||||
} else {
|
} else {
|
||||||
target.setHealth(newHealth);
|
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) {
|
public static boolean combatAllowed(Player v, Player a) {
|
||||||
LocalPlayer victim = WorldGuardPlugin.inst().wrapPlayer(v);
|
LocalPlayer victim = WorldGuardPlugin.inst().wrapPlayer(v);
|
||||||
LocalPlayer attacker = WorldGuardPlugin.inst().wrapPlayer(a);
|
LocalPlayer attacker = WorldGuardPlugin.inst().wrapPlayer(a);
|
||||||
@@ -101,10 +120,31 @@ public class PlayerUtils implements Main {
|
|||||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||||
RegionQuery query = container.createQuery();
|
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.");
|
main.warning(a,"You cannot attack players protected by regions.");
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,24 +171,6 @@ public class CustomDisplayRaytracer {
|
|||||||
BiPredicate<Point, Block> blockReflectCondition,
|
BiPredicate<Point, Block> blockReflectCondition,
|
||||||
BiPredicate<Point, Entity> entityReflectCondition) {
|
BiPredicate<Point, Entity> 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 (interval <= 0) throw new IllegalArgumentException("interval cannot be zero or negative!");
|
||||||
if (distance <= 0) throw new IllegalArgumentException("distance 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;
|
int reflections = 0;
|
||||||
|
|
||||||
while (remainingDistance > 0 && reflections <= maxReflections) {
|
while (remainingDistance > 0 && reflections <= maxReflections) {
|
||||||
// Trace along the current ray direction
|
|
||||||
for (double i = 0.0; i < remainingDistance; i += interval) {
|
for (double i = 0.0; i < remainingDistance; i += interval) {
|
||||||
Point point = blocksInFrontOf(currentLocation, currentDirection, i, false);
|
Point point = blocksInFrontOf(currentLocation, currentDirection, i, false);
|
||||||
|
|
||||||
// Check if the hit condition is satisfied
|
|
||||||
if (hitCondition.test(point)) {
|
if (hitCondition.test(point)) {
|
||||||
return point; // Hit condition met, return the hit point
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for potential reflection
|
|
||||||
boolean shouldReflect = false;
|
boolean shouldReflect = false;
|
||||||
Vector newDirection = null;
|
Vector newDirection = null;
|
||||||
|
|
||||||
// Check if point hits a block for reflection
|
|
||||||
if (HIT_BLOCK.test(point) && point.getBlock() != null) {
|
if (HIT_BLOCK.test(point) && point.getBlock() != null) {
|
||||||
Block hitBlock = point.getBlock();
|
Block hitBlock = point.getBlock();
|
||||||
if (blockReflectCondition.test(point, hitBlock)) {
|
if (blockReflectCondition.test(point, hitBlock)) {
|
||||||
// Step back slightly to get accurate reflection
|
|
||||||
Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false);
|
Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false);
|
||||||
|
|
||||||
// Determine which face was hit
|
|
||||||
BlockFace hitFace = traceBlockFace(previousPoint.getLoc(), currentDirection, interval * 2);
|
BlockFace hitFace = traceBlockFace(previousPoint.getLoc(), currentDirection, interval * 2);
|
||||||
|
|
||||||
if (hitFace != null) {
|
if (hitFace != null) {
|
||||||
@@ -231,12 +207,10 @@ public class CustomDisplayRaytracer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if point hits an entity for reflection
|
|
||||||
List<Entity> nearbyEntities = point.getNearbyEntities(null, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead());
|
List<Entity> nearbyEntities = point.getNearbyEntities(null, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead());
|
||||||
if (!nearbyEntities.isEmpty()) {
|
if (!nearbyEntities.isEmpty()) {
|
||||||
for (Entity entity : nearbyEntities) {
|
for (Entity entity : nearbyEntities) {
|
||||||
if (entityReflectCondition.test(point, entity)) {
|
if (entityReflectCondition.test(point, entity)) {
|
||||||
// Step back slightly for glancing reflection
|
|
||||||
Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false);
|
Point previousPoint = blocksInFrontOf(currentLocation, currentDirection, Math.max(0, i - interval), false);
|
||||||
|
|
||||||
newDirection = glanceReflect(currentDirection);
|
newDirection = glanceReflect(currentDirection);
|
||||||
@@ -247,41 +221,33 @@ public class CustomDisplayRaytracer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shouldReflect) {
|
if (shouldReflect) {
|
||||||
// Update current location to point before collision
|
|
||||||
double backStep = Math.max(0, i - interval);
|
double backStep = Math.max(0, i - interval);
|
||||||
currentLocation = blocksInFrontOf(currentLocation, currentDirection, backStep, false).getLoc();
|
currentLocation = blocksInFrontOf(currentLocation, currentDirection, backStep, false).getLoc();
|
||||||
|
|
||||||
// Update direction to reflection direction
|
|
||||||
currentDirection = newDirection;
|
currentDirection = newDirection;
|
||||||
|
|
||||||
// Update remaining distance
|
|
||||||
remainingDistance -= backStep;
|
remainingDistance -= backStep;
|
||||||
|
|
||||||
// Increment reflection counter
|
|
||||||
reflections++;
|
reflections++;
|
||||||
|
|
||||||
// Skip a small amount to prevent immediate reflection off the same object
|
|
||||||
currentLocation = currentLocation.add(currentDirection.clone().multiply(interval * 0.1));
|
currentLocation = currentLocation.add(currentDirection.clone().multiply(interval * 0.1));
|
||||||
remainingDistance -= 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) {
|
if (i + interval >= remainingDistance) {
|
||||||
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
|
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
|
||||||
return finalPoint;
|
return finalPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've used all reflections but didn't reach the hit condition
|
|
||||||
if (reflections > maxReflections) {
|
if (reflections > maxReflections) {
|
||||||
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
|
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
|
||||||
return finalPoint;
|
return finalPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should only reach here if we've exhausted all distance
|
|
||||||
return blocksInFrontOf(start, normalizedDir, distance, true);
|
return blocksInFrontOf(start, normalizedDir, distance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,38 +19,38 @@ import java.util.function.Function;
|
|||||||
public class DisplayUtils implements Main {
|
public class DisplayUtils implements Main {
|
||||||
|
|
||||||
|
|
||||||
public static void sphere(Location center, double radius, double verticalStep, double maxDistanceBetweenPoints, Consumer<Location> action) {
|
public static void sphere(Location center, double radius, double pointDistance, Consumer<Location> action) {
|
||||||
for (double yOffset = -radius; yOffset <= radius; yOffset += verticalStep) {
|
double dPhi = pointDistance / radius;
|
||||||
double horizontalRadius = Math.sqrt(radius * radius - yOffset * yOffset);
|
|
||||||
|
|
||||||
if (horizontalRadius < 0.01) {
|
for (double phi = 0.0; phi <= Math.PI; phi += dPhi) {
|
||||||
Location point = center.clone().add(0, yOffset, 0);
|
double yOffset = radius * Math.cos(phi);
|
||||||
action.accept(point);
|
double ringRadius = radius * Math.sin(phi);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
double circumference = 2 * Math.PI * horizontalRadius;
|
if (ringRadius < 1e-6) {
|
||||||
int points = Math.max(4, (int) (circumference / maxDistanceBetweenPoints));
|
Location loc = center.clone().add(0, yOffset, 0);
|
||||||
double angleStep = 360.0 / points;
|
action.accept(loc);
|
||||||
|
} else {
|
||||||
|
double dTheta = pointDistance / ringRadius;
|
||||||
|
|
||||||
for (int i = 0; i < points; i++) {
|
for (double theta = 0.0; theta < 2 * Math.PI; theta += dTheta) {
|
||||||
double theta = i * angleStep;
|
double xOffset = ringRadius * Math.cos(theta);
|
||||||
double x = Math.cos(Math.toRadians(theta)) * horizontalRadius;
|
double zOffset = ringRadius * Math.sin(theta);
|
||||||
double z = Math.sin(Math.toRadians(theta)) * horizontalRadius;
|
|
||||||
Location point = center.clone().add(x, yOffset, z);
|
Location loc = center.clone().add(xOffset, yOffset, zOffset);
|
||||||
action.accept(point);
|
action.accept(loc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sphereWave(Location center, double maxRadius, double radialStep, double verticalStep, double maxDistanceBetweenPoints, Consumer<Location> action) {
|
public static void sphereWave(Location center, double maxRadius, double radialStep, double maxDistanceBetweenPoints, Consumer<Location> action) {
|
||||||
AtomicReference<Double> currentRadius = new AtomicReference<>(radialStep);
|
AtomicReference<Double> currentRadius = new AtomicReference<>(radialStep);
|
||||||
|
|
||||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(main.getPlugin(), () -> {
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(main.getPlugin(), () -> {
|
||||||
double r = currentRadius.get();
|
double r = currentRadius.get();
|
||||||
if (r > maxRadius) return;
|
if (r > maxRadius) return;
|
||||||
|
|
||||||
sphere(center, r, verticalStep, maxDistanceBetweenPoints, action);
|
sphere(center, r, maxDistanceBetweenPoints, action);
|
||||||
currentRadius.set(r + radialStep);
|
currentRadius.set(r + radialStep);
|
||||||
}, 0L, 1L);
|
}, 0L, 1L);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user