mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 19:34:09 +00:00
Max Hits for Piece and Multi
This commit is contained in:
1 parent
21cd8e9e01
commit
e4fe8c5112
6 files changed
+109
-12
No files matched your search
@@ -10,6 +10,8 @@ import noppes.npcs.api.ability.data.IEnergyCombatData;
|
||||
*/
|
||||
public class EnergyCombatData implements IEnergyCombatData {
|
||||
public static final float MAX_EXPLOSION_RADIUS = 15.0f;
|
||||
public static final int DEFAULT_MAX_HITS = 5;
|
||||
public static final int MAX_HITS = 200;
|
||||
|
||||
public float damage = 7.0f;
|
||||
public float knockback = 1.0f;
|
||||
@@ -19,6 +21,7 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
public float explosionDamageFalloff = 0.5f;
|
||||
public HitType hitType = HitType.SINGLE;
|
||||
public int multiHitDelayTicks = 5;
|
||||
public int maxHits = DEFAULT_MAX_HITS;
|
||||
|
||||
public EnergyCombatData() {
|
||||
}
|
||||
@@ -26,6 +29,12 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
public EnergyCombatData(float damage, float knockback, float knockbackUp,
|
||||
boolean explosive, float explosionRadius, float explosionDamageFalloff,
|
||||
HitType hitType, int multiHitDelay) {
|
||||
this(damage, knockback, knockbackUp, explosive, explosionRadius, explosionDamageFalloff, hitType, multiHitDelay, DEFAULT_MAX_HITS);
|
||||
}
|
||||
|
||||
public EnergyCombatData(float damage, float knockback, float knockbackUp,
|
||||
boolean explosive, float explosionRadius, float explosionDamageFalloff,
|
||||
HitType hitType, int multiHitDelay, int maxHits) {
|
||||
this.damage = damage;
|
||||
this.knockback = knockback;
|
||||
this.knockbackUp = knockbackUp;
|
||||
@@ -34,6 +43,7 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
this.explosionDamageFalloff = explosionDamageFalloff;
|
||||
this.hitType = hitType;
|
||||
this.multiHitDelayTicks = multiHitDelay;
|
||||
this.maxHits = clampMaxHits(maxHits);
|
||||
}
|
||||
|
||||
public EnergyCombatData(float damage, float knockback, float knockbackUp,
|
||||
@@ -106,6 +116,14 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
this.explosionDamageFalloff = explosionDamageFalloff;
|
||||
}
|
||||
|
||||
public int getMaxHits() {
|
||||
return maxHits;
|
||||
}
|
||||
|
||||
public void setMaxHits(int maxHits) {
|
||||
this.maxHits = clampMaxHits(maxHits);
|
||||
}
|
||||
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("damage", damage);
|
||||
nbt.setFloat("knockback", knockback);
|
||||
@@ -115,6 +133,7 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
nbt.setFloat("explosionDamageFalloff", explosionDamageFalloff);
|
||||
nbt.setInteger("hitType", hitType.ordinal());
|
||||
nbt.setInteger("multiHitDelayTicks", multiHitDelayTicks);
|
||||
nbt.setInteger("maxHits", maxHits);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
@@ -126,6 +145,7 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
explosionDamageFalloff = nbt.hasKey("explosionDamageFalloff") ? nbt.getFloat("explosionDamageFalloff") : 0.5f;
|
||||
hitType = HitType.fromOrdinal(nbt.hasKey("hitType") ? nbt.getInteger("hitType") : 0);
|
||||
multiHitDelayTicks = nbt.hasKey("multiHitDelayTicks") ? nbt.getInteger("multiHitDelayTicks") : 5;
|
||||
maxHits = nbt.hasKey("maxHits") ? nbt.getInteger("maxHits") : DEFAULT_MAX_HITS;
|
||||
|
||||
// Sanitize
|
||||
if (Float.isNaN(damage) || Float.isInfinite(damage)) damage = 7.0f;
|
||||
@@ -133,6 +153,7 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
if (Float.isNaN(explosionRadius) || Float.isInfinite(explosionRadius) || explosionRadius < 0) explosionRadius = 3.0f;
|
||||
explosionRadius = clampExplosionRadius(explosionRadius);
|
||||
if (multiHitDelayTicks < 1) multiHitDelayTicks = 1;
|
||||
maxHits = clampMaxHits(maxHits);
|
||||
}
|
||||
|
||||
private static float clampExplosionRadius(float explosionRadius) {
|
||||
@@ -140,11 +161,16 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
return Math.max(0.0f, Math.min(MAX_EXPLOSION_RADIUS, explosionRadius));
|
||||
}
|
||||
|
||||
private static int clampMaxHits(int maxHits) {
|
||||
return Math.max(1, Math.min(MAX_HITS, maxHits));
|
||||
}
|
||||
|
||||
public EnergyCombatData copy() {
|
||||
EnergyCombatData copy = new EnergyCombatData(damage, knockback, knockbackUp,
|
||||
explosive, explosionRadius, explosionDamageFalloff);
|
||||
copy.hitType = hitType;
|
||||
copy.multiHitDelayTicks = multiHitDelayTicks;
|
||||
copy.maxHits = maxHits;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
+12
@@ -685,6 +685,14 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
this.combatData.multiHitDelayTicks = Math.max(1, delay);
|
||||
}
|
||||
|
||||
public int getMaxHits() {
|
||||
return combatData.getMaxHits();
|
||||
}
|
||||
|
||||
public void setMaxHits(int maxHits) {
|
||||
combatData.setMaxHits(maxHits);
|
||||
}
|
||||
|
||||
// Lifespan data
|
||||
@Override
|
||||
public float getMaxDistance() {
|
||||
@@ -832,6 +840,10 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
.range(1, 200)
|
||||
.visibleWhen(() -> getHitType() == HitType.MULTI.ordinal())
|
||||
.hover("ability.hover.multiHitDelay"));
|
||||
defs.add(FieldDef.intField("ability.maxHits", this::getMaxHits, this::setMaxHits)
|
||||
.range(1, EnergyCombatData.MAX_HITS)
|
||||
.visibleWhen(() -> getHitType() != HitType.SINGLE.ordinal())
|
||||
.hover("ability.hover.maxHits"));
|
||||
|
||||
// Type-specific fields first
|
||||
addTypeDefinitions(defs);
|
||||
|
||||
@@ -124,6 +124,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
// ==================== STATE ====================
|
||||
protected boolean hasHit = false;
|
||||
protected int hitCount = 0;
|
||||
protected final Set<Integer> hitOnceEntities = new HashSet<Integer>();
|
||||
protected final Map<Integer, Integer> lastHitTickByEntity = new HashMap<Integer, Integer>();
|
||||
protected static final int BARRIER_IMPACT_PAUSE_TICKS = 10;
|
||||
@@ -508,6 +509,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
hitOnceEntities.clear();
|
||||
lastHitTickByEntity.clear();
|
||||
hitCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -943,13 +945,12 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
// Using feet position (target.posY) causes explosions at impact height to miss
|
||||
// entities standing below — e.g. a projectile hitting at eye height (~1.62 above feet)
|
||||
// would measure dist=1.62, failing a radius<=1.6 check despite a direct hit.
|
||||
double closestX = Math.max(target.boundingBox.minX, Math.min(posX, target.boundingBox.maxX));
|
||||
double closestY = Math.max(target.boundingBox.minY, Math.min(posY, target.boundingBox.maxY));
|
||||
double closestZ = Math.max(target.boundingBox.minZ, Math.min(posZ, target.boundingBox.maxZ));
|
||||
Vec3 closest = closestPointOnBoundingBox(target.boundingBox, posX, posY, posZ);
|
||||
if (closest == null) continue;
|
||||
double dist = Math.sqrt(
|
||||
(closestX - posX) * (closestX - posX) +
|
||||
(closestY - posY) * (closestY - posY) +
|
||||
(closestZ - posZ) * (closestZ - posZ)
|
||||
(closest.xCoord - posX) * (closest.xCoord - posX) +
|
||||
(closest.yCoord - posY) * (closest.yCoord - posY) +
|
||||
(closest.zCoord - posZ) * (closest.zCoord - posZ)
|
||||
);
|
||||
|
||||
if (dist <= explosionRad) {
|
||||
@@ -970,6 +971,17 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
return shouldIgnoreEntity(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp a point to the nearest point inside the provided AABB.
|
||||
*/
|
||||
protected Vec3 closestPointOnBoundingBox(AxisAlignedBB box, double x, double y, double z) {
|
||||
if (box == null) return null;
|
||||
double closestX = Math.max(box.minX, Math.min(x, box.maxX));
|
||||
double closestY = Math.max(box.minY, Math.min(y, box.maxY));
|
||||
double closestZ = Math.max(box.minZ, Math.min(z, box.maxZ));
|
||||
return Vec3.createVectorHelper(closestX, closestY, closestZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a packet-driven client preview so explosions are visible as geometry,
|
||||
* not only as particles.
|
||||
@@ -1861,8 +1873,17 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
combatData.multiHitDelayTicks = Math.max(1, delayTicks);
|
||||
}
|
||||
|
||||
public int getMaxHits() {
|
||||
return combatData.getMaxHits();
|
||||
}
|
||||
|
||||
public void setMaxHits(int maxHits) {
|
||||
combatData.setMaxHits(maxHits);
|
||||
}
|
||||
|
||||
protected boolean canHitEntityNow(EntityLivingBase entity) {
|
||||
if (entity == null) return false;
|
||||
if (combatData.hitType != HitType.SINGLE && hasReachedMaxHits()) return false;
|
||||
|
||||
int entityId = entity.getEntityId();
|
||||
switch (combatData.hitType) {
|
||||
@@ -1884,10 +1905,17 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
int entityId = entity.getEntityId();
|
||||
hitOnceEntities.add(entityId);
|
||||
lastHitTickByEntity.put(entityId, ticksExisted);
|
||||
hitCount++;
|
||||
}
|
||||
|
||||
protected boolean hasReachedMaxHits() {
|
||||
if (combatData.hitType == HitType.SINGLE) return false;
|
||||
return hitCount >= combatData.getMaxHits();
|
||||
}
|
||||
|
||||
protected boolean shouldTerminateAfterHit() {
|
||||
return combatData.hitType == HitType.SINGLE;
|
||||
if (combatData.hitType == HitType.SINGLE) return true;
|
||||
return hasReachedMaxHits();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1931,12 +1959,13 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
recordEntityHit(entity);
|
||||
if (isExplosive()) {
|
||||
Vec3 impactPoint = resolveEntityImpactPoint(entity, impactX, impactY, impactZ);
|
||||
double oldX = posX;
|
||||
double oldY = posY;
|
||||
double oldZ = posZ;
|
||||
posX = impactX;
|
||||
posY = impactY;
|
||||
posZ = impactZ;
|
||||
posX = impactPoint.xCoord;
|
||||
posY = impactPoint.yCoord;
|
||||
posZ = impactPoint.zCoord;
|
||||
doExplosion();
|
||||
posX = oldX;
|
||||
posY = oldY;
|
||||
@@ -1954,6 +1983,26 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a stable impact point on the target so explosive collisions use actual contact.
|
||||
*/
|
||||
protected Vec3 resolveEntityImpactPoint(EntityLivingBase entity, double impactX, double impactY, double impactZ) {
|
||||
if (entity == null || entity.boundingBox == null) {
|
||||
return Vec3.createVectorHelper(impactX, impactY, impactZ);
|
||||
}
|
||||
|
||||
Vec3 segmentStart = Vec3.createVectorHelper(posX, posY, posZ);
|
||||
Vec3 segmentEnd = Vec3.createVectorHelper(impactX, impactY, impactZ);
|
||||
AxisAlignedBB expandedBox = entity.boundingBox.expand(1.0e-4, 1.0e-4, 1.0e-4);
|
||||
MovingObjectPosition intercept = expandedBox.calculateIntercept(segmentStart, segmentEnd);
|
||||
if (intercept != null && intercept.hitVec != null) {
|
||||
return intercept.hitVec;
|
||||
}
|
||||
|
||||
Vec3 closest = closestPointOnBoundingBox(entity.boundingBox, impactX, impactY, impactZ);
|
||||
return closest != null ? closest : Vec3.createVectorHelper(impactX, impactY, impactZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan entities in a hitbox and process the first/each valid hit based on hit mode.
|
||||
*/
|
||||
|
||||
@@ -177,6 +177,14 @@ public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends Sc
|
||||
entity.setMultiHitDelayTicks(delayTicks);
|
||||
}
|
||||
|
||||
public int getMaxHits() {
|
||||
return entity.getMaxHits();
|
||||
}
|
||||
|
||||
public void setMaxHits(int maxHits) {
|
||||
entity.setMaxHits(maxHits);
|
||||
}
|
||||
|
||||
// ==================== MOVEMENT ====================
|
||||
|
||||
public float getSpeed() {
|
||||
|
||||
Reference in new issue
Block a user