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