Check Barrier Collisions within Laser Shot

This commit is contained in:
Kam committed 2026-02-20 03:50:41 -05:00
1 parent bc9342c2eb
commit 4bd149c01b
1 file changed
+104
@@ -14,6 +14,7 @@ import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import noppes.npcs.EventHooks;
import noppes.npcs.entity.EntityNPCInterface;
import java.util.HashSet;
import java.util.List;
@@ -369,6 +370,109 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
return true;
}
// ==================== BARRIER COLLISION ====================
/**
* Override barrier collision for lasers. The base class uses projectile position/velocity
* which doesn't work for lasers (posX/Y/Z stays at origin, motionX/Y/Z is zero).
* Instead, performs line-sphere intersection against domes.
*/
@Override
@SuppressWarnings("unchecked")
protected boolean checkBarrierCollision() {
if (currentLength <= 0 || fullyExtended) return false;
// Search box covers the full laser line plus barrier search range
double searchRange = MAX_ENTITY_RADIUS + 5;
double minX = Math.min(startX, endX) - searchRange;
double minY = Math.min(startY, endY) - searchRange;
double minZ = Math.min(startZ, endZ) - searchRange;
double maxX = Math.max(startX, endX) + searchRange;
double maxY = Math.max(startY, endY) + searchRange;
double maxZ = Math.max(startZ, endZ) + searchRange;
AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
List<EntityEnergyBarrier> barriers = worldObj.getEntitiesWithinAABB(EntityEnergyBarrier.class, searchBox);
for (EntityEnergyBarrier barrier : barriers) {
if (barrier.isDead || barrier.isCharging()) continue;
if (barrier.getOwnerEntityId() == this.ownerEntityId) continue;
// Same-faction NPC check
Entity bOwner = barrier.getOwnerEntity();
Entity lOwner = this.getOwnerEntity();
if (bOwner instanceof EntityNPCInterface && lOwner instanceof EntityNPCInterface) {
if (((EntityNPCInterface) bOwner).faction.id == ((EntityNPCInterface) lOwner).faction.id) {
continue;
}
}
if (barrier instanceof EntityEnergyDome) {
EntityEnergyDome dome = (EntityEnergyDome) barrier;
float intersectDist = getLineSphereIntersection(dome);
if (intersectDist >= 0) {
// Truncate laser at dome surface
currentLength = intersectDist;
endX = startX + dirX * currentLength;
endY = startY + dirY * currentLength;
endZ = startZ + dirZ * currentLength;
fullyExtended = true;
float damage = getModifiedDamage();
dome.onProjectileHit(this, damage);
return false; // Don't kill laser — it's truncated and will linger
}
} else {
// Non-dome barriers: fall through to standard check
if (barrier.isIncomingProjectile(this)) {
float damage = getModifiedDamage();
if (barrier.onProjectileHit(this, damage)) {
hasHit = true;
this.setDead();
return true;
}
}
}
}
return false;
}
/**
* Line-sphere intersection between the laser line segment and a dome.
* Returns the distance along the laser direction to the first entry point,
* or -1 if no intersection from outside.
*/
private float getLineSphereIntersection(EntityEnergyDome dome) {
double cx = dome.posX;
double cy = dome.posY;
double cz = dome.posZ;
float radius = dome.getDomeRadius();
// If laser origin is inside the dome, don't block (outgoing)
double ocX = startX - cx;
double ocY = startY - cy;
double ocZ = startZ - cz;
double originDistSq = ocX * ocX + ocY * ocY + ocZ * ocZ;
if (originDistSq < (double) radius * radius) return -1;
// Solve: |start + t*dir - C|^2 = R^2
// a*t^2 + b*t + c = 0
double a = dirX * dirX + dirY * dirY + dirZ * dirZ;
double b = 2.0 * (dirX * ocX + dirY * ocY + dirZ * ocZ);
double c = originDistSq - (double) radius * radius;
double discriminant = b * b - 4.0 * a * c;
if (discriminant < 0) return -1;
double sqrtD = Math.sqrt(discriminant);
double t1 = (-b - sqrtD) / (2.0 * a); // Entry point
if (t1 >= 0 && t1 <= currentLength) {
return (float) t1;
}
return -1;
}
// ==================== GETTERS FOR RENDERER ====================
public void setLockVerticalDirection(boolean lock) {