mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 18:57:32 +00:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
52269705b5
62 files changed
+3847
-713
No files matched your search
@@ -2,7 +2,6 @@ package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -24,7 +23,7 @@ import java.util.List;
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderAbilityBeam extends RenderAbilityProjectile {
|
||||
public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
@@ -117,7 +116,7 @@ public class RenderAbilityBeam extends RenderAbilityProjectile {
|
||||
|
||||
// Render lightning during charging if enabled
|
||||
if (beam.hasLightningEffect()) {
|
||||
renderAttachedLightning(beam, scale);
|
||||
renderAttachedLightning(beam, 0.6f * 0.5f, scale);
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
@@ -545,7 +544,7 @@ public class RenderAbilityBeam extends RenderAbilityProjectile {
|
||||
|
||||
// Render lightning BEFORE rotation so it crackles in all directions (only on head)
|
||||
if (beam.hasLightningEffect()) {
|
||||
renderAttachedLightning(beam, scale);
|
||||
renderAttachedLightning(beam, 0.6f * 0.5f, scale);
|
||||
}
|
||||
|
||||
// Rotation
|
||||
@@ -579,31 +578,4 @@ public class RenderAbilityBeam extends RenderAbilityProjectile {
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render fading lightning arcs attached to the beam head (in local space).
|
||||
*/
|
||||
private void renderAttachedLightning(EntityAbilityBeam beam, float headScale) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(beam);
|
||||
|
||||
float density = beam.getLightningDensity();
|
||||
// Lightning radius extends outward from inner surface (innerScale = 0.6)
|
||||
float innerRadius = 0.6f * headScale * 0.5f;
|
||||
float radius = innerRadius + beam.getLightningRadius() * headScale;
|
||||
int outerColor = beam.getOuterColor();
|
||||
int innerColor = beam.getInnerColor();
|
||||
int fadeTime = beam.getLightningFadeTime();
|
||||
|
||||
state.update(density, radius, outerColor, innerColor, fadeTime);
|
||||
state.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the lightning state for an entity.
|
||||
*/
|
||||
private AttachedLightningRenderer.LightningState getLightningState(EntityAbilityBeam beam) {
|
||||
if (beam.lightningState == null) {
|
||||
beam.lightningState = new AttachedLightningRenderer.LightningState();
|
||||
}
|
||||
return (AttachedLightningRenderer.LightningState) beam.lightningState;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -14,7 +13,7 @@ import org.lwjgl.opengl.GL11;
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderAbilityDisc extends RenderAbilityProjectile {
|
||||
public class RenderAbilityDisc extends RenderEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
@@ -37,7 +36,7 @@ public class RenderAbilityDisc extends RenderAbilityProjectile {
|
||||
|
||||
// Render lightning BEFORE rotation so it crackles in all directions
|
||||
if (disc.hasLightningEffect()) {
|
||||
renderAttachedLightning(disc, radius * scale);
|
||||
renderAttachedLightning(disc, 0.6f * 0.5f, radius * scale);
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
@@ -76,34 +75,6 @@ public class RenderAbilityDisc extends RenderAbilityProjectile {
|
||||
restoreRenderState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render fading lightning arcs attached to the disc (in local space).
|
||||
*/
|
||||
private void renderAttachedLightning(EntityAbilityDisc disc, float discSize) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(disc);
|
||||
|
||||
float density = disc.getLightningDensity();
|
||||
// Lightning radius extends outward from inner surface (innerScale = 0.6)
|
||||
float innerRadius = 0.6f * discSize * 0.5f;
|
||||
float radius = innerRadius + disc.getLightningRadius() * discSize;
|
||||
int outerColor = disc.getOuterColor();
|
||||
int innerColor = disc.getInnerColor();
|
||||
int fadeTime = disc.getLightningFadeTime();
|
||||
|
||||
state.update(density, radius, outerColor, innerColor, fadeTime);
|
||||
state.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the lightning state for an entity.
|
||||
*/
|
||||
private AttachedLightningRenderer.LightningState getLightningState(EntityAbilityDisc disc) {
|
||||
if (disc.lightningState == null) {
|
||||
disc.lightningState = new AttachedLightningRenderer.LightningState();
|
||||
}
|
||||
return (AttachedLightningRenderer.LightningState) disc.lightningState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a flat square (thin cube) centered at origin.
|
||||
* The square lies flat on the XZ plane with thin Y height.
|
||||
|
||||
@@ -3,7 +3,6 @@ package kamkeel.npcs.client.renderer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -15,7 +14,7 @@ import org.lwjgl.opengl.GL11;
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderAbilityLaser extends RenderAbilityProjectile {
|
||||
public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
@@ -147,7 +146,7 @@ public class RenderAbilityLaser extends RenderAbilityProjectile {
|
||||
|
||||
// Render lightning during charging if enabled
|
||||
if (laser.hasLightningEffect()) {
|
||||
renderAttachedLightning(laser, scale);
|
||||
renderAttachedLightning(laser, 0.6f * 0.5f, scale);
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
@@ -170,7 +169,7 @@ public class RenderAbilityLaser extends RenderAbilityProjectile {
|
||||
|
||||
// Render inner core
|
||||
GL11.glScalef(innerScale, innerScale, innerScale);
|
||||
renderCube(innerColor, 1.0f, 0.5f);
|
||||
renderCube(innerColor, laser.getInnerAlpha(), 0.5f);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopMatrix();
|
||||
@@ -215,31 +214,6 @@ public class RenderAbilityLaser extends RenderAbilityProjectile {
|
||||
}
|
||||
|
||||
|
||||
private void renderAttachedLightning(EntityAbilityLaser laser, float headScale) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(laser);
|
||||
|
||||
float density = laser.getLightningDensity();
|
||||
// Lightning radius extends outward from inner surface (innerScale = 0.6)
|
||||
float innerRadius = 0.6f * headScale * 0.5f;
|
||||
float radius = innerRadius + laser.getLightningRadius() * headScale;
|
||||
int outerColor = laser.getOuterColor();
|
||||
int innerColor = laser.getInnerColor();
|
||||
int fadeTime = laser.getLightningFadeTime();
|
||||
|
||||
state.update(density, radius, outerColor, innerColor, fadeTime);
|
||||
state.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the main lightning state for the laser.
|
||||
*/
|
||||
private AttachedLightningRenderer.LightningState getLightningState(EntityAbilityLaser laser) {
|
||||
if (laser.lightningState == null) {
|
||||
laser.lightningState = new AttachedLightningRenderer.LightningState();
|
||||
}
|
||||
return (AttachedLightningRenderer.LightningState) laser.lightningState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the tip lightning state for the laser.
|
||||
* Stored as a secondary object in lightningState2.
|
||||
|
||||
@@ -2,7 +2,6 @@ package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -12,7 +11,7 @@ import org.lwjgl.opengl.GL11;
|
||||
* Minecraft-style blocky appearance using Tessellator.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderAbilityOrb extends RenderAbilityProjectile {
|
||||
public class RenderAbilityOrb extends RenderEnergyAbility {
|
||||
|
||||
private static final int LIGHTNING_FADE_TICKS = 6;
|
||||
|
||||
@@ -35,7 +34,7 @@ public class RenderAbilityOrb extends RenderAbilityProjectile {
|
||||
|
||||
// Render lightning BEFORE rotation so it crackles in all directions
|
||||
if (orb.hasLightningEffect()) {
|
||||
renderAttachedLightning(orb, scale);
|
||||
renderAttachedLightning(orb, 0.6f * 0.5f, scale);
|
||||
}
|
||||
|
||||
// Use entity's interpolated rotation for smooth spinning
|
||||
@@ -63,7 +62,7 @@ public class RenderAbilityOrb extends RenderAbilityProjectile {
|
||||
|
||||
// Render inner cube (solid)
|
||||
GL11.glScalef(innerScale, innerScale, innerScale);
|
||||
renderCube(orb.getInnerColor(), 1.0f, 0.5f);
|
||||
renderCube(orb.getInnerColor(), orb.getInnerAlpha(), 0.5f);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopMatrix();
|
||||
@@ -71,36 +70,4 @@ public class RenderAbilityOrb extends RenderAbilityProjectile {
|
||||
restoreRenderState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render fading lightning arcs attached to the orb (in local space).
|
||||
* Arcs persist for a few ticks and fade out, while staying attached to the orb.
|
||||
*/
|
||||
private void renderAttachedLightning(EntityAbilityOrb orb, float orbScale) {
|
||||
// Get or create the lightning state for this entity
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(orb);
|
||||
|
||||
float density = orb.getLightningDensity();
|
||||
// Lightning radius extends outward from inner surface (innerScale = 0.6)
|
||||
float innerRadius = 0.6f * orbScale * 0.5f; // Half size of inner cube
|
||||
float radius = innerRadius + orb.getLightningRadius() * orbScale;
|
||||
int outerColor = orb.getOuterColor();
|
||||
int innerColor = orb.getInnerColor();
|
||||
int fadeTime = orb.getLightningFadeTime();
|
||||
|
||||
// Update: age existing arcs, spawn new ones based on density
|
||||
state.update(density, radius, outerColor, innerColor, fadeTime);
|
||||
|
||||
// Render all active arcs in local space (they move with the orb)
|
||||
state.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the lightning state for an entity.
|
||||
*/
|
||||
private AttachedLightningRenderer.LightningState getLightningState(EntityAbilityOrb orb) {
|
||||
if (orb.lightningState == null) {
|
||||
orb.lightningState = new AttachedLightningRenderer.LightningState();
|
||||
}
|
||||
return (AttachedLightningRenderer.LightningState) orb.lightningState;
|
||||
}
|
||||
}
|
||||
+38
-2
@@ -2,6 +2,8 @@ package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
|
||||
import kamkeel.npcs.entity.EntityEnergyAbility;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
@@ -17,11 +19,11 @@ import org.lwjgl.opengl.GL12;
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class RenderAbilityProjectile extends Render {
|
||||
public abstract class RenderEnergyAbility extends Render {
|
||||
|
||||
protected static final ResourceLocation WHITE_TEXTURE = new ResourceLocation("customnpcs", "textures/entity/white.png");
|
||||
|
||||
public RenderAbilityProjectile() {
|
||||
public RenderEnergyAbility() {
|
||||
this.shadowSize = 0.0f;
|
||||
}
|
||||
|
||||
@@ -252,6 +254,40 @@ public abstract class RenderAbilityProjectile extends Render {
|
||||
tess.draw();
|
||||
}
|
||||
|
||||
// ==================== SHARED LIGHTNING ====================
|
||||
|
||||
/**
|
||||
* Get or create the lightning state for an energy entity.
|
||||
* Uses the lightningState field on EntityEnergyAbility (stored as Object
|
||||
* to avoid client class loading on server).
|
||||
*/
|
||||
protected AttachedLightningRenderer.LightningState getLightningState(EntityEnergyAbility entity) {
|
||||
if (entity.lightningState == null) {
|
||||
entity.lightningState = new AttachedLightningRenderer.LightningState();
|
||||
}
|
||||
return (AttachedLightningRenderer.LightningState) entity.lightningState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render attached lightning arcs around an energy entity.
|
||||
* @param entity the energy entity
|
||||
* @param innerScale multiplier for inner radius (e.g. 0.3f for projectiles, 0.95f for dome)
|
||||
* @param baseSize the entity's current render size/scale
|
||||
*/
|
||||
protected void renderAttachedLightning(EntityEnergyAbility entity, float innerScale, float baseSize) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(entity);
|
||||
|
||||
float density = entity.getLightningDensity();
|
||||
float innerRadius = innerScale * baseSize;
|
||||
float radius = innerRadius + entity.getLightningRadius() * baseSize;
|
||||
int outerColor = entity.getOuterColor();
|
||||
int innerColor = entity.getInnerColor();
|
||||
int fadeTime = entity.getLightningFadeTime();
|
||||
|
||||
state.update(density, radius, outerColor, innerColor, fadeTime);
|
||||
state.render();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(Entity entity) {
|
||||
return WHITE_TEXTURE;
|
||||
@@ -0,0 +1,23 @@
|
||||
package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
|
||||
/**
|
||||
* Intermediate renderer base for energy barrier entities (Dome, Panel).
|
||||
* Provides shared hit flash alpha computation.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class RenderEnergyBarrier extends RenderEnergyAbility {
|
||||
|
||||
/**
|
||||
* Compute the alpha boost from a hit flash effect.
|
||||
* Flash value decays from 4 to 0, producing alpha from 0.3 to 0.
|
||||
*/
|
||||
protected float computeFlashAlpha(EntityEnergyBarrier barrier) {
|
||||
byte flash = barrier.getHitFlash();
|
||||
if (flash <= 0) return 0.0f;
|
||||
return flash / 4.0f * 0.3f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Renders the Dome entity as a translucent sphere.
|
||||
* Inner layer solid, outer layer translucent glow.
|
||||
* Optional skybox texture rendered on the interior surface.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderEnergyDome extends RenderEnergyBarrier {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
EntityEnergyDome dome = (EntityEnergyDome) entity;
|
||||
float radius = dome.getDomeRadius();
|
||||
float healthPercent = dome.getHealthPercent();
|
||||
|
||||
setupRenderState();
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(x, y, z);
|
||||
|
||||
// Lightning BEFORE any rotation (uniform spread)
|
||||
if (dome.hasLightningEffect()) {
|
||||
renderAttachedLightning(dome, 0.95f, radius);
|
||||
}
|
||||
|
||||
// Hit flash effect
|
||||
float flashAlpha = computeFlashAlpha(dome);
|
||||
|
||||
float innerScale = 0.95f;
|
||||
|
||||
// Render outer dome (translucent glow)
|
||||
if (dome.isOuterColorEnabled()) {
|
||||
float outerScale = 1.0f + dome.getOuterColorWidth() * 0.1f;
|
||||
float outerAlpha = dome.getOuterColorAlpha() * healthPercent;
|
||||
GL11.glDepthMask(false);
|
||||
renderSphere(dome.getOuterColor(), outerAlpha + flashAlpha, radius * outerScale, 8);
|
||||
GL11.glDepthMask(true);
|
||||
}
|
||||
|
||||
// TODO: Skybox Feature
|
||||
// if (dome.isSkyboxEnabled() && !dome.getSkyboxTexture().isEmpty()) {
|
||||
// renderSkyboxSphere(dome.getSkyboxTexture(), radius, radius * 0.94f, 32, x, y, z);
|
||||
// }
|
||||
|
||||
// Render inner dome
|
||||
renderSphere(dome.getInnerColor(), dome.getInnerAlpha(), radius * innerScale, 8);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
|
||||
restoreRenderState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a sphere made of quad panels.
|
||||
* Uses latitude/longitude segments to form a full sphere.
|
||||
*/
|
||||
private void renderSphere(int color, float alpha, float radius, int segments) {
|
||||
float[] rgb = extractRGB(color);
|
||||
|
||||
Tessellator tess = Tessellator.instance;
|
||||
tess.startDrawingQuads();
|
||||
tess.setColorRGBA_F(rgb[0], rgb[1], rgb[2], alpha);
|
||||
|
||||
for (int lat = 0; lat < segments; lat++) {
|
||||
float theta1 = (float) (Math.PI * lat / segments - Math.PI * 0.5);
|
||||
float theta2 = (float) (Math.PI * (lat + 1) / segments - Math.PI * 0.5);
|
||||
|
||||
float y1 = (float) Math.sin(theta1) * radius;
|
||||
float y2 = (float) Math.sin(theta2) * radius;
|
||||
float r1 = (float) Math.cos(theta1) * radius;
|
||||
float r2 = (float) Math.cos(theta2) * radius;
|
||||
|
||||
for (int lon = 0; lon < segments; lon++) {
|
||||
float phi1 = (float) (2 * Math.PI * lon / segments);
|
||||
float phi2 = (float) (2 * Math.PI * (lon + 1) / segments);
|
||||
|
||||
float x1 = (float) Math.cos(phi1) * r1;
|
||||
float z1 = (float) Math.sin(phi1) * r1;
|
||||
float x2 = (float) Math.cos(phi2) * r1;
|
||||
float z2 = (float) Math.sin(phi2) * r1;
|
||||
float x3 = (float) Math.cos(phi2) * r2;
|
||||
float z3 = (float) Math.sin(phi2) * r2;
|
||||
float x4 = (float) Math.cos(phi1) * r2;
|
||||
float z4 = (float) Math.sin(phi1) * r2;
|
||||
|
||||
float nx = (x1 + x2 + x3 + x4) * 0.25f;
|
||||
float ny = (y1 + y1 + y2 + y2) * 0.25f;
|
||||
float nz = (z1 + z2 + z3 + z4) * 0.25f;
|
||||
float nLen = (float) Math.sqrt(nx * nx + ny * ny + nz * nz);
|
||||
if (nLen > 0) { nx /= nLen; ny /= nLen; nz /= nLen; }
|
||||
|
||||
tess.setNormal(nx, ny, nz);
|
||||
tess.addVertex(x1, y1, z1);
|
||||
tess.addVertex(x2, y1, z2);
|
||||
tess.addVertex(x3, y2, z3);
|
||||
tess.addVertex(x4, y2, z4);
|
||||
}
|
||||
}
|
||||
|
||||
tess.draw();
|
||||
}
|
||||
|
||||
// TODO: Skybox Feature — renderSkyboxSphere method removed
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Renders the Energy Panel entity as a flat translucent rectangle.
|
||||
* Used by both Energy Wall and Energy Shield abilities.
|
||||
* Voxel-blocky style with inner/outer layers.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderEnergyPanel extends RenderEnergyBarrier {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
EntityEnergyPanel panel = (EntityEnergyPanel) entity;
|
||||
|
||||
float width = panel.getPanelData().panelWidth;
|
||||
float height = panel.getPanelData().panelHeight;
|
||||
float panelYaw = panel.getPanelYaw();
|
||||
float healthPercent = panel.getHealthPercent();
|
||||
|
||||
setupRenderState();
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(x, y, z);
|
||||
|
||||
// Lightning BEFORE rotation for uniform spread (like Orb pattern)
|
||||
if (panel.hasLightningEffect()) {
|
||||
renderAttachedLightning(panel, 0.9f, Math.max(width, height) * 0.5f);
|
||||
}
|
||||
|
||||
// Rotate panel to face the correct direction
|
||||
GL11.glRotatef(-panelYaw, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Hit flash
|
||||
float flashAlpha = computeFlashAlpha(panel);
|
||||
|
||||
// Subtle pulsing
|
||||
float pulseTime = entity.ticksExisted + partialTicks;
|
||||
float pulse = (float) Math.sin(pulseTime * 0.08f) * 0.02f;
|
||||
float scale = 1.0f + pulse;
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glScalef(scale, scale, scale);
|
||||
|
||||
float innerScale = 0.9f;
|
||||
float panelThickness = 0.1f;
|
||||
|
||||
// Render outer panel (translucent glow)
|
||||
if (panel.isOuterColorEnabled()) {
|
||||
float outerScale = 1.0f + panel.getOuterColorWidth() * 0.15f;
|
||||
float outerAlpha = panel.getOuterColorAlpha() * healthPercent;
|
||||
GL11.glDepthMask(false);
|
||||
renderPanel(panel.getOuterColor(), outerAlpha + flashAlpha,
|
||||
width * 0.5f * outerScale, height * 0.5f * outerScale, panelThickness * 1.5f);
|
||||
GL11.glDepthMask(true);
|
||||
}
|
||||
|
||||
// Render inner panel (uses configurable innerAlpha for semi-transparency)
|
||||
renderPanel(panel.getInnerColor(), panel.getInnerAlpha(),
|
||||
width * 0.5f * innerScale, height * 0.5f * innerScale, panelThickness);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopMatrix();
|
||||
|
||||
restoreRenderState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a flat panel (thin box) centered at origin.
|
||||
* Panel faces along the Z axis (width on X, height on Y).
|
||||
* All 6 faces batched into a single draw call.
|
||||
*/
|
||||
private void renderPanel(int color, float alpha, float halfWidth, float halfHeight, float halfThickness) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
|
||||
Tessellator tess = Tessellator.instance;
|
||||
tess.startDrawingQuads();
|
||||
tess.setColorRGBA_F(r, g, b, alpha);
|
||||
|
||||
// Front face (z+)
|
||||
tess.setNormal(0, 0, 1);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfThickness);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, halfThickness);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfThickness);
|
||||
|
||||
// Back face (z-)
|
||||
tess.setNormal(0, 0, -1);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfThickness);
|
||||
|
||||
// Top edge (y+)
|
||||
tess.setNormal(0, 1, 0);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfThickness);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfThickness);
|
||||
|
||||
// Bottom edge (y-)
|
||||
tess.setNormal(0, -1, 0);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfThickness);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfThickness);
|
||||
|
||||
// Right edge (x+)
|
||||
tess.setNormal(1, 0, 0);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfThickness);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfThickness);
|
||||
tess.addVertex(halfWidth, halfHeight, halfThickness);
|
||||
|
||||
// Left edge (x-)
|
||||
tess.setNormal(-1, 0, 0);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfThickness);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfThickness);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfThickness);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfThickness);
|
||||
|
||||
tess.draw();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package kamkeel.npcs.client.renderer;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Renders the Energy Slicer entity as a thin wide blade.
|
||||
* Oriented perpendicular to travel direction.
|
||||
* Inner solid core with outer translucent glow.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class RenderEnergySlicer extends RenderEnergyAbility {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float yaw, float partialTicks) {
|
||||
EntityEnergySlicer slicer = (EntityEnergySlicer) entity;
|
||||
|
||||
float width = slicer.getSliceWidth();
|
||||
float thickness = slicer.getSliceThickness();
|
||||
|
||||
// During charging, width/thickness grow from 0.01 to target via updateCharging().
|
||||
// Use current dimensions directly - no separate sizeRatio needed.
|
||||
if (width <= 0.01f) return;
|
||||
|
||||
setupRenderState();
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(x, y, z);
|
||||
|
||||
// Lightning BEFORE rotation for uniform spread (like Orb pattern)
|
||||
if (slicer.hasLightningEffect()) {
|
||||
renderAttachedLightning(slicer, 0.7f, width * 0.5f);
|
||||
}
|
||||
|
||||
// Orient perpendicular to travel direction
|
||||
float travelYaw = slicer.getTravelYaw();
|
||||
float travelPitch = slicer.getTravelPitch();
|
||||
GL11.glRotatef(travelYaw, 0.0f, 1.0f, 0.0f);
|
||||
GL11.glRotatef(travelPitch, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
float innerScale = 0.7f;
|
||||
|
||||
// Render outer blade (translucent glow)
|
||||
if (slicer.isOuterColorEnabled()) {
|
||||
float outerScale = 1.0f + slicer.getOuterColorWidth() * 0.2f;
|
||||
GL11.glDepthMask(false);
|
||||
renderBlade(slicer.getOuterColor(), slicer.getOuterColorAlpha(),
|
||||
width * 0.5f * outerScale, thickness * 2.0f, 0.05f);
|
||||
GL11.glDepthMask(true);
|
||||
}
|
||||
|
||||
// Render inner blade (solid core, alpha 1.0 like Orb pattern)
|
||||
renderBlade(slicer.getInnerColor(), 1.0f,
|
||||
width * 0.5f * innerScale, thickness, 0.03f);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
|
||||
restoreRenderState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a thin wide blade shape.
|
||||
* The blade extends along X (width), thin on Y (thickness), and very thin on Z (depth).
|
||||
* All 6 faces batched into a single draw call.
|
||||
*/
|
||||
private void renderBlade(int color, float alpha, float halfWidth, float halfHeight, float halfDepth) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
|
||||
Tessellator tess = Tessellator.instance;
|
||||
tess.startDrawingQuads();
|
||||
|
||||
// Front face (z+)
|
||||
tess.setColorRGBA_F(r, g, b, alpha);
|
||||
tess.setNormal(0, 0, 1);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfDepth);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, halfDepth);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfDepth);
|
||||
|
||||
// Back face (z-)
|
||||
tess.setNormal(0, 0, -1);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfDepth);
|
||||
|
||||
// Top edge (y+)
|
||||
tess.setColorRGBA_F(r, g, b, alpha * 0.8f);
|
||||
tess.setNormal(0, 1, 0);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfDepth);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfDepth);
|
||||
|
||||
// Bottom edge (y-)
|
||||
tess.setNormal(0, -1, 0);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfDepth);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfDepth);
|
||||
|
||||
// Right edge (x+)
|
||||
tess.setColorRGBA_F(r, g, b, alpha * 0.6f);
|
||||
tess.setNormal(1, 0, 0);
|
||||
tess.addVertex(halfWidth, -halfHeight, halfDepth);
|
||||
tess.addVertex(halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, -halfDepth);
|
||||
tess.addVertex(halfWidth, halfHeight, halfDepth);
|
||||
|
||||
// Left edge (x-)
|
||||
tess.setNormal(-1, 0, 0);
|
||||
tess.addVertex(-halfWidth, -halfHeight, -halfDepth);
|
||||
tess.addVertex(-halfWidth, -halfHeight, halfDepth);
|
||||
tess.addVertex(-halfWidth, halfHeight, halfDepth);
|
||||
tess.addVertex(-halfWidth, halfHeight, -halfDepth);
|
||||
|
||||
tess.draw();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public abstract class Ability implements IAbility {
|
||||
protected boolean ignoreCooldown = false;
|
||||
|
||||
// Configurable potion effects
|
||||
protected List<AbilityEffect> effects = new ArrayList<>();
|
||||
protected List<AbilityPotionEffect> effects = new ArrayList<>();
|
||||
|
||||
// Burst
|
||||
protected boolean burstEnabled = false;
|
||||
@@ -378,7 +378,7 @@ public abstract class Ability implements IAbility {
|
||||
if (entity == null || effects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effect.apply(entity);
|
||||
}
|
||||
}
|
||||
@@ -1164,7 +1164,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
// Effects
|
||||
NBTTagList effectList = new NBTTagList();
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effectList.appendTag(effect.writeNBT());
|
||||
}
|
||||
nbt.setTag("effects", effectList);
|
||||
@@ -1235,7 +1235,7 @@ public abstract class Ability implements IAbility {
|
||||
if (nbt.hasKey("effects")) {
|
||||
NBTTagList effectList = nbt.getTagList("effects", 10);
|
||||
for (int i = 0; i < effectList.tagCount(); i++) {
|
||||
AbilityEffect effect = AbilityEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
AbilityPotionEffect effect = AbilityPotionEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
if (effect != null && effect.isValid()) {
|
||||
effects.add(effect);
|
||||
}
|
||||
@@ -1727,15 +1727,15 @@ public abstract class Ability implements IAbility {
|
||||
this.ignoreCooldown = ignoreCooldown;
|
||||
}
|
||||
|
||||
public List<AbilityEffect> getEffects() {
|
||||
public List<AbilityPotionEffect> getEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
public void setEffects(List<AbilityEffect> effects) {
|
||||
public void setEffects(List<AbilityPotionEffect> effects) {
|
||||
this.effects = effects != null ? effects : new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addEffect(AbilityEffect effect) {
|
||||
public void addEffect(AbilityPotionEffect effect) {
|
||||
if (effect != null && effect.isValid()) {
|
||||
effects.add(effect);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,15 @@ package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.type.*;
|
||||
import kamkeel.npcs.controllers.SyncController;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityBeam;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityDisc;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityDome;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityLaserShot;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityOrb;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityShield;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilitySlicer;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilitySweeper;
|
||||
import kamkeel.npcs.controllers.data.ability.type.energy.AbilityWall;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.CustomNpcs;
|
||||
@@ -99,6 +108,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
registerType("cnpc:hazard", AbilityHazard::new);
|
||||
registerType("cnpc:trap", AbilityTrap::new);
|
||||
|
||||
registerType("cnpc:dome", AbilityDome::new);
|
||||
registerType("cnpc:wall", AbilityWall::new);
|
||||
registerType("cnpc:shield", AbilityShield::new);
|
||||
registerType("cnpc:slicer", AbilitySlicer::new);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
+8
-8
@@ -9,17 +9,17 @@ import noppes.npcs.constants.EnumPotionType;
|
||||
* Represents a configurable potion effect that can be applied by abilities.
|
||||
* Uses the unified EnumPotionType enum shared across melee, ranged, and ability systems.
|
||||
*/
|
||||
public class AbilityEffect {
|
||||
public class AbilityPotionEffect {
|
||||
|
||||
private EnumPotionType type = EnumPotionType.None;
|
||||
private int manualPotionId = 0;
|
||||
private int durationTicks = 60;
|
||||
private int amplifier = 0; // 0-10
|
||||
|
||||
public AbilityEffect() {
|
||||
public AbilityPotionEffect() {
|
||||
}
|
||||
|
||||
public AbilityEffect(EnumPotionType type, int durationTicks, int amplifier) {
|
||||
public AbilityPotionEffect(EnumPotionType type, int durationTicks, int amplifier) {
|
||||
this.type = type;
|
||||
this.durationTicks = Math.max(1, durationTicks);
|
||||
this.amplifier = Math.max(0, Math.min(10, amplifier));
|
||||
@@ -28,8 +28,8 @@ public class AbilityEffect {
|
||||
/**
|
||||
* Creates a copy of this effect.
|
||||
*/
|
||||
public AbilityEffect copy() {
|
||||
AbilityEffect copy = new AbilityEffect(type, durationTicks, amplifier);
|
||||
public AbilityPotionEffect copy() {
|
||||
AbilityPotionEffect copy = new AbilityPotionEffect(type, durationTicks, amplifier);
|
||||
copy.manualPotionId = this.manualPotionId;
|
||||
return copy;
|
||||
}
|
||||
@@ -81,10 +81,10 @@ public class AbilityEffect {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AbilityEffect from NBT.
|
||||
* Creates an AbilityPotionEffect from NBT.
|
||||
*/
|
||||
public static AbilityEffect fromNBT(NBTTagCompound nbt) {
|
||||
AbilityEffect effect = new AbilityEffect();
|
||||
public static AbilityPotionEffect fromNBT(NBTTagCompound nbt) {
|
||||
AbilityPotionEffect effect = new AbilityPotionEffect();
|
||||
effect.readNBT(nbt);
|
||||
return effect;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package kamkeel.npcs.controllers.data.ability.data;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Groups barrier properties shared by energy barrier abilities (Dome, Wall, Shield).
|
||||
* Handles health/durability, duration, and per-projectile-type damage multipliers.
|
||||
*/
|
||||
public class EnergyBarrierData {
|
||||
// Knockback target display keys
|
||||
private static final String[] KNOCKBACK_TARGET_KEYS = {"gui.both", "gui.players", "gui.npcs"};
|
||||
|
||||
public float maxHealth = 100.0f;
|
||||
public boolean useHealth = true;
|
||||
public int durationTicks = 200;
|
||||
public boolean useDuration = true;
|
||||
public float defaultMultiplier = 1.0f;
|
||||
|
||||
// Knockback settings
|
||||
public boolean knockbackEnabled = false;
|
||||
public float knockbackStrength = 1.0f;
|
||||
/** 0=Both, 1=Player only, 2=NPC only */
|
||||
public int knockbackTarget = 0;
|
||||
|
||||
// Melee settings
|
||||
public boolean meleeEnabled = false;
|
||||
public float meleeDamageMultiplier = 1.0f;
|
||||
|
||||
/**
|
||||
* Per-projectile-type damage multipliers.
|
||||
* Key is the ability typeId (e.g., "ability.cnpc.orb", "ability.cnpc.beam").
|
||||
* Value is the multiplier applied to damage dealt to this barrier.
|
||||
*/
|
||||
private Map<String, Float> damageMultipliers = new HashMap<>();
|
||||
|
||||
public EnergyBarrierData() {}
|
||||
|
||||
public EnergyBarrierData(float maxHealth, boolean useHealth, int durationTicks, boolean useDuration) {
|
||||
this.maxHealth = maxHealth;
|
||||
this.useHealth = useHealth;
|
||||
this.durationTicks = durationTicks;
|
||||
this.useDuration = useDuration;
|
||||
}
|
||||
|
||||
// ==================== MULTIPLIER METHODS ====================
|
||||
|
||||
public float getMultiplier(String abilityTypeId) {
|
||||
Float mult = damageMultipliers.get(abilityTypeId);
|
||||
return mult != null ? mult : defaultMultiplier;
|
||||
}
|
||||
|
||||
public void setMultiplier(String abilityTypeId, float multiplier) {
|
||||
damageMultipliers.put(abilityTypeId, multiplier);
|
||||
}
|
||||
|
||||
public void removeMultiplier(String abilityTypeId) {
|
||||
damageMultipliers.remove(abilityTypeId);
|
||||
}
|
||||
|
||||
public Map<String, Float> getDamageMultipliers() {
|
||||
return damageMultipliers;
|
||||
}
|
||||
|
||||
public void setDamageMultipliers(Map<String, Float> multipliers) {
|
||||
this.damageMultipliers = multipliers != null ? multipliers : new HashMap<>();
|
||||
}
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getMaxHealth() { return maxHealth; }
|
||||
public void setMaxHealth(float maxHealth) { this.maxHealth = Math.max(0, maxHealth); }
|
||||
|
||||
public boolean isUseHealth() { return useHealth; }
|
||||
public void setUseHealth(boolean useHealth) { this.useHealth = useHealth; }
|
||||
|
||||
public int getDurationTicks() { return durationTicks; }
|
||||
public void setDurationTicks(int durationTicks) { this.durationTicks = Math.max(1, durationTicks); }
|
||||
|
||||
public boolean isUseDuration() { return useDuration; }
|
||||
public void setUseDuration(boolean useDuration) { this.useDuration = useDuration; }
|
||||
|
||||
public float getDefaultMultiplier() { return defaultMultiplier; }
|
||||
public void setDefaultMultiplier(float defaultMultiplier) { this.defaultMultiplier = defaultMultiplier; }
|
||||
|
||||
// Knockback target key helpers
|
||||
public static String[] getKnockbackTargetKeys() { return KNOCKBACK_TARGET_KEYS; }
|
||||
|
||||
public String getKnockbackTargetKey() {
|
||||
return KNOCKBACK_TARGET_KEYS[Math.max(0, Math.min(knockbackTarget, 2))];
|
||||
}
|
||||
|
||||
public void setKnockbackTargetFromKey(String key) {
|
||||
for (int i = 0; i < KNOCKBACK_TARGET_KEYS.length; i++) {
|
||||
if (KNOCKBACK_TARGET_KEYS[i].equals(key)) {
|
||||
knockbackTarget = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("barrierMaxHealth", maxHealth);
|
||||
nbt.setBoolean("barrierUseHealth", useHealth);
|
||||
nbt.setInteger("barrierDuration", durationTicks);
|
||||
nbt.setBoolean("barrierUseDuration", useDuration);
|
||||
nbt.setFloat("barrierDefaultMult", defaultMultiplier);
|
||||
nbt.setBoolean("barrierKnockback", knockbackEnabled);
|
||||
nbt.setFloat("barrierKnockbackStr", knockbackStrength);
|
||||
nbt.setInteger("barrierKnockbackTarget", knockbackTarget);
|
||||
nbt.setBoolean("barrierMelee", meleeEnabled);
|
||||
nbt.setFloat("barrierMeleeMult", meleeDamageMultiplier);
|
||||
|
||||
NBTTagCompound multNbt = new NBTTagCompound();
|
||||
for (Map.Entry<String, Float> entry : damageMultipliers.entrySet()) {
|
||||
multNbt.setFloat(entry.getKey(), entry.getValue());
|
||||
}
|
||||
nbt.setTag("barrierMultipliers", multNbt);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
maxHealth = nbt.hasKey("barrierMaxHealth") ? nbt.getFloat("barrierMaxHealth") : 100.0f;
|
||||
useHealth = !nbt.hasKey("barrierUseHealth") || nbt.getBoolean("barrierUseHealth");
|
||||
durationTicks = nbt.hasKey("barrierDuration") ? nbt.getInteger("barrierDuration") : 200;
|
||||
useDuration = !nbt.hasKey("barrierUseDuration") || nbt.getBoolean("barrierUseDuration");
|
||||
defaultMultiplier = nbt.hasKey("barrierDefaultMult") ? nbt.getFloat("barrierDefaultMult") : 1.0f;
|
||||
knockbackEnabled = nbt.hasKey("barrierKnockback") && nbt.getBoolean("barrierKnockback");
|
||||
knockbackStrength = nbt.hasKey("barrierKnockbackStr") ? nbt.getFloat("barrierKnockbackStr") : 1.0f;
|
||||
knockbackTarget = nbt.hasKey("barrierKnockbackTarget") ? nbt.getInteger("barrierKnockbackTarget") : 0;
|
||||
meleeEnabled = nbt.hasKey("barrierMelee") && nbt.getBoolean("barrierMelee");
|
||||
meleeDamageMultiplier = nbt.hasKey("barrierMeleeMult") ? nbt.getFloat("barrierMeleeMult") : 1.0f;
|
||||
|
||||
damageMultipliers.clear();
|
||||
if (nbt.hasKey("barrierMultipliers")) {
|
||||
NBTTagCompound multNbt = nbt.getCompoundTag("barrierMultipliers");
|
||||
@SuppressWarnings("unchecked")
|
||||
java.util.Set<String> keys = multNbt.func_150296_c();
|
||||
for (String key : keys) {
|
||||
damageMultipliers.put(key, multNbt.getFloat(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnergyBarrierData copy() {
|
||||
EnergyBarrierData copy = new EnergyBarrierData(maxHealth, useHealth, durationTicks, useDuration);
|
||||
copy.defaultMultiplier = defaultMultiplier;
|
||||
copy.knockbackEnabled = knockbackEnabled;
|
||||
copy.knockbackStrength = knockbackStrength;
|
||||
copy.knockbackTarget = knockbackTarget;
|
||||
copy.meleeEnabled = meleeEnabled;
|
||||
copy.meleeDamageMultiplier = meleeDamageMultiplier;
|
||||
copy.damageMultipliers = new HashMap<>(damageMultipliers);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,13 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
public boolean outerColorEnabled = true;
|
||||
public float outerColorWidth = 0.4f;
|
||||
public float outerColorAlpha = 0.5f;
|
||||
public float innerAlpha = 1.0f;
|
||||
public float rotationSpeed = 4.0f;
|
||||
|
||||
// TODO: Skybox Feature
|
||||
// public boolean skyboxEnabled = false;
|
||||
// public String skyboxTexture = "";
|
||||
|
||||
public EnergyDisplayData() {}
|
||||
|
||||
public EnergyDisplayData(int innerColor, int outerColor) {
|
||||
@@ -32,6 +37,12 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
this.rotationSpeed = rotationSpeed;
|
||||
}
|
||||
|
||||
public EnergyDisplayData(int innerColor, int outerColor, boolean outerColorEnabled,
|
||||
float outerColorWidth, float outerColorAlpha, float innerAlpha, float rotationSpeed) {
|
||||
this(innerColor, outerColor, outerColorEnabled, outerColorWidth, outerColorAlpha, rotationSpeed);
|
||||
this.innerAlpha = innerAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInnerColor() {
|
||||
return innerColor;
|
||||
@@ -82,6 +93,16 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
this.outerColorAlpha = outerColorAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInnerAlpha() {
|
||||
return innerAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInnerAlpha(float innerAlpha) {
|
||||
this.innerAlpha = innerAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRotationSpeed() {
|
||||
return rotationSpeed;
|
||||
@@ -98,7 +119,11 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
nbt.setBoolean("outerColorEnabled", outerColorEnabled);
|
||||
nbt.setFloat("outerColorWidth", outerColorWidth);
|
||||
nbt.setFloat("outerColorAlpha", outerColorAlpha);
|
||||
nbt.setFloat("innerAlpha", innerAlpha);
|
||||
nbt.setFloat("rotationSpeed", rotationSpeed);
|
||||
// TODO: Skybox Feature
|
||||
// nbt.setBoolean("skyboxEnabled", skyboxEnabled);
|
||||
// nbt.setString("skyboxTexture", skyboxTexture);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
@@ -107,10 +132,18 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
outerColorEnabled = nbt.getBoolean("outerColorEnabled");
|
||||
outerColorWidth = nbt.getFloat("outerColorWidth");
|
||||
outerColorAlpha = nbt.getFloat("outerColorAlpha");
|
||||
innerAlpha = nbt.hasKey("innerAlpha") ? nbt.getFloat("innerAlpha") : 1.0f;
|
||||
rotationSpeed = nbt.getFloat("rotationSpeed");
|
||||
// TODO: Skybox Feature
|
||||
// skyboxEnabled = nbt.hasKey("skyboxEnabled") && nbt.getBoolean("skyboxEnabled");
|
||||
// skyboxTexture = nbt.hasKey("skyboxTexture") ? nbt.getString("skyboxTexture") : "";
|
||||
}
|
||||
|
||||
public EnergyDisplayData copy() {
|
||||
return new EnergyDisplayData(innerColor, outerColor, outerColorEnabled, outerColorWidth, outerColorAlpha, rotationSpeed);
|
||||
EnergyDisplayData copy = new EnergyDisplayData(innerColor, outerColor, outerColorEnabled, outerColorWidth, outerColorAlpha, innerAlpha, rotationSpeed);
|
||||
// TODO: Skybox Feature
|
||||
// copy.skyboxEnabled = skyboxEnabled;
|
||||
// copy.skyboxTexture = skyboxTexture;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package kamkeel.npcs.controllers.data.ability.data;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* Groups panel-specific properties for energy wall/shield abilities.
|
||||
* Handles dimensions, positioning, and launch behavior.
|
||||
*/
|
||||
public class EnergyPanelData {
|
||||
public float panelWidth = 3.0f;
|
||||
public float panelHeight = 3.0f;
|
||||
public float heightOffset = 0.0f;
|
||||
|
||||
// Launch properties (Wall only)
|
||||
public boolean launching = false;
|
||||
public float launchSpeed = 0.5f;
|
||||
public float launchDamage = 8.0f;
|
||||
public float launchKnockback = 2.0f;
|
||||
|
||||
public EnergyPanelData() {}
|
||||
|
||||
public EnergyPanelData(float panelWidth, float panelHeight, float heightOffset) {
|
||||
this.panelWidth = panelWidth;
|
||||
this.panelHeight = panelHeight;
|
||||
this.heightOffset = heightOffset;
|
||||
}
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getPanelWidth() { return panelWidth; }
|
||||
public void setPanelWidth(float panelWidth) { this.panelWidth = Math.max(0.5f, panelWidth); }
|
||||
|
||||
public float getPanelHeight() { return panelHeight; }
|
||||
public void setPanelHeight(float panelHeight) { this.panelHeight = Math.max(0.5f, panelHeight); }
|
||||
|
||||
public float getHeightOffset() { return heightOffset; }
|
||||
public void setHeightOffset(float heightOffset) { this.heightOffset = heightOffset; }
|
||||
|
||||
public boolean isLaunching() { return launching; }
|
||||
public void setLaunching(boolean launching) { this.launching = launching; }
|
||||
|
||||
public float getLaunchSpeed() { return launchSpeed; }
|
||||
public void setLaunchSpeed(float launchSpeed) { this.launchSpeed = Math.max(0.1f, launchSpeed); }
|
||||
|
||||
public float getLaunchDamage() { return launchDamage; }
|
||||
public void setLaunchDamage(float launchDamage) { this.launchDamage = Math.max(0, launchDamage); }
|
||||
|
||||
public float getLaunchKnockback() { return launchKnockback; }
|
||||
public void setLaunchKnockback(float launchKnockback) { this.launchKnockback = Math.max(0, launchKnockback); }
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("panelWidth", panelWidth);
|
||||
nbt.setFloat("panelHeight", panelHeight);
|
||||
nbt.setFloat("panelHeightOffset", heightOffset);
|
||||
nbt.setBoolean("panelLaunching", launching);
|
||||
nbt.setFloat("panelLaunchSpeed", launchSpeed);
|
||||
nbt.setFloat("panelLaunchDamage", launchDamage);
|
||||
nbt.setFloat("panelLaunchKnockback", launchKnockback);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
panelWidth = nbt.hasKey("panelWidth") ? nbt.getFloat("panelWidth") : 3.0f;
|
||||
panelHeight = nbt.hasKey("panelHeight") ? nbt.getFloat("panelHeight") : 3.0f;
|
||||
heightOffset = nbt.hasKey("panelHeightOffset") ? nbt.getFloat("panelHeightOffset") : 0.0f;
|
||||
launching = nbt.hasKey("panelLaunching") && nbt.getBoolean("panelLaunching");
|
||||
launchSpeed = nbt.hasKey("panelLaunchSpeed") ? nbt.getFloat("panelLaunchSpeed") : 0.5f;
|
||||
launchDamage = nbt.hasKey("panelLaunchDamage") ? nbt.getFloat("panelLaunchDamage") : 8.0f;
|
||||
launchKnockback = nbt.hasKey("panelLaunchKnockback") ? nbt.getFloat("panelLaunchKnockback") : 2.0f;
|
||||
}
|
||||
|
||||
public EnergyPanelData copy() {
|
||||
EnergyPanelData copy = new EnergyPanelData(panelWidth, panelHeight, heightOffset);
|
||||
copy.launching = launching;
|
||||
copy.launchSpeed = launchSpeed;
|
||||
copy.launchDamage = launchDamage;
|
||||
copy.launchKnockback = launchKnockback;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package kamkeel.npcs.controllers.data.ability.gui;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
@@ -55,14 +55,14 @@ public class AbilityFieldBuilder extends GuiFieldBuilder {
|
||||
sw.addLabel(new GuiNpcLabel(labelId++, def.getLabel(), colLLabel, y + 2, 0xFFFF55));
|
||||
y += 15;
|
||||
|
||||
List<AbilityEffect> effects = (List<AbilityEffect>) def.getValue();
|
||||
List<AbilityPotionEffect> effects = (List<AbilityPotionEffect>) def.getValue();
|
||||
if (effects == null) effects = new ArrayList<>();
|
||||
|
||||
String[] typeNames = EnumPotionType.getLangKeysNoNone();
|
||||
String[] ampValues = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
|
||||
|
||||
for (int e = 0; e < effects.size() && e < 5; e++) {
|
||||
AbilityEffect effect = effects.get(e);
|
||||
AbilityPotionEffect effect = effects.get(e);
|
||||
|
||||
// Type selector button (index offset by -1 since None is excluded)
|
||||
int typeIdx = effect.getType().ordinal() - 1;
|
||||
@@ -144,7 +144,7 @@ public class AbilityFieldBuilder extends GuiFieldBuilder {
|
||||
FieldDef def = buttonFieldMap.get(buttonId);
|
||||
if (def == null) def = clearFieldMap.get(buttonId);
|
||||
if (def != null && def.getType() == FieldType.EFFECTS_LIST) {
|
||||
List<AbilityEffect> effects = (List<AbilityEffect>) def.getValue();
|
||||
List<AbilityPotionEffect> effects = (List<AbilityPotionEffect>) def.getValue();
|
||||
if (effects == null) return false;
|
||||
int effectIdx = meta[0];
|
||||
int action = meta[1];
|
||||
@@ -167,7 +167,7 @@ public class AbilityFieldBuilder extends GuiFieldBuilder {
|
||||
return true;
|
||||
case 4: // Add
|
||||
if (effects.size() < 5) {
|
||||
effects.add(new AbilityEffect(EnumPotionType.Slowness, 60, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Slowness, 60, 0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ public class AbilityFieldBuilder extends GuiFieldBuilder {
|
||||
if (meta != null) {
|
||||
FieldDef def = textFieldMap.get(textFieldId);
|
||||
if (def != null && def.getType() == FieldType.EFFECTS_LIST) {
|
||||
List<AbilityEffect> effects = (List<AbilityEffect>) def.getValue();
|
||||
List<AbilityPotionEffect> effects = (List<AbilityPotionEffect>) def.getValue();
|
||||
if (effects != null && meta[0] < effects.size()) {
|
||||
if (meta[1] == 1) { // duration field
|
||||
effects.get(meta[0]).setDurationTicks(field.getInteger());
|
||||
|
||||
@@ -2,7 +2,7 @@ package kamkeel.npcs.controllers.data.ability.gui;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.client.gui.builder.FieldType;
|
||||
|
||||
@@ -18,10 +18,10 @@ import java.util.function.Supplier;
|
||||
public class AbilityFieldDefs {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static FieldDef effectsListField(String label, Supplier<List<AbilityEffect>> getter, Consumer<List<AbilityEffect>> setter) {
|
||||
public static FieldDef effectsListField(String label, Supplier<List<AbilityPotionEffect>> getter, Consumer<List<AbilityPotionEffect>> setter) {
|
||||
return FieldDef.custom(label, FieldType.EFFECTS_LIST,
|
||||
() -> getter.get(),
|
||||
v -> setter.accept((List<AbilityEffect>) v));
|
||||
v -> setter.accept((List<AbilityPotionEffect>) v));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone;
|
||||
@@ -119,7 +119,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
particleMotion = 1; particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44; colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44; activeColor = 0xC044FF44;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Poison, 100, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Poison, 100, 0));
|
||||
break;
|
||||
case "EXPLOSIVE":
|
||||
groundAlpha = 0.04f;
|
||||
@@ -127,7 +127,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
particleMotion = 0; particleDir = "mc:smoke";
|
||||
colorData.innerColor = 0xFF6611; colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611; activeColor = 0xC0FF4400;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Fire, 60, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Fire, 60, 0));
|
||||
break;
|
||||
case "CURSED":
|
||||
groundAlpha = 0.04f;
|
||||
@@ -135,7 +135,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
particleMotion = 1; particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF; colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF; activeColor = 0xC0CC66FF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Weakness, 100, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Weakness, 100, 0));
|
||||
break;
|
||||
case "SHOCK":
|
||||
groundAlpha = 0.04f;
|
||||
@@ -143,7 +143,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
particleMotion = 2; particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF; colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF; activeColor = 0xC066AAFF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
break;
|
||||
case "SNARE":
|
||||
groundAlpha = 0.04f;
|
||||
@@ -151,7 +151,7 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
particleMotion = 1; particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF; colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF; activeColor = 0xC0AADDFF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Slowness, 100, 1));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Slowness, 100, 1));
|
||||
break;
|
||||
case "HIDDEN":
|
||||
default:
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.UserType;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.AccentStyle;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ParticleMotion;
|
||||
@@ -220,7 +219,7 @@ public abstract class AbilityZone extends Ability {
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44; colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44; activeColor = 0xC044FF44;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Poison, 100, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Poison, 100, 0));
|
||||
break;
|
||||
case "INFERNO":
|
||||
groundFill = true; groundAlpha = 0.35f; rings = true; ringCount = 3;
|
||||
@@ -229,7 +228,7 @@ public abstract class AbilityZone extends Ability {
|
||||
particleMotion = 0; particleGlow = true; particleDir = "mc:flame";
|
||||
colorData.innerColor = 0xFF6611; colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611; activeColor = 0xC0FF4400;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Fire, 60, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Fire, 60, 0));
|
||||
break;
|
||||
case "ARCANE":
|
||||
groundFill = true; groundAlpha = 0.20f; rings = true; ringCount = 1;
|
||||
@@ -238,7 +237,7 @@ public abstract class AbilityZone extends Ability {
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF; colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF; activeColor = 0xC0CC66FF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Weakness, 100, 0));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Weakness, 100, 0));
|
||||
break;
|
||||
case "ELECTRIC":
|
||||
groundFill = true; groundAlpha = 0.15f; rings = false; ringCount = 1;
|
||||
@@ -247,7 +246,7 @@ public abstract class AbilityZone extends Ability {
|
||||
particleMotion = 2; particleGlow = true; particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF; colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF; activeColor = 0xC066AAFF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
break;
|
||||
case "FROST":
|
||||
groundFill = true; groundAlpha = 0.25f; rings = true; ringCount = 3;
|
||||
@@ -256,7 +255,7 @@ public abstract class AbilityZone extends Ability {
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF; colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF; activeColor = 0xC0AADDFF;
|
||||
effects.add(new AbilityEffect(EnumPotionType.Slowness, 100, 1));
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Slowness, 100, 1));
|
||||
break;
|
||||
case "DEFAULT":
|
||||
groundFill = true; groundAlpha = 0.25f; rings = true; ringCount = 3;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
@@ -0,0 +1,130 @@
|
||||
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.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Dome ability: Spawns a spherical barrier centered on the caster.
|
||||
* Blocks incoming energy projectiles with configurable damage multipliers.
|
||||
* Duration and/or HP based.
|
||||
*/
|
||||
public class AbilityDome extends AbilityEnergyBarrier {
|
||||
|
||||
private float domeRadius = 5.0f;
|
||||
private boolean followCaster = false;
|
||||
|
||||
public AbilityDome() {
|
||||
super(
|
||||
new EnergyDisplayData(0x44CCFF, 0x2288FF, true, 0.3f, 0.35f, 0.5f, 0.0f),
|
||||
new EnergyBarrierData(100.0f, true, 200, true)
|
||||
);
|
||||
this.typeId = "ability.cnpc.dome";
|
||||
this.name = "Dome";
|
||||
this.targetingMode = TargetingMode.SELF;
|
||||
this.cooldownTicks = 100;
|
||||
this.windUpTicks = 30;
|
||||
this.lockMovement = LockMovementType.WINDUP;
|
||||
this.telegraphType = TelegraphType.RING;
|
||||
this.showTelegraph = true;
|
||||
this.windUpAnimationName = "";
|
||||
this.activeAnimationName = "";
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT IMPLEMENTATIONS ====================
|
||||
|
||||
@Override
|
||||
protected EntityEnergyBarrier createBarrierEntity(EntityLivingBase caster, EntityLivingBase target) {
|
||||
EntityEnergyDome dome = new EntityEnergyDome(
|
||||
caster.worldObj, caster,
|
||||
caster.posX, caster.posY, caster.posZ,
|
||||
domeRadius, displayData.copy(), lightningData.copy(), barrierData.copy()
|
||||
);
|
||||
dome.setFollowCaster(followCaster);
|
||||
dome.setSourceAbility(this);
|
||||
return dome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTargetingModeLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetingMode[] getAllowedTargetingModes() {
|
||||
return new TargetingMode[]{TargetingMode.SELF};
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTelegraphRadius() {
|
||||
return domeRadius;
|
||||
}
|
||||
|
||||
// ==================== VARIANTS ====================
|
||||
|
||||
@Override
|
||||
public List<AbilityVariant> getVariants() {
|
||||
return Arrays.asList(
|
||||
new AbilityVariant("ability.variant.small", a -> {
|
||||
AbilityDome dome = (AbilityDome) a;
|
||||
a.setName("Small Dome");
|
||||
dome.setDomeRadius(3.0f);
|
||||
dome.setBarrierMaxHealth(60.0f);
|
||||
}),
|
||||
new AbilityVariant("ability.variant.large", a -> {
|
||||
AbilityDome dome = (AbilityDome) a;
|
||||
a.setName("Large Dome");
|
||||
dome.setDomeRadius(8.0f);
|
||||
dome.setBarrierMaxHealth(200.0f);
|
||||
dome.setBarrierDuration(300);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC NBT ====================
|
||||
|
||||
@Override
|
||||
protected void writeBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("domeRadius", domeRadius);
|
||||
nbt.setBoolean("followCaster", followCaster);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
this.domeRadius = nbt.hasKey("domeRadius") ? nbt.getFloat("domeRadius") : 5.0f;
|
||||
this.followCaster = nbt.hasKey("followCaster") && nbt.getBoolean("followCaster");
|
||||
}
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getDomeRadius() { return domeRadius; }
|
||||
public void setDomeRadius(float radius) { this.domeRadius = Math.max(1.0f, radius); }
|
||||
|
||||
public boolean isFollowCaster() { return followCaster; }
|
||||
public void setFollowCaster(boolean follow) { this.followCaster = follow; }
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
protected void addBarrierTypeDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.floatField("ability.domeRadius", this::getDomeRadius, this::setDomeRadius)
|
||||
.range(1.0f, 30.0f));
|
||||
defs.add(FieldDef.boolField("ability.followCaster", this::isFollowCaster, this::setFollowCaster)
|
||||
.hover("ability.hover.followCaster"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
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.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract base for all energy-based abilities (Projectile, Barrier, Sweeper, etc.).
|
||||
* Provides shared visual data (colors, lightning) and corresponding API/GUI/NBT.
|
||||
*/
|
||||
public abstract class AbilityEnergy extends Ability {
|
||||
|
||||
protected EnergyDisplayData displayData;
|
||||
protected EnergyLightningData lightningData;
|
||||
|
||||
protected AbilityEnergy(EnergyDisplayData displayData) {
|
||||
this.displayData = displayData;
|
||||
this.lightningData = new EnergyLightningData();
|
||||
}
|
||||
|
||||
// ==================== DISPLAY DATA ====================
|
||||
|
||||
public int getInnerColor() { return displayData.innerColor; }
|
||||
public void setInnerColor(int color) { displayData.innerColor = color; }
|
||||
|
||||
public float getInnerAlpha() { return displayData.innerAlpha; }
|
||||
public void setInnerAlpha(float alpha) { displayData.innerAlpha = alpha; }
|
||||
|
||||
public int getOuterColor() { return displayData.outerColor; }
|
||||
public void setOuterColor(int color) { displayData.outerColor = color; }
|
||||
|
||||
public boolean isOuterColorEnabled() { return displayData.outerColorEnabled; }
|
||||
public void setOuterColorEnabled(boolean enabled) { displayData.outerColorEnabled = enabled; }
|
||||
|
||||
public float getOuterColorWidth() { return displayData.outerColorWidth; }
|
||||
public void setOuterColorWidth(float width) { displayData.outerColorWidth = width; }
|
||||
|
||||
public float getOuterColorAlpha() { return displayData.outerColorAlpha; }
|
||||
public void setOuterColorAlpha(float alpha) { displayData.outerColorAlpha = alpha; }
|
||||
|
||||
public float getRotationSpeed() { return displayData.rotationSpeed; }
|
||||
public void setRotationSpeed(float speed) { displayData.rotationSpeed = speed; }
|
||||
|
||||
// ==================== LIGHTNING DATA ====================
|
||||
|
||||
public boolean hasLightningEffect() { return lightningData.lightningEffect; }
|
||||
public void setLightningEffect(boolean enabled) { lightningData.lightningEffect = enabled; }
|
||||
|
||||
public float getLightningDensity() { return lightningData.lightningDensity; }
|
||||
public void setLightningDensity(float density) { lightningData.lightningDensity = density; }
|
||||
|
||||
public float getLightningRadius() { return lightningData.lightningRadius; }
|
||||
public void setLightningRadius(float radius) { lightningData.lightningRadius = radius; }
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.lightningFadeTime; }
|
||||
public void setLightningFadeTime(int fadeTime) { lightningData.lightningFadeTime = fadeTime; }
|
||||
|
||||
// ==================== NBT HELPERS ====================
|
||||
|
||||
protected void writeEnergyNBT(NBTTagCompound nbt) {
|
||||
displayData.writeNBT(nbt);
|
||||
lightningData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
protected void readEnergyNBT(NBTTagCompound nbt) {
|
||||
displayData.readNBT(nbt);
|
||||
lightningData.readNBT(nbt);
|
||||
}
|
||||
|
||||
// ==================== GUI HELPERS ====================
|
||||
|
||||
/**
|
||||
* Add complete visual tab definitions (colors section + effects/lightning section).
|
||||
* Subclasses can call this directly or use the individual methods for more control.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void addEnergyVisualDefinitions(List<FieldDef> defs) {
|
||||
addEnergyColorDefinitions(defs);
|
||||
addEnergyEffectDefinitions(defs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the colors section to the visual tab.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void addEnergyColorDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.section("ability.section.colors").tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.colorSubGui("ability.innerColor", this::getInnerColor, this::setInnerColor),
|
||||
FieldDef.floatField("ability.innerAlpha", this::getInnerAlpha, this::setInnerAlpha).range(0, 1)
|
||||
).tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor)
|
||||
.tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth)
|
||||
.visibleWhen(this::isOuterColorEnabled),
|
||||
FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha)
|
||||
.range(0, 1).visibleWhen(this::isOuterColorEnabled)
|
||||
).tab("ability.tab.visual"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the effects section (lightning) to the visual tab.
|
||||
* Override to insert additional fields before lightning (e.g., rotationSpeed).
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void addEnergyEffectDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.section("ability.section.effects").tab("ability.tab.visual"));
|
||||
addEnergyLightningDefinitions(defs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add just the lightning fields (no section header) to the visual tab.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void addEnergyLightningDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity)
|
||||
.visibleWhen(this::hasLightningEffect).range(0.01f, 100f),
|
||||
FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius)
|
||||
.range(0.1f, 100f).visibleWhen(this::hasLightningEffect)
|
||||
).tab("ability.tab.visual"));
|
||||
}
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
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.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract base for energy barrier abilities (Dome, Wall, Shield).
|
||||
* Handles shared visual data, barrier configuration, and lifecycle management.
|
||||
*/
|
||||
public abstract class AbilityEnergyBarrier extends AbilityEnergy {
|
||||
|
||||
protected final EnergyBarrierData barrierData;
|
||||
|
||||
// Runtime entity tracking
|
||||
protected transient EntityEnergyBarrier barrierEntity;
|
||||
|
||||
protected AbilityEnergyBarrier(EnergyDisplayData displayData, EnergyBarrierData barrierData) {
|
||||
super(displayData);
|
||||
this.barrierData = barrierData;
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT METHODS ====================
|
||||
|
||||
/**
|
||||
* Create and spawn the barrier entity during execution.
|
||||
*/
|
||||
protected abstract EntityEnergyBarrier createBarrierEntity(EntityLivingBase caster, EntityLivingBase target);
|
||||
|
||||
/**
|
||||
* Add type-specific GUI field definitions.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected abstract void addBarrierTypeDefinitions(List<FieldDef> defs);
|
||||
|
||||
/**
|
||||
* Write type-specific fields to NBT.
|
||||
*/
|
||||
protected abstract void writeBarrierTypeNBT(NBTTagCompound nbt);
|
||||
|
||||
/**
|
||||
* Read type-specific fields from NBT.
|
||||
*/
|
||||
protected abstract void readBarrierTypeNBT(NBTTagCompound nbt);
|
||||
|
||||
// ==================== LIFECYCLE ====================
|
||||
|
||||
@Override
|
||||
public boolean allowBurst() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDamage() {
|
||||
return false; // Barriers are defensive
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindUpTick(EntityLivingBase caster, EntityLivingBase target, int tick) {
|
||||
if (caster.worldObj.isRemote) return;
|
||||
|
||||
if (tick == 1) {
|
||||
barrierEntity = createBarrierEntity(caster, target);
|
||||
if (barrierEntity != null) {
|
||||
barrierEntity.setupCharging(getWindUpTicks());
|
||||
spawnAbilityEntity(barrierEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(EntityLivingBase caster, EntityLivingBase target) {
|
||||
if (barrierEntity != null && !barrierEntity.isDead) {
|
||||
// Barrier was spawned during windup — transition to active
|
||||
barrierEntity.finishCharging();
|
||||
} else {
|
||||
// No windup or entity died — create fresh
|
||||
barrierEntity = createBarrierEntity(caster, target);
|
||||
if (barrierEntity != null) {
|
||||
spawnAbilityEntity(barrierEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, int tick) {
|
||||
if (barrierEntity == null || barrierEntity.isDead) {
|
||||
signalCompletion();
|
||||
return;
|
||||
}
|
||||
|
||||
// Duration tracked by entity itself, but check here too as a failsafe
|
||||
if (barrierData.useDuration && tick >= barrierData.durationTicks) {
|
||||
cleanup();
|
||||
signalCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterrupt(EntityLivingBase caster, DamageSource source, float damage) {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
if (barrierEntity != null && !barrierEntity.isDead) {
|
||||
barrierEntity.setDead();
|
||||
}
|
||||
barrierEntity = null;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
public final void writeTypeNBT(NBTTagCompound nbt) {
|
||||
writeBarrierTypeNBT(nbt);
|
||||
writeEnergyNBT(nbt);
|
||||
barrierData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readTypeNBT(NBTTagCompound nbt) {
|
||||
readBarrierTypeNBT(nbt);
|
||||
readEnergyNBT(nbt);
|
||||
barrierData.readNBT(nbt);
|
||||
}
|
||||
|
||||
// ==================== API GETTERS & SETTERS ====================
|
||||
|
||||
// Display and lightning data inherited from AbilityEnergy
|
||||
|
||||
// Barrier data
|
||||
public float getBarrierMaxHealth() { return barrierData.maxHealth; }
|
||||
public void setBarrierMaxHealth(float maxHealth) { barrierData.setMaxHealth(maxHealth); }
|
||||
|
||||
public boolean isUseHealth() { return barrierData.useHealth; }
|
||||
public void setUseHealth(boolean useHealth) { barrierData.useHealth = useHealth; }
|
||||
|
||||
public int getBarrierDuration() { return barrierData.durationTicks; }
|
||||
public void setBarrierDuration(int ticks) { barrierData.setDurationTicks(ticks); }
|
||||
|
||||
public boolean isUseDuration() { return barrierData.useDuration; }
|
||||
public void setUseDuration(boolean useDuration) { barrierData.useDuration = useDuration; }
|
||||
|
||||
public float getDefaultMultiplier() { return barrierData.defaultMultiplier; }
|
||||
public void setDefaultMultiplier(float mult) { barrierData.defaultMultiplier = mult; }
|
||||
|
||||
public void setDamageMultiplier(String typeId, float mult) { barrierData.setMultiplier(typeId, mult); }
|
||||
public float getDamageMultiplier(String typeId) { return barrierData.getMultiplier(typeId); }
|
||||
|
||||
// Knockback data
|
||||
public boolean isKnockbackEnabled() { return barrierData.knockbackEnabled; }
|
||||
public void setKnockbackEnabled(boolean enabled) { barrierData.knockbackEnabled = enabled; }
|
||||
public float getKnockbackStrength() { return barrierData.knockbackStrength; }
|
||||
public void setKnockbackStrength(float strength) { barrierData.knockbackStrength = strength; }
|
||||
public String getKnockbackTargetKey() { return barrierData.getKnockbackTargetKey(); }
|
||||
public void setKnockbackTargetKey(String key) { barrierData.setKnockbackTargetFromKey(key); }
|
||||
|
||||
// Melee data
|
||||
public boolean isMeleeEnabled() { return barrierData.meleeEnabled; }
|
||||
public void setMeleeEnabled(boolean enabled) { barrierData.meleeEnabled = enabled; }
|
||||
public float getMeleeDamageMultiplier() { return barrierData.meleeDamageMultiplier; }
|
||||
public void setMeleeDamageMultiplier(float mult) { barrierData.meleeDamageMultiplier = mult; }
|
||||
|
||||
// ==================== GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public final void getAbilityDefinitions(List<FieldDef> defs) {
|
||||
// Type-specific fields first
|
||||
addBarrierTypeDefinitions(defs);
|
||||
|
||||
// Barrier section
|
||||
defs.add(FieldDef.section("ability.section.barrier"));
|
||||
defs.add(FieldDef.boolField("ability.useHealth", this::isUseHealth, this::setUseHealth));
|
||||
defs.add(FieldDef.floatField("ability.maxHealth", this::getBarrierMaxHealth, this::setBarrierMaxHealth)
|
||||
.visibleWhen(this::isUseHealth));
|
||||
defs.add(FieldDef.boolField("ability.useDuration", this::isUseDuration, this::setUseDuration));
|
||||
defs.add(FieldDef.intField("ability.duration", this::getBarrierDuration, this::setBarrierDuration)
|
||||
.range(1, 6000).visibleWhen(this::isUseDuration));
|
||||
defs.add(FieldDef.floatField("ability.defaultMultiplier", this::getDefaultMultiplier, this::setDefaultMultiplier));
|
||||
|
||||
// Knockback section
|
||||
defs.add(FieldDef.section("ability.section.knockback"));
|
||||
defs.add(FieldDef.boolField("ability.knockbackEnabled", this::isKnockbackEnabled, this::setKnockbackEnabled));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("ability.knockbackStrength", this::getKnockbackStrength, this::setKnockbackStrength)
|
||||
.range(0, 10).visibleWhen(this::isKnockbackEnabled),
|
||||
FieldDef.stringEnumField("ability.knockbackTarget", EnergyBarrierData.getKnockbackTargetKeys(),
|
||||
this::getKnockbackTargetKey, this::setKnockbackTargetKey)
|
||||
.visibleWhen(this::isKnockbackEnabled)
|
||||
));
|
||||
|
||||
// Melee section
|
||||
defs.add(FieldDef.section("ability.section.melee"));
|
||||
defs.add(FieldDef.boolField("ability.meleeEnabled", this::isMeleeEnabled, this::setMeleeEnabled));
|
||||
defs.add(FieldDef.floatField("ability.meleeDamageMultiplier", this::getMeleeDamageMultiplier, this::setMeleeDamageMultiplier)
|
||||
.range(0, 10).visibleWhen(this::isMeleeEnabled));
|
||||
|
||||
// Visual tab - colors + effects (from AbilityEnergy)
|
||||
addEnergyVisualDefinitions(defs);
|
||||
}
|
||||
}
|
||||
+12
-67
@@ -1,4 +1,4 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
@@ -9,7 +9,7 @@ import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -29,8 +29,7 @@ import java.util.List;
|
||||
*
|
||||
* @param <E> The entity type this ability spawns
|
||||
*/
|
||||
public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
extends Ability implements IAbilityEnergyProjectile {
|
||||
public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile> extends AbilityEnergy implements IAbilityEnergyProjectile {
|
||||
|
||||
protected static final int MAX_PROJECTILES = 8;
|
||||
|
||||
@@ -38,9 +37,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
protected int projectileCount = 1;
|
||||
protected int fireDelay = 0;
|
||||
|
||||
// Shared visual data
|
||||
protected EnergyDisplayData displayData;
|
||||
protected EnergyLightningData lightningData;
|
||||
// Trajectory data
|
||||
protected EnergyTrajectoryData trajectoryData;
|
||||
|
||||
// Shared combat/movement data
|
||||
@@ -62,11 +59,10 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
EnergyHomingData homingData,
|
||||
EnergyLifespanData lifespanData
|
||||
) {
|
||||
this.displayData = displayData;
|
||||
super(displayData);
|
||||
this.combatData = combatData;
|
||||
this.homingData = homingData;
|
||||
this.lifespanData = lifespanData;
|
||||
this.lightningData = new EnergyLightningData();
|
||||
this.trajectoryData = new EnergyTrajectoryData();
|
||||
initProjectiles(1);
|
||||
}
|
||||
@@ -389,8 +385,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
nbt.setInteger("fireDelay", fireDelay);
|
||||
|
||||
// Shared data classes
|
||||
displayData.writeNBT(nbt);
|
||||
lightningData.writeNBT(nbt);
|
||||
writeEnergyNBT(nbt);
|
||||
combatData.writeNBT(nbt);
|
||||
homingData.writeNBT(nbt);
|
||||
lifespanData.writeNBT(nbt);
|
||||
@@ -414,8 +409,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
this.fireDelay = nbt.getInteger("fireDelay");
|
||||
|
||||
// Shared data classes
|
||||
displayData.readNBT(nbt);
|
||||
lightningData.readNBT(nbt);
|
||||
readEnergyNBT(nbt);
|
||||
combatData.readNBT(nbt);
|
||||
homingData.readNBT(nbt);
|
||||
lifespanData.readNBT(nbt);
|
||||
@@ -473,37 +467,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
public float getHomingRange() { return homingData.homingRange; }
|
||||
public void setHomingRange(float range) { homingData.homingRange = range; }
|
||||
|
||||
// Display data - primary colors
|
||||
@Override public int getInnerColor() { return displayData.innerColor; }
|
||||
@Override public void setInnerColor(int color) { displayData.innerColor = color; }
|
||||
|
||||
@Override public int getOuterColor() { return displayData.outerColor; }
|
||||
@Override public void setOuterColor(int color) { displayData.outerColor = color; }
|
||||
|
||||
@Override public boolean isOuterColorEnabled() { return displayData.outerColorEnabled; }
|
||||
@Override public void setOuterColorEnabled(boolean enabled) { displayData.outerColorEnabled = enabled; }
|
||||
|
||||
@Override public float getOuterColorWidth() { return displayData.outerColorWidth; }
|
||||
@Override public void setOuterColorWidth(float width) { displayData.outerColorWidth = width; }
|
||||
|
||||
@Override public float getOuterColorAlpha() { return displayData.outerColorAlpha; }
|
||||
@Override public void setOuterColorAlpha(float alpha) { displayData.outerColorAlpha = alpha; }
|
||||
|
||||
public float getRotationSpeed() { return displayData.rotationSpeed; }
|
||||
public void setRotationSpeed(float speed) { displayData.rotationSpeed = speed; }
|
||||
|
||||
// Lightning data
|
||||
@Override public boolean hasLightningEffect() { return lightningData.lightningEffect; }
|
||||
@Override public void setLightningEffect(boolean enabled) { lightningData.lightningEffect = enabled; }
|
||||
|
||||
@Override public float getLightningDensity() { return lightningData.lightningDensity; }
|
||||
@Override public void setLightningDensity(float density) { lightningData.lightningDensity = density; }
|
||||
|
||||
@Override public float getLightningRadius() { return lightningData.lightningRadius; }
|
||||
@Override public void setLightningRadius(float radius) { lightningData.lightningRadius = radius; }
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.lightningFadeTime; }
|
||||
public void setLightningFadeTime(int fadeTime) { lightningData.lightningFadeTime = fadeTime; }
|
||||
// Display and lightning data inherited from AbilityEnergy
|
||||
|
||||
// Anchor - default to projectile 0
|
||||
public AnchorPoint getAnchorPointEnum() { return projectiles[0].anchor.anchorPoint; }
|
||||
@@ -556,33 +520,14 @@ public abstract class AbilityEnergyProjectile<E extends EntityAbilityProjectile>
|
||||
// Type-specific fields first
|
||||
addTypeDefinitions(defs);
|
||||
|
||||
// Shared visual tab - primary colors
|
||||
defs.add(FieldDef.section("ability.section.colors").tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.colorSubGui("ability.innerColor", this::getInnerColor, this::setInnerColor)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor)
|
||||
.tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth)
|
||||
.visibleWhen(this::isOuterColorEnabled),
|
||||
FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha)
|
||||
.range(0, 1).visibleWhen(this::isOuterColorEnabled)
|
||||
).tab("ability.tab.visual"));
|
||||
// Shared visual tab - colors + effects (from AbilityEnergy)
|
||||
addEnergyColorDefinitions(defs);
|
||||
|
||||
// Shared visual tab - effects
|
||||
// Effects section with projectile-specific rotationSpeed before lightning
|
||||
defs.add(FieldDef.section("ability.section.effects").tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.floatField("ability.rotationSpeed", this::getRotationSpeed, this::setRotationSpeed)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect)
|
||||
.tab("ability.tab.visual"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity)
|
||||
.visibleWhen(this::hasLightningEffect).range(0.01f, 100f),
|
||||
FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius)
|
||||
.range(0.1f, 100f).visibleWhen(this::hasLightningEffect)
|
||||
).tab("ability.tab.visual"));
|
||||
addEnergyLightningDefinitions(defs);
|
||||
|
||||
// Shared visual tab - per-projectile sections
|
||||
for (int i = 0; i < MAX_PROJECTILES; i++) {
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
@@ -73,7 +73,7 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
|
||||
/**
|
||||
* LINE telegraph: positioned at caster, aimed toward target.
|
||||
* Overrides the circle telegraph from AbstractEnergyProjectileAbility.
|
||||
* Overrides the circle telegraph from AbilityEnergyProjectile.
|
||||
*/
|
||||
@Override
|
||||
public TelegraphInstance createTelegraph(EntityLivingBase caster, EntityLivingBase target) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
package kamkeel.npcs.controllers.data.ability.type.energy;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
@@ -0,0 +1,143 @@
|
||||
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.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.UserType;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyPanelData;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Shield ability: Spawns a flat energy panel held in front of the caster.
|
||||
* The shield follows the caster's position and rotates with their look direction.
|
||||
* Cannot be placed — it's always held.
|
||||
*/
|
||||
public class AbilityShield extends AbilityEnergyBarrier {
|
||||
|
||||
private float shieldWidth = 2.5f;
|
||||
private float shieldHeight = 2.5f;
|
||||
|
||||
public AbilityShield() {
|
||||
super(
|
||||
new EnergyDisplayData(0xFFDD44, 0xFFAA00, true, 0.3f, 0.4f, 0.5f, 0.0f),
|
||||
new EnergyBarrierData(60.0f, true, 120, true)
|
||||
);
|
||||
this.typeId = "ability.cnpc.shield";
|
||||
this.name = "Shield";
|
||||
this.targetingMode = TargetingMode.SELF;
|
||||
this.cooldownTicks = 60;
|
||||
this.windUpTicks = 10;
|
||||
this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE;
|
||||
this.telegraphType = TelegraphType.NONE;
|
||||
this.showTelegraph = false;
|
||||
this.windUpAnimationName = "";
|
||||
this.activeAnimationName = "";
|
||||
this.allowedBy = UserType.BOTH;
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT IMPLEMENTATIONS ====================
|
||||
|
||||
@Override
|
||||
protected EntityEnergyBarrier createBarrierEntity(EntityLivingBase caster, EntityLivingBase target) {
|
||||
EnergyPanelData panelData = new EnergyPanelData(shieldWidth, shieldHeight, 0.0f);
|
||||
|
||||
float frontDist = 1.5f;
|
||||
float yawRad = (float) Math.toRadians(caster.rotationYaw);
|
||||
double spawnX = caster.posX + (-Math.sin(yawRad) * frontDist);
|
||||
double spawnY = caster.posY + (caster.height * 0.5f);
|
||||
double spawnZ = caster.posZ + (Math.cos(yawRad) * frontDist);
|
||||
|
||||
EntityEnergyPanel panel = new EntityEnergyPanel(
|
||||
caster.worldObj, caster,
|
||||
spawnX, spawnY, spawnZ, caster.rotationYaw,
|
||||
EntityEnergyPanel.PanelMode.HELD,
|
||||
displayData.copy(), lightningData.copy(), barrierData.copy(), panelData
|
||||
);
|
||||
panel.setSourceAbility(this);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTargetingModeLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetingMode[] getAllowedTargetingModes() {
|
||||
return new TargetingMode[]{TargetingMode.SELF};
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTelegraphRadius() {
|
||||
return 0; // No telegraph for shield
|
||||
}
|
||||
|
||||
// ==================== VARIANTS ====================
|
||||
|
||||
@Override
|
||||
public List<AbilityVariant> getVariants() {
|
||||
return Arrays.asList(
|
||||
new AbilityVariant("ability.variant.small", a -> {
|
||||
AbilityShield shield = (AbilityShield) a;
|
||||
a.setName("Small Shield");
|
||||
shield.setShieldWidth(1.5f);
|
||||
shield.setShieldHeight(1.5f);
|
||||
shield.setBarrierMaxHealth(40.0f);
|
||||
}),
|
||||
new AbilityVariant("ability.variant.large", a -> {
|
||||
AbilityShield shield = (AbilityShield) a;
|
||||
a.setName("Large Shield");
|
||||
shield.setShieldWidth(4.0f);
|
||||
shield.setShieldHeight(4.0f);
|
||||
shield.setBarrierMaxHealth(120.0f);
|
||||
shield.setBarrierDuration(200);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC NBT ====================
|
||||
|
||||
@Override
|
||||
protected void writeBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("shieldWidth", shieldWidth);
|
||||
nbt.setFloat("shieldHeight", shieldHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
this.shieldWidth = nbt.hasKey("shieldWidth") ? nbt.getFloat("shieldWidth") : 2.5f;
|
||||
this.shieldHeight = nbt.hasKey("shieldHeight") ? nbt.getFloat("shieldHeight") : 2.5f;
|
||||
}
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getShieldWidth() { return shieldWidth; }
|
||||
public void setShieldWidth(float width) { this.shieldWidth = Math.max(0.5f, width); }
|
||||
|
||||
public float getShieldHeight() { return shieldHeight; }
|
||||
public void setShieldHeight(float height) { this.shieldHeight = Math.max(0.5f, height); }
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
protected void addBarrierTypeDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("gui.width", this::getShieldWidth, this::setShieldWidth).range(0.5f, 10.0f),
|
||||
FieldDef.floatField("gui.height", this::getShieldHeight, this::setShieldHeight).range(0.5f, 10.0f)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
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.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.Vec3;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Slicer ability: Fires a thin, wide blade projectile in a straight line.
|
||||
* JJK Cleave/Dismantle inspired. Piercing by default.
|
||||
* 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(
|
||||
new EnergyDisplayData(0xFF4444, 0xFF0000, true, 0.2f, 0.6f, 0.0f),
|
||||
new EnergyCombatData(12.0f, 0.5f, 0.0f, false, 3.0f, 0.5f),
|
||||
new EnergyHomingData(0.8f, false, 0.0f, 0.0f),
|
||||
new EnergyLifespanData(40.0f, 100)
|
||||
);
|
||||
this.typeId = "ability.cnpc.slicer";
|
||||
this.name = "Slicer";
|
||||
this.targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
this.maxRange = 30.0f;
|
||||
this.minRange = 3.0f;
|
||||
this.cooldownTicks = 40;
|
||||
this.windUpTicks = 15;
|
||||
this.lockMovement = LockMovementType.WINDUP;
|
||||
this.telegraphType = TelegraphType.LINE;
|
||||
this.showTelegraph = true;
|
||||
this.windUpAnimationName = "";
|
||||
this.activeAnimationName = "";
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT IMPLEMENTATIONS ====================
|
||||
|
||||
@Override
|
||||
protected EntityEnergySlicer createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityEnergySlicer(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
sliceWidth, sliceThickness,
|
||||
resolved, combatData, homingData, lightningData, lifespanData, trajectoryData,
|
||||
piercing
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireEntity(EntityEnergySlicer slicer, EntityLivingBase target) {
|
||||
if (isPreview()) {
|
||||
slicer.startPreviewFiring();
|
||||
} else {
|
||||
slicer.startMoving(target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupEntityCharging(EntityEnergySlicer slicer, ProjectileData projData, int index) {
|
||||
slicer.setupSlicerCharging(projData.anchor, windUpTicks, sliceWidth, sliceThickness);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityEnergySlicer slicer, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
slicer.setupPreview(caster, sliceWidth, sliceThickness, resolved, lightningData, projData.anchor, windUpTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityEnergySlicer[] createEntityArray(int size) {
|
||||
return new EntityEnergySlicer[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getProjectileTelegraphRadius() {
|
||||
return sliceWidth * 0.75f;
|
||||
}
|
||||
|
||||
// ==================== VARIANTS ====================
|
||||
|
||||
@Override
|
||||
public List<AbilityVariant> getVariants() {
|
||||
return Arrays.asList(
|
||||
new AbilityVariant("ability.variant.single", a -> {
|
||||
a.setName("Slicer");
|
||||
}),
|
||||
new AbilityVariant("ability.variant.dual", a -> {
|
||||
AbilitySlicer slicer = (AbilitySlicer) a;
|
||||
a.setName("Double Slicer");
|
||||
slicer.setProjectileCount(2);
|
||||
slicer.setFireDelay(5);
|
||||
a.setWindUpAnimationName("");
|
||||
a.setActiveAnimationName("");
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC NBT ====================
|
||||
|
||||
@Override
|
||||
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 ====================
|
||||
|
||||
public float getSlicerSpeed() { return homingData.speed; }
|
||||
public void setSlicerSpeed(float speed) { homingData.speed = speed; }
|
||||
|
||||
public float getSliceWidth() { return sliceWidth; }
|
||||
public void setSliceWidth(float width) { this.sliceWidth = Math.max(0.5f, width); }
|
||||
|
||||
public float getSliceThickness() { return sliceThickness; }
|
||||
public void setSliceThickness(float thickness) { 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)
|
||||
@Override
|
||||
protected void addTypeDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.intField("ability.projectileCount", this::getProjectileCount, this::setProjectileCount).range(1, MAX_PROJECTILES),
|
||||
FieldDef.intField("ability.fireDelay", this::getFireDelay, this::setFireDelay)
|
||||
.range(0, 200).visibleWhen(() -> projectileCount > 1)
|
||||
));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage),
|
||||
FieldDef.floatField("stats.speed", this::getSlicerSpeed, this::setSlicerSpeed)
|
||||
));
|
||||
defs.add(FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback));
|
||||
defs.add(FieldDef.section("ability.section.slicer"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("gui.width", this::getSliceWidth, this::setSliceWidth).range(0.5f, 20.0f),
|
||||
FieldDef.floatField("gui.thickness", this::getSliceThickness, this::setSliceThickness).range(0.05f, 2.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),
|
||||
FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime)
|
||||
));
|
||||
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));
|
||||
defs.add(AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects));
|
||||
}
|
||||
}
|
||||
+12
-36
@@ -1,12 +1,10 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
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.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
@@ -14,8 +12,8 @@ import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilitySweeper;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilitySweeper;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -28,7 +26,7 @@ import java.util.List;
|
||||
* All damage logic is handled by the EntityAbilitySweeper entity to ensure
|
||||
* visual and damage hitbox alignment.
|
||||
*/
|
||||
public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
public class AbilitySweeper extends AbilityEnergy implements IAbilitySweeper {
|
||||
|
||||
// Type-specific parameters
|
||||
private float beamLength = 10.0f;
|
||||
@@ -41,13 +39,11 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
private int numberOfRotations = 2; // How many full rotations before ability ends
|
||||
private boolean lockOnTarget = false;
|
||||
|
||||
// Visual properties
|
||||
private EnergyDisplayData colorData = new EnergyDisplayData(0xFF6600, 0xFF0000, true, 1.8f, 0.5f, 0.0f);
|
||||
|
||||
// Runtime state (transient)
|
||||
private transient EntityAbilitySweeper activeEntity = null;
|
||||
|
||||
public AbilitySweeper() {
|
||||
super(new EnergyDisplayData(0xFF6600, 0xFF0000, true, 1.8f, 0.5f, 0.0f));
|
||||
this.typeId = "ability.cnpc.sweeper";
|
||||
this.name = "Sweeper";
|
||||
this.targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
@@ -83,7 +79,7 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
// Player: target is null — sweep rotates around caster's facing direction, lockOnTarget has no effect.
|
||||
activeEntity = new EntityAbilitySweeper(caster.worldObj, caster, target,
|
||||
beamLength, beamWidth, beamHeight,
|
||||
colorData,
|
||||
displayData,
|
||||
sweepSpeed, numberOfRotations,
|
||||
damage, damageInterval, piercing,
|
||||
lockOnTarget);
|
||||
@@ -93,9 +89,6 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
}
|
||||
|
||||
spawnAbilityEntity(activeEntity);
|
||||
|
||||
// Ability stays active until entity dies (prevents firing another while projectile is alive)
|
||||
// Movement locking is handled separately by the base class
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,7 +155,7 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
nbt.setFloat("sweepSpeed", sweepSpeed);
|
||||
nbt.setInteger("numberOfRotations", numberOfRotations);
|
||||
nbt.setBoolean("lockOnTarget", lockOnTarget);
|
||||
colorData.writeNBT(nbt);
|
||||
writeEnergyNBT(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,10 +169,10 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
this.sweepSpeed = nbt.getFloat("sweepSpeed");
|
||||
this.numberOfRotations = nbt.getInteger("numberOfRotations");
|
||||
this.lockOnTarget = nbt.getBoolean("lockOnTarget");
|
||||
colorData.readNBT(nbt);
|
||||
readEnergyNBT(nbt);
|
||||
}
|
||||
|
||||
// Getters & Setters
|
||||
// Getters & Setters (type-specific only; color/lightning inherited from AbilityEnergy)
|
||||
public float getBeamLength() { return beamLength; }
|
||||
public void setBeamLength(float beamLength) { this.beamLength = beamLength; }
|
||||
public float getBeamWidth() { return beamWidth; }
|
||||
@@ -198,14 +191,6 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
public void setNumberOfRotations(int numberOfRotations) { this.numberOfRotations = numberOfRotations; }
|
||||
public boolean isLockOnTarget() { return lockOnTarget; }
|
||||
public void setLockOnTarget(boolean lockOnTarget) { this.lockOnTarget = lockOnTarget; }
|
||||
public int getInnerColor() { return colorData.innerColor; }
|
||||
public void setInnerColor(int innerColor) { colorData.innerColor = innerColor; }
|
||||
public int getOuterColor() { return colorData.outerColor; }
|
||||
public void setOuterColor(int outerColor) { colorData.outerColor = outerColor; }
|
||||
public float getOuterColorWidth() { return colorData.outerColorWidth; }
|
||||
public void setOuterColorWidth(float outerColorWidth) { colorData.outerColorWidth = outerColorWidth; }
|
||||
public boolean isOuterColorEnabled() { return colorData.outerColorEnabled; }
|
||||
public void setOuterColorEnabled(boolean outerColorEnabled) { colorData.outerColorEnabled = outerColorEnabled; }
|
||||
|
||||
@Override
|
||||
public int getMaxPreviewDuration() {
|
||||
@@ -216,7 +201,6 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
@Override
|
||||
public void getAbilityDefinitions(List<FieldDef> defs) {
|
||||
defs.addAll(Arrays.asList(
|
||||
|
||||
FieldDef.row(
|
||||
FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage),
|
||||
FieldDef.intField("ability.damageInterval", this::getDamageInterval, this::setDamageInterval)
|
||||
@@ -237,18 +221,10 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper {
|
||||
FieldDef.boolField("ability.lockTarget", this::isLockOnTarget, this::setLockOnTarget)
|
||||
.hover("ability.hover.lockTarget")
|
||||
),
|
||||
AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects),
|
||||
|
||||
// Visual tab
|
||||
FieldDef.section("ability.section.colors").tab("ability.tab.visual"),
|
||||
FieldDef.colorSubGui("ability.innerColor", this::getInnerColor, this::setInnerColor)
|
||||
.tab("ability.tab.visual"),
|
||||
FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled)
|
||||
.tab("ability.tab.visual"),
|
||||
FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor)
|
||||
.tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled),
|
||||
FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth)
|
||||
.tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled)
|
||||
AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects)
|
||||
));
|
||||
|
||||
// Visual tab - colors + effects (from AbilityEnergy)
|
||||
addEnergyVisualDefinitions(defs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
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.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyPanelData;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Wall ability: Spawns a placeable flat energy barrier.
|
||||
* Can float above ground (configurable height offset).
|
||||
* Optional launching mode fires the wall forward with damage/knockback.
|
||||
*/
|
||||
public class AbilityWall extends AbilityEnergyBarrier {
|
||||
|
||||
private final EnergyPanelData panelData;
|
||||
|
||||
public AbilityWall() {
|
||||
super(
|
||||
new EnergyDisplayData(0x44FFCC, 0x22CCAA, true, 0.3f, 0.4f, 0.5f, 0.0f),
|
||||
new EnergyBarrierData(80.0f, true, 160, true)
|
||||
);
|
||||
this.panelData = new EnergyPanelData(4.0f, 3.0f, 0.0f);
|
||||
this.typeId = "ability.cnpc.wall";
|
||||
this.name = "Wall";
|
||||
this.targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
this.maxRange = 15.0f;
|
||||
this.minRange = 2.0f;
|
||||
this.cooldownTicks = 80;
|
||||
this.windUpTicks = 20;
|
||||
this.lockMovement = LockMovementType.WINDUP;
|
||||
this.telegraphType = TelegraphType.LINE;
|
||||
this.showTelegraph = true;
|
||||
this.windUpAnimationName = "";
|
||||
this.activeAnimationName = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDamage() {
|
||||
return panelData.launching; // Only has damage when launching
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT IMPLEMENTATIONS ====================
|
||||
|
||||
@Override
|
||||
protected EntityEnergyBarrier createBarrierEntity(EntityLivingBase caster, EntityLivingBase target) {
|
||||
// Place wall between caster and target
|
||||
double placeX, placeY, placeZ;
|
||||
float yaw;
|
||||
|
||||
if (target != null) {
|
||||
double dx = target.posX - caster.posX;
|
||||
double dz = target.posZ - caster.posZ;
|
||||
double dist = Math.sqrt(dx * dx + dz * dz);
|
||||
|
||||
if (dist < 0.01) {
|
||||
// Target at same position — fall through to look-direction placement
|
||||
float yawRad = (float) Math.toRadians(caster.rotationYaw);
|
||||
placeX = caster.posX + (-Math.sin(yawRad) * 3.0);
|
||||
placeY = caster.posY;
|
||||
placeZ = caster.posZ + (Math.cos(yawRad) * 3.0);
|
||||
yaw = caster.rotationYaw;
|
||||
} else {
|
||||
double placeDist = Math.min(dist * 0.5, 5.0);
|
||||
placeX = caster.posX + (dx / dist) * placeDist;
|
||||
placeY = caster.posY;
|
||||
placeZ = caster.posZ + (dz / dist) * placeDist;
|
||||
yaw = (float) (Math.atan2(-dx, dz) * 180.0 / Math.PI);
|
||||
}
|
||||
} else {
|
||||
float yawRad = (float) Math.toRadians(caster.rotationYaw);
|
||||
placeX = caster.posX + (-Math.sin(yawRad) * 3.0);
|
||||
placeY = caster.posY;
|
||||
placeZ = caster.posZ + (Math.cos(yawRad) * 3.0);
|
||||
yaw = caster.rotationYaw;
|
||||
}
|
||||
|
||||
EntityEnergyPanel.PanelMode mode = panelData.launching
|
||||
? EntityEnergyPanel.PanelMode.LAUNCHED
|
||||
: EntityEnergyPanel.PanelMode.PLACED;
|
||||
|
||||
EntityEnergyPanel panel = new EntityEnergyPanel(
|
||||
caster.worldObj, caster,
|
||||
placeX, placeY, placeZ, yaw, mode,
|
||||
displayData.copy(), lightningData.copy(), barrierData.copy(), panelData.copy()
|
||||
);
|
||||
panel.setSourceAbility(this);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTelegraphRadius() {
|
||||
return Math.max(panelData.panelWidth, panelData.panelHeight) * 0.5f;
|
||||
}
|
||||
|
||||
// ==================== VARIANTS ====================
|
||||
|
||||
@Override
|
||||
public List<AbilityVariant> getVariants() {
|
||||
return Arrays.asList(
|
||||
new AbilityVariant("ability.variant.static", a -> {
|
||||
a.setName("Static Wall");
|
||||
}),
|
||||
new AbilityVariant("ability.variant.launched", a -> {
|
||||
AbilityWall wall = (AbilityWall) a;
|
||||
a.setName("Launched Wall");
|
||||
wall.panelData.launching = true;
|
||||
wall.panelData.launchSpeed = 0.6f;
|
||||
wall.panelData.launchDamage = 10.0f;
|
||||
wall.panelData.launchKnockback = 3.0f;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC NBT ====================
|
||||
|
||||
@Override
|
||||
protected void writeBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
panelData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readBarrierTypeNBT(NBTTagCompound nbt) {
|
||||
panelData.readNBT(nbt);
|
||||
}
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public EnergyPanelData getPanelData() { return panelData; }
|
||||
|
||||
public float getPanelWidth() { return panelData.panelWidth; }
|
||||
public void setPanelWidth(float width) { panelData.setPanelWidth(width); }
|
||||
|
||||
public float getPanelHeight() { return panelData.panelHeight; }
|
||||
public void setPanelHeight(float height) { panelData.setPanelHeight(height); }
|
||||
|
||||
public float getHeightOffset() { return panelData.heightOffset; }
|
||||
public void setHeightOffset(float offset) { panelData.heightOffset = offset; }
|
||||
|
||||
public boolean isLaunching() { return panelData.launching; }
|
||||
public void setLaunching(boolean launching) { panelData.launching = launching; }
|
||||
|
||||
public float getLaunchSpeed() { return panelData.launchSpeed; }
|
||||
public void setLaunchSpeed(float speed) { panelData.setLaunchSpeed(speed); }
|
||||
|
||||
public float getLaunchDamage() { return panelData.launchDamage; }
|
||||
public void setLaunchDamage(float damage) { panelData.setLaunchDamage(damage); }
|
||||
|
||||
public float getLaunchKnockback() { return panelData.launchKnockback; }
|
||||
public void setLaunchKnockback(float kb) { panelData.setLaunchKnockback(kb); }
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
protected void addBarrierTypeDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.section("ability.section.panel"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("gui.width", this::getPanelWidth, this::setPanelWidth).range(0.5f, 20.0f),
|
||||
FieldDef.floatField("gui.height", this::getPanelHeight, this::setPanelHeight).range(0.5f, 20.0f)
|
||||
));
|
||||
defs.add(FieldDef.floatField("ability.heightOffset", this::getHeightOffset, this::setHeightOffset)
|
||||
.min(Float.NEGATIVE_INFINITY));
|
||||
defs.add(FieldDef.section("ability.section.launch"));
|
||||
defs.add(FieldDef.boolField("gui.enabled", this::isLaunching, this::setLaunching)
|
||||
.hover("ability.hover.launching"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("stats.speed", this::getLaunchSpeed, this::setLaunchSpeed)
|
||||
.visibleWhen(this::isLaunching),
|
||||
FieldDef.floatField("enchantment.damage", this::getLaunchDamage, this::setLaunchDamage)
|
||||
.visibleWhen(this::isLaunching)
|
||||
));
|
||||
defs.add(FieldDef.floatField("ability.knockback", this::getLaunchKnockback, this::setLaunchKnockback)
|
||||
.visibleWhen(this::isLaunching));
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import java.util.List;
|
||||
*
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
|
||||
// Beam shape properties
|
||||
private float beamWidth = 0.3f;
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.List;
|
||||
*
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityDisc extends EntityAbilityProjectile {
|
||||
public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
|
||||
// Disc-specific movement propertie
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
||||
*
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityLaser extends EntityAbilityProjectile {
|
||||
public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
|
||||
// Laser-specific properties
|
||||
private float laserWidth = 0.2f;
|
||||
|
||||
@@ -15,11 +15,11 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Orb projectile - spherical homing energy ball.
|
||||
* Extends EntityAbilityProjectile for shared functionality.
|
||||
* Extends EntityEnergyAbility for shared functionality.
|
||||
*
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityOrb extends EntityAbilityProjectile {
|
||||
public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
|
||||
public EntityAbilityOrb(World world) {
|
||||
super(world);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
@@ -24,19 +22,16 @@ import java.util.Set;
|
||||
* Sweeper ability entity - a rotating beam attached to the NPC.
|
||||
* Unlike other projectiles, this handles its own damage logic since it's
|
||||
* attached to and rotates around the caster.
|
||||
* Extends EntityEnergyAbility for shared visual/owner/charging state.
|
||||
*
|
||||
* Design: Similar to Beam trail visuals but rotating around origin.
|
||||
*/
|
||||
public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpawnData {
|
||||
public class EntityAbilitySweeper extends EntityEnergyAbility {
|
||||
|
||||
// Beam properties
|
||||
private float beamLength = 10.0f;
|
||||
private float beamWidth = 0.3f; // Thin like beam trail
|
||||
private float beamHeight = 0.8f;
|
||||
private int innerColor = 0xFF6600;
|
||||
private int outerColor = 0xFF0000;
|
||||
private boolean outerColorEnabled = true;
|
||||
private float outerColorWidth = 1.8f;
|
||||
|
||||
// Combat properties
|
||||
private float damage = 5.0f;
|
||||
@@ -52,18 +47,13 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
private float baseYaw = 0; // Starting yaw direction
|
||||
private boolean lockOnTarget = false;
|
||||
|
||||
// Owner tracking
|
||||
private int ownerEntityId = -1;
|
||||
// Target tracking
|
||||
private int targetEntityId = -1;
|
||||
|
||||
// Lifetime
|
||||
private int maxTicks = 400;
|
||||
private long deathWorldTime = -1;
|
||||
|
||||
// Preview mode
|
||||
private boolean previewMode = false;
|
||||
private EntityLivingBase previewOwner = null;
|
||||
|
||||
// Damage state
|
||||
private transient int ticksSinceDamage = 0;
|
||||
private transient Set<Integer> hitThisTick = new HashSet<>();
|
||||
@@ -72,8 +62,6 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
super(world);
|
||||
this.setSize(0.1f, 0.1f);
|
||||
this.noClip = true;
|
||||
this.isImmuneToFire = true;
|
||||
this.ignoreFrustumCheck = true;
|
||||
}
|
||||
|
||||
public EntityAbilitySweeper(World world, EntityLivingBase owner, EntityLivingBase target,
|
||||
@@ -89,10 +77,7 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
this.beamLength = beamLength;
|
||||
this.beamWidth = beamWidth;
|
||||
this.beamHeight = beamHeight;
|
||||
this.innerColor = displayData.innerColor;
|
||||
this.outerColor = displayData.outerColor;
|
||||
this.outerColorEnabled = displayData.outerColorEnabled;
|
||||
this.outerColorWidth = displayData.outerColorWidth;
|
||||
this.displayData = displayData;
|
||||
this.sweepSpeed = sweepSpeed;
|
||||
this.numberOfRotations = numberOfRotations;
|
||||
this.damage = damage;
|
||||
@@ -121,7 +106,7 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
// No DataWatcher needed
|
||||
super.entityInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,7 +129,7 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
return;
|
||||
}
|
||||
|
||||
Entity owner = getOwner();
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner != null && owner.isDead) {
|
||||
this.setDead();
|
||||
return;
|
||||
@@ -297,12 +282,6 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
this.previewOwner = owner;
|
||||
}
|
||||
|
||||
private Entity getOwner() {
|
||||
if (previewMode && previewOwner != null) return previewOwner;
|
||||
if (ownerEntityId == -1) return null;
|
||||
return worldObj.getEntityByID(ownerEntityId);
|
||||
}
|
||||
|
||||
// ==================== RENDERING ====================
|
||||
|
||||
@Override
|
||||
@@ -311,22 +290,6 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
return distance < 16384.0D; // 128 blocks squared
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
return pass == 1; // Translucent pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBrightness(float partialTicks) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getBrightnessForRender(float partialTicks) {
|
||||
return 0xF000F0;
|
||||
}
|
||||
|
||||
// ==================== GETTERS FOR RENDERER ====================
|
||||
|
||||
public float getBeamLength() {
|
||||
@@ -341,22 +304,6 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
return beamHeight;
|
||||
}
|
||||
|
||||
public int getInnerColor() {
|
||||
return innerColor;
|
||||
}
|
||||
|
||||
public int getOuterColor() {
|
||||
return outerColor;
|
||||
}
|
||||
|
||||
public boolean isOuterColorEnabled() {
|
||||
return outerColorEnabled;
|
||||
}
|
||||
|
||||
public float getOuterColorWidth() {
|
||||
return outerColorWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full interpolated angle INCLUDING base yaw for rendering.
|
||||
*/
|
||||
@@ -382,18 +329,14 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound nbt) {
|
||||
readEnergyBaseNBT(nbt);
|
||||
this.beamLength = nbt.getFloat("BeamLength");
|
||||
this.beamWidth = nbt.getFloat("BeamWidth");
|
||||
this.beamHeight = nbt.getFloat("BeamHeight");
|
||||
this.innerColor = nbt.getInteger("InnerColor");
|
||||
this.outerColor = nbt.getInteger("OuterColor");
|
||||
this.outerColorEnabled = !nbt.hasKey("OuterColorEnabled") || nbt.getBoolean("OuterColorEnabled");
|
||||
this.outerColorWidth = nbt.hasKey("OuterColorWidth") ? nbt.getFloat("OuterColorWidth") : 1.8f;
|
||||
this.sweepSpeed = nbt.getFloat("SweepSpeed");
|
||||
this.numberOfRotations = nbt.getInteger("NumRotations");
|
||||
this.completedRotations = nbt.getInteger("CompletedRotations");
|
||||
this.maxTicks = nbt.getInteger("MaxTicks");
|
||||
this.ownerEntityId = nbt.getInteger("OwnerId");
|
||||
this.targetEntityId = nbt.getInteger("TargetId");
|
||||
this.currentAngle = nbt.getFloat("CurrentAngle");
|
||||
this.baseYaw = nbt.getFloat("BaseYaw");
|
||||
@@ -406,18 +349,14 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound nbt) {
|
||||
writeEnergyBaseNBT(nbt);
|
||||
nbt.setFloat("BeamLength", beamLength);
|
||||
nbt.setFloat("BeamWidth", beamWidth);
|
||||
nbt.setFloat("BeamHeight", beamHeight);
|
||||
nbt.setInteger("InnerColor", innerColor);
|
||||
nbt.setInteger("OuterColor", outerColor);
|
||||
nbt.setBoolean("OuterColorEnabled", outerColorEnabled);
|
||||
nbt.setFloat("OuterColorWidth", outerColorWidth);
|
||||
nbt.setFloat("SweepSpeed", sweepSpeed);
|
||||
nbt.setInteger("NumRotations", numberOfRotations);
|
||||
nbt.setInteger("CompletedRotations", completedRotations);
|
||||
nbt.setInteger("MaxTicks", maxTicks);
|
||||
nbt.setInteger("OwnerId", ownerEntityId);
|
||||
nbt.setInteger("TargetId", targetEntityId);
|
||||
nbt.setFloat("CurrentAngle", currentAngle);
|
||||
nbt.setFloat("BaseYaw", baseYaw);
|
||||
@@ -427,53 +366,4 @@ public class EntityAbilitySweeper extends Entity implements IEntityAdditionalSpa
|
||||
nbt.setBoolean("Piercing", piercing);
|
||||
nbt.setBoolean("LockOnTarget", lockOnTarget);
|
||||
}
|
||||
|
||||
// ==================== SPAWN DATA ====================
|
||||
|
||||
@Override
|
||||
public void writeSpawnData(ByteBuf buffer) {
|
||||
buffer.writeFloat(beamLength);
|
||||
buffer.writeFloat(beamWidth);
|
||||
buffer.writeFloat(beamHeight);
|
||||
buffer.writeInt(innerColor);
|
||||
buffer.writeInt(outerColor);
|
||||
buffer.writeBoolean(outerColorEnabled);
|
||||
buffer.writeFloat(outerColorWidth);
|
||||
buffer.writeFloat(sweepSpeed);
|
||||
buffer.writeInt(numberOfRotations);
|
||||
buffer.writeInt(completedRotations);
|
||||
buffer.writeInt(maxTicks);
|
||||
buffer.writeInt(ownerEntityId);
|
||||
buffer.writeInt(targetEntityId);
|
||||
buffer.writeFloat(currentAngle);
|
||||
buffer.writeFloat(baseYaw);
|
||||
buffer.writeFloat(damage);
|
||||
buffer.writeInt(damageInterval);
|
||||
buffer.writeBoolean(piercing);
|
||||
buffer.writeBoolean(lockOnTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSpawnData(ByteBuf buffer) {
|
||||
this.beamLength = buffer.readFloat();
|
||||
this.beamWidth = buffer.readFloat();
|
||||
this.beamHeight = buffer.readFloat();
|
||||
this.innerColor = buffer.readInt();
|
||||
this.outerColor = buffer.readInt();
|
||||
this.outerColorEnabled = buffer.readBoolean();
|
||||
this.outerColorWidth = buffer.readFloat();
|
||||
this.sweepSpeed = buffer.readFloat();
|
||||
this.numberOfRotations = buffer.readInt();
|
||||
this.completedRotations = buffer.readInt();
|
||||
this.maxTicks = buffer.readInt();
|
||||
this.ownerEntityId = buffer.readInt();
|
||||
this.targetEntityId = buffer.readInt();
|
||||
this.currentAngle = buffer.readFloat();
|
||||
this.baseYaw = buffer.readFloat();
|
||||
this.damage = buffer.readFloat();
|
||||
this.damageInterval = buffer.readInt();
|
||||
this.piercing = buffer.readBoolean();
|
||||
this.lockOnTarget = buffer.readBoolean();
|
||||
this.prevAngle = this.currentAngle;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -121,7 +121,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
private boolean particleGlow = true;
|
||||
|
||||
private long deathWorldTime = -1;
|
||||
private List<AbilityEffect> effects = new ArrayList<>();
|
||||
private List<AbilityPotionEffect> effects = new ArrayList<>();
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// TRAP-SPECIFIC PROPERTIES
|
||||
@@ -194,7 +194,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
boolean visible,
|
||||
List<AbilityEffect> effects) {
|
||||
List<AbilityPotionEffect> effects) {
|
||||
EntityAbilityZone zone = new EntityAbilityZone(world, ZoneType.TRAP, owner, x, y, z);
|
||||
zone.shape = shape;
|
||||
zone.radius = triggerRadius;
|
||||
@@ -217,7 +217,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
zone.lightningDensity = lightningDensity;
|
||||
zone.visible = visible;
|
||||
if (effects != null) {
|
||||
for (AbilityEffect e : effects) {
|
||||
for (AbilityPotionEffect e : effects) {
|
||||
zone.effects.add(e.copy());
|
||||
}
|
||||
}
|
||||
@@ -236,7 +236,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
float zoneHeight,
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
List<AbilityEffect> effects) {
|
||||
List<AbilityPotionEffect> effects) {
|
||||
EntityAbilityZone zone = new EntityAbilityZone(world, ZoneType.HAZARD, owner, x, y, z);
|
||||
zone.shape = shape;
|
||||
zone.radius = radius;
|
||||
@@ -255,7 +255,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
zone.animSpeed = animSpeed;
|
||||
zone.lightningDensity = lightningDensity;
|
||||
if (effects != null) {
|
||||
for (AbilityEffect e : effects) {
|
||||
for (AbilityPotionEffect e : effects) {
|
||||
zone.effects.add(e.copy());
|
||||
}
|
||||
}
|
||||
@@ -499,7 +499,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
|
||||
private void applyEffects(EntityLivingBase entity) {
|
||||
if (entity == null || effects.isEmpty()) return;
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effect.apply(entity);
|
||||
}
|
||||
}
|
||||
@@ -668,7 +668,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
if (nbt.hasKey("Effects")) {
|
||||
NBTTagList effectList = nbt.getTagList("Effects", 10);
|
||||
for (int i = 0; i < effectList.tagCount(); i++) {
|
||||
AbilityEffect effect = AbilityEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
AbilityPotionEffect effect = AbilityPotionEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
if (effect != null && effect.isValid()) {
|
||||
effects.add(effect);
|
||||
}
|
||||
@@ -728,7 +728,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
|
||||
// Effects
|
||||
NBTTagList effectList = new NBTTagList();
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effectList.appendTag(effect.writeNBT());
|
||||
}
|
||||
nbt.setTag("Effects", effectList);
|
||||
@@ -778,7 +778,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
// Effects
|
||||
NBTTagCompound effectsNbt = new NBTTagCompound();
|
||||
NBTTagList effectList = new NBTTagList();
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effectList.appendTag(effect.writeNBT());
|
||||
}
|
||||
effectsNbt.setTag("Effects", effectList);
|
||||
@@ -832,7 +832,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
if (effectsNbt != null && effectsNbt.hasKey("Effects")) {
|
||||
NBTTagList effectList = effectsNbt.getTagList("Effects", 10);
|
||||
for (int i = 0; i < effectList.tagCount(); i++) {
|
||||
AbilityEffect effect = AbilityEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
AbilityPotionEffect effect = AbilityPotionEffect.fromNBT(effectList.getCompoundTagAt(i));
|
||||
if (effect != null && effect.isValid()) {
|
||||
effects.add(effect);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Universal base class for all energy ability entities (Projectiles, Barriers, Sweeper).
|
||||
* Provides shared visual data, owner tracking, charging state, and common entity properties.
|
||||
*/
|
||||
public abstract class EntityEnergyAbility extends Entity implements IEntityAdditionalSpawnData {
|
||||
|
||||
// ==================== VISUAL PROPERTIES ====================
|
||||
protected EnergyDisplayData displayData = new EnergyDisplayData();
|
||||
protected EnergyLightningData lightningData = new EnergyLightningData();
|
||||
|
||||
// Client-side lightning state (not saved to NBT)
|
||||
@SideOnly(Side.CLIENT)
|
||||
public transient Object lightningState; // Actually AttachedLightningRenderer.LightningState
|
||||
|
||||
// ==================== TRACKING ====================
|
||||
protected int ownerEntityId = -1;
|
||||
|
||||
// ==================== STATE ====================
|
||||
/** The ability that spawned this entity. Transient, not saved to NBT. */
|
||||
protected transient Ability sourceAbility = null;
|
||||
protected boolean previewMode = false;
|
||||
protected EntityLivingBase previewOwner = null;
|
||||
|
||||
// ==================== CHARGING STATE ====================
|
||||
protected boolean charging = false;
|
||||
protected int chargeDuration = 0;
|
||||
protected int chargeTick = 0;
|
||||
protected static final int DW_CHARGING = 20;
|
||||
|
||||
public EntityEnergyAbility(World world) {
|
||||
super(world);
|
||||
this.isImmuneToFire = true;
|
||||
this.ignoreFrustumCheck = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
this.dataWatcher.addObject(DW_CHARGING, (byte) 0);
|
||||
}
|
||||
|
||||
// ==================== CHARGING ====================
|
||||
|
||||
/**
|
||||
* Check if entity is in charging state (synced via data watcher).
|
||||
* In preview mode, uses local field since data watcher isn't synced.
|
||||
*/
|
||||
public boolean isCharging() {
|
||||
if (previewMode) return this.charging;
|
||||
return this.dataWatcher.getWatchableObjectByte(DW_CHARGING) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set charging state (server only, synced to clients via data watcher).
|
||||
*/
|
||||
protected void setCharging(boolean value) {
|
||||
this.charging = value;
|
||||
if (!worldObj.isRemote) {
|
||||
this.dataWatcher.updateObject(DW_CHARGING, (byte) (value ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
public float getChargeProgress() {
|
||||
if (chargeDuration <= 0) return 1.0f;
|
||||
return Math.min(1.0f, (float) chargeTick / chargeDuration);
|
||||
}
|
||||
|
||||
public float getInterpolatedChargeProgress(float partialTicks) {
|
||||
if (chargeDuration <= 0) return 1.0f;
|
||||
float prevProgress = Math.max(0, (float) (chargeTick - 1) / chargeDuration);
|
||||
float currProgress = Math.min(1.0f, (float) chargeTick / chargeDuration);
|
||||
return prevProgress + (currProgress - prevProgress) * partialTicks;
|
||||
}
|
||||
|
||||
// ==================== OWNER ====================
|
||||
|
||||
/**
|
||||
* Get the owner entity. In preview mode, returns the preview owner directly.
|
||||
*/
|
||||
public Entity getOwnerEntity() {
|
||||
if (previewMode && previewOwner != null) {
|
||||
return previewOwner;
|
||||
}
|
||||
if (ownerEntityId == -1) return null;
|
||||
return worldObj.getEntityByID(ownerEntityId);
|
||||
}
|
||||
|
||||
public int getOwnerEntityId() { return ownerEntityId; }
|
||||
public void setOwnerEntityId(int id) { this.ownerEntityId = id; }
|
||||
|
||||
// ==================== SOURCE ABILITY ====================
|
||||
|
||||
public Ability getSourceAbility() { return sourceAbility; }
|
||||
public void setSourceAbility(Ability ability) { this.sourceAbility = ability; }
|
||||
|
||||
// ==================== PREVIEW MODE ====================
|
||||
|
||||
public boolean isPreviewMode() { return previewMode; }
|
||||
public void setPreviewMode(boolean preview) { this.previewMode = preview; }
|
||||
public void setPreviewOwner(EntityLivingBase owner) { this.previewOwner = owner; }
|
||||
|
||||
// ==================== DISPLAY GETTERS & SETTERS ====================
|
||||
|
||||
public EnergyDisplayData getDisplayData() { return displayData; }
|
||||
public EnergyLightningData getLightningData() { return lightningData; }
|
||||
|
||||
public int getInnerColor() { return displayData.getInnerColor(); }
|
||||
public void setInnerColor(int color) { displayData.setInnerColor(color); }
|
||||
|
||||
public float getInnerAlpha() { return displayData.getInnerAlpha(); }
|
||||
public void setInnerAlpha(float alpha) { displayData.setInnerAlpha(alpha); }
|
||||
|
||||
public int getOuterColor() { return displayData.getOuterColor(); }
|
||||
public void setOuterColor(int color) { displayData.setOuterColor(color); }
|
||||
|
||||
public boolean isOuterColorEnabled() { return displayData.isOuterColorEnabled(); }
|
||||
public void setOuterColorEnabled(boolean enabled) { displayData.setOuterColorEnabled(enabled); }
|
||||
|
||||
public float getOuterColorWidth() { return displayData.getOuterColorWidth(); }
|
||||
public void setOuterColorWidth(float width) { displayData.setOuterColorWidth(width); }
|
||||
|
||||
public float getOuterColorAlpha() { return displayData.getOuterColorAlpha(); }
|
||||
public void setOuterColorAlpha(float alpha) { displayData.setOuterColorAlpha(alpha); }
|
||||
|
||||
public float getRotationSpeed() { return displayData.getRotationSpeed(); }
|
||||
public void setRotationSpeed(float speed) { displayData.setRotationSpeed(speed); }
|
||||
|
||||
// ==================== LIGHTNING GETTERS & SETTERS ====================
|
||||
|
||||
public boolean hasLightningEffect() { return lightningData.isLightningEffect(); }
|
||||
public void setLightningEffect(boolean enabled) { lightningData.setLightningEffect(enabled); }
|
||||
|
||||
public float getLightningDensity() { return lightningData.getLightningDensity(); }
|
||||
public void setLightningDensity(float density) { lightningData.setLightningDensity(density); }
|
||||
|
||||
public float getLightningRadius() { return lightningData.getLightningRadius(); }
|
||||
public void setLightningRadius(float radius) { lightningData.setLightningRadius(radius); }
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.getLightningFadeTime(); }
|
||||
public void setLightningFadeTime(int ticks) { lightningData.setLightningFadeTime(ticks); }
|
||||
|
||||
// ==================== BRIGHTNESS ====================
|
||||
|
||||
@Override
|
||||
public float getBrightness(float partialTicks) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getBrightnessForRender(float partialTicks) {
|
||||
return 0xF000F0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
return pass == 1; // Translucent pass
|
||||
}
|
||||
|
||||
// ==================== COLLISION SETTINGS ====================
|
||||
|
||||
@Override
|
||||
public boolean canBePushed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canTriggerWalking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getShadowSize() {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// ==================== NBT HELPERS ====================
|
||||
|
||||
/**
|
||||
* Write shared energy base fields to NBT (owner, display, lightning).
|
||||
* Call from subclass NBT writers before writing type-specific fields.
|
||||
*/
|
||||
protected void writeEnergyBaseNBT(NBTTagCompound nbt) {
|
||||
nbt.setInteger("OwnerId", ownerEntityId);
|
||||
displayData.writeNBT(nbt);
|
||||
lightningData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read shared energy base fields from NBT (owner, display, lightning).
|
||||
* Call from subclass NBT readers before reading type-specific fields.
|
||||
*/
|
||||
protected void readEnergyBaseNBT(NBTTagCompound nbt) {
|
||||
this.ownerEntityId = nbt.getInteger("OwnerId");
|
||||
displayData.readNBT(nbt);
|
||||
lightningData.readNBT(nbt);
|
||||
}
|
||||
|
||||
// ==================== SPAWN DATA ====================
|
||||
|
||||
@Override
|
||||
public void writeSpawnData(ByteBuf buffer) {
|
||||
try {
|
||||
NBTTagCompound compound = new NBTTagCompound();
|
||||
this.writeEntityToNBT(compound);
|
||||
cpw.mods.fml.common.network.ByteBufUtils.writeTag(buffer, compound);
|
||||
} catch (Exception e) {
|
||||
noppes.npcs.LogWriter.error("Error writing energy ability spawn data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSpawnData(ByteBuf buffer) {
|
||||
try {
|
||||
NBTTagCompound compound = cpw.mods.fml.common.network.ByteBufUtils.readTag(buffer);
|
||||
if (compound != null) {
|
||||
this.readEntityFromNBT(compound);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
noppes.npcs.LogWriter.error("Error reading energy ability spawn data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
/**
|
||||
* Base class for energy barrier entities (Dome, Panel).
|
||||
* Provides shared health, damage, hit flash, knockback target,
|
||||
* and barrier lifecycle management.
|
||||
* Extends EntityEnergyAbility for shared visual/owner/charging state.
|
||||
*/
|
||||
public abstract class EntityEnergyBarrier extends EntityEnergyAbility {
|
||||
|
||||
// ==================== BARRIER PROPERTIES ====================
|
||||
protected EnergyBarrierData barrierData = new EnergyBarrierData();
|
||||
protected float currentHealth;
|
||||
protected int ticksAlive = 0;
|
||||
|
||||
// ==================== DATA WATCHER INDICES ====================
|
||||
protected static final int DW_HEALTH_PERCENT = 21;
|
||||
protected static final int DW_HIT_FLASH = 22;
|
||||
|
||||
public EntityEnergyBarrier(World world) {
|
||||
super(world);
|
||||
this.noClip = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
super.entityInit(); // DW_CHARGING = 20
|
||||
this.dataWatcher.addObject(DW_HEALTH_PERCENT, 1.0f);
|
||||
this.dataWatcher.addObject(DW_HIT_FLASH, (byte) 0);
|
||||
}
|
||||
|
||||
// ==================== ABSTRACT METHODS ====================
|
||||
|
||||
/**
|
||||
* Check if a projectile is incoming toward this barrier.
|
||||
* Dome uses spherical check, Panel uses planar check.
|
||||
*/
|
||||
public abstract boolean isIncomingProjectile(EntityEnergyProjectile projectile);
|
||||
|
||||
/**
|
||||
* Setup charging state. Called during windup phase.
|
||||
*/
|
||||
public abstract void setupCharging(int duration);
|
||||
|
||||
/**
|
||||
* Finish charging — snap to full size and become active.
|
||||
*/
|
||||
public abstract void finishCharging();
|
||||
|
||||
/**
|
||||
* Push entities away from the barrier surface.
|
||||
*/
|
||||
protected abstract void knockbackEntities();
|
||||
|
||||
// ==================== PROJECTILE HIT ====================
|
||||
|
||||
/**
|
||||
* Apply damage to this barrier from a projectile.
|
||||
* Returns true if the barrier absorbed the hit (projectile should be destroyed).
|
||||
*/
|
||||
public boolean onProjectileHit(EntityEnergyProjectile projectile, float baseDamage) {
|
||||
// Get damage multiplier for this projectile type
|
||||
String typeId = "";
|
||||
if (projectile.getSourceAbility() != null) {
|
||||
typeId = projectile.getSourceAbility().getTypeId();
|
||||
}
|
||||
float multiplier = barrierData.getMultiplier(typeId);
|
||||
float damage = baseDamage * multiplier;
|
||||
|
||||
// Fire hit event (may cancel or modify damage)
|
||||
if (!worldObj.isRemote) {
|
||||
float eventDamage = EventHooks.onEnergyBarrierHit(this, ownerEntityId, projectile, damage);
|
||||
if (eventDamage < 0) return false; // Event cancelled — don't block
|
||||
damage = eventDamage;
|
||||
}
|
||||
|
||||
triggerHitFlash();
|
||||
|
||||
if (!barrierData.useHealth) {
|
||||
return true; // Duration-only mode: block but don't take damage
|
||||
}
|
||||
|
||||
currentHealth -= damage;
|
||||
syncHealthPercent();
|
||||
|
||||
if (currentHealth <= 0) {
|
||||
onBarrierDestroyed();
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== MELEE DAMAGE ====================
|
||||
|
||||
@Override
|
||||
public boolean canBeCollidedWith() {
|
||||
return barrierData.meleeEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attackEntityFrom(DamageSource source, float amount) {
|
||||
if (worldObj.isRemote || !barrierData.meleeEnabled) return false;
|
||||
if (isCharging()) return false;
|
||||
|
||||
float damage = amount * barrierData.meleeDamageMultiplier;
|
||||
|
||||
// Fire hit event with null projectile (melee hit)
|
||||
float eventDamage = EventHooks.onEnergyBarrierHit(this, ownerEntityId, null, damage);
|
||||
if (eventDamage < 0) return false;
|
||||
damage = eventDamage;
|
||||
|
||||
triggerHitFlash();
|
||||
|
||||
if (!barrierData.useHealth) return true;
|
||||
|
||||
currentHealth -= damage;
|
||||
syncHealthPercent();
|
||||
|
||||
if (currentHealth <= 0) {
|
||||
onBarrierDestroyed();
|
||||
this.setDead();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== SHARED UPDATE LOGIC ====================
|
||||
|
||||
/**
|
||||
* Shared barrier tick logic for onUpdate(). Handles spawned event, owner death,
|
||||
* duration check, hit flash decay, and tick event.
|
||||
* Call this after incrementing ticksAlive in subclass onUpdate().
|
||||
* @return true if barrier died this tick (caller should return early)
|
||||
*/
|
||||
protected boolean updateBarrierTick() {
|
||||
if (!worldObj.isRemote) {
|
||||
// Fire spawned event on first tick
|
||||
if (ticksAlive == 1) {
|
||||
EventHooks.onEnergyBarrierSpawned(this, ownerEntityId);
|
||||
}
|
||||
|
||||
// Check owner death
|
||||
if (ownerEntityId >= 0 && ticksAlive > 5) {
|
||||
Entity owner = worldObj.getEntityByID(ownerEntityId);
|
||||
if (owner != null) {
|
||||
if (owner.isDead) {
|
||||
onBarrierDestroyed();
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
if (owner instanceof EntityNPCInterface && ((EntityNPCInterface) owner).isKilled()) {
|
||||
onBarrierDestroyed();
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Duration check
|
||||
if (barrierData.useDuration && ticksAlive >= barrierData.durationTicks) {
|
||||
onBarrierDestroyed();
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset hit flash
|
||||
if (getHitFlash() > 0) {
|
||||
setHitFlash((byte) (getHitFlash() - 1));
|
||||
}
|
||||
|
||||
// Fire tick event
|
||||
EventHooks.onEnergyBarrierTick(this, ownerEntityId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ==================== HELPERS ====================
|
||||
|
||||
protected void onBarrierDestroyed() {
|
||||
EventHooks.onEnergyBarrierDestroyed(this, ownerEntityId);
|
||||
}
|
||||
|
||||
protected void syncHealthPercent() {
|
||||
float percent = barrierData.useHealth && barrierData.maxHealth > 0
|
||||
? Math.max(0, currentHealth / barrierData.maxHealth)
|
||||
: 1.0f;
|
||||
if (!worldObj.isRemote) {
|
||||
this.dataWatcher.updateObject(DW_HEALTH_PERCENT, percent);
|
||||
}
|
||||
}
|
||||
|
||||
protected void triggerHitFlash() {
|
||||
if (!worldObj.isRemote) {
|
||||
setHitFlash((byte) 4);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setHitFlash(byte value) {
|
||||
this.dataWatcher.updateObject(DW_HIT_FLASH, value);
|
||||
}
|
||||
|
||||
public byte getHitFlash() {
|
||||
return this.dataWatcher.getWatchableObjectByte(DW_HIT_FLASH);
|
||||
}
|
||||
|
||||
public float getHealthPercent() {
|
||||
return this.dataWatcher.getWatchableObjectFloat(DW_HEALTH_PERCENT);
|
||||
}
|
||||
|
||||
protected boolean isKnockbackTarget(EntityLivingBase entity) {
|
||||
switch (barrierData.knockbackTarget) {
|
||||
case 1: return entity instanceof EntityPlayer;
|
||||
case 2: return entity instanceof EntityNPCInterface;
|
||||
default: return entity instanceof EntityPlayer || entity instanceof EntityNPCInterface;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public EnergyBarrierData getBarrierData() { return barrierData; }
|
||||
public float getCurrentHealth() { return currentHealth; }
|
||||
public void setCurrentHealth(float health) { this.currentHealth = health; syncHealthPercent(); }
|
||||
public int getTicksAlive() { return ticksAlive; }
|
||||
|
||||
// ==================== NBT HELPERS ====================
|
||||
|
||||
/**
|
||||
* Write shared barrier base fields to NBT.
|
||||
* Call from subclass writeEntityToNBT() before writing type-specific fields.
|
||||
*/
|
||||
protected void writeBarrierBaseNBT(NBTTagCompound nbt) {
|
||||
writeEnergyBaseNBT(nbt);
|
||||
nbt.setInteger("TicksAlive", ticksAlive);
|
||||
nbt.setFloat("CurrentHealth", currentHealth);
|
||||
nbt.setBoolean("Charging", charging);
|
||||
nbt.setInteger("ChargeTick", chargeTick);
|
||||
nbt.setInteger("ChargeDuration", chargeDuration);
|
||||
barrierData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read shared barrier base fields from NBT.
|
||||
* Call from subclass readEntityFromNBT() before reading type-specific fields.
|
||||
*/
|
||||
protected void readBarrierBaseNBT(NBTTagCompound nbt) {
|
||||
readEnergyBaseNBT(nbt);
|
||||
this.ticksAlive = nbt.getInteger("TicksAlive");
|
||||
this.currentHealth = nbt.getFloat("CurrentHealth");
|
||||
this.charging = nbt.hasKey("Charging") && nbt.getBoolean("Charging");
|
||||
this.chargeTick = nbt.getInteger("ChargeTick");
|
||||
this.chargeDuration = nbt.getInteger("ChargeDuration");
|
||||
this.dataWatcher.updateObject(DW_CHARGING, (byte) (charging ? 1 : 0));
|
||||
barrierData.readNBT(nbt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Dome entity - a spherical barrier that blocks incoming energy projectiles.
|
||||
* Centered on the caster's position at time of casting.
|
||||
* Only blocks incoming attacks (not outgoing from allies inside).
|
||||
* Extends EntityEnergyBarrier for shared barrier logic.
|
||||
*/
|
||||
public class EntityEnergyDome extends EntityEnergyBarrier {
|
||||
|
||||
// ==================== DOME-SPECIFIC PROPERTIES ====================
|
||||
protected float domeRadius = 5.0f;
|
||||
protected float targetDomeRadius = 5.0f;
|
||||
protected boolean followCaster = false;
|
||||
|
||||
public EntityEnergyDome(World world) {
|
||||
super(world);
|
||||
this.setSize(1.0f, 1.0f); // Hitbox doesn't really matter, we use radius checks
|
||||
}
|
||||
|
||||
public EntityEnergyDome(World world, EntityLivingBase owner, double x, double y, double z,
|
||||
float domeRadius, EnergyDisplayData display, EnergyLightningData lightning,
|
||||
EnergyBarrierData barrier) {
|
||||
this(world);
|
||||
this.setPosition(x, y, z);
|
||||
this.ownerEntityId = owner.getEntityId();
|
||||
this.domeRadius = domeRadius;
|
||||
this.displayData = display;
|
||||
this.lightningData = lightning;
|
||||
this.barrierData = barrier;
|
||||
this.currentHealth = barrier.maxHealth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// Follow caster: both sides for smooth interpolated rendering
|
||||
if (followCaster) {
|
||||
Entity owner = ownerEntityId >= 0 ? worldObj.getEntityByID(ownerEntityId) : null;
|
||||
if (owner != null) {
|
||||
this.setPosition(owner.posX, owner.posY, owner.posZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle charging animation (both sides for smooth rendering)
|
||||
if (isCharging()) {
|
||||
chargeTick++;
|
||||
float progress = getChargeProgress();
|
||||
this.domeRadius = targetDomeRadius * progress;
|
||||
return; // Don't tick duration/death during charging
|
||||
}
|
||||
|
||||
ticksAlive++;
|
||||
|
||||
if (updateBarrierTick()) return;
|
||||
|
||||
// Knockback entities inside the dome
|
||||
if (!worldObj.isRemote && barrierData.knockbackEnabled) {
|
||||
knockbackEntities();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== INCOMING CHECK ====================
|
||||
|
||||
/**
|
||||
* Check if a projectile at the given position is entering this dome from outside.
|
||||
* Only blocks incoming projectiles (dot product check).
|
||||
*/
|
||||
@Override
|
||||
public boolean isIncomingProjectile(EntityEnergyProjectile projectile) {
|
||||
// Don't block during charging phase
|
||||
if (isCharging()) return false;
|
||||
// Don't block projectiles from the dome's owner
|
||||
if (projectile.getOwnerEntityId() == this.ownerEntityId) return false;
|
||||
|
||||
// Don't block projectiles from same-faction NPCs
|
||||
Entity owner = getOwnerEntity();
|
||||
Entity projOwner = projectile.getOwnerEntity();
|
||||
if (owner instanceof noppes.npcs.entity.EntityNPCInterface && projOwner instanceof noppes.npcs.entity.EntityNPCInterface) {
|
||||
if (((noppes.npcs.entity.EntityNPCInterface) owner).faction.id == ((noppes.npcs.entity.EntityNPCInterface) projOwner).faction.id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
double dx = projectile.posX - this.posX;
|
||||
double dy = projectile.posY - this.posY;
|
||||
double dz = projectile.posZ - this.posZ;
|
||||
double distSq = dx * dx + dy * dy + dz * dz;
|
||||
|
||||
// Check if projectile is within dome radius
|
||||
if (distSq > domeRadius * domeRadius) return false;
|
||||
|
||||
// Check if projectile is moving inward (dot product of velocity and position relative to center)
|
||||
double dot = dx * projectile.motionX + dy * projectile.motionY + dz * projectile.motionZ;
|
||||
// Negative dot = moving toward center = incoming
|
||||
return dot < 0;
|
||||
}
|
||||
|
||||
// ==================== CHARGING ====================
|
||||
|
||||
@Override
|
||||
public void setupCharging(int duration) {
|
||||
this.targetDomeRadius = this.domeRadius;
|
||||
this.domeRadius = 0.01f;
|
||||
this.chargeDuration = duration;
|
||||
this.chargeTick = 0;
|
||||
setCharging(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishCharging() {
|
||||
this.domeRadius = targetDomeRadius;
|
||||
setCharging(false);
|
||||
}
|
||||
|
||||
// ==================== KNOCKBACK ====================
|
||||
|
||||
/**
|
||||
* Push entities away from the dome surface.
|
||||
* Entities outside are pushed outward, entities inside are pushed inward (containment).
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void knockbackEntities() {
|
||||
float margin = 1.0f;
|
||||
AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox(
|
||||
posX - domeRadius - margin, posY - domeRadius - margin, posZ - domeRadius - margin,
|
||||
posX + domeRadius + margin, posY + domeRadius + margin, posZ + domeRadius + margin
|
||||
);
|
||||
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, searchBox);
|
||||
for (EntityLivingBase ent : entities) {
|
||||
if (ent.getEntityId() == ownerEntityId) continue;
|
||||
if (!isKnockbackTarget(ent)) continue;
|
||||
|
||||
double dx = ent.posX - posX;
|
||||
double dy = (ent.posY + ent.height * 0.5) - posY;
|
||||
double dz = ent.posZ - posZ;
|
||||
double dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
if (dist < 0.01) continue;
|
||||
|
||||
// Only affect entities near the dome surface
|
||||
if (dist < domeRadius + margin && dist > domeRadius - margin) {
|
||||
double pushStrength = barrierData.knockbackStrength * 0.5;
|
||||
double pushDir = dist >= domeRadius ? 1.0 : -1.0; // Outside = outward, Inside = inward
|
||||
ent.addVelocity(
|
||||
(dx / dist) * pushStrength * pushDir,
|
||||
0.05 * pushDir,
|
||||
(dz / dist) * pushStrength * pushDir
|
||||
);
|
||||
ent.velocityChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== BOUNDING BOX ====================
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
if (barrierData.meleeEnabled) {
|
||||
return AxisAlignedBB.getBoundingBox(
|
||||
posX - domeRadius, posY - domeRadius, posZ - domeRadius,
|
||||
posX + domeRadius, posY + domeRadius, posZ + domeRadius
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isInRangeToRenderDist(double distance) {
|
||||
double d = domeRadius * 8.0D;
|
||||
d *= 64.0D;
|
||||
return distance < d * d;
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public float getDomeRadius() { return domeRadius; }
|
||||
public void setDomeRadius(float radius) { this.domeRadius = Math.max(0.1f, radius); }
|
||||
public boolean isFollowCaster() { return followCaster; }
|
||||
public void setFollowCaster(boolean follow) { this.followCaster = follow; }
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound nbt) {
|
||||
readBarrierBaseNBT(nbt);
|
||||
this.domeRadius = nbt.getFloat("DomeRadius");
|
||||
this.targetDomeRadius = nbt.hasKey("TargetDomeRadius") ? nbt.getFloat("TargetDomeRadius") : domeRadius;
|
||||
this.followCaster = nbt.hasKey("FollowCaster") && nbt.getBoolean("FollowCaster");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound nbt) {
|
||||
writeBarrierBaseNBT(nbt);
|
||||
nbt.setFloat("DomeRadius", domeRadius);
|
||||
nbt.setFloat("TargetDomeRadius", targetDomeRadius);
|
||||
nbt.setBoolean("FollowCaster", followCaster);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyBarrierData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyPanelData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.NpcDamageSource;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Energy Panel entity - a flat rectangular barrier used by Wall and Shield abilities.
|
||||
* Supports three modes: PLACED (stationary), HELD (tracks caster), LAUNCHED (moves forward).
|
||||
* Extends EntityEnergyBarrier for shared barrier logic.
|
||||
*/
|
||||
public class EntityEnergyPanel extends EntityEnergyBarrier {
|
||||
|
||||
public enum PanelMode {
|
||||
PLACED, // Stationary wall
|
||||
HELD, // Follows caster, rotates with caster look
|
||||
LAUNCHED // Moves forward, deals damage/knockback on contact
|
||||
}
|
||||
|
||||
// ==================== PANEL-SPECIFIC PROPERTIES ====================
|
||||
protected EnergyPanelData panelData = new EnergyPanelData();
|
||||
protected PanelMode mode = PanelMode.PLACED;
|
||||
protected float panelYaw = 0.0f; // Rotation of the panel face (degrees)
|
||||
|
||||
// ==================== CHARGING (panel-specific targets) ====================
|
||||
protected float targetPanelWidth;
|
||||
protected float targetPanelHeight;
|
||||
|
||||
public EntityEnergyPanel(World world) {
|
||||
super(world);
|
||||
this.setSize(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public EntityEnergyPanel(World world, EntityLivingBase owner, double x, double y, double z,
|
||||
float yaw, PanelMode mode,
|
||||
EnergyDisplayData display, EnergyLightningData lightning,
|
||||
EnergyBarrierData barrier, EnergyPanelData panel) {
|
||||
this(world);
|
||||
this.setPosition(x, y + panel.heightOffset, z);
|
||||
this.ownerEntityId = owner.getEntityId();
|
||||
this.panelYaw = yaw;
|
||||
this.mode = mode;
|
||||
this.displayData = display;
|
||||
this.lightningData = lightning;
|
||||
this.barrierData = barrier;
|
||||
this.panelData = panel;
|
||||
this.currentHealth = barrier.maxHealth;
|
||||
|
||||
// For launched panels, set initial velocity
|
||||
if (mode == PanelMode.LAUNCHED) {
|
||||
float yawRad = (float) Math.toRadians(yaw);
|
||||
this.motionX = -Math.sin(yawRad) * panel.launchSpeed;
|
||||
this.motionY = 0;
|
||||
this.motionZ = Math.cos(yawRad) * panel.launchSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// Handle charging animation (both sides for smooth rendering)
|
||||
if (isCharging()) {
|
||||
chargeTick++;
|
||||
float progress = getChargeProgress();
|
||||
panelData.panelWidth = targetPanelWidth * progress;
|
||||
panelData.panelHeight = targetPanelHeight * progress;
|
||||
|
||||
// During charging, held panels still track owner
|
||||
if (mode == PanelMode.HELD) {
|
||||
updateHeld();
|
||||
}
|
||||
return; // Don't tick duration/death during charging
|
||||
}
|
||||
|
||||
ticksAlive++;
|
||||
|
||||
if (updateBarrierTick()) return;
|
||||
|
||||
// Knockback (not during launched mode)
|
||||
if (!worldObj.isRemote && barrierData.knockbackEnabled && mode != PanelMode.LAUNCHED) {
|
||||
knockbackEntities();
|
||||
}
|
||||
|
||||
// Mode-specific updates
|
||||
switch (mode) {
|
||||
case HELD:
|
||||
updateHeld();
|
||||
break;
|
||||
case LAUNCHED:
|
||||
updateLaunched();
|
||||
break;
|
||||
case PLACED:
|
||||
default:
|
||||
// Stationary, no update needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHeld() {
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner == null) return;
|
||||
|
||||
// Update yaw BEFORE position calc to avoid 1-tick lag
|
||||
this.panelYaw = owner.rotationYaw;
|
||||
|
||||
// Follow owner position
|
||||
float frontDist = 1.5f;
|
||||
float yawRad = (float) Math.toRadians(panelYaw);
|
||||
double newX = owner.posX + (-Math.sin(yawRad) * frontDist);
|
||||
double newY = owner.posY + panelData.heightOffset + (owner.height * 0.5f);
|
||||
double newZ = owner.posZ + (Math.cos(yawRad) * frontDist);
|
||||
|
||||
this.setPosition(newX, newY, newZ);
|
||||
}
|
||||
|
||||
private void updateLaunched() {
|
||||
// Move forward on both sides for smooth client rendering
|
||||
this.posX += motionX;
|
||||
this.posY += motionY;
|
||||
this.posZ += motionZ;
|
||||
this.setPosition(posX, posY, posZ);
|
||||
|
||||
// Damage and knockback are server-only
|
||||
if (!worldObj.isRemote) {
|
||||
// Check entity collision for damage
|
||||
float halfW = panelData.panelWidth * 0.5f;
|
||||
float halfH = panelData.panelHeight * 0.5f;
|
||||
float halfD = 0.5f; // Panel collision depth
|
||||
float searchRadius = Math.max(halfW, halfD);
|
||||
AxisAlignedBB hitBox = AxisAlignedBB.getBoundingBox(
|
||||
posX - searchRadius, posY - halfH, posZ - searchRadius,
|
||||
posX + searchRadius, posY + halfH, posZ + searchRadius
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
|
||||
Entity owner = getOwnerEntity();
|
||||
|
||||
for (EntityLivingBase target : entities) {
|
||||
if (target == owner) continue;
|
||||
if (owner instanceof EntityNPCInterface && target instanceof EntityNPCInterface) {
|
||||
if (((EntityNPCInterface) owner).faction.id == ((EntityNPCInterface) target).faction.id) continue;
|
||||
}
|
||||
|
||||
// Apply damage
|
||||
if (panelData.launchDamage > 0) {
|
||||
if (owner instanceof EntityNPCInterface) {
|
||||
target.attackEntityFrom(new NpcDamageSource("npc_ability", (EntityNPCInterface) owner), panelData.launchDamage);
|
||||
} else if (owner instanceof EntityPlayer) {
|
||||
target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) owner), panelData.launchDamage);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply knockback
|
||||
if (panelData.launchKnockback > 0) {
|
||||
double dx = target.posX - posX;
|
||||
double dz = target.posZ - posZ;
|
||||
double len = Math.sqrt(dx * dx + dz * dz);
|
||||
if (len > 0) {
|
||||
target.addVelocity(
|
||||
(dx / len) * panelData.launchKnockback * 0.5,
|
||||
0.1,
|
||||
(dz / len) * panelData.launchKnockback * 0.5
|
||||
);
|
||||
target.velocityChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Max lifetime check
|
||||
if (ticksAlive > 200) {
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== INCOMING CHECK ====================
|
||||
|
||||
/**
|
||||
* Check if a projectile hits this panel surface.
|
||||
* Only blocks incoming projectiles (not from the panel's owner).
|
||||
*/
|
||||
@Override
|
||||
public boolean isIncomingProjectile(EntityEnergyProjectile projectile) {
|
||||
// Don't block during charging phase
|
||||
if (isCharging()) return false;
|
||||
if (projectile.getOwnerEntityId() == this.ownerEntityId) return false;
|
||||
|
||||
// Faction check
|
||||
Entity owner = getOwnerEntity();
|
||||
Entity projOwner = projectile.getOwnerEntity();
|
||||
if (owner instanceof EntityNPCInterface && projOwner instanceof EntityNPCInterface) {
|
||||
if (((EntityNPCInterface) owner).faction.id == ((EntityNPCInterface) projOwner).faction.id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if projectile is within panel bounds
|
||||
float halfW = panelData.panelWidth * 0.5f;
|
||||
float halfH = panelData.panelHeight * 0.5f;
|
||||
float panelThickness = 0.5f; // Collision thickness
|
||||
|
||||
// Transform projectile position to panel-local space
|
||||
float yawRad = (float) Math.toRadians(panelYaw);
|
||||
double relX = projectile.posX - this.posX;
|
||||
double relY = projectile.posY - this.posY;
|
||||
double relZ = projectile.posZ - this.posZ;
|
||||
|
||||
// Rotate into panel space (panel faces along -sin(yaw), cos(yaw))
|
||||
double cos = Math.cos(yawRad);
|
||||
double sin = Math.sin(yawRad);
|
||||
double localForward = relX * (-sin) + relZ * cos; // Distance along panel normal
|
||||
double localRight = relX * cos + relZ * sin; // Distance along panel width
|
||||
|
||||
// Check bounds
|
||||
if (Math.abs(localForward) > panelThickness) return false;
|
||||
if (Math.abs(localRight) > halfW) return false;
|
||||
if (Math.abs(relY) > halfH) return false;
|
||||
|
||||
// Check incoming direction via dot product with panel normal
|
||||
double normalX = -Math.sin(yawRad);
|
||||
double normalZ = Math.cos(yawRad);
|
||||
double dot = projectile.motionX * normalX + projectile.motionZ * normalZ;
|
||||
|
||||
// Determine which side of the panel the projectile is on
|
||||
if (localForward > 0 && dot >= 0) return false; // Moving away from front side
|
||||
if (localForward < 0 && dot <= 0) return false; // Moving away from back side
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== CHARGING ====================
|
||||
|
||||
@Override
|
||||
public void setupCharging(int duration) {
|
||||
this.targetPanelWidth = panelData.panelWidth;
|
||||
this.targetPanelHeight = panelData.panelHeight;
|
||||
panelData.panelWidth = 0.01f;
|
||||
panelData.panelHeight = 0.01f;
|
||||
this.chargeDuration = duration;
|
||||
this.chargeTick = 0;
|
||||
setCharging(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishCharging() {
|
||||
panelData.panelWidth = targetPanelWidth;
|
||||
panelData.panelHeight = targetPanelHeight;
|
||||
setCharging(false);
|
||||
}
|
||||
|
||||
// ==================== KNOCKBACK ====================
|
||||
|
||||
/**
|
||||
* Push entities away from the panel surface.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void knockbackEntities() {
|
||||
float halfW = panelData.panelWidth * 0.5f;
|
||||
float halfH = panelData.panelHeight * 0.5f;
|
||||
float margin = 1.0f;
|
||||
|
||||
AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox(
|
||||
posX - halfW - margin, posY - halfH - margin, posZ - halfW - margin,
|
||||
posX + halfW + margin, posY + halfH + margin, posZ + halfW + margin
|
||||
);
|
||||
|
||||
List<EntityLivingBase> entities = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, searchBox);
|
||||
float yawRad = (float) Math.toRadians(panelYaw);
|
||||
float normalX = -(float) Math.sin(yawRad);
|
||||
float normalZ = (float) Math.cos(yawRad);
|
||||
|
||||
for (EntityLivingBase ent : entities) {
|
||||
if (ent.getEntityId() == ownerEntityId) continue;
|
||||
if (!isKnockbackTarget(ent)) continue;
|
||||
|
||||
// Transform entity position to panel-local space
|
||||
double dx = ent.posX - posX;
|
||||
double dy = (ent.posY + ent.height * 0.5) - posY;
|
||||
double dz = ent.posZ - posZ;
|
||||
|
||||
// Check proximity to panel surface
|
||||
float localForward = (float) (dx * normalX + dz * normalZ);
|
||||
float localRight = (float) (dx * (-normalZ) + dz * normalX);
|
||||
|
||||
if (Math.abs(localForward) < margin && Math.abs(localRight) < halfW + margin && Math.abs(dy) < halfH + margin) {
|
||||
// Push entity away from the panel face
|
||||
float pushDir = localForward >= 0 ? 1.0f : -1.0f;
|
||||
double pushStrength = barrierData.knockbackStrength * 0.5;
|
||||
ent.addVelocity(
|
||||
normalX * pushDir * pushStrength,
|
||||
0.1,
|
||||
normalZ * pushDir * pushStrength
|
||||
);
|
||||
ent.velocityChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== BOUNDING BOX ====================
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
if (barrierData.meleeEnabled) {
|
||||
float halfW = panelData.panelWidth * 0.5f;
|
||||
float halfH = panelData.panelHeight * 0.5f;
|
||||
float extent = Math.max(halfW, 0.5f);
|
||||
return AxisAlignedBB.getBoundingBox(
|
||||
posX - extent, posY - halfH, posZ - extent,
|
||||
posX + extent, posY + halfH, posZ + extent
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isInRangeToRenderDist(double distance) {
|
||||
double d = Math.max(panelData.panelWidth, panelData.panelHeight) * 8.0D;
|
||||
d *= 64.0D;
|
||||
return distance < d * d;
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public PanelMode getMode() { return mode; }
|
||||
public float getPanelYaw() { return panelYaw; }
|
||||
public EnergyPanelData getPanelData() { return panelData; }
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound nbt) {
|
||||
readBarrierBaseNBT(nbt);
|
||||
this.panelYaw = nbt.getFloat("PanelYaw");
|
||||
int modeOrdinal = nbt.getInteger("PanelMode");
|
||||
this.mode = (modeOrdinal >= 0 && modeOrdinal < PanelMode.values().length)
|
||||
? PanelMode.values()[modeOrdinal] : PanelMode.PLACED;
|
||||
panelData.readNBT(nbt);
|
||||
this.targetPanelWidth = nbt.hasKey("TargetPanelWidth") ? nbt.getFloat("TargetPanelWidth") : panelData.panelWidth;
|
||||
this.targetPanelHeight = nbt.hasKey("TargetPanelHeight") ? nbt.getFloat("TargetPanelHeight") : panelData.panelHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound nbt) {
|
||||
writeBarrierBaseNBT(nbt);
|
||||
nbt.setFloat("PanelYaw", panelYaw);
|
||||
nbt.setInteger("PanelMode", mode.ordinal());
|
||||
nbt.setFloat("TargetPanelWidth", targetPanelWidth);
|
||||
nbt.setFloat("TargetPanelHeight", targetPanelHeight);
|
||||
panelData.writeNBT(nbt);
|
||||
}
|
||||
}
|
||||
+65
-242
@@ -1,14 +1,10 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -35,20 +31,21 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for all ability projectiles (Orb, Disc, Beam, Laser).
|
||||
* Provides common functionality for visuals, combat, effects, and interpolation.
|
||||
* Base class for all ability projectiles (Orb, Disc, Beam, Laser, Slicer).
|
||||
* Provides common functionality for combat, effects, homing, and interpolation.
|
||||
* Extends EntityEnergyAbility for shared visual/owner/charging state.
|
||||
*
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public abstract class EntityAbilityProjectile extends Entity implements IEntityAdditionalSpawnData {
|
||||
public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
// ==================== ACTIVE PROJECTILE TRACKING ====================
|
||||
private static final Map<Integer, List<WeakReference<EntityAbilityProjectile>>> activeProjectiles = new HashMap<>();
|
||||
private static final Map<Integer, List<WeakReference<EntityEnergyProjectile>>> activeProjectiles = new HashMap<>();
|
||||
|
||||
public static void trackProjectile(EntityAbilityProjectile projectile) {
|
||||
public static void trackProjectile(EntityEnergyProjectile projectile) {
|
||||
int ownerId = projectile.getOwnerEntityId();
|
||||
if (ownerId < 0) return;
|
||||
List<WeakReference<EntityAbilityProjectile>> refs = activeProjectiles.get(ownerId);
|
||||
List<WeakReference<EntityEnergyProjectile>> refs = activeProjectiles.get(ownerId);
|
||||
if (refs == null) {
|
||||
refs = new ArrayList<>();
|
||||
activeProjectiles.put(ownerId, refs);
|
||||
@@ -56,13 +53,13 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
refs.add(new WeakReference<>(projectile));
|
||||
}
|
||||
|
||||
public static List<EntityAbilityProjectile> getActiveProjectiles(int ownerEntityId) {
|
||||
List<WeakReference<EntityAbilityProjectile>> refs = activeProjectiles.get(ownerEntityId);
|
||||
public static List<EntityEnergyProjectile> getActiveProjectiles(int ownerEntityId) {
|
||||
List<WeakReference<EntityEnergyProjectile>> refs = activeProjectiles.get(ownerEntityId);
|
||||
if (refs == null) return Collections.emptyList();
|
||||
List<EntityAbilityProjectile> result = new ArrayList<>();
|
||||
Iterator<WeakReference<EntityAbilityProjectile>> it = refs.iterator();
|
||||
List<EntityEnergyProjectile> result = new ArrayList<>();
|
||||
Iterator<WeakReference<EntityEnergyProjectile>> it = refs.iterator();
|
||||
while (it.hasNext()) {
|
||||
EntityAbilityProjectile p = it.next().get();
|
||||
EntityEnergyProjectile p = it.next().get();
|
||||
if (p == null || p.isDead) {
|
||||
it.remove();
|
||||
} else {
|
||||
@@ -80,17 +77,7 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
protected EnergyCombatData combatData = new EnergyCombatData();
|
||||
|
||||
// ==================== EFFECT PROPERTIES ====================
|
||||
protected List<AbilityEffect> effects = new ArrayList<>();
|
||||
|
||||
// ==================== LIGHTNING EFFECT PROPERTIES ====================
|
||||
protected EnergyLightningData lightningData = new EnergyLightningData();
|
||||
|
||||
// Client-side lightning state (not saved to NBT)
|
||||
@cpw.mods.fml.relauncher.SideOnly(cpw.mods.fml.relauncher.Side.CLIENT)
|
||||
public transient Object lightningState; // Actually AttachedLightningRenderer.LightningState
|
||||
|
||||
// ==================== DISPLAY PROPERTIES ====================
|
||||
protected EnergyDisplayData displayData = new EnergyDisplayData();
|
||||
protected List<AbilityPotionEffect> effects = new ArrayList<>();
|
||||
|
||||
// ==================== ANCHOR PROPERTIES ====================
|
||||
protected EnergyAnchorData anchorData = new EnergyAnchorData(AnchorPoint.FRONT);
|
||||
@@ -108,23 +95,13 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
|
||||
// ==================== TRACKING ====================
|
||||
protected double startX, startY, startZ;
|
||||
protected int ownerEntityId = -1;
|
||||
protected int targetEntityId = -1;
|
||||
|
||||
// ==================== STATE ====================
|
||||
protected boolean hasHit = false;
|
||||
protected boolean previewMode = false; // Client-side preview mode (no damage/effects)
|
||||
protected EntityLivingBase previewOwner = null; // Direct reference for GUI preview (no world lookup)
|
||||
|
||||
/** The ability that spawned this projectile. Transient, not saved to NBT. */
|
||||
protected transient Ability sourceAbility = null;
|
||||
|
||||
// ==================== CHARGING STATE ====================
|
||||
protected boolean charging = false;
|
||||
protected int chargeDuration = 40;
|
||||
protected int chargeTick = 0;
|
||||
// ==================== CHARGING STATE (projectile-specific) ====================
|
||||
protected float targetSize = 1.0f;
|
||||
protected static final int DW_CHARGING = 20;
|
||||
|
||||
// ==================== ROTATION INTERPOLATION ====================
|
||||
public float prevRotationValX, prevRotationValY, prevRotationValZ;
|
||||
@@ -139,12 +116,10 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
protected double interpTargetMotionX, interpTargetMotionY, interpTargetMotionZ;
|
||||
protected int interpSteps;
|
||||
|
||||
public EntityAbilityProjectile(World world) {
|
||||
public EntityEnergyProjectile(World world) {
|
||||
super(world);
|
||||
this.setSize(0.5f, 0.5f);
|
||||
this.noClip = false;
|
||||
this.isImmuneToFire = true;
|
||||
this.ignoreFrustumCheck = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,11 +152,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
this.prevRenderSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
this.dataWatcher.addObject(DW_CHARGING, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isInRangeToRenderDist(double distance) {
|
||||
@@ -190,11 +160,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
return distance < d1 * d1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
return pass == 1; // Translucent pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
// Store previous values for interpolation
|
||||
@@ -270,6 +235,13 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
}
|
||||
}
|
||||
|
||||
// Check barrier collisions (server-side, non-preview, non-charging)
|
||||
if (!previewMode && !worldObj.isRemote && !isCharging()) {
|
||||
if (checkBarrierCollision()) {
|
||||
return; // Projectile was absorbed by a barrier
|
||||
}
|
||||
}
|
||||
|
||||
// Subclass-specific update
|
||||
updateProjectile();
|
||||
|
||||
@@ -310,6 +282,37 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
*/
|
||||
protected abstract void updateProjectile();
|
||||
|
||||
// ==================== BARRIER COLLISION ====================
|
||||
|
||||
/**
|
||||
* Check for collision with energy barrier entities.
|
||||
* Barriers only block incoming projectiles from enemies.
|
||||
* @return true if projectile was absorbed (caller should stop processing)
|
||||
*/
|
||||
protected boolean checkBarrierCollision() {
|
||||
// Search area for barriers - must cover large domes (up to 30 radius)
|
||||
double searchRange = 32.0;
|
||||
AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox(
|
||||
posX - searchRange, posY - searchRange, posZ - searchRange,
|
||||
posX + searchRange, posY + searchRange, posZ + searchRange
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<EntityEnergyBarrier> barriers = worldObj.getEntitiesWithinAABB(EntityEnergyBarrier.class, searchBox);
|
||||
for (EntityEnergyBarrier barrier : barriers) {
|
||||
if (barrier.isDead) continue;
|
||||
if (barrier.isIncomingProjectile(this)) {
|
||||
if (barrier.onProjectileHit(this, getDamage())) {
|
||||
hasHit = true;
|
||||
this.setDead();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ==================== POSITION INTERPOLATION ====================
|
||||
|
||||
@Override
|
||||
@@ -353,23 +356,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== PREVIEW MODE ====================
|
||||
|
||||
/**
|
||||
* Set preview mode for GUI display.
|
||||
* In preview mode, no damage or world effects are applied.
|
||||
*/
|
||||
public void setPreviewMode(boolean preview) {
|
||||
this.previewMode = preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if entity is in preview mode.
|
||||
*/
|
||||
public boolean isPreviewMode() {
|
||||
return previewMode;
|
||||
}
|
||||
|
||||
// ==================== DAMAGE & EFFECTS ====================
|
||||
|
||||
protected void applyDamage(EntityLivingBase target) {
|
||||
@@ -430,7 +416,7 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
}
|
||||
|
||||
protected void applyEffects(EntityLivingBase target) {
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effect.apply(target);
|
||||
}
|
||||
}
|
||||
@@ -438,25 +424,10 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
/**
|
||||
* Set the effects list from the ability's configured effects.
|
||||
*/
|
||||
public void setEffects(List<AbilityEffect> effects) {
|
||||
public void setEffects(List<AbilityPotionEffect> effects) {
|
||||
this.effects = effects != null ? effects : new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source ability that spawned this projectile.
|
||||
* Used by external damage handlers to access ability-specific data.
|
||||
*/
|
||||
public void setSourceAbility(Ability ability) {
|
||||
this.sourceAbility = ability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source ability that spawned this projectile.
|
||||
*/
|
||||
public Ability getSourceAbility() {
|
||||
return sourceAbility;
|
||||
}
|
||||
|
||||
protected void doExplosion() {
|
||||
if (previewMode) return; // Skip explosion in preview mode
|
||||
worldObj.playSoundEffect(posX, posY, posZ, "random.explode", 1.0f, 1.0f);
|
||||
@@ -513,38 +484,7 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
prevPosZ = newZ;
|
||||
}
|
||||
|
||||
// ==================== CHARGING METHODS ====================
|
||||
|
||||
/**
|
||||
* Check if entity is in charging state (synced via data watcher).
|
||||
* In preview mode, uses local field since data watcher isn't synced.
|
||||
*/
|
||||
public boolean isCharging() {
|
||||
if (previewMode) return this.charging;
|
||||
return this.dataWatcher.getWatchableObjectByte(DW_CHARGING) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set charging state (server only, synced to clients via data watcher).
|
||||
*/
|
||||
protected void setCharging(boolean value) {
|
||||
this.charging = value;
|
||||
if (!worldObj.isRemote) {
|
||||
this.dataWatcher.updateObject(DW_CHARGING, (byte) (value ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
public float getChargeProgress() {
|
||||
if (chargeDuration <= 0) return 1.0f;
|
||||
return Math.min(1.0f, (float) chargeTick / chargeDuration);
|
||||
}
|
||||
|
||||
public float getInterpolatedChargeProgress(float partialTicks) {
|
||||
if (chargeDuration <= 0) return 1.0f;
|
||||
float prevProgress = Math.max(0, (float) (chargeTick - 1) / chargeDuration);
|
||||
float currProgress = Math.min(1.0f, (float) chargeTick / chargeDuration);
|
||||
return prevProgress + (currProgress - prevProgress) * partialTicks;
|
||||
}
|
||||
// ==================== CHARGING METHODS (projectile-specific) ====================
|
||||
|
||||
/**
|
||||
* Setup this entity in charging mode (for windup phase).
|
||||
@@ -677,37 +617,12 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
|
||||
// ==================== ENTITY HELPERS ====================
|
||||
|
||||
public Entity getOwnerEntity() {
|
||||
// In preview mode, use direct reference (no world lookup)
|
||||
if (previewMode && previewOwner != null) {
|
||||
return previewOwner;
|
||||
}
|
||||
if (ownerEntityId == -1) return null;
|
||||
return worldObj.getEntityByID(ownerEntityId);
|
||||
}
|
||||
|
||||
public int getOwnerEntityId() {
|
||||
return ownerEntityId;
|
||||
}
|
||||
|
||||
public void setOwnerEntityId(int id) {
|
||||
this.ownerEntityId = id;
|
||||
}
|
||||
|
||||
public IEntity getOwner() {
|
||||
if (previewMode) return null;
|
||||
if (getOwnerEntity() == null) return null;
|
||||
return NpcAPI.Instance().getIEntity(getOwnerEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the preview owner for GUI preview mode.
|
||||
* This allows anchor point calculations without world entity lookup.
|
||||
*/
|
||||
public void setPreviewOwner(EntityLivingBase owner) {
|
||||
this.previewOwner = owner;
|
||||
}
|
||||
|
||||
public int getTargetEntityId() {
|
||||
return targetEntityId;
|
||||
}
|
||||
@@ -741,8 +656,8 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
}
|
||||
|
||||
// Ignore other projectiles from the same caster (e.g. multi-projectile abilities)
|
||||
if (entity instanceof EntityAbilityProjectile) {
|
||||
EntityAbilityProjectile other = (EntityAbilityProjectile) entity;
|
||||
if (entity instanceof EntityEnergyProjectile) {
|
||||
EntityEnergyProjectile other = (EntityEnergyProjectile) entity;
|
||||
if (other.ownerEntityId == this.ownerEntityId) return true;
|
||||
}
|
||||
|
||||
@@ -768,24 +683,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
this.startZ = z;
|
||||
}
|
||||
|
||||
public int getInnerColor() { return displayData.getInnerColor(); }
|
||||
public void setInnerColor(int color) { displayData.setInnerColor(color); }
|
||||
|
||||
public int getOuterColor() { return displayData.getOuterColor(); }
|
||||
public void setOuterColor(int color) { displayData.setOuterColor(color); }
|
||||
|
||||
public boolean isOuterColorEnabled() { return displayData.isOuterColorEnabled(); }
|
||||
public void setOuterColorEnabled(boolean enabled) { displayData.setOuterColorEnabled(enabled); }
|
||||
|
||||
public float getOuterColorWidth() { return displayData.getOuterColorWidth(); }
|
||||
public void setOuterColorWidth(float width) { displayData.setOuterColorWidth(width); }
|
||||
|
||||
public float getOuterColorAlpha() { return displayData.getOuterColorAlpha(); }
|
||||
public void setOuterColorAlpha(float alpha) { displayData.setOuterColorAlpha(alpha); }
|
||||
|
||||
public float getRotationSpeed() { return displayData.getRotationSpeed(); }
|
||||
public void setRotationSpeed(float speed) { displayData.setRotationSpeed(speed); }
|
||||
|
||||
// ==================== ROTATION GETTERS ====================
|
||||
|
||||
public float getInterpolatedRotationX(float partialTicks) {
|
||||
@@ -804,20 +701,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
return this.prevRenderSize + (this.renderCurrentSize - this.prevRenderSize) * partialTicks;
|
||||
}
|
||||
|
||||
// ==================== LIGHTNING GETTERS & SETTERS ====================
|
||||
|
||||
public boolean hasLightningEffect() { return lightningData.isLightningEffect(); }
|
||||
public void setLightningEffect(boolean enabled) { lightningData.setLightningEffect(enabled); }
|
||||
|
||||
public float getLightningDensity() { return lightningData.getLightningDensity(); }
|
||||
public void setLightningDensity(float density) { lightningData.setLightningDensity(density); }
|
||||
|
||||
public float getLightningRadius() { return lightningData.getLightningRadius(); }
|
||||
public void setLightningRadius(float radius) { lightningData.setLightningRadius(radius); }
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.getLightningFadeTime(); }
|
||||
public void setLightningFadeTime(int ticks) { lightningData.setLightningFadeTime(ticks); }
|
||||
|
||||
// ==================== LIFESPAN GETTERS & SETTERS ====================
|
||||
|
||||
public float getMaxDistance() { return lifespanData.getMaxDistance(); }
|
||||
@@ -879,19 +762,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
|
||||
public boolean getHasHit() { return hasHit; }
|
||||
|
||||
// ==================== BRIGHTNESS ====================
|
||||
|
||||
@Override
|
||||
public float getBrightness(float partialTicks) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getBrightnessForRender(float partialTicks) {
|
||||
return 0xF000F0;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
@@ -910,6 +780,8 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
* Read base projectile properties from NBT.
|
||||
*/
|
||||
protected void readBaseNBT(NBTTagCompound nbt) {
|
||||
readEnergyBaseNBT(nbt);
|
||||
|
||||
this.size = nbt.getFloat("Size");
|
||||
|
||||
// Read effects list
|
||||
@@ -917,7 +789,7 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
if (nbt.hasKey("Effects")) {
|
||||
NBTTagList effectsList = nbt.getTagList("Effects", 10); // 10 = compound tag
|
||||
for (int i = 0; i < effectsList.tagCount(); i++) {
|
||||
effects.add(AbilityEffect.fromNBT(effectsList.getCompoundTagAt(i)));
|
||||
effects.add(AbilityPotionEffect.fromNBT(effectsList.getCompoundTagAt(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -927,7 +799,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
this.startY = nbt.getDouble("StartY");
|
||||
this.startZ = nbt.getDouble("StartZ");
|
||||
|
||||
this.ownerEntityId = nbt.getInteger("OwnerId");
|
||||
this.targetEntityId = nbt.getInteger("TargetId");
|
||||
|
||||
this.motionX = nbt.getDouble("MotionX");
|
||||
@@ -941,10 +812,8 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
|
||||
anchorData.readNBT(nbt);
|
||||
combatData.readNBT(nbt);
|
||||
displayData.readNBT(nbt);
|
||||
homingData.readNBT(nbt);
|
||||
lifespanData.readNBT(nbt);
|
||||
lightningData.readNBT(nbt);
|
||||
trajectoryData.readNBT(nbt);
|
||||
}
|
||||
|
||||
@@ -952,12 +821,14 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
* Write base projectile properties to NBT.
|
||||
*/
|
||||
protected void writeBaseNBT(NBTTagCompound nbt) {
|
||||
writeEnergyBaseNBT(nbt);
|
||||
|
||||
nbt.setFloat("Size", size);
|
||||
|
||||
// Write effects list
|
||||
if (!effects.isEmpty()) {
|
||||
NBTTagList effectsList = new NBTTagList();
|
||||
for (AbilityEffect effect : effects) {
|
||||
for (AbilityPotionEffect effect : effects) {
|
||||
effectsList.appendTag(effect.writeNBT());
|
||||
}
|
||||
nbt.setTag("Effects", effectsList);
|
||||
@@ -969,7 +840,6 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
nbt.setDouble("StartY", startY);
|
||||
nbt.setDouble("StartZ", startZ);
|
||||
|
||||
nbt.setInteger("OwnerId", ownerEntityId);
|
||||
nbt.setInteger("TargetId", targetEntityId);
|
||||
|
||||
nbt.setDouble("MotionX", motionX);
|
||||
@@ -978,10 +848,8 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
|
||||
anchorData.writeNBT(nbt);
|
||||
combatData.writeNBT(nbt);
|
||||
displayData.writeNBT(nbt);
|
||||
homingData.writeNBT(nbt);
|
||||
lifespanData.writeNBT(nbt);
|
||||
lightningData.writeNBT(nbt);
|
||||
trajectoryData.writeNBT(nbt);
|
||||
}
|
||||
|
||||
@@ -995,55 +863,10 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA
|
||||
*/
|
||||
protected abstract void writeProjectileNBT(NBTTagCompound nbt);
|
||||
|
||||
// ==================== SPAWN DATA ====================
|
||||
|
||||
@Override
|
||||
public void writeSpawnData(ByteBuf buffer) {
|
||||
try {
|
||||
NBTTagCompound compound = new NBTTagCompound();
|
||||
this.writeEntityToNBT(compound);
|
||||
cpw.mods.fml.common.network.ByteBufUtils.writeTag(buffer, compound);
|
||||
} catch (Exception e) {
|
||||
noppes.npcs.LogWriter.error("Error writing ability projectile spawn data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSpawnData(ByteBuf buffer) {
|
||||
try {
|
||||
NBTTagCompound compound = cpw.mods.fml.common.network.ByteBufUtils.readTag(buffer);
|
||||
if (compound != null) {
|
||||
this.readEntityFromNBT(compound);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
noppes.npcs.LogWriter.error("Error reading ability projectile spawn data", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== COLLISION SETTINGS ====================
|
||||
|
||||
@Override
|
||||
public boolean canBeCollidedWith() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBePushed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canTriggerWalking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getShadowSize() {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
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).
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor with all parameters.
|
||||
*/
|
||||
public EntityEnergySlicer(World world, EntityLivingBase owner, EntityLivingBase target,
|
||||
double x, double y, double z,
|
||||
float sliceWidth, float sliceThickness,
|
||||
EnergyDisplayData display, EnergyCombatData combat,
|
||||
EnergyHomingData homing, EnergyLightningData lightning,
|
||||
EnergyLifespanData lifespan, EnergyTrajectoryData trajectory,
|
||||
boolean piercing) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Targets stored during charging for grow animation
|
||||
private float targetSliceWidth = 3.0f;
|
||||
private float targetSliceThickness = 0.15f;
|
||||
|
||||
/**
|
||||
* Setup charging with full target dimensions.
|
||||
*/
|
||||
public void setupSlicerCharging(EnergyAnchorData anchor, int chargeDuration, float width, float thickness) {
|
||||
this.targetSliceWidth = width;
|
||||
this.targetSliceThickness = thickness;
|
||||
this.sliceWidth = 0.01f;
|
||||
this.sliceThickness = 0.01f;
|
||||
super.setupCharging(anchor, chargeDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup preview mode.
|
||||
*/
|
||||
public void setupPreview(EntityLivingBase owner, float width, float thickness,
|
||||
EnergyDisplayData display, EnergyLightningData lightning,
|
||||
EnergyAnchorData anchor, int chargeDuration) {
|
||||
this.setPreviewMode(true);
|
||||
this.setPreviewOwner(owner);
|
||||
this.displayData = display;
|
||||
this.lightningData = lightning;
|
||||
this.setCharging(true);
|
||||
this.chargeDuration = chargeDuration;
|
||||
this.chargeTick = 0;
|
||||
this.anchorData = anchor;
|
||||
|
||||
this.targetSliceWidth = width;
|
||||
this.targetSliceThickness = thickness;
|
||||
this.sliceWidth = 0.01f;
|
||||
this.sliceThickness = 0.01f;
|
||||
this.size = 0.01f;
|
||||
this.renderCurrentSize = 0.01f;
|
||||
this.prevRenderSize = 0.01f;
|
||||
|
||||
Vec3 pos = kamkeel.npcs.util.AnchorPointHelper.calculateAnchorPosition(owner, anchorData);
|
||||
this.setPosition(pos.xCoord, pos.yCoord, pos.zCoord);
|
||||
this.prevPosX = pos.xCoord;
|
||||
this.prevPosY = pos.yCoord;
|
||||
this.prevPosZ = pos.zCoord;
|
||||
this.startX = pos.xCoord;
|
||||
this.startY = pos.yCoord;
|
||||
this.startZ = pos.zCoord;
|
||||
this.motionX = 0;
|
||||
this.motionY = 0;
|
||||
this.motionZ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start preview firing.
|
||||
*/
|
||||
public void startPreviewFiring() {
|
||||
setCharging(false);
|
||||
startX = posX;
|
||||
startY = posY;
|
||||
startZ = posZ;
|
||||
prevPosX = posX;
|
||||
prevPosY = posY;
|
||||
prevPosZ = posZ;
|
||||
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner != null) {
|
||||
float yaw = (float) Math.toRadians(owner.rotationYaw);
|
||||
motionX = -Math.sin(yaw) * getSpeed();
|
||||
motionY = 0;
|
||||
motionZ = Math.cos(yaw) * getSpeed();
|
||||
} else {
|
||||
motionX = getSpeed();
|
||||
motionY = 0;
|
||||
motionZ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the slicer moving (exit charging mode).
|
||||
*/
|
||||
public void startMoving(EntityLivingBase target) {
|
||||
setCharging(false);
|
||||
snapToPlayerLookVector();
|
||||
startX = posX;
|
||||
startY = posY;
|
||||
startZ = posZ;
|
||||
|
||||
Entity owner = getOwnerEntity();
|
||||
if (target != null) {
|
||||
double dx = target.posX - posX;
|
||||
double dy = (target.posY + target.getEyeHeight()) - posY;
|
||||
double dz = target.posZ - posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) {
|
||||
motionX = (dx / len) * getSpeed();
|
||||
motionY = (dy / len) * getSpeed();
|
||||
motionZ = (dz / len) * getSpeed();
|
||||
}
|
||||
} else if (owner != null) {
|
||||
float yaw = (float) Math.toRadians(owner.rotationYaw);
|
||||
float pitch = (float) Math.toRadians(owner.rotationPitch);
|
||||
motionX = -Math.sin(yaw) * Math.cos(pitch) * getSpeed();
|
||||
motionY = -Math.sin(pitch) * getSpeed();
|
||||
motionZ = Math.cos(yaw) * Math.cos(pitch) * getSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation() {
|
||||
// Slicer doesn't spin - it stays oriented perpendicular to travel direction
|
||||
// No rotation update needed
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateProjectile() {
|
||||
if (isCharging()) {
|
||||
updateCharging();
|
||||
return;
|
||||
}
|
||||
|
||||
if (previewMode) {
|
||||
posX += motionX;
|
||||
posY += motionY;
|
||||
posZ += motionZ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (worldObj.isRemote) {
|
||||
handleClientInterpolation();
|
||||
} else {
|
||||
// No homing by default for slicer (straight line flight)
|
||||
if (homingData.isHoming()) {
|
||||
updateHoming();
|
||||
}
|
||||
|
||||
checkBlockCollision();
|
||||
checkEntityCollision();
|
||||
this.moveEntity(motionX, motionY, motionZ);
|
||||
}
|
||||
|
||||
// Wall collision
|
||||
if (this.isCollidedHorizontally || this.isCollidedVertically) {
|
||||
if (!worldObj.isRemote) {
|
||||
hasHit = true;
|
||||
if (isExplosive()) {
|
||||
doExplosion();
|
||||
}
|
||||
}
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCharging() {
|
||||
chargeTick++;
|
||||
float progress = getChargeProgress();
|
||||
this.sliceWidth = targetSliceWidth * progress;
|
||||
this.sliceThickness = targetSliceThickness * progress;
|
||||
this.size = this.sliceWidth;
|
||||
|
||||
Entity owner = getOwnerEntity();
|
||||
if (owner instanceof EntityLivingBase) {
|
||||
Vec3 pos = kamkeel.npcs.util.AnchorPointHelper.calculateAnchorPosition((EntityLivingBase) owner, anchorData);
|
||||
setPosition(pos.xCoord, pos.yCoord, pos.zCoord);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEntityCollision() {
|
||||
float halfW = sliceWidth * 0.5f;
|
||||
float halfH = sliceThickness * 0.5f;
|
||||
AxisAlignedBB hitBox = AxisAlignedBB.getBoundingBox(
|
||||
posX - halfW, posY - halfH, posZ - halfW,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the yaw angle from motion vector for orientation.
|
||||
*/
|
||||
public float getTravelYaw() {
|
||||
if (isCharging()) {
|
||||
Entity owner = previewMode ? previewOwner : getOwnerEntity();
|
||||
if (owner != null) return owner.rotationYaw;
|
||||
}
|
||||
double speed = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||
if (speed > 0.001) {
|
||||
return (float) (Math.atan2(-motionX, motionZ) * 180.0 / Math.PI);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pitch angle from motion vector.
|
||||
*/
|
||||
public float getTravelPitch() {
|
||||
double horizSpeed = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||
if (horizSpeed > 0.001 || Math.abs(motionY) > 0.001) {
|
||||
return (float) (-Math.atan2(motionY, horizSpeed) * 180.0 / Math.PI);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public float getSliceWidth() { return sliceWidth; }
|
||||
public void setSliceWidth(float width) { this.sliceWidth = width; }
|
||||
|
||||
public float getSliceThickness() { return sliceThickness; }
|
||||
public void setSliceThickness(float thickness) { this.sliceThickness = thickness; }
|
||||
|
||||
public boolean isPiercing() { return piercing; }
|
||||
public void setPiercing(boolean piercing) { this.piercing = piercing; }
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
protected void readProjectileNBT(NBTTagCompound nbt) {
|
||||
readChargingNBT(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");
|
||||
this.targetSliceWidth = nbt.hasKey("TargetSliceWidth") ? nbt.getFloat("TargetSliceWidth") : sliceWidth;
|
||||
this.targetSliceThickness = nbt.hasKey("TargetSliceThickness") ? nbt.getFloat("TargetSliceThickness") : sliceThickness;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeProjectileNBT(NBTTagCompound nbt) {
|
||||
writeChargingNBT(nbt);
|
||||
nbt.setFloat("SliceWidth", sliceWidth);
|
||||
nbt.setFloat("SliceThickness", sliceThickness);
|
||||
nbt.setBoolean("Piercing", piercing);
|
||||
nbt.setFloat("TargetSliceWidth", targetSliceWidth);
|
||||
nbt.setFloat("TargetSliceThickness", targetSliceThickness);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,9 @@ import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import kamkeel.npcs.entity.EntityAbilitySweeper;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone;
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
import noppes.npcs.entity.old.EntityNPCDwarfFemale;
|
||||
import noppes.npcs.entity.old.EntityNPCDwarfMale;
|
||||
import noppes.npcs.entity.old.EntityNPCElfFemale;
|
||||
@@ -294,6 +297,9 @@ public class CustomNpcs {
|
||||
registerNewEntity(EntityAbilityBeam.class, "abilitybeam", 64, 3, true);
|
||||
registerNewEntity(EntityAbilitySweeper.class, "abilitysweeper", 64, 3, true);
|
||||
registerNewEntity(EntityAbilityZone.class, "abilityzone", 64, 3, true);
|
||||
registerNewEntity(EntityEnergyDome.class, "energydome", 64, 3, true);
|
||||
registerNewEntity(EntityEnergyPanel.class, "energypanel", 64, 3, true);
|
||||
registerNewEntity(EntityEnergySlicer.class, "energyslicer", 64, 3, true);
|
||||
|
||||
new RecipeController();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package noppes.npcs;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import kamkeel.npcs.network.packets.data.AchievementPacket;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -455,7 +455,7 @@ public class EventHooks {
|
||||
|
||||
// ==================== ENERGY PROJECTILE EVENTS ====================
|
||||
|
||||
public static void onEnergyProjectileFired(EntityAbilityProjectile projectile) {
|
||||
public static void onEnergyProjectileFired(EntityEnergyProjectile projectile) {
|
||||
IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile);
|
||||
EnergyProjectileEvent.FiredEvent event = new EnergyProjectileEvent.FiredEvent(wrapped);
|
||||
ScriptController.Instance.globalNpcScripts.callScript(EnumScriptType.ENERGY_PROJECTILE_FIRED, event);
|
||||
@@ -473,7 +473,7 @@ public class EventHooks {
|
||||
NpcAPI.EVENT_BUS.post(event);
|
||||
}
|
||||
|
||||
public static void onEnergyProjectileTick(EntityAbilityProjectile projectile) {
|
||||
public static void onEnergyProjectileTick(EntityEnergyProjectile projectile) {
|
||||
IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile);
|
||||
EnergyProjectileEvent.UpdateEvent event = new EnergyProjectileEvent.UpdateEvent(wrapped);
|
||||
ScriptController.Instance.globalNpcScripts.callScript(EnumScriptType.ENERGY_PROJECTILE_TICK, event);
|
||||
@@ -494,7 +494,7 @@ public class EventHooks {
|
||||
/**
|
||||
* Fires the entity impact event. Returns the (possibly modified) damage, or -1 if cancelled.
|
||||
*/
|
||||
public static float onEnergyProjectileEntityImpact(EntityAbilityProjectile projectile, EntityLivingBase target, float damage) {
|
||||
public static float onEnergyProjectileEntityImpact(EntityEnergyProjectile projectile, EntityLivingBase target, float damage) {
|
||||
IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile);
|
||||
IEntity wrappedTarget = NpcAPI.Instance().getIEntity(target);
|
||||
EnergyProjectileEvent.EntityImpactEvent event = new EnergyProjectileEvent.EntityImpactEvent(wrapped, wrappedTarget, damage);
|
||||
@@ -518,7 +518,7 @@ public class EventHooks {
|
||||
return event.getDamage();
|
||||
}
|
||||
|
||||
public static void onEnergyProjectileBlockImpact(EntityAbilityProjectile projectile, int blockX, int blockY, int blockZ) {
|
||||
public static void onEnergyProjectileBlockImpact(EntityEnergyProjectile projectile, int blockX, int blockY, int blockZ) {
|
||||
IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile);
|
||||
IPos pos = NpcAPI.Instance().getIPos(blockX, blockY, blockZ);
|
||||
IWorld world = NpcAPI.Instance().getIWorld(projectile.worldObj);
|
||||
@@ -539,7 +539,7 @@ public class EventHooks {
|
||||
NpcAPI.EVENT_BUS.post(event);
|
||||
}
|
||||
|
||||
public static void onEnergyProjectileExpired(EntityAbilityProjectile projectile) {
|
||||
public static void onEnergyProjectileExpired(EntityEnergyProjectile projectile) {
|
||||
IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile);
|
||||
EnergyProjectileEvent.ExpiredEvent event = new EnergyProjectileEvent.ExpiredEvent(wrapped);
|
||||
ScriptController.Instance.globalNpcScripts.callScript(EnumScriptType.ENERGY_PROJECTILE_EXPIRED, event);
|
||||
@@ -557,6 +557,54 @@ public class EventHooks {
|
||||
NpcAPI.EVENT_BUS.post(event);
|
||||
}
|
||||
|
||||
// ==================== ENERGY BARRIER EVENTS ====================
|
||||
|
||||
private static void dispatchBarrierEvent(net.minecraft.entity.Entity barrierEntity, int ownerEntityId,
|
||||
noppes.npcs.scripted.event.EnergyBarrierEvent event, EnumScriptType type) {
|
||||
ScriptController.Instance.globalNpcScripts.callScript(type, event);
|
||||
|
||||
net.minecraft.entity.Entity owner = barrierEntity.worldObj.getEntityByID(ownerEntityId);
|
||||
if (owner instanceof EntityNPCInterface) {
|
||||
((EntityNPCInterface) owner).script.callScript(type, event);
|
||||
} else if (owner instanceof EntityPlayer) {
|
||||
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts((EntityPlayer) owner);
|
||||
if (handler != null) {
|
||||
handler.callScript(type, event);
|
||||
}
|
||||
}
|
||||
|
||||
NpcAPI.EVENT_BUS.post(event);
|
||||
}
|
||||
|
||||
public static void onEnergyBarrierSpawned(net.minecraft.entity.Entity barrierEntity, int ownerEntityId) {
|
||||
noppes.npcs.api.entity.IEnergyBarrier wrapped = (noppes.npcs.api.entity.IEnergyBarrier) NpcAPI.Instance().getIEntity(barrierEntity);
|
||||
noppes.npcs.scripted.event.EnergyBarrierEvent.SpawnedEvent event = new noppes.npcs.scripted.event.EnergyBarrierEvent.SpawnedEvent(wrapped);
|
||||
dispatchBarrierEvent(barrierEntity, ownerEntityId, event, EnumScriptType.ENERGY_BARRIER_SPAWNED);
|
||||
}
|
||||
|
||||
public static void onEnergyBarrierTick(net.minecraft.entity.Entity barrierEntity, int ownerEntityId) {
|
||||
noppes.npcs.api.entity.IEnergyBarrier wrapped = (noppes.npcs.api.entity.IEnergyBarrier) NpcAPI.Instance().getIEntity(barrierEntity);
|
||||
noppes.npcs.scripted.event.EnergyBarrierEvent.UpdateEvent event = new noppes.npcs.scripted.event.EnergyBarrierEvent.UpdateEvent(wrapped);
|
||||
dispatchBarrierEvent(barrierEntity, ownerEntityId, event, EnumScriptType.ENERGY_BARRIER_TICK);
|
||||
}
|
||||
|
||||
public static float onEnergyBarrierHit(net.minecraft.entity.Entity barrierEntity, int ownerEntityId,
|
||||
EntityEnergyProjectile projectile, float damage) {
|
||||
noppes.npcs.api.entity.IEnergyBarrier wrappedBarrier = (noppes.npcs.api.entity.IEnergyBarrier) NpcAPI.Instance().getIEntity(barrierEntity);
|
||||
noppes.npcs.api.entity.IEnergyProjectile wrappedProjectile = projectile != null
|
||||
? (noppes.npcs.api.entity.IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile) : null;
|
||||
noppes.npcs.scripted.event.EnergyBarrierEvent.HitEvent event = new noppes.npcs.scripted.event.EnergyBarrierEvent.HitEvent(wrappedBarrier, wrappedProjectile, damage);
|
||||
dispatchBarrierEvent(barrierEntity, ownerEntityId, event, EnumScriptType.ENERGY_BARRIER_HIT);
|
||||
if (event.isCanceled()) return -1;
|
||||
return event.getDamage();
|
||||
}
|
||||
|
||||
public static void onEnergyBarrierDestroyed(net.minecraft.entity.Entity barrierEntity, int ownerEntityId) {
|
||||
noppes.npcs.api.entity.IEnergyBarrier wrapped = (noppes.npcs.api.entity.IEnergyBarrier) NpcAPI.Instance().getIEntity(barrierEntity);
|
||||
noppes.npcs.scripted.event.EnergyBarrierEvent.DestroyedEvent event = new noppes.npcs.scripted.event.EnergyBarrierEvent.DestroyedEvent(wrapped);
|
||||
dispatchBarrierEvent(barrierEntity, ownerEntityId, event, EnumScriptType.ENERGY_BARRIER_DESTROYED);
|
||||
}
|
||||
|
||||
public static void onPlayerInit(PlayerDataScript handler, IPlayer player) {
|
||||
PlayerEvent.InitEvent event = new PlayerEvent.InitEvent(player);
|
||||
handler.callScript(EnumScriptType.INIT, event);
|
||||
|
||||
@@ -152,6 +152,9 @@ import kamkeel.npcs.client.renderer.RenderAbilityLaser;
|
||||
import kamkeel.npcs.client.renderer.RenderAbilityBeam;
|
||||
import kamkeel.npcs.client.renderer.RenderAbilitySweeper;
|
||||
import kamkeel.npcs.client.renderer.RenderAbilityZone;
|
||||
import kamkeel.npcs.client.renderer.RenderEnergyDome;
|
||||
import kamkeel.npcs.client.renderer.RenderEnergyPanel;
|
||||
import kamkeel.npcs.client.renderer.RenderEnergySlicer;
|
||||
import kamkeel.npcs.client.renderer.lightning.LightningHandler;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
@@ -159,6 +162,9 @@ import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import kamkeel.npcs.entity.EntityAbilitySweeper;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone;
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
import noppes.npcs.client.renderer.blocks.BlockBannerRenderer;
|
||||
import noppes.npcs.client.renderer.blocks.BlockBarrelRenderer;
|
||||
import noppes.npcs.client.renderer.blocks.BlockBeamRenderer;
|
||||
@@ -273,6 +279,9 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityAbilityBeam.class, new RenderAbilityBeam());
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityAbilitySweeper.class, new RenderAbilitySweeper());
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityAbilityZone.class, new RenderAbilityZone());
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityEnergyDome.class, new RenderEnergyDome());
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityEnergyPanel.class, new RenderEnergyPanel());
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityEnergySlicer.class, new RenderEnergySlicer());
|
||||
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityCustomNpc.class, new RenderCustomNpc());
|
||||
|
||||
|
||||
@@ -284,12 +284,12 @@ public class GuiFieldBuilder {
|
||||
String btnText = def.getButtonLabel();
|
||||
int btnW;
|
||||
if (def.hasClearAction()) {
|
||||
btnW = contentRight - 22 - fieldX;
|
||||
GuiNpcButton clearBtn = new GuiNpcButton(clearId, contentRight - 20, y, 20, 20, "X");
|
||||
btnW = fieldW - 22;
|
||||
GuiNpcButton clearBtn = new GuiNpcButton(clearId, fieldX + fieldW - 20, y, 20, 20, "X");
|
||||
sw.addButton(clearBtn);
|
||||
clearFieldMap.put(clearId, def);
|
||||
} else {
|
||||
btnW = contentRight - fieldX;
|
||||
btnW = fieldW;
|
||||
}
|
||||
GuiNpcButton btn = new GuiNpcButton(widgetId, fieldX, y, btnW, 20, btnText);
|
||||
Integer textColor = def.getButtonTextColor();
|
||||
|
||||
@@ -131,7 +131,13 @@ public enum EnumScriptType {
|
||||
ENERGY_PROJECTILE_TICK("energyProjectileTick"),
|
||||
ENERGY_PROJECTILE_ENTITY_IMPACT("energyProjectileEntityImpact"),
|
||||
ENERGY_PROJECTILE_BLOCK_IMPACT("energyProjectileBlockImpact"),
|
||||
ENERGY_PROJECTILE_EXPIRED("energyProjectileExpired");
|
||||
ENERGY_PROJECTILE_EXPIRED("energyProjectileExpired"),
|
||||
|
||||
// Energy Barrier Events
|
||||
ENERGY_BARRIER_SPAWNED("energyBarrierSpawned"),
|
||||
ENERGY_BARRIER_TICK("energyBarrierTick"),
|
||||
ENERGY_BARRIER_HIT("energyBarrierHit"),
|
||||
ENERGY_BARRIER_DESTROYED("energyBarrierDestroyed");
|
||||
|
||||
public String function;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.command.CommandHandler;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -127,6 +128,7 @@ import noppes.npcs.scripted.entity.ScriptEnergyBeam;
|
||||
import noppes.npcs.scripted.entity.ScriptEnergyDisc;
|
||||
import noppes.npcs.scripted.entity.ScriptEnergyLaser;
|
||||
import noppes.npcs.scripted.entity.ScriptEnergyOrb;
|
||||
import noppes.npcs.scripted.entity.ScriptEnergyProjectile;
|
||||
import noppes.npcs.scripted.entity.ScriptEntity;
|
||||
import noppes.npcs.scripted.entity.ScriptEntityItem;
|
||||
import noppes.npcs.scripted.entity.ScriptFishHook;
|
||||
@@ -470,6 +472,14 @@ public class NpcAPI extends AbstractNpcAPI {
|
||||
data = new ScriptEntityData(new ScriptEnergyDisc<>((EntityAbilityDisc) entity));
|
||||
else if (entity instanceof EntityAbilityLaser)
|
||||
data = new ScriptEntityData(new ScriptEnergyLaser<>((EntityAbilityLaser) entity));
|
||||
else if (entity instanceof kamkeel.npcs.entity.EntityEnergySlicer)
|
||||
data = new ScriptEntityData(new noppes.npcs.scripted.entity.ScriptEnergySlicer<>((kamkeel.npcs.entity.EntityEnergySlicer) entity));
|
||||
else if (entity instanceof EntityEnergyProjectile)
|
||||
data = new ScriptEntityData(new ScriptEnergyProjectile((EntityEnergyProjectile) entity));
|
||||
else if (entity instanceof kamkeel.npcs.entity.EntityEnergyDome)
|
||||
data = new ScriptEntityData(new noppes.npcs.scripted.entity.ScriptEnergyDome<>((kamkeel.npcs.entity.EntityEnergyDome) entity));
|
||||
else if (entity instanceof kamkeel.npcs.entity.EntityEnergyPanel)
|
||||
data = new ScriptEntityData(new noppes.npcs.scripted.entity.ScriptEnergyPanel<>((kamkeel.npcs.entity.EntityEnergyPanel) entity));
|
||||
else
|
||||
data = new ScriptEntityData(new ScriptEntity<>(entity));
|
||||
entity.registerExtendedProperties("ScriptedObject", data);
|
||||
|
||||
@@ -19,4 +19,8 @@ public class EntityType {
|
||||
public static final int ENERGY_BEAM = 15;
|
||||
public static final int ENERGY_DISC = 16;
|
||||
public static final int ENERGY_LASER = 17;
|
||||
public static final int ENERGY_SLICER = 18;
|
||||
public static final int ENERGY_BARRIER = 19;
|
||||
public static final int ENERGY_DOME = 20;
|
||||
public static final int ENERGY_PANEL = 21;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityEnergyAbility;
|
||||
import net.minecraft.entity.Entity;
|
||||
import noppes.npcs.api.entity.IEnergyAbility;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.scripted.NpcAPI;
|
||||
|
||||
/**
|
||||
* Base script wrapper for all energy ability entities.
|
||||
* Implements shared display, lightning, owner, and charging methods.
|
||||
*/
|
||||
public abstract class ScriptEnergyAbility<T extends EntityEnergyAbility> extends ScriptEntity<T> implements IEnergyAbility {
|
||||
|
||||
public ScriptEnergyAbility(T entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
// ==================== OWNER ====================
|
||||
|
||||
public int getOwnerEntityId() {
|
||||
return entity.getOwnerEntityId();
|
||||
}
|
||||
|
||||
public IEntity getOwner() {
|
||||
Entity owner = entity.getOwnerEntity();
|
||||
return owner != null ? NpcAPI.Instance().getIEntity(owner) : null;
|
||||
}
|
||||
|
||||
// ==================== DISPLAY ====================
|
||||
|
||||
public int getInnerColor() { return entity.getInnerColor(); }
|
||||
public void setInnerColor(int color) { entity.setInnerColor(color); }
|
||||
|
||||
public float getInnerAlpha() { return entity.getInnerAlpha(); }
|
||||
public void setInnerAlpha(float alpha) { entity.setInnerAlpha(alpha); }
|
||||
|
||||
public int getOuterColor() { return entity.getOuterColor(); }
|
||||
public void setOuterColor(int color) { entity.setOuterColor(color); }
|
||||
|
||||
public boolean isOuterColorEnabled() { return entity.isOuterColorEnabled(); }
|
||||
public void setOuterColorEnabled(boolean enabled) { entity.setOuterColorEnabled(enabled); }
|
||||
|
||||
public float getOuterColorWidth() { return entity.getOuterColorWidth(); }
|
||||
public void setOuterColorWidth(float width) { entity.setOuterColorWidth(width); }
|
||||
|
||||
public float getOuterColorAlpha() { return entity.getOuterColorAlpha(); }
|
||||
public void setOuterColorAlpha(float alpha) { entity.setOuterColorAlpha(alpha); }
|
||||
|
||||
// ==================== LIGHTNING ====================
|
||||
|
||||
public boolean hasLightningEffect() { return entity.hasLightningEffect(); }
|
||||
public void setLightningEffect(boolean enabled) { entity.setLightningEffect(enabled); }
|
||||
|
||||
public float getLightningDensity() { return entity.getLightningDensity(); }
|
||||
public void setLightningDensity(float density) { entity.setLightningDensity(density); }
|
||||
|
||||
public float getLightningRadius() { return entity.getLightningRadius(); }
|
||||
public void setLightningRadius(float radius) { entity.setLightningRadius(radius); }
|
||||
|
||||
public int getLightningFadeTime() { return entity.getLightningFadeTime(); }
|
||||
public void setLightningFadeTime(int ticks) { entity.setLightningFadeTime(ticks); }
|
||||
|
||||
// ==================== STATE ====================
|
||||
|
||||
public boolean isCharging() { return entity.isCharging(); }
|
||||
public float getChargeProgress() { return entity.getChargeProgress(); }
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityEnergyBarrier;
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import noppes.npcs.api.entity.IEnergyBarrier;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
/**
|
||||
* Base script wrapper for energy barrier entities (Dome, Panel).
|
||||
* All shared methods delegate directly to EntityEnergyBarrier base.
|
||||
*/
|
||||
public class ScriptEnergyBarrier<T extends EntityEnergyBarrier> extends ScriptEnergyAbility<T> implements IEnergyBarrier {
|
||||
|
||||
public ScriptEnergyBarrier(T entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return EntityType.ENERGY_BARRIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean typeOf(int type) {
|
||||
return type == EntityType.ENERGY_BARRIER || super.typeOf(type);
|
||||
}
|
||||
|
||||
// ==================== HEALTH ====================
|
||||
|
||||
public float getCurrentHealth() {
|
||||
return entity.getCurrentHealth();
|
||||
}
|
||||
|
||||
public void setCurrentHealth(float health) {
|
||||
entity.setCurrentHealth(health);
|
||||
}
|
||||
|
||||
public float getHealthPercent() {
|
||||
return entity.getHealthPercent();
|
||||
}
|
||||
|
||||
public float getMaxHealth() {
|
||||
return entity.getBarrierData().maxHealth;
|
||||
}
|
||||
|
||||
public void setMaxHealth(float maxHealth) {
|
||||
entity.getBarrierData().setMaxHealth(maxHealth);
|
||||
}
|
||||
|
||||
public boolean isUseHealth() {
|
||||
return entity.getBarrierData().useHealth;
|
||||
}
|
||||
|
||||
public void setUseHealth(boolean useHealth) {
|
||||
entity.getBarrierData().useHealth = useHealth;
|
||||
}
|
||||
|
||||
// ==================== DURATION ====================
|
||||
|
||||
public int getDuration() {
|
||||
return entity.getBarrierData().durationTicks;
|
||||
}
|
||||
|
||||
public void setDuration(int ticks) {
|
||||
entity.getBarrierData().setDurationTicks(ticks);
|
||||
}
|
||||
|
||||
public boolean isUseDuration() {
|
||||
return entity.getBarrierData().useDuration;
|
||||
}
|
||||
|
||||
public void setUseDuration(boolean useDuration) {
|
||||
entity.getBarrierData().useDuration = useDuration;
|
||||
}
|
||||
|
||||
// ==================== STATE (BARRIER-SPECIFIC) ====================
|
||||
|
||||
public int getTicksAlive() {
|
||||
return entity.getTicksAlive();
|
||||
}
|
||||
|
||||
// ==================== BARRIER ====================
|
||||
|
||||
public float getDefaultMultiplier() { return entity.getBarrierData().defaultMultiplier; }
|
||||
public void setDefaultMultiplier(float multiplier) { entity.getBarrierData().defaultMultiplier = multiplier; }
|
||||
|
||||
public boolean isKnockbackEnabled() { return entity.getBarrierData().knockbackEnabled; }
|
||||
public void setKnockbackEnabled(boolean enabled) { entity.getBarrierData().knockbackEnabled = enabled; }
|
||||
|
||||
public float getKnockbackStrength() { return entity.getBarrierData().knockbackStrength; }
|
||||
public void setKnockbackStrength(float strength) { entity.getBarrierData().knockbackStrength = strength; }
|
||||
|
||||
public int getKnockbackTarget() { return entity.getBarrierData().knockbackTarget; }
|
||||
public void setKnockbackTarget(int target) { entity.getBarrierData().knockbackTarget = target; }
|
||||
|
||||
public int getBarrierType() {
|
||||
return entity instanceof EntityEnergyDome ? 0 : 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityEnergyDome;
|
||||
import noppes.npcs.api.entity.IEnergyDome;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyDome<T extends EntityEnergyDome> extends ScriptEnergyBarrier<T> implements IEnergyDome {
|
||||
|
||||
public ScriptEnergyDome(T entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return EntityType.ENERGY_DOME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean typeOf(int type) {
|
||||
return type == EntityType.ENERGY_DOME || super.typeOf(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBarrierType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ==================== DOME-SPECIFIC ====================
|
||||
|
||||
public float getDomeRadius() { return entity.getDomeRadius(); }
|
||||
public void setDomeRadius(float radius) { entity.setDomeRadius(radius); }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityEnergyPanel;
|
||||
import noppes.npcs.api.entity.IEnergyPanel;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyPanel<T extends EntityEnergyPanel> extends ScriptEnergyBarrier<T> implements IEnergyPanel {
|
||||
|
||||
public ScriptEnergyPanel(T entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return EntityType.ENERGY_PANEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean typeOf(int type) {
|
||||
return type == EntityType.ENERGY_PANEL || super.typeOf(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBarrierType() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ==================== PANEL-SPECIFIC ====================
|
||||
|
||||
public float getPanelWidth() { return entity.getPanelData().panelWidth; }
|
||||
public void setPanelWidth(float width) { entity.getPanelData().setPanelWidth(width); }
|
||||
|
||||
public float getPanelHeight() { return entity.getPanelData().panelHeight; }
|
||||
public void setPanelHeight(float height) { entity.getPanelData().setPanelHeight(height); }
|
||||
|
||||
public float getPanelYaw() { return entity.getPanelYaw(); }
|
||||
|
||||
public int getPanelMode() { return entity.getMode().ordinal(); }
|
||||
|
||||
public boolean isLaunched() { return entity.getMode() == EntityEnergyPanel.PanelMode.LAUNCHED; }
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.api.entity.IEnergyProjectile;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.api.entity.IEntityLivingBase;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.scripted.NpcAPI;
|
||||
import noppes.npcs.scripted.constants.EntityType;
|
||||
|
||||
public class ScriptEnergyProjectile<T extends EntityAbilityProjectile> extends ScriptEntity<T> implements IEnergyProjectile {
|
||||
protected T entity;
|
||||
public class ScriptEnergyProjectile<T extends EntityEnergyProjectile> extends ScriptEnergyAbility<T> implements IEnergyProjectile {
|
||||
|
||||
public ScriptEnergyProjectile(T entity) {
|
||||
super(entity);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
// ==================== TYPE ====================
|
||||
@@ -36,14 +33,6 @@ public class ScriptEnergyProjectile<T extends EntityAbilityProjectile> extends S
|
||||
|
||||
// ==================== OWNER & TARGET ====================
|
||||
|
||||
public int getOwnerEntityId() {
|
||||
return entity.getOwnerEntityId();
|
||||
}
|
||||
|
||||
public IEntity getOwner() {
|
||||
return entity.getOwner();
|
||||
}
|
||||
|
||||
public void setOwner(IEntity owner) {
|
||||
if (owner != null) {
|
||||
entity.setOwnerEntityId(owner.getMCEntity().getEntityId());
|
||||
@@ -76,22 +65,7 @@ public class ScriptEnergyProjectile<T extends EntityAbilityProjectile> extends S
|
||||
entity.setProjectileSize(size);
|
||||
}
|
||||
|
||||
// ==================== DISPLAY ====================
|
||||
|
||||
public int getInnerColor() { return entity.getInnerColor(); }
|
||||
public void setInnerColor(int color) { entity.setInnerColor(color); }
|
||||
|
||||
public int getOuterColor() { return entity.getOuterColor(); }
|
||||
public void setOuterColor(int color) { entity.setOuterColor(color); }
|
||||
|
||||
public boolean isOuterColorEnabled() { return entity.isOuterColorEnabled(); }
|
||||
public void setOuterColorEnabled(boolean enabled) { entity.setOuterColorEnabled(enabled); }
|
||||
|
||||
public float getOuterColorWidth() { return entity.getOuterColorWidth(); }
|
||||
public void setOuterColorWidth(float width) { entity.setOuterColorWidth(width); }
|
||||
|
||||
public float getOuterColorAlpha() { return entity.getOuterColorAlpha(); }
|
||||
public void setOuterColorAlpha(float alpha) { entity.setOuterColorAlpha(alpha); }
|
||||
// ==================== DISPLAY (PROJECTILE-SPECIFIC) ====================
|
||||
|
||||
public float getRotationSpeed() { return entity.getRotationSpeed(); }
|
||||
public void setRotationSpeed(float speed) { entity.setRotationSpeed(speed); }
|
||||
@@ -103,20 +77,6 @@ public class ScriptEnergyProjectile<T extends EntityAbilityProjectile> extends S
|
||||
public float getInterpolatedRotationZ(float partialTicks) { return entity.getInterpolatedRotationZ(partialTicks); }
|
||||
public float getInterpolatedSize(float partialTicks) { return entity.getInterpolatedSize(partialTicks); }
|
||||
|
||||
// ==================== LIGHTNING ====================
|
||||
|
||||
public boolean hasLightningEffect() { return entity.hasLightningEffect(); }
|
||||
public void setLightningEffect(boolean enabled) { entity.setLightningEffect(enabled); }
|
||||
|
||||
public float getLightningDensity() { return entity.getLightningDensity(); }
|
||||
public void setLightningDensity(float density) { entity.setLightningDensity(density); }
|
||||
|
||||
public float getLightningRadius() { return entity.getLightningRadius(); }
|
||||
public void setLightningRadius(float radius) { entity.setLightningRadius(radius); }
|
||||
|
||||
public int getLightningFadeTime() { return entity.getLightningFadeTime(); }
|
||||
public void setLightningFadeTime(int ticks) { entity.setLightningFadeTime(ticks); }
|
||||
|
||||
// ==================== LIFESPAN ====================
|
||||
|
||||
public float getMaxDistance() { return entity.getMaxDistance(); }
|
||||
@@ -175,8 +135,6 @@ public class ScriptEnergyProjectile<T extends EntityAbilityProjectile> extends S
|
||||
// ==================== STATE ====================
|
||||
|
||||
public boolean hasHit() { return entity.getHasHit(); }
|
||||
public boolean isCharging() { return entity.isCharging(); }
|
||||
public float getChargeProgress() { return entity.getChargeProgress(); }
|
||||
|
||||
// ==================== FIRE ====================
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
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 {
|
||||
|
||||
public ScriptEnergySlicer(T entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return EntityType.ENERGY_SLICER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean typeOf(int type) {
|
||||
return type == EntityType.ENERGY_SLICER || super.typeOf(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEnergyType() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
// ==================== SLICER-SPECIFIC ====================
|
||||
|
||||
public float getSliceWidth() { return entity.getSliceWidth(); }
|
||||
public void setSliceWidth(float width) { entity.setSliceWidth(width); }
|
||||
|
||||
public float getSliceThickness() { return entity.getSliceThickness(); }
|
||||
public void setSliceThickness(float thickness) { entity.setSliceThickness(thickness); }
|
||||
|
||||
public boolean isPiercing() { return entity.isPiercing(); }
|
||||
public void setPiercing(boolean piercing) { entity.setPiercing(piercing); }
|
||||
|
||||
// ==================== FIRE ====================
|
||||
|
||||
@Override
|
||||
public void fire(IEntity target) {
|
||||
ensureSpawned();
|
||||
EntityLivingBase mcTarget = null;
|
||||
if (target != null && target.getMCEntity() instanceof EntityLivingBase) {
|
||||
mcTarget = (EntityLivingBase) target.getMCEntity();
|
||||
}
|
||||
entity.startMoving(mcTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fire(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);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
import kamkeel.npcs.entity.EntityAbilityLaser;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
@@ -532,7 +532,7 @@ public class ScriptEntity<T extends Entity> implements IEntity {
|
||||
else if (type == EntityType.NPC)
|
||||
cls = EntityNPCInterface.class;
|
||||
else if (type == EntityType.ENERGY_PROJECTILE)
|
||||
cls = EntityAbilityProjectile.class;
|
||||
cls = EntityEnergyProjectile.class;
|
||||
else if (type == EntityType.ENERGY_ORB)
|
||||
cls = EntityAbilityOrb.class;
|
||||
else if (type == EntityType.ENERGY_BEAM)
|
||||
|
||||
@@ -29,7 +29,7 @@ import noppes.npcs.constants.EnumMovingType;
|
||||
import noppes.npcs.constants.EnumNavType;
|
||||
import noppes.npcs.constants.EnumRoleType;
|
||||
import noppes.npcs.constants.EnumStandingType;
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import noppes.npcs.controllers.FactionController;
|
||||
import noppes.npcs.controllers.data.DialogOption;
|
||||
import noppes.npcs.controllers.data.Line;
|
||||
@@ -1467,7 +1467,7 @@ public class ScriptNpc<T extends EntityNPCInterface> extends ScriptLiving<T> imp
|
||||
}
|
||||
|
||||
public IEnergyProjectile[] getActiveEnergyProjectiles() {
|
||||
java.util.List<EntityAbilityProjectile> entities = EntityAbilityProjectile.getActiveProjectiles(npc.getEntityId());
|
||||
java.util.List<EntityEnergyProjectile> entities = EntityEnergyProjectile.getActiveProjectiles(npc.getEntityId());
|
||||
IEnergyProjectile[] result = new IEnergyProjectile[entities.size()];
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
result[i] = (IEnergyProjectile) NpcAPI.Instance().getIEntity(entities.get(i));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package noppes.npcs.scripted.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.AttributeController;
|
||||
import kamkeel.npcs.entity.EntityAbilityProjectile;
|
||||
import kamkeel.npcs.entity.EntityEnergyProjectile;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.packets.data.AchievementPacket;
|
||||
import kamkeel.npcs.network.packets.data.ChatAlertPacket;
|
||||
@@ -937,7 +937,7 @@ public class ScriptPlayer<T extends EntityPlayerMP> extends ScriptLivingBase<T>
|
||||
}
|
||||
|
||||
public IEnergyProjectile[] getActiveEnergyProjectiles() {
|
||||
List<EntityAbilityProjectile> entities = EntityAbilityProjectile.getActiveProjectiles(player.getEntityId());
|
||||
List<EntityEnergyProjectile> entities = EntityEnergyProjectile.getActiveProjectiles(player.getEntityId());
|
||||
IEnergyProjectile[] result = new IEnergyProjectile[entities.size()];
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
result[i] = (IEnergyProjectile) NpcAPI.Instance().getIEntity(entities.get(i));
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package noppes.npcs.scripted.event;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.Cancelable;
|
||||
import noppes.npcs.api.entity.IEnergyBarrier;
|
||||
import noppes.npcs.api.entity.IEnergyProjectile;
|
||||
import noppes.npcs.api.entity.IEntity;
|
||||
import noppes.npcs.api.event.IEnergyBarrierEvent;
|
||||
import noppes.npcs.constants.EnumScriptType;
|
||||
|
||||
public class EnergyBarrierEvent extends CustomNPCsEvent implements IEnergyBarrierEvent {
|
||||
public final IEnergyBarrier barrier;
|
||||
public final IEntity owner;
|
||||
|
||||
public EnergyBarrierEvent(IEnergyBarrier barrier) {
|
||||
this.barrier = barrier;
|
||||
this.owner = barrier.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEnergyBarrier getBarrier() {
|
||||
return barrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEntity getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookName() {
|
||||
return "energyBarrierEvent";
|
||||
}
|
||||
|
||||
public static class SpawnedEvent extends EnergyBarrierEvent implements IEnergyBarrierEvent.SpawnedEvent {
|
||||
public SpawnedEvent(IEnergyBarrier barrier) {
|
||||
super(barrier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookName() {
|
||||
return EnumScriptType.ENERGY_BARRIER_SPAWNED.function;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateEvent extends EnergyBarrierEvent implements IEnergyBarrierEvent.UpdateEvent {
|
||||
public UpdateEvent(IEnergyBarrier barrier) {
|
||||
super(barrier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookName() {
|
||||
return EnumScriptType.ENERGY_BARRIER_TICK.function;
|
||||
}
|
||||
}
|
||||
|
||||
@Cancelable
|
||||
public static class HitEvent extends EnergyBarrierEvent implements IEnergyBarrierEvent.HitEvent {
|
||||
private final IEnergyProjectile projectile;
|
||||
private float damage;
|
||||
|
||||
public HitEvent(IEnergyBarrier barrier, IEnergyProjectile projectile, float damage) {
|
||||
super(barrier);
|
||||
this.projectile = projectile;
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEnergyProjectile getProjectile() {
|
||||
return projectile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDamage(float damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookName() {
|
||||
return EnumScriptType.ENERGY_BARRIER_HIT.function;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DestroyedEvent extends EnergyBarrierEvent implements IEnergyBarrierEvent.DestroyedEvent {
|
||||
public DestroyedEvent(IEnergyBarrier barrier) {
|
||||
super(barrier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookName() {
|
||||
return EnumScriptType.ENERGY_BARRIER_DESTROYED.function;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user