mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 18:57:32 +00:00
Add Hit Type to Projectiles
This commit is contained in:
1 parent
26da3ae2f9
commit
b6749e306b
15 files changed
+265
-292
No files matched your search
@@ -0,0 +1,32 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
/**
|
||||
* Shared hit behavior for energy projectiles.
|
||||
*/
|
||||
public enum HitType {
|
||||
SINGLE,
|
||||
PIERCE,
|
||||
MULTI;
|
||||
|
||||
public static HitType fromOrdinal(int ordinal) {
|
||||
HitType[] values = values();
|
||||
if (ordinal >= 0 && ordinal < values.length) {
|
||||
return values[ordinal];
|
||||
}
|
||||
return SINGLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case SINGLE:
|
||||
return "ability.hitType.single";
|
||||
case PIERCE:
|
||||
return "ability.hitType.pierce";
|
||||
case MULTI:
|
||||
return "ability.hitType.multi";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package kamkeel.npcs.controllers.data.ability.data;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.HitType;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.api.ability.data.IEnergyCombatData;
|
||||
|
||||
@@ -14,6 +15,8 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
public boolean explosive = false;
|
||||
public float explosionRadius = 3.0f;
|
||||
public float explosionDamageFalloff = 0.5f;
|
||||
public HitType hitType = HitType.SINGLE;
|
||||
public int multiHitDelayTicks = 5;
|
||||
|
||||
public EnergyCombatData() {
|
||||
}
|
||||
@@ -95,6 +98,8 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
nbt.setBoolean("explosive", explosive);
|
||||
nbt.setFloat("explosionRadius", explosionRadius);
|
||||
nbt.setFloat("explosionDamageFalloff", explosionDamageFalloff);
|
||||
nbt.setInteger("hitType", hitType.ordinal());
|
||||
nbt.setInteger("multiHitDelayTicks", multiHitDelayTicks);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
@@ -104,15 +109,21 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
explosive = nbt.hasKey("explosive") && nbt.getBoolean("explosive");
|
||||
explosionRadius = nbt.hasKey("explosionRadius") ? nbt.getFloat("explosionRadius") : 3.0f;
|
||||
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;
|
||||
|
||||
// Sanitize
|
||||
if (Float.isNaN(damage) || Float.isInfinite(damage)) damage = 7.0f;
|
||||
if (Float.isNaN(knockback) || Float.isInfinite(knockback) || knockback < 0) knockback = 1.0f;
|
||||
if (Float.isNaN(explosionRadius) || Float.isInfinite(explosionRadius) || explosionRadius < 0) explosionRadius = 3.0f;
|
||||
if (multiHitDelayTicks < 1) multiHitDelayTicks = 1;
|
||||
}
|
||||
|
||||
public EnergyCombatData copy() {
|
||||
return new EnergyCombatData(damage, knockback, knockbackUp,
|
||||
EnergyCombatData copy = new EnergyCombatData(damage, knockback, knockbackUp,
|
||||
explosive, explosionRadius, explosionDamageFalloff);
|
||||
copy.hitType = hitType;
|
||||
copy.multiHitDelayTicks = multiHitDelayTicks;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
+26
@@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.HitType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
@@ -557,6 +558,22 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
combatData.explosionDamageFalloff = falloff;
|
||||
}
|
||||
|
||||
public int getHitType() {
|
||||
return combatData.hitType.ordinal();
|
||||
}
|
||||
|
||||
public void setHitType(int hitType) {
|
||||
this.combatData.hitType = HitType.fromOrdinal(hitType);
|
||||
}
|
||||
|
||||
public int getMultiHitDelayTicks() {
|
||||
return combatData.multiHitDelayTicks;
|
||||
}
|
||||
|
||||
public void setMultiHitDelayTicks(int delay) {
|
||||
this.combatData.multiHitDelayTicks = Math.max(1, delay);
|
||||
}
|
||||
|
||||
// Lifespan data
|
||||
@Override
|
||||
public float getMaxDistance() {
|
||||
@@ -696,6 +713,15 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public final void getAbilityDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.enumField("ability.hitType", HitType.class,
|
||||
() -> HitType.fromOrdinal(getHitType()),
|
||||
(v) -> setHitType(v.ordinal()))
|
||||
.hover("ability.hover.hitType"));
|
||||
defs.add(FieldDef.intField("ability.multiHitDelay", this::getMultiHitDelayTicks, this::setMultiHitDelayTicks)
|
||||
.range(1, 200)
|
||||
.visibleWhen(() -> getHitType() == HitType.MULTI.ordinal())
|
||||
.hover("ability.hover.multiHitDelay"));
|
||||
|
||||
// Type-specific fields first
|
||||
addTypeDefinitions(defs);
|
||||
|
||||
|
||||
+2
-15
@@ -25,8 +25,8 @@ import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Laser Shot ability: Fast expanding thin line that pierces through targets.
|
||||
* Travels in a straight line from origin, damaging all entities it passes through.
|
||||
* Laser Shot ability: Fast expanding thin line.
|
||||
* Travels in a straight line from origin.
|
||||
* Single-projectile only (always projectileCount=1).
|
||||
*/
|
||||
public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser> implements IAbilityLaserShot {
|
||||
@@ -34,7 +34,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
private float laserWidth = 0.3f;
|
||||
private float expansionSpeed = 3.0f;
|
||||
private int lingerTicks = 8;
|
||||
private boolean dieOnImpact = false;
|
||||
|
||||
public AbilityLaserShot() {
|
||||
super(
|
||||
@@ -123,7 +122,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
laserWidth,
|
||||
resolved, combatData, lightningData, lifespanData, trajectoryData,
|
||||
expansionSpeed, lingerTicks);
|
||||
laser.setDieOnImpact(dieOnImpact);
|
||||
return laser;
|
||||
}
|
||||
|
||||
@@ -161,7 +159,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
nbt.setFloat("laserWidth", laserWidth);
|
||||
nbt.setFloat("expansionSpeed", expansionSpeed);
|
||||
nbt.setInteger("lingerTicks", lingerTicks);
|
||||
nbt.setBoolean("dieOnImpact", dieOnImpact);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,7 +166,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
this.laserWidth = nbt.getFloat("laserWidth");
|
||||
this.expansionSpeed = nbt.getFloat("expansionSpeed");
|
||||
this.lingerTicks = nbt.getInteger("lingerTicks");
|
||||
this.dieOnImpact = nbt.getBoolean("dieOnImpact");
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
@@ -198,14 +194,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
this.lingerTicks = lingerTicks;
|
||||
}
|
||||
|
||||
public boolean isDieOnImpact() {
|
||||
return dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDieOnImpact(boolean dieOnImpact) {
|
||||
this.dieOnImpact = dieOnImpact;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -226,7 +214,6 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200)
|
||||
));
|
||||
defs.add(FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f));
|
||||
defs.add(FieldDef.boolField("ability.dieOnImpact", this::isDieOnImpact, this::setDieOnImpact));
|
||||
defs.add(FieldDef.section("ability.section.explosive"));
|
||||
defs.add(FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive"));
|
||||
defs.add(FieldDef.floatField("gui.radius", this::getExplosionRadius, this::setExplosionRadius).visibleWhen(this::isExplosive));
|
||||
|
||||
@@ -23,14 +23,13 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Slicer ability: Fires a thin, wide blade projectile in a straight line.
|
||||
* JJK Cleave/Dismantle inspired. Piercing by default.
|
||||
* JJK Cleave/Dismantle inspired.
|
||||
* Extends AbilityEnergyProjectile to leverage the existing projectile infrastructure.
|
||||
*/
|
||||
public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
|
||||
private float sliceWidth = 3.0f;
|
||||
private float sliceThickness = 0.15f;
|
||||
private boolean piercing = true;
|
||||
|
||||
public AbilitySlicer() {
|
||||
super(
|
||||
@@ -62,8 +61,7 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
sliceWidth, sliceThickness,
|
||||
resolved, combatData, homingData, lightningData, lifespanData, trajectoryData,
|
||||
piercing
|
||||
resolved, combatData, homingData, lightningData, lifespanData, trajectoryData
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,14 +120,12 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
protected void writeTypeSpecificNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("sliceWidth", sliceWidth);
|
||||
nbt.setFloat("sliceThickness", sliceThickness);
|
||||
nbt.setBoolean("piercing", piercing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readTypeSpecificNBT(NBTTagCompound nbt) {
|
||||
this.sliceWidth = nbt.hasKey("sliceWidth") ? nbt.getFloat("sliceWidth") : 3.0f;
|
||||
this.sliceThickness = nbt.hasKey("sliceThickness") ? nbt.getFloat("sliceThickness") : 0.15f;
|
||||
this.piercing = !nbt.hasKey("piercing") || nbt.getBoolean("piercing");
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
@@ -158,14 +154,6 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
this.sliceThickness = Math.max(0.05f, thickness);
|
||||
}
|
||||
|
||||
public boolean isPiercing() {
|
||||
return piercing;
|
||||
}
|
||||
|
||||
public void setPiercing(boolean piercing) {
|
||||
this.piercing = piercing;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -186,8 +174,6 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
FieldDef.floatField("gui.width", this::getSliceWidth, this::setSliceWidth).range(0.5f, 100.0f),
|
||||
FieldDef.floatField("gui.thickness", this::getSliceThickness, this::setSliceThickness).range(0.05f, 100.0f)
|
||||
));
|
||||
defs.add(FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing)
|
||||
.hover("ability.hover.piercing"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).range(1.0f, 500.0f),
|
||||
FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).range(1, 1200)
|
||||
|
||||
@@ -13,10 +13,8 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.LogWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -546,24 +544,7 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
double prevHeadWorldY = startY + prevHeadOffsetY;
|
||||
double prevHeadWorldZ = startZ + prevHeadOffsetZ;
|
||||
|
||||
Vec3 currentPos = Vec3.createVectorHelper(prevHeadWorldX, prevHeadWorldY, prevHeadWorldZ);
|
||||
Vec3 nextPos = Vec3.createVectorHelper(headX, headY, headZ);
|
||||
// Use full raytrace that doesn't stop at liquids and checks all blocks
|
||||
MovingObjectPosition blockHit = worldObj.func_147447_a(currentPos, nextPos, false, true, false);
|
||||
|
||||
if (blockHit != null && blockHit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
if (!worldObj.isRemote) {
|
||||
EventHooks.onEnergyProjectileBlockImpact(this, blockHit.blockX, blockHit.blockY, blockHit.blockZ);
|
||||
}
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
posX = blockHit.hitVec.xCoord;
|
||||
posY = blockHit.hitVec.yCoord;
|
||||
posZ = blockHit.hitVec.zCoord;
|
||||
doExplosion();
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleBlockImpact(rayTraceBlocks(prevHeadWorldX, prevHeadWorldY, prevHeadWorldZ, headX, headY, headZ), true);
|
||||
}
|
||||
|
||||
private void checkEntityCollision(double headX, double headY, double headZ) {
|
||||
@@ -577,24 +558,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (shouldIgnoreEntity(entity)) continue;
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
LogWriter.info("[Beam] DEAD: Entity collision with " + entity.getClass().getSimpleName() + " at tick " + ticksExisted);
|
||||
if (processEntityHit(entity, headX, headY, headZ)) {
|
||||
if (DEBUG_LOGGING) {
|
||||
LogWriter.info("[Beam] DEAD: Entity collision with " + entity.getClass().getSimpleName() + " at tick " + ticksExisted);
|
||||
}
|
||||
return;
|
||||
}
|
||||
hasHit = true;
|
||||
|
||||
if (isExplosive()) {
|
||||
posX = headX;
|
||||
posY = headY;
|
||||
posZ = headZ;
|
||||
doExplosion();
|
||||
} else {
|
||||
applyDamage(entity);
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,8 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Disc projectile - flat spinning disc with optional boomerang behavior.
|
||||
@@ -185,7 +181,6 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
|
||||
// Calculate velocity toward target
|
||||
Entity owner = getOwnerEntity();
|
||||
|
||||
if (target != null) {
|
||||
double dx = target.posX - posX;
|
||||
double dy = (target.posY + target.getEyeHeight()) - posY;
|
||||
@@ -248,15 +243,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
// Check wall collision
|
||||
if (this.isCollidedHorizontally || this.isCollidedVertically) {
|
||||
if (!worldObj.isRemote) {
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
}
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleSolidCollisionTermination();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -352,24 +339,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
private void checkBlockCollision() {
|
||||
Vec3 currentPos = Vec3.createVectorHelper(posX, posY, posZ);
|
||||
Vec3 nextPos = Vec3.createVectorHelper(posX + motionX, posY + motionY, posZ + motionZ);
|
||||
// Use full raytrace that doesn't stop at liquids and checks all blocks
|
||||
MovingObjectPosition blockHit = worldObj.func_147447_a(currentPos, nextPos, false, true, false);
|
||||
|
||||
if (blockHit != null && blockHit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
if (!worldObj.isRemote) {
|
||||
EventHooks.onEnergyProjectileBlockImpact(this, blockHit.blockX, blockHit.blockY, blockHit.blockZ);
|
||||
}
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
posX = blockHit.hitVec.xCoord;
|
||||
posY = blockHit.hitVec.yCoord;
|
||||
posZ = blockHit.hitVec.zCoord;
|
||||
doExplosion();
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleBlockImpact(rayTraceBlocks(posX, posY, posZ, posX + motionX, posY + motionY, posZ + motionZ), true);
|
||||
}
|
||||
|
||||
private void checkEntityCollision() {
|
||||
@@ -381,23 +351,7 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
posX + halfWidth, posY + halfHeight, posZ + halfWidth
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (shouldIgnoreEntity(entity)) continue;
|
||||
|
||||
hasHit = true;
|
||||
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
} else {
|
||||
applyDamage(entity);
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
processEntitiesInHitBox(hitBox, posX, posY, posZ);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,12 +17,10 @@ import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Laser projectile - fast expanding thin line that pierces through multiple targets.
|
||||
* Laser projectile - fast expanding thin line.
|
||||
* No homing, travels in a straight line from origin to max distance.
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
@@ -45,12 +43,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
// Lock vertical direction after firing (only update yaw, keep pitch fixed)
|
||||
private boolean lockVerticalDirection = false;
|
||||
|
||||
// Whether to die on first entity impact (hit-scan mode)
|
||||
private boolean dieOnImpact = false;
|
||||
|
||||
// Track hit entities to avoid double-damage
|
||||
private Set<Integer> hitEntities = new HashSet<>();
|
||||
|
||||
// End point for rendering
|
||||
private double endX, endY, endZ;
|
||||
|
||||
@@ -217,8 +209,8 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
public void startMoving(EntityLivingBase target) {
|
||||
setCharging(false);
|
||||
|
||||
// Set initial direction from owner's rotation
|
||||
Entity owner = getOwnerEntity();
|
||||
// Set initial direction from owner's rotation
|
||||
if (owner != null) {
|
||||
float yaw = (float) Math.toRadians(owner.rotationYaw);
|
||||
float pitch = (float) Math.toRadians(owner.rotationPitch);
|
||||
@@ -262,10 +254,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
private void checkBlockCollision() {
|
||||
Vec3 start = Vec3.createVectorHelper(startX, startY, startZ);
|
||||
Vec3 end = Vec3.createVectorHelper(endX, endY, endZ);
|
||||
// Use full raytrace that doesn't stop at liquids and checks all blocks
|
||||
MovingObjectPosition blockHit = worldObj.func_147447_a(start, end, false, true, false);
|
||||
MovingObjectPosition blockHit = rayTraceBlocks(startX, startY, startZ, endX, endY, endZ);
|
||||
|
||||
if (blockHit != null && blockHit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
if (!worldObj.isRemote) {
|
||||
@@ -315,15 +304,12 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (shouldIgnoreEntity(entity)) continue;
|
||||
if (hitEntities.contains(entity.getEntityId())) continue;
|
||||
if (!canHitEntityNow(entity)) continue;
|
||||
|
||||
// Check if entity's bounding box intersects with the laser line
|
||||
if (isEntityOnLine(entity)) {
|
||||
hitEntities.add(entity.getEntityId());
|
||||
applyDamage(entity);
|
||||
|
||||
if (dieOnImpact) {
|
||||
// Stop at impact point and begin linger/fade
|
||||
if (processEntityHit(entity, entity.posX, entity.posY + entity.height * 0.5, entity.posZ)) {
|
||||
// Stop at impact point and terminate
|
||||
double dx = entity.posX - startX;
|
||||
double dy = (entity.posY + entity.height * 0.5) - startY;
|
||||
double dz = entity.posZ - startZ;
|
||||
@@ -332,11 +318,10 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
endX = startX + dirX * currentLength;
|
||||
endY = startY + dirY * currentLength;
|
||||
endZ = startZ + dirZ * currentLength;
|
||||
fullyExtended = true;
|
||||
return; // Stop checking further entities
|
||||
return;
|
||||
}
|
||||
|
||||
// Piercing - don't stop, continue to next entity
|
||||
// PIERCE/MULTI continue through remaining entities.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -517,14 +502,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.lingerTicks = ticks;
|
||||
}
|
||||
|
||||
public boolean isDieOnImpact() {
|
||||
return dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDieOnImpact(boolean dieOnImpact) {
|
||||
this.dieOnImpact = dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDirection(double x, double y, double z) {
|
||||
this.dirX = x;
|
||||
this.dirY = y;
|
||||
@@ -593,7 +570,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
if (Float.isNaN(expansionSpeed) || Float.isInfinite(expansionSpeed) || expansionSpeed <= 0) expansionSpeed = 2.0f;
|
||||
this.lingerTicks = nbt.hasKey("LingerTicks") ? nbt.getInteger("LingerTicks") : 10;
|
||||
if (lingerTicks <= 0) lingerTicks = 1;
|
||||
this.dieOnImpact = nbt.getBoolean("DieOnImpact");
|
||||
this.lockVerticalDirection = nbt.getBoolean("LockVerticalDir");
|
||||
this.ticksSinceFullExtension = nbt.getInteger("TicksSinceExtended");
|
||||
this.dirX = nbt.getDouble("DirX");
|
||||
@@ -613,7 +589,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
nbt.setFloat("LaserWidth", laserWidth);
|
||||
nbt.setFloat("ExpansionSpeed", expansionSpeed);
|
||||
nbt.setInteger("LingerTicks", lingerTicks);
|
||||
nbt.setBoolean("DieOnImpact", dieOnImpact);
|
||||
nbt.setBoolean("LockVerticalDir", lockVerticalDirection);
|
||||
nbt.setInteger("TicksSinceExtended", ticksSinceFullExtension);
|
||||
nbt.setDouble("DirX", dirX);
|
||||
|
||||
@@ -12,12 +12,8 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Orb projectile - spherical homing energy ball.
|
||||
@@ -140,7 +136,6 @@ public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
|
||||
// Calculate velocity toward target
|
||||
Entity owner = getOwnerEntity();
|
||||
|
||||
if (target != null) {
|
||||
double dx = target.posX - posX;
|
||||
double dy = (target.posY + target.getEyeHeight()) - posY;
|
||||
@@ -185,15 +180,7 @@ public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
// Check wall collision
|
||||
if (this.isCollidedHorizontally || this.isCollidedVertically) {
|
||||
if (!worldObj.isRemote) {
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
}
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleSolidCollisionTermination();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,24 +220,7 @@ public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
private void checkBlockCollision() {
|
||||
Vec3 currentPos = Vec3.createVectorHelper(posX, posY, posZ);
|
||||
Vec3 nextPos = Vec3.createVectorHelper(posX + motionX, posY + motionY, posZ + motionZ);
|
||||
// Use full raytrace that doesn't stop at liquids and checks all blocks
|
||||
MovingObjectPosition blockHit = worldObj.func_147447_a(currentPos, nextPos, false, true, false);
|
||||
|
||||
if (blockHit != null && blockHit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
if (!worldObj.isRemote) {
|
||||
EventHooks.onEnergyProjectileBlockImpact(this, blockHit.blockX, blockHit.blockY, blockHit.blockZ);
|
||||
}
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
posX = blockHit.hitVec.xCoord;
|
||||
posY = blockHit.hitVec.yCoord;
|
||||
posZ = blockHit.hitVec.zCoord;
|
||||
doExplosion();
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleBlockImpact(rayTraceBlocks(posX, posY, posZ, posX + motionX, posY + motionY, posZ + motionZ), true);
|
||||
}
|
||||
|
||||
private void checkEntityCollision() {
|
||||
@@ -259,24 +229,7 @@ public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
posX - hitSize, posY - hitSize, posZ - hitSize,
|
||||
posX + hitSize, posY + hitSize, posZ + hitSize
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (shouldIgnoreEntity(entity)) continue;
|
||||
|
||||
hasHit = true;
|
||||
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
} else {
|
||||
applyDamage(entity);
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
processEntitiesInHitBox(hitBox, posX, posY, posZ);
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
@@ -5,6 +5,7 @@ import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.HitType;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
@@ -20,6 +21,7 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
@@ -35,9 +37,11 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for all ability projectiles (Orb, Disc, Beam, Laser, Slicer).
|
||||
@@ -112,6 +116,8 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
// ==================== STATE ====================
|
||||
protected boolean hasHit = false;
|
||||
protected final Set<Integer> hitOnceEntities = new HashSet<Integer>();
|
||||
protected final Map<Integer, Integer> lastHitTickByEntity = new HashMap<Integer, Integer>();
|
||||
|
||||
// ==================== CHARGING STATE (projectile-specific) ====================
|
||||
protected float targetSize = 1.0f;
|
||||
@@ -364,20 +370,6 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int posRotationIncrements) {
|
||||
// If position changed significantly (e.g. snap from anchor to look vector),
|
||||
// skip interpolation and jump directly to prevent visual offset from crosshair
|
||||
double dx = x - this.posX;
|
||||
double dy = y - this.posY;
|
||||
double dz = z - this.posZ;
|
||||
if (dx * dx + dy * dy + dz * dz > 1.0) {
|
||||
this.setPosition(x, y, z);
|
||||
this.prevPosX = x;
|
||||
this.prevPosY = y;
|
||||
this.prevPosZ = z;
|
||||
this.interpSteps = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.interpTargetX = x;
|
||||
this.interpTargetY = y;
|
||||
this.interpTargetZ = z;
|
||||
@@ -861,6 +853,142 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
combatData.setExplosionDamageFalloff(falloff);
|
||||
}
|
||||
|
||||
public int getHitType() {
|
||||
return combatData.hitType.ordinal();
|
||||
}
|
||||
|
||||
public void setHitType(int hitType) {
|
||||
combatData.hitType = HitType.fromOrdinal(hitType);
|
||||
}
|
||||
|
||||
public int getMultiHitDelayTicks() {
|
||||
return combatData.multiHitDelayTicks;
|
||||
}
|
||||
|
||||
public void setMultiHitDelayTicks(int delayTicks) {
|
||||
combatData.multiHitDelayTicks = Math.max(1, delayTicks);
|
||||
}
|
||||
|
||||
protected boolean canHitEntityNow(EntityLivingBase entity) {
|
||||
if (entity == null) return false;
|
||||
|
||||
int entityId = entity.getEntityId();
|
||||
switch (combatData.hitType) {
|
||||
case PIERCE:
|
||||
return !hitOnceEntities.contains(entityId);
|
||||
case MULTI:
|
||||
Integer lastHitTick = lastHitTickByEntity.get(entityId);
|
||||
if (lastHitTick == null) return true;
|
||||
int delay = Math.max(1, combatData.multiHitDelayTicks);
|
||||
return ticksExisted - lastHitTick >= delay;
|
||||
case SINGLE:
|
||||
default:
|
||||
return !hasHit;
|
||||
}
|
||||
}
|
||||
|
||||
protected void recordEntityHit(EntityLivingBase entity) {
|
||||
if (entity == null) return;
|
||||
int entityId = entity.getEntityId();
|
||||
hitOnceEntities.add(entityId);
|
||||
lastHitTickByEntity.put(entityId, ticksExisted);
|
||||
}
|
||||
|
||||
protected boolean shouldTerminateAfterHit() {
|
||||
return combatData.hitType == HitType.SINGLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared block raytrace helper used by most projectile types.
|
||||
*/
|
||||
protected MovingObjectPosition rayTraceBlocks(double fromX, double fromY, double fromZ, double toX, double toY, double toZ) {
|
||||
Vec3 currentPos = Vec3.createVectorHelper(fromX, fromY, fromZ);
|
||||
Vec3 nextPos = Vec3.createVectorHelper(toX, toY, toZ);
|
||||
return worldObj.func_147447_a(currentPos, nextPos, false, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared block-hit handling: fires block impact hook, optional explosion, and kills projectile.
|
||||
*/
|
||||
protected boolean handleBlockImpact(MovingObjectPosition blockHit, boolean explodeAtHitPoint) {
|
||||
if (blockHit == null || blockHit.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) return false;
|
||||
|
||||
if (!worldObj.isRemote) {
|
||||
EventHooks.onEnergyProjectileBlockImpact(this, blockHit.blockX, blockHit.blockY, blockHit.blockZ);
|
||||
}
|
||||
hasHit = true;
|
||||
|
||||
if (isExplosive()) {
|
||||
if (explodeAtHitPoint && blockHit.hitVec != null) {
|
||||
posX = blockHit.hitVec.xCoord;
|
||||
posY = blockHit.hitVec.yCoord;
|
||||
posZ = blockHit.hitVec.zCoord;
|
||||
}
|
||||
doExplosion();
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply projectile hit behavior to a target and return true if the projectile terminated.
|
||||
*/
|
||||
protected boolean processEntityHit(EntityLivingBase entity, double impactX, double impactY, double impactZ) {
|
||||
if (entity == null || shouldIgnoreEntity(entity) || !canHitEntityNow(entity)) return false;
|
||||
|
||||
recordEntityHit(entity);
|
||||
if (isExplosive()) {
|
||||
double oldX = posX;
|
||||
double oldY = posY;
|
||||
double oldZ = posZ;
|
||||
posX = impactX;
|
||||
posY = impactY;
|
||||
posZ = impactZ;
|
||||
doExplosion();
|
||||
posX = oldX;
|
||||
posY = oldY;
|
||||
posZ = oldZ;
|
||||
} else {
|
||||
applyDamage(entity);
|
||||
}
|
||||
|
||||
if (shouldTerminateAfterHit()) {
|
||||
hasHit = true;
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan entities in a hitbox and process the first/each valid hit based on hit mode.
|
||||
*/
|
||||
protected boolean processEntitiesInHitBox(AxisAlignedBB hitBox, double impactX, double impactY, double impactZ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (processEntityHit(entity, impactX, impactY, impactZ)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean handleSolidCollisionTermination() {
|
||||
if (!this.isCollidedHorizontally && !this.isCollidedVertically) return false;
|
||||
|
||||
if (!worldObj.isRemote) {
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
}
|
||||
}
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== HOMING GETTERS & SETTERS ====================
|
||||
|
||||
public boolean isHoming() {
|
||||
|
||||
@@ -11,25 +11,18 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Slicer entity - a thin, wide blade projectile that flies in a straight line.
|
||||
* JJK Cleave/Dismantle inspired. Piercing by default (passes through entities).
|
||||
* JJK Cleave/Dismantle inspired.
|
||||
* Extends EntityEnergyAbility to leverage the existing projectile infrastructure.
|
||||
*/
|
||||
public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
|
||||
private float sliceWidth = 3.0f;
|
||||
private float sliceThickness = 0.15f;
|
||||
private boolean piercing = true;
|
||||
private List<Integer> hitEntities = new ArrayList<>();
|
||||
|
||||
public EntityEnergySlicer(World world) {
|
||||
super(world);
|
||||
@@ -43,15 +36,13 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
float sliceWidth, float sliceThickness,
|
||||
EnergyDisplayData display, EnergyCombatData combat,
|
||||
EnergyHomingData homing, EnergyLightningData lightning,
|
||||
EnergyLifespanData lifespan, EnergyTrajectoryData trajectory,
|
||||
boolean piercing) {
|
||||
EnergyLifespanData lifespan, EnergyTrajectoryData trajectory) {
|
||||
super(world);
|
||||
|
||||
initProjectile(owner, target, x, y, z, sliceWidth, display, combat, lightning, lifespan, trajectory);
|
||||
this.homingData = homing;
|
||||
this.sliceWidth = sliceWidth;
|
||||
this.sliceThickness = sliceThickness;
|
||||
this.piercing = piercing;
|
||||
|
||||
calculateInitialVelocity(owner, target, x, y, z);
|
||||
}
|
||||
@@ -196,15 +187,7 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
// Wall collision
|
||||
if (this.isCollidedHorizontally || this.isCollidedVertically) {
|
||||
if (!worldObj.isRemote) {
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
}
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
handleSolidCollisionTermination();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -223,19 +206,7 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
private void checkBlockCollision() {
|
||||
if (piercing) return; // Piercing slicers pass through blocks
|
||||
|
||||
Vec3 currentPos = Vec3.createVectorHelper(posX, posY, posZ);
|
||||
Vec3 nextPos = Vec3.createVectorHelper(posX + motionX, posY + motionY, posZ + motionZ);
|
||||
MovingObjectPosition blockHit = worldObj.func_147447_a(currentPos, nextPos, false, true, false);
|
||||
|
||||
if (blockHit != null && blockHit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
|
||||
if (!worldObj.isRemote) {
|
||||
EventHooks.onEnergyProjectileBlockImpact(this, blockHit.blockX, blockHit.blockY, blockHit.blockZ);
|
||||
}
|
||||
hasHit = true;
|
||||
this.setDead();
|
||||
}
|
||||
handleBlockImpact(rayTraceBlocks(posX, posY, posZ, posX + motionX, posY + motionY, posZ + motionZ), false);
|
||||
}
|
||||
|
||||
private void checkEntityCollision() {
|
||||
@@ -246,29 +217,7 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
posX + halfW, posY + halfH, posZ + halfW
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
|
||||
for (EntityLivingBase entity : entities) {
|
||||
if (shouldIgnoreEntity(entity)) continue;
|
||||
if (hitEntities.contains(entity.getEntityId())) continue; // Already hit this entity
|
||||
|
||||
if (piercing) {
|
||||
// Pierce: damage but keep flying
|
||||
applyDamage(entity);
|
||||
hitEntities.add(entity.getEntityId());
|
||||
} else {
|
||||
// Non-piercing: damage and die
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
} else {
|
||||
applyDamage(entity);
|
||||
}
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
}
|
||||
processEntitiesInHitBox(hitBox, posX, posY, posZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,14 +264,6 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
this.sliceThickness = thickness;
|
||||
}
|
||||
|
||||
public boolean isPiercing() {
|
||||
return piercing;
|
||||
}
|
||||
|
||||
public void setPiercing(boolean piercing) {
|
||||
this.piercing = piercing;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
@@ -330,7 +271,6 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
readChargingNBT(nbt);
|
||||
this.sliceWidth = sanitize(nbt.hasKey("SliceWidth") ? nbt.getFloat("SliceWidth") : 3.0f, 3.0f, MAX_ENTITY_SIZE);
|
||||
this.sliceThickness = sanitize(nbt.hasKey("SliceThickness") ? nbt.getFloat("SliceThickness") : 0.15f, 0.15f, MAX_ENTITY_SIZE);
|
||||
this.piercing = !nbt.hasKey("Piercing") || nbt.getBoolean("Piercing");
|
||||
this.targetSliceWidth = sanitize(nbt.hasKey("TargetSliceWidth") ? nbt.getFloat("TargetSliceWidth") : sliceWidth, sliceWidth, MAX_ENTITY_SIZE);
|
||||
this.targetSliceThickness = sanitize(nbt.hasKey("TargetSliceThickness") ? nbt.getFloat("TargetSliceThickness") : sliceThickness, sliceThickness, MAX_ENTITY_SIZE);
|
||||
}
|
||||
@@ -340,7 +280,6 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
writeChargingNBT(nbt);
|
||||
nbt.setFloat("SliceWidth", sliceWidth);
|
||||
nbt.setFloat("SliceThickness", sliceThickness);
|
||||
nbt.setBoolean("Piercing", piercing);
|
||||
nbt.setFloat("TargetSliceWidth", targetSliceWidth);
|
||||
nbt.setFloat("TargetSliceThickness", targetSliceThickness);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,22 @@ public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends Sc
|
||||
entity.setExplosionDamageFalloff(falloff);
|
||||
}
|
||||
|
||||
public int getHitType() {
|
||||
return entity.getHitType();
|
||||
}
|
||||
|
||||
public void setHitType(int hitType) {
|
||||
entity.setHitType(hitType);
|
||||
}
|
||||
|
||||
public int getMultiHitDelayTicks() {
|
||||
return entity.getMultiHitDelayTicks();
|
||||
}
|
||||
|
||||
public void setMultiHitDelayTicks(int delayTicks) {
|
||||
entity.setMultiHitDelayTicks(delayTicks);
|
||||
}
|
||||
|
||||
// ==================== MOVEMENT ====================
|
||||
|
||||
public float getSpeed() {
|
||||
|
||||
@@ -45,14 +45,6 @@ public class ScriptEnergySlicer<T extends EntityEnergySlicer> extends ScriptEner
|
||||
entity.setSliceThickness(thickness);
|
||||
}
|
||||
|
||||
public boolean isPiercing() {
|
||||
return entity.isPiercing();
|
||||
}
|
||||
|
||||
public void setPiercing(boolean piercing) {
|
||||
entity.setPiercing(piercing);
|
||||
}
|
||||
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
|
||||
Reference in new issue
Block a user