mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 19:34:09 +00:00
Merge remote-tracking branch 'origin/syntax-highlighter-unified' into syntax-highlighter-unified
This commit is contained in:
commit
879dca7391
14 files changed
+220
-168
No files matched your search
@@ -33,13 +33,13 @@ public class RenderEnergyLaser extends RenderEnergy {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get laser parameters
|
||||
double startX = laser.getStartX();
|
||||
double startY = laser.getStartY();
|
||||
double startZ = laser.getStartZ();
|
||||
double endX = laser.getEndX();
|
||||
double endY = laser.getEndY();
|
||||
double endZ = laser.getEndZ();
|
||||
// Get interpolated laser positions for smooth rendering between ticks
|
||||
double startX = laser.getInterpolatedStartX(partialTicks);
|
||||
double startY = laser.getInterpolatedStartY(partialTicks);
|
||||
double startZ = laser.getInterpolatedStartZ(partialTicks);
|
||||
double endX = laser.getInterpolatedEndX(partialTicks);
|
||||
double endY = laser.getInterpolatedEndY(partialTicks);
|
||||
double endZ = laser.getInterpolatedEndZ(partialTicks);
|
||||
float width = laser.getLaserWidth();
|
||||
float alpha = 1.0f;
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
protected LockMode lockMovement = LockMode.WINDUP;
|
||||
protected RotationMode rotationMode = RotationMode.FREE;
|
||||
protected LockMode rotationPhase = LockMode.WINDUP_AND_ACTIVE;
|
||||
protected float trackDelay = 0; // 0 = instant tracking (legacy). Higher = slower lerp toward target.
|
||||
protected float trackSpeed = 0; // 0 = instant tracking. Linear tracking speed in blocks/second.
|
||||
protected int windUpColor = 0x80FF4400; // Telegraph color during wind up
|
||||
protected int activeColor = 0xC0FF0000; // Telegraph warning/active color
|
||||
|
||||
@@ -771,9 +771,9 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
.hover("ability.hover.rotationPhase")
|
||||
.visibleWhen(() -> this.rotationMode != RotationMode.FREE)
|
||||
).tab("General"));
|
||||
defs.add(FieldDef.floatField("ability.trackDelay", this::getTrackDelay, this::setTrackDelay)
|
||||
.range(0.0f, 20.0f)
|
||||
.hover("ability.hover.trackDelay")
|
||||
defs.add(FieldDef.floatField("ability.trackSpeed", this::getTrackSpeed, this::setTrackSpeed)
|
||||
.range(0.0f, 12.0f)
|
||||
.hover("ability.hover.trackSpeed")
|
||||
.visibleWhen(() -> this.rotationMode == RotationMode.TRACK)
|
||||
.tab("General"));
|
||||
defs.add(FieldDef.row(
|
||||
@@ -1516,7 +1516,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
nbt.setInteger("lockMovement", lockMovement.ordinal());
|
||||
nbt.setInteger("rotationMode", rotationMode.ordinal());
|
||||
nbt.setInteger("rotationPhase", rotationPhase.ordinal());
|
||||
nbt.setFloat("trackDelay", trackDelay);
|
||||
nbt.setFloat("trackSpeed", trackSpeed);
|
||||
nbt.setInteger("windUpColor", windUpColor);
|
||||
nbt.setInteger("activeColor", activeColor);
|
||||
nbt.setString("windUpSound", windUpSound);
|
||||
@@ -1613,7 +1613,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
lockMovement = LockMode.fromOrdinal(nbt.getInteger("lockMovement"));
|
||||
rotationMode = RotationMode.fromOrdinal(nbt.getInteger("rotationMode"));
|
||||
rotationPhase = LockMode.fromOrdinal(nbt.getInteger("rotationPhase"));
|
||||
trackDelay = nbt.hasKey("trackDelay") ? nbt.getFloat("trackDelay") : 0;
|
||||
trackSpeed = nbt.hasKey("trackSpeed") ? nbt.getFloat("trackSpeed") : 0;
|
||||
windUpColor = nbt.hasKey("windUpColor") ? nbt.getInteger("windUpColor") : 0x80FF4400;
|
||||
activeColor = nbt.hasKey("activeColor") ? nbt.getInteger("activeColor") : 0xC0FF0000;
|
||||
windUpSound = nbt.getString("windUpSound");
|
||||
@@ -1958,14 +1958,15 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
this.rotationPhase = rotationPhase;
|
||||
}
|
||||
|
||||
public float getTrackDelay() {
|
||||
return trackDelay;
|
||||
public float getTrackSpeed() {
|
||||
return trackSpeed;
|
||||
}
|
||||
|
||||
public void setTrackDelay(float trackDelay) {
|
||||
this.trackDelay = trackDelay;
|
||||
public void setTrackSpeed(float trackSpeed) {
|
||||
this.trackSpeed = trackSpeed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* API method: Get lock movement type as integer.
|
||||
*
|
||||
@@ -2027,22 +2028,22 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* API method: Get track delay for TRACK rotation mode.
|
||||
* 0 = instant tracking (legacy). Higher = slower lerp toward target.
|
||||
* API method: Get track speed for TRACK rotation mode (blocks/second).
|
||||
* 0 = instant tracking. Comparable to player sprint speed (~5.6 blocks/sec).
|
||||
*/
|
||||
@Override
|
||||
public float getTrackDelayValue() {
|
||||
return trackDelay;
|
||||
public float getTrackSpeedValue() {
|
||||
return trackSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* API method: Set track delay for TRACK rotation mode.
|
||||
* API method: Set track speed for TRACK rotation mode (blocks/second).
|
||||
*
|
||||
* @param delay 0 = instant tracking. Higher = slower lerp toward target.
|
||||
* @param speed 0 = instant tracking. ~4 = dodgeable while sprinting. ~6 = barely undodgeable.
|
||||
*/
|
||||
@Override
|
||||
public void setTrackDelayValue(float delay) {
|
||||
this.trackDelay = Math.max(0, delay);
|
||||
public void setTrackSpeedValue(float speed) {
|
||||
this.trackSpeed = Math.max(0, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ public class AbilityLaser extends AbilityEnergyProjectile<EntityAbilityLaser> im
|
||||
this.lockMovement = LockMode.WINDUP_AND_ACTIVE;
|
||||
this.rotationMode = RotationMode.TRACK;
|
||||
this.rotationPhase = LockMode.WINDUP_AND_ACTIVE;
|
||||
this.trackDelay = 3;
|
||||
this.trackSpeed = 4.0f;
|
||||
this.telegraphType = TelegraphType.LINE;
|
||||
this.showTelegraph = true;
|
||||
this.windUpAnimationName = "Ability_Laser_Windup";
|
||||
|
||||
@@ -47,6 +47,10 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
// End point for rendering
|
||||
private double endX, endY, endZ;
|
||||
|
||||
// Previous tick positions for partial tick interpolation
|
||||
private double prevStartX, prevStartY, prevStartZ;
|
||||
private double prevEndX, prevEndY, prevEndZ;
|
||||
|
||||
// Block hit deduplication — prevents event/explosion spam every tick
|
||||
private int lastBlockHitX = Integer.MIN_VALUE;
|
||||
private int lastBlockHitY = Integer.MIN_VALUE;
|
||||
@@ -107,10 +111,16 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize end point
|
||||
// Initialize end point and prev positions
|
||||
this.endX = x;
|
||||
this.endY = y;
|
||||
this.endZ = z;
|
||||
this.prevStartX = x;
|
||||
this.prevStartY = y;
|
||||
this.prevStartZ = z;
|
||||
this.prevEndX = x;
|
||||
this.prevEndY = y;
|
||||
this.prevEndZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,6 +148,14 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save previous positions for partial tick interpolation
|
||||
prevStartX = startX;
|
||||
prevStartY = startY;
|
||||
prevStartZ = startZ;
|
||||
prevEndX = endX;
|
||||
prevEndY = endY;
|
||||
prevEndZ = endZ;
|
||||
|
||||
// Origin/direction tracking runs on BOTH sides so the client can render the beam.
|
||||
// Once reflected, never resume owner-tracking — the laser flies in a fixed direction.
|
||||
if (!reflected) {
|
||||
@@ -285,6 +303,14 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.endX = startX;
|
||||
this.endY = startY;
|
||||
this.endZ = startZ;
|
||||
|
||||
// Initialize prev positions to current so first frame doesn't jump
|
||||
this.prevStartX = startX;
|
||||
this.prevStartY = startY;
|
||||
this.prevStartZ = startZ;
|
||||
this.prevEndX = startX;
|
||||
this.prevEndY = startY;
|
||||
this.prevEndZ = startZ;
|
||||
}
|
||||
|
||||
private boolean setDirectionTowardTarget(EntityLivingBase target, double sourceX, double sourceY, double sourceZ) {
|
||||
@@ -733,6 +759,30 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
return endZ;
|
||||
}
|
||||
|
||||
public double getInterpolatedStartX(float partialTicks) {
|
||||
return prevStartX + (startX - prevStartX) * partialTicks;
|
||||
}
|
||||
|
||||
public double getInterpolatedStartY(float partialTicks) {
|
||||
return prevStartY + (startY - prevStartY) * partialTicks;
|
||||
}
|
||||
|
||||
public double getInterpolatedStartZ(float partialTicks) {
|
||||
return prevStartZ + (startZ - prevStartZ) * partialTicks;
|
||||
}
|
||||
|
||||
public double getInterpolatedEndX(float partialTicks) {
|
||||
return prevEndX + (endX - prevEndX) * partialTicks;
|
||||
}
|
||||
|
||||
public double getInterpolatedEndY(float partialTicks) {
|
||||
return prevEndY + (endY - prevEndY) * partialTicks;
|
||||
}
|
||||
|
||||
public double getInterpolatedEndZ(float partialTicks) {
|
||||
return prevEndZ + (endZ - prevEndZ) * partialTicks;
|
||||
}
|
||||
|
||||
public double getDirX() {
|
||||
return dirX;
|
||||
}
|
||||
@@ -761,6 +811,12 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.endX = posX;
|
||||
this.endY = posY;
|
||||
this.endZ = posZ;
|
||||
this.prevStartX = posX;
|
||||
this.prevStartY = posY;
|
||||
this.prevStartZ = posZ;
|
||||
this.prevEndX = posX;
|
||||
this.prevEndY = posY;
|
||||
this.prevEndZ = posZ;
|
||||
}
|
||||
|
||||
// ==================== REFLECTION SYNC ====================
|
||||
@@ -862,6 +918,12 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.endX = posX;
|
||||
this.endY = posY;
|
||||
this.endZ = posZ;
|
||||
this.prevStartX = posX;
|
||||
this.prevStartY = posY;
|
||||
this.prevStartZ = posZ;
|
||||
this.prevEndX = posX;
|
||||
this.prevEndY = posY;
|
||||
this.prevEndZ = posZ;
|
||||
|
||||
// Precompute initial direction from owner look for launch.
|
||||
Vec3 look = owner == null ? null : owner.getLookVec();
|
||||
|
||||
@@ -785,6 +785,9 @@ public abstract class AbstractDataAbilities {
|
||||
// Fire tick event
|
||||
fireTickEvent(currentAbility, target);
|
||||
|
||||
// Script may have completed/cancelled the ability during the tick event
|
||||
if (currentAbility == null || !currentAbility.isExecuting()) return;
|
||||
|
||||
// Fire extender tick hook (e.g., per-tick resource drain)
|
||||
if (!AbilityController.Instance.fireOnAbilityTick(currentAbility, entity, target,
|
||||
currentAbility.getPhase(), currentAbility.getCurrentTick())) {
|
||||
|
||||
@@ -88,7 +88,11 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
*/
|
||||
private transient boolean hitScanActive = false;
|
||||
private transient EntityLivingBase hitScanTarget = null;
|
||||
private transient float currentTrackDelay = 0;
|
||||
private transient float currentTrackSpeed = 0;
|
||||
private transient float trackedYaw = 0;
|
||||
private transient float trackedPitch = 0;
|
||||
private transient boolean trackLerpedThisTick = false;
|
||||
private transient boolean preserveTrackedRotation = false;
|
||||
|
||||
/**
|
||||
* Bit flag for rotation control (LOCKED or TRACK) in data watcher slot 15
|
||||
@@ -219,19 +223,28 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
|
||||
@Override
|
||||
protected void onPreExecute(Ability ability, EntityLivingBase target) {
|
||||
// Snap NPC to face target before execute so startMoving() reads correct rotation
|
||||
// Face target before execute so startMoving() reads correct rotation
|
||||
// Use trackSpeed so the NPC plays catchup rather than instant-snapping
|
||||
if (ability.isHitScanForCurrentPhase() && target != null) {
|
||||
faceTarget(target);
|
||||
float speed = ability.getTrackSpeed();
|
||||
if (speed <= 0) {
|
||||
faceTarget(target);
|
||||
} else {
|
||||
faceTarget(target, speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostPhaseTick(Ability ability, EntityLivingBase target) {
|
||||
// Reset per-tick lerp flag so faceTarget only computes the lerp once per tick
|
||||
trackLerpedThisTick = false;
|
||||
|
||||
// Update hit scan state - actual facing is deferred to applyRotationControl()
|
||||
// which runs AFTER super.onLivingUpdate() to override AI look helper
|
||||
if (ability != null && ability.isExecuting() && target != null) {
|
||||
if (ability.isHitScanForCurrentPhase()) {
|
||||
enableHitScan(target, ability.getTrackDelay());
|
||||
enableHitScan(target, ability.getTrackSpeed());
|
||||
} else {
|
||||
// Release hit scan if it was previously active
|
||||
if (hitScanActive) {
|
||||
@@ -254,7 +267,10 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
|
||||
@Override
|
||||
protected void onBurstDelayReleaseLocks() {
|
||||
if (hitScanActive) releaseRotationControl();
|
||||
if (hitScanActive) {
|
||||
preserveTrackedRotation = true;
|
||||
releaseRotationControl();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -881,31 +897,44 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
/**
|
||||
* Enable hit scan tracking for the given target.
|
||||
*/
|
||||
private void enableHitScan(EntityLivingBase target, float trackDelay) {
|
||||
private void enableHitScan(EntityLivingBase target, float trackSpeed) {
|
||||
if (!hitScanActive) {
|
||||
hitScanActive = true;
|
||||
npc.setBoolFlag(true, ROTATION_CONTROLLED_FLAG);
|
||||
// Preserve tracked rotation across burst delays so the NPC doesn't snap
|
||||
if (!preserveTrackedRotation) {
|
||||
trackedYaw = npc.rotationYawHead;
|
||||
trackedPitch = npc.rotationPitch;
|
||||
}
|
||||
preserveTrackedRotation = false;
|
||||
}
|
||||
hitScanTarget = target;
|
||||
currentTrackDelay = trackDelay;
|
||||
currentTrackSpeed = trackSpeed;
|
||||
}
|
||||
|
||||
private static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||
private static final double RAD_TO_DEG = 180.0 / Math.PI;
|
||||
|
||||
/**
|
||||
* Face the target with optional track delay.
|
||||
* When trackDelay <= 0, snaps instantly (legacy behavior).
|
||||
* When trackDelay > 0, lerps toward the target each tick.
|
||||
* Face the target with optional track speed (linear speed in blocks/second).
|
||||
* When trackSpeed <= 0, snaps instantly.
|
||||
* When trackSpeed > 0, the NPC's aim point moves at trackSpeed blocks/second,
|
||||
* converted to angular velocity based on distance. This makes tracking feel
|
||||
* consistent regardless of range — directly comparable to player movement speed.
|
||||
*/
|
||||
private void faceTarget(EntityLivingBase target, float trackDelay) {
|
||||
private void faceTarget(EntityLivingBase target, float trackSpeed) {
|
||||
double dx = target.posX - npc.posX;
|
||||
double dz = target.posZ - npc.posZ;
|
||||
double dy = (target.posY + target.getEyeHeight() * 0.5) - (npc.posY + npc.getEyeHeight());
|
||||
double distXZ = Math.sqrt(dx * dx + dz * dz);
|
||||
|
||||
float targetYaw = (float) (Math.atan2(-dx, dz) * 180.0 / Math.PI);
|
||||
float targetPitch = (float) (-(Math.atan2(dy, distXZ)) * 180.0 / Math.PI);
|
||||
float targetYaw = (float) (Math.atan2(-dx, dz) * RAD_TO_DEG);
|
||||
float targetPitch = (float) (-(Math.atan2(dy, distXZ)) * RAD_TO_DEG);
|
||||
|
||||
if (trackDelay <= 0) {
|
||||
// Instant snap (legacy behavior)
|
||||
if (trackSpeed <= 0) {
|
||||
// Instant snap
|
||||
trackedYaw = targetYaw;
|
||||
trackedPitch = targetPitch;
|
||||
npc.rotationYaw = targetYaw;
|
||||
npc.rotationYawHead = targetYaw;
|
||||
npc.renderYawOffset = targetYaw;
|
||||
@@ -915,14 +944,28 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
npc.prevRenderYawOffset = targetYaw;
|
||||
npc.prevRotationPitch = targetPitch;
|
||||
} else {
|
||||
float lerpFactor = 1.0f / (1.0f + trackDelay);
|
||||
if (!trackLerpedThisTick) {
|
||||
trackLerpedThisTick = true;
|
||||
|
||||
// Wrap yaw difference to [-180, 180] for correct interpolation
|
||||
float yawDiff = wrapAngle(targetYaw - npc.rotationYawHead);
|
||||
float pitchDiff = targetPitch - npc.rotationPitch;
|
||||
// Convert linear speed (blocks/sec) to angular speed (degrees/tick)
|
||||
// using the actual distance to the target
|
||||
double dist = Math.max(1.0, Math.sqrt(dx * dx + dy * dy + dz * dz));
|
||||
float blocksPerTick = trackSpeed / 20.0f;
|
||||
float maxAngularSpeed = (float) (Math.atan2(blocksPerTick, dist) * RAD_TO_DEG);
|
||||
|
||||
float newYaw = npc.rotationYawHead + yawDiff * lerpFactor;
|
||||
float newPitch = npc.rotationPitch + pitchDiff * lerpFactor;
|
||||
float yawDiff = wrapAngle(targetYaw - trackedYaw);
|
||||
float pitchDiff = targetPitch - trackedPitch;
|
||||
|
||||
float totalAngle = (float) Math.sqrt(yawDiff * yawDiff + pitchDiff * pitchDiff);
|
||||
if (totalAngle > maxAngularSpeed) {
|
||||
float scale = maxAngularSpeed / totalAngle;
|
||||
yawDiff *= scale;
|
||||
pitchDiff *= scale;
|
||||
}
|
||||
|
||||
trackedYaw = trackedYaw + yawDiff;
|
||||
trackedPitch = trackedPitch + pitchDiff;
|
||||
}
|
||||
|
||||
// Set prev to current before updating (for smooth client interpolation)
|
||||
npc.prevRotationYaw = npc.rotationYaw;
|
||||
@@ -930,10 +973,10 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
npc.prevRenderYawOffset = npc.renderYawOffset;
|
||||
npc.prevRotationPitch = npc.rotationPitch;
|
||||
|
||||
npc.rotationYaw = newYaw;
|
||||
npc.rotationYawHead = newYaw;
|
||||
npc.renderYawOffset = newYaw;
|
||||
npc.rotationPitch = newPitch;
|
||||
npc.rotationYaw = trackedYaw;
|
||||
npc.rotationYawHead = trackedYaw;
|
||||
npc.renderYawOffset = trackedYaw;
|
||||
npc.rotationPitch = trackedPitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,7 +1019,7 @@ public class DataAbilities extends AbstractDataAbilities {
|
||||
|
||||
// Server: apply the appropriate rotation
|
||||
if (hitScanActive && hitScanTarget != null && !hitScanTarget.isDead) {
|
||||
faceTarget(hitScanTarget, currentTrackDelay);
|
||||
faceTarget(hitScanTarget, currentTrackSpeed);
|
||||
} else if (rotationLocked) {
|
||||
npc.rotationYaw = lockedYaw;
|
||||
npc.rotationYawHead = lockedYawHead;
|
||||
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.scripted.entity;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergyBeam;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyBeam<T extends EntityAbilityBeam> extends ScriptEnergyProjectile<T> implements IEnergyBeam {
|
||||
@@ -60,27 +59,7 @@ public class ScriptEnergyBeam<T extends EntityAbilityBeam> extends ScriptEnergyP
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
public void fireAt(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startFiring(mcTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(double x, double y, double z) {
|
||||
ensureSpawned();
|
||||
double dx = x - entity.posX;
|
||||
double dy = y - entity.posY;
|
||||
double dz = z - entity.posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) {
|
||||
entity.motionX = (dx / len) * entity.getSpeed();
|
||||
entity.motionY = (dy / len) * entity.getSpeed();
|
||||
entity.motionZ = (dz / len) * entity.getSpeed();
|
||||
}
|
||||
entity.startFiring(null);
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
entity.startFiring(target);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.scripted.entity;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergyDisc;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyDisc<T extends EntityAbilityDisc> extends ScriptEnergyProjectile<T> implements IEnergyDisc {
|
||||
@@ -76,27 +75,7 @@ public class ScriptEnergyDisc<T extends EntityAbilityDisc> extends ScriptEnergyP
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
public void fireAt(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startMoving(mcTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(double x, double y, double z) {
|
||||
ensureSpawned();
|
||||
double dx = x - entity.posX;
|
||||
double dy = y - entity.posY;
|
||||
double dz = z - entity.posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) {
|
||||
entity.motionX = (dx / len) * entity.getSpeed();
|
||||
entity.motionY = (dy / len) * entity.getSpeed();
|
||||
entity.motionZ = (dz / len) * entity.getSpeed();
|
||||
}
|
||||
entity.startMoving(null);
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
entity.startMoving(target);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.scripted.entity;
|
||||
import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergyLaser;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyLaser<T extends EntityAbilityLaser> extends ScriptEnergyProjectile<T> implements IEnergyLaser {
|
||||
@@ -92,18 +91,12 @@ public class ScriptEnergyLaser<T extends EntityAbilityLaser> extends ScriptEnerg
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
public void fireAt(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startMoving(mcTarget);
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
entity.startMoving(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(double x, double y, double z) {
|
||||
ensureSpawned();
|
||||
double dx = x - entity.posX;
|
||||
double dy = y - entity.posY;
|
||||
double dz = z - entity.posZ;
|
||||
@@ -111,6 +104,6 @@ public class ScriptEnergyLaser<T extends EntityAbilityLaser> extends ScriptEnerg
|
||||
if (len > 0) {
|
||||
entity.setDirection(dx / len, dy / len, dz / len);
|
||||
}
|
||||
entity.startMoving(null);
|
||||
ensureSpawned();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.scripted.entity;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergyOrb;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyOrb<T extends EntityAbilityOrb> extends ScriptEnergyProjectile<T> implements IEnergyOrb {
|
||||
@@ -28,27 +27,7 @@ public class ScriptEnergyOrb<T extends EntityAbilityOrb> extends ScriptEnergyPro
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startMoving(mcTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(double x, double y, double z) {
|
||||
ensureSpawned();
|
||||
double dx = x - entity.posX;
|
||||
double dy = y - entity.posY;
|
||||
double dz = z - entity.posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) {
|
||||
entity.motionX = (dx / len) * entity.getSpeed();
|
||||
entity.motionY = (dy / len) * entity.getSpeed();
|
||||
entity.motionZ = (dz / len) * entity.getSpeed();
|
||||
}
|
||||
entity.startMoving(null);
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
entity.startMoving(target);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.api.entity.IEnergyProjectile;
|
||||
@@ -261,8 +260,14 @@ public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends Sc
|
||||
|
||||
public void fireAt(IEntity target) {
|
||||
if (target != null) {
|
||||
Entity mcTarget = target.getMCEntity();
|
||||
setMotionToward(mcTarget.posX, mcTarget.posY + mcTarget.getEyeHeight(), mcTarget.posZ);
|
||||
EntityLivingBase living = resolveLivingTarget(target);
|
||||
if (living != null) {
|
||||
entity.setTargetEntityId(living.getEntityId());
|
||||
setMotionToward(living.posX, living.posY + living.getEyeHeight(), living.posZ);
|
||||
} else {
|
||||
net.minecraft.entity.Entity mcTarget = target.getMCEntity();
|
||||
setMotionToward(mcTarget.posX, mcTarget.posY + mcTarget.getEyeHeight(), mcTarget.posZ);
|
||||
}
|
||||
}
|
||||
ensureSpawned();
|
||||
}
|
||||
@@ -273,24 +278,22 @@ public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends Sc
|
||||
}
|
||||
|
||||
public void fireDirection(float yaw, float pitch) {
|
||||
float yawRad = (float) Math.toRadians(yaw);
|
||||
float pitchRad = (float) Math.toRadians(pitch);
|
||||
entity.motionX = -Math.sin(yawRad) * Math.cos(pitchRad) * entity.getSpeed();
|
||||
entity.motionY = -Math.sin(pitchRad) * entity.getSpeed();
|
||||
entity.motionZ = Math.cos(yawRad) * Math.cos(pitchRad) * entity.getSpeed();
|
||||
setMotionFromDirection(yaw, pitch);
|
||||
ensureSpawned();
|
||||
}
|
||||
|
||||
public void fireFrom(IEntityLivingBase caster) {
|
||||
if (caster == null) return;
|
||||
initFromCaster(caster);
|
||||
fireDirection(caster.getRotation(), caster.getPitch());
|
||||
launchFromOwner(null);
|
||||
ensureSpawned();
|
||||
}
|
||||
|
||||
public void fireFrom(IEntityLivingBase caster, IEntity target) {
|
||||
if (caster == null) return;
|
||||
initFromCaster(caster);
|
||||
fireAt(target);
|
||||
launchFromOwner(resolveLivingTarget(target));
|
||||
ensureSpawned();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,6 +307,37 @@ public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends Sc
|
||||
entity.setStartPosition(mc.posX, eyeY, mc.posZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for subclasses to call their entity's full launch sequence (startMoving/startFiring).
|
||||
* Called by fireFrom methods — handles look-vector snap, charge exit, homing init, etc.
|
||||
* Default: sets motion toward target, or along owner's look direction if target is null.
|
||||
*/
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
if (target != null) {
|
||||
setMotionToward(target.posX, target.posY + target.getEyeHeight(), target.posZ);
|
||||
} else {
|
||||
net.minecraft.entity.Entity owner = entity.getOwnerEntity();
|
||||
if (owner != null) {
|
||||
setMotionFromDirection(owner.rotationYaw, owner.rotationPitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMotionFromDirection(float yaw, float pitch) {
|
||||
float yawRad = (float) Math.toRadians(yaw);
|
||||
float pitchRad = (float) Math.toRadians(pitch);
|
||||
entity.motionX = -Math.sin(yawRad) * Math.cos(pitchRad) * entity.getSpeed();
|
||||
entity.motionY = -Math.sin(pitchRad) * entity.getSpeed();
|
||||
entity.motionZ = Math.cos(yawRad) * Math.cos(pitchRad) * entity.getSpeed();
|
||||
}
|
||||
|
||||
protected static EntityLivingBase resolveLivingTarget(IEntity target) {
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
return (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates and sets motion from the projectile's current position toward a target point.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,6 @@ package noppes.npcs.scripted.entity;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergySlicer;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergySlicer<T extends EntityEnergySlicer> extends ScriptEnergyProjectile<T> implements IEnergySlicer {
|
||||
@@ -48,27 +47,7 @@ public class ScriptEnergySlicer<T extends EntityEnergySlicer> extends ScriptEner
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
public void fireAt(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startMoving(mcTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireAt(double x, double y, double z) {
|
||||
ensureSpawned();
|
||||
double dx = x - entity.posX;
|
||||
double dy = y - entity.posY;
|
||||
double dz = z - entity.posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) {
|
||||
entity.motionX = (dx / len) * entity.getSpeed();
|
||||
entity.motionY = (dy / len) * entity.getSpeed();
|
||||
entity.motionZ = (dz / len) * entity.getSpeed();
|
||||
}
|
||||
entity.startMoving(null);
|
||||
protected void launchFromOwner(EntityLivingBase target) {
|
||||
entity.startMoving(target);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user