From 9d6799bc4f6d6c28e248b7b920dc68dd35e03133 Mon Sep 17 00:00:00 2001 From: KeyLime17 Date: Tue, 6 May 2025 01:04:21 -0400 Subject: [PATCH] Added Morgul Blast Projectile --- gradle.properties | 2 +- .../carriage/CarriageDestinationsData.java | 127 +++++++++--------- .../cinder_loe/projectiles/MorgulBlast.java | 100 ++++++++++++++ 3 files changed, 167 insertions(+), 62 deletions(-) create mode 100644 src/main/java/com/zivilon/cinder_loe/projectiles/MorgulBlast.java diff --git a/gradle.properties b/gradle.properties index a61743f..9e263d6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ modName = CinderLoE -modVersion = 1.5.0 +modVersion = 1.5.1 modId = cinder_loe modGroup = com.zivilon.cinder_loe diff --git a/src/main/java/com/zivilon/cinder_loe/carriage/CarriageDestinationsData.java b/src/main/java/com/zivilon/cinder_loe/carriage/CarriageDestinationsData.java index bd3a25a..d4afe8c 100644 --- a/src/main/java/com/zivilon/cinder_loe/carriage/CarriageDestinationsData.java +++ b/src/main/java/com/zivilon/cinder_loe/carriage/CarriageDestinationsData.java @@ -8,6 +8,7 @@ import net.minecraft.world.WorldServer; import net.minecraft.world.storage.MapStorage; import java.util.*; +import java.util.function.BiPredicate; public class CarriageDestinationsData extends WorldSavedData { public static final String DATA_NAME = "carriage_destinations"; @@ -76,73 +77,77 @@ public class CarriageDestinationsData extends WorldSavedData { } public List getNearestFour(double px, double pz) { - CarriageDestination north = null, south = null, east = null, west = null; - double nDist = Double.MAX_VALUE, sDist = Double.MAX_VALUE, eDist = Double.MAX_VALUE, wDist = Double.MAX_VALUE; - - Set alreadyPicked = new HashSet<>(); - - for (CarriageDestination dest : destinations.values()) { - double dx = dest.x - px; - double dz = dest.z - pz; - double distance = Math.sqrt(dx * dx + dz * dz); - - if (distance < 10) { - continue; // skip nearby - } - - // north - if (dz < 0 && Math.abs(dz) < nDist && !alreadyPicked.contains(dest)) { - nDist = Math.abs(dz); - north = dest; - } - // south - if (dz > 0 && dz < sDist && !alreadyPicked.contains(dest)) { - sDist = dz; - south = dest; - } - // east - if (dx > 0 && dx < eDist && !alreadyPicked.contains(dest)) { - eDist = dx; - east = dest; - } - // west - if (dx < 0 && Math.abs(dx) < wDist && !alreadyPicked.contains(dest)) { - wDist = Math.abs(dx); - west = dest; - } + double skipRadius = 100; + Set picked = new HashSet<>(); + List result = new ArrayList<>(4); + + // north + CarriageDestination best = null; + double bestDist = Double.MAX_VALUE; + for (CarriageDestination d : destinations.values()) { + if (picked.contains(d)) continue; + double dx = d.x - px, dz = d.z - pz; + double dist = Math.sqrt(dx*dx + dz*dz); + if (dist < skipRadius || dz >= 0) continue; + double measure = Math.abs(dz); + if (measure < bestDist) { bestDist = measure; best = d; } } - - // track already selected - if (north != null) alreadyPicked.add(north); - if (south != null) alreadyPicked.add(south); - if (east != null) alreadyPicked.add(east); - if (west != null) alreadyPicked.add(west); - - // second pass: fill missing slots with next nearest - for (CarriageDestination dest : destinations.values()) { - if (alreadyPicked.contains(dest)) continue; - - double dx = dest.x - px; - double dz = dest.z - pz; - double distance = Math.sqrt(dx * dx + dz * dz); - - if (distance < 10) continue; - - if (north == null && dz < 0) { north = dest; alreadyPicked.add(dest); continue; } - if (south == null && dz > 0) { south = dest; alreadyPicked.add(dest); continue; } - if (east == null && dx > 0) { east = dest; alreadyPicked.add(dest); continue; } - if (west == null && dx < 0) { west = dest; alreadyPicked.add(dest); continue; } + if (best != null) { picked.add(best); result.add(best); } + + // south + best = null; bestDist = Double.MAX_VALUE; + for (CarriageDestination d : destinations.values()) { + if (picked.contains(d)) continue; + double dx = d.x - px, dz = d.z - pz; + double dist = Math.sqrt(dx*dx + dz*dz); + if (dist < skipRadius || dz <= 0) continue; + if (dz < bestDist) { bestDist = dz; best = d; } + } + if (best != null) { picked.add(best); result.add(best); } + + // east + best = null; bestDist = Double.MAX_VALUE; + for (CarriageDestination d : destinations.values()) { + if (picked.contains(d)) continue; + double dx = d.x - px, dz = d.z - pz; + double dist = Math.sqrt(dx*dx + dz*dz); + if (dist < skipRadius || dx <= 0) continue; + if (dx < bestDist) { bestDist = dx; best = d; } + } + if (best != null) { picked.add(best); result.add(best); } + + // west + best = null; bestDist = Double.MAX_VALUE; + for (CarriageDestination d : destinations.values()) { + if (picked.contains(d)) continue; + double dx = d.x - px, dz = d.z - pz; + double dist = Math.sqrt(dx*dx + dz*dz); + if (dist < skipRadius || dx >= 0) continue; + double measure = Math.abs(dx); + if (measure < bestDist) { bestDist = measure; best = d; } + } + if (best != null) { picked.add(best); result.add(best); } + + // fill remaining slots + List sorted = new ArrayList<>(destinations.values()); + sorted.sort(Comparator.comparingDouble(d -> { + double dx = d.x - px, dz = d.z - pz; + return Math.sqrt(dx*dx + dz*dz); + })); + for (CarriageDestination d : sorted) { + if (result.size() >= 4) break; + double dx = d.x - px, dz = d.z - pz; + double dist = Math.sqrt(dx*dx + dz*dz); + if (dist < skipRadius) continue; + if (!picked.contains(d)) { + picked.add(d); + result.add(d); + } } - List result = new ArrayList<>(); - if (north != null) result.add(north); - if (south != null) result.add(south); - if (east != null) result.add(east); - if (west != null) result.add(west); return result; } - } diff --git a/src/main/java/com/zivilon/cinder_loe/projectiles/MorgulBlast.java b/src/main/java/com/zivilon/cinder_loe/projectiles/MorgulBlast.java new file mode 100644 index 0000000..cb9e9bf --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/projectiles/MorgulBlast.java @@ -0,0 +1,100 @@ +package com.zivilon.cinder_loe.projectiles; + +import lotr.common.LOTRMod; +import lotr.common.entity.npc.LOTREntityNPC; +import lotr.common.entity.projectile.LOTREntityMallornLeafBomb; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.projectile.EntityThrowable; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +import java.util.List; +import java.util.UUID; + +public class MorgulBlast extends LOTREntityMallornLeafBomb { + private UUID throwerUUID; + private int leavesAge; + private static int MAX_LEAVES_AGE = 200; + public float leavesDamage = 10; + + + public MorgulBlast(World world) { + super(world); + this.setSize(2.0f, 2.0f); + this.setPosition(this.posX, this.posY, this.posZ); + } + + private void explode(Entity target) { + if (!this.worldObj.isRemote) { + double range = 2.0; + List entities = this.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, this.boundingBox.expand(range, range, range)); + if (!entities.isEmpty()) { + for (int i = 0; i < entities.size(); ++i) { + float damage; + EntityLivingBase entity = (EntityLivingBase)entities.get(i); + if (!this.isEntityVulnerable((Entity)entity) || !((damage = this.leavesDamage / Math.max(1.0f, this.getDistanceToEntity((Entity)entity))) > 0.0f)) continue; + entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase)this.getThrower()), damage); + } + } + this.setDead(); + } + } + private boolean isEntityVulnerable(Entity target) { + if (target == this.getThrower()) { + return false; + } + if (target instanceof EntityLivingBase) { + EntityLivingBase livingTarget = (EntityLivingBase)target; + EntityLivingBase thrower = this.getThrower(); + if (thrower instanceof LOTREntityNPC) { + ((LOTREntityNPC)thrower).getJumpHelper().doJump(); + return LOTRMod.canNPCAttackEntity((LOTREntityNPC)thrower, livingTarget, false); + } + return true; + } + return false; + } + + @Override + public void onUpdate() { + super.onUpdate(); + if (!this.worldObj.isRemote) { + ++this.leavesAge; + if (this.leavesAge >= MAX_LEAVES_AGE) { + this.explode(null); + } + } else { + Vec3 axis = Vec3.createVectorHelper((double)(-this.motionX), (double)(-this.motionY), (double)(-this.motionZ)); + int leaves = 20; + for (int l = 0; l < leaves; ++l) { + float angle = (float)l / (float)leaves * 2.0f * (float)Math.PI; + Vec3 rotate = Vec3.createVectorHelper((double)1.0, (double)1.0, (double)1.0); + rotate.rotateAroundX((float)Math.toRadians(40.0)); + rotate.rotateAroundY(angle); + float dot = (float)rotate.dotProduct(axis); + Vec3 parallel = Vec3.createVectorHelper((double)(axis.xCoord * (double)dot), (double)(axis.yCoord * (double)dot), (double)(axis.zCoord * (double)dot)); + Vec3 perp = parallel.subtract(rotate); + Vec3 cross = rotate.crossProduct(axis); + float sin = MathHelper.sin((float)(-angle)); + float cos = MathHelper.cos((float)(-angle)); + Vec3 crossSin = Vec3.createVectorHelper((double)(cross.xCoord * (double)sin), (double)(cross.yCoord * (double)sin), (double)(cross.zCoord * (double)sin)); + Vec3 perpCos = Vec3.createVectorHelper((double)(perp.xCoord * (double)cos), (double)(perp.yCoord * (double)cos), (double)(perp.zCoord * (double)cos)); + Vec3 result = parallel.addVector(crossSin.xCoord + perpCos.xCoord, crossSin.yCoord + perpCos.yCoord, crossSin.zCoord + perpCos.zCoord); + double d = this.posX; + double d1 = this.posY; + double d2 = this.posZ; + double d3 = result.xCoord / 10.0; + double d4 = result.yCoord / 10.0; + double d5 = result.zCoord / 10.0; + LOTRMod.proxy.spawnParticle("morgulPortal", d, d1, d2, d3, d4, d5); + LOTRMod.proxy.spawnParticle("smoke", d, d1, d2, d3 * 0.5, d4 * 0.5, d5 * 0.5); + } + } + } +}