mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 19:34:09 +00:00
Merge branch 'dev' into syntax-highlighter-unified
This commit is contained in:
commit
df6beb4f15
207 files changed
+10330
-2705
No files matched your search
+1
-1
@@ -6,7 +6,7 @@ plugins {
|
||||
id "dts.typescript-generator"
|
||||
}
|
||||
|
||||
version = "1.11-beta3"
|
||||
version = "1.11-beta4"
|
||||
group= "kamkeel.customnpc-plus"
|
||||
archivesBaseName = "CustomNPC-Plus"
|
||||
|
||||
|
||||
+1
-1
Submodule src/api updated: 22bce4b2ac...2c2f0c0d8f.
@@ -14,12 +14,12 @@ import java.util.List;
|
||||
/**
|
||||
* Renders the AbilityBeam entity with a head, tail orb, and curving trail.
|
||||
* The trail shows the path the head has traveled using laser-style rectangular segments.
|
||||
*
|
||||
* <p>
|
||||
* IMPORTANT: Trail points are stored RELATIVE to the origin position.
|
||||
* We render by translating to the origin first, then drawing all points relative to that.
|
||||
*
|
||||
* <p>
|
||||
* Trail segments now share vertices at connection points to prevent gaps during curves.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -182,7 +182,7 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
* Uses averaged perpendicular vectors at connection points to prevent gaps.
|
||||
*/
|
||||
private void renderSmoothTrail(List<Vec3> trail, float width, int innerColor, int outerColor,
|
||||
boolean outerColorEnabled, float outerColorWidth) {
|
||||
boolean outerColorEnabled, float outerColorWidth) {
|
||||
if (trail.size() < 2) return;
|
||||
|
||||
int trailSize = trail.size();
|
||||
@@ -213,7 +213,7 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
* Older trail points fade out based on their age.
|
||||
*/
|
||||
private void renderFadingTrail(EntityAbilityBeam beam, List<Vec3> trail, float width, int innerColor, int outerColor,
|
||||
boolean outerColorEnabled, float outerColorWidth) {
|
||||
boolean outerColorEnabled, float outerColorWidth) {
|
||||
if (trail.size() < 2) return;
|
||||
|
||||
List<Integer> ages = beam.getTrailPointAges();
|
||||
@@ -242,7 +242,7 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
* Render trail tube with age-based fading.
|
||||
*/
|
||||
private void renderFadingTrailTube(List<Vec3> trail, List<double[]> perpFrames, List<Integer> ages,
|
||||
int fadeTime, float width, int color, float baseAlpha) {
|
||||
int fadeTime, float width, int color, float baseAlpha) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
float halfWidth = width * 0.5f;
|
||||
@@ -392,13 +392,17 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
dy /= len;
|
||||
dz /= len;
|
||||
} else {
|
||||
dx = 0; dy = 0; dz = 1;
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
dz = 1;
|
||||
}
|
||||
|
||||
// Calculate perpendicular vectors using consistent up reference
|
||||
double upX = 0, upY = 1, upZ = 0;
|
||||
if (Math.abs(dy) > 0.9) {
|
||||
upX = 1; upY = 0; upZ = 0;
|
||||
upX = 1;
|
||||
upY = 0;
|
||||
upZ = 0;
|
||||
}
|
||||
|
||||
// Cross product for horizontal perpendicular
|
||||
@@ -417,8 +421,12 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
double vertY = dz * horzX - dx * horzZ;
|
||||
double vertZ = dx * horzY - dy * horzX;
|
||||
|
||||
frame[0] = horzX; frame[1] = horzY; frame[2] = horzZ;
|
||||
frame[3] = vertX; frame[4] = vertY; frame[5] = vertZ;
|
||||
frame[0] = horzX;
|
||||
frame[1] = horzY;
|
||||
frame[2] = horzZ;
|
||||
frame[3] = vertX;
|
||||
frame[4] = vertY;
|
||||
frame[5] = vertZ;
|
||||
frames.add(frame);
|
||||
}
|
||||
|
||||
@@ -429,7 +437,7 @@ public class RenderAbilityBeam extends RenderEnergyAbility {
|
||||
* Render the trail as a continuous tube using pre-computed perpendicular frames.
|
||||
*/
|
||||
private void renderTrailTube(List<Vec3> trail, List<double[]> perpFrames,
|
||||
float width, int color, float baseAlpha, boolean fadeFromStart) {
|
||||
float width, int color, float baseAlpha, boolean fadeFromStart) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
float halfWidth = width * 0.5f;
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.lwjgl.opengl.GL11;
|
||||
/**
|
||||
* Renders the AbilityDisc entity as a flat spinning square.
|
||||
* Rotates only on Y axis (flat spin like a saw blade).
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Renders the AbilityLaser entity as a rectangular beam with clear inner/outer colors.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -69,7 +69,9 @@ public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
// Calculate perpendicular vectors (one horizontal, one vertical relative to beam)
|
||||
double upX = 0, upY = 1, upZ = 0;
|
||||
if (Math.abs(dy) > 0.9) {
|
||||
upX = 1; upY = 0; upZ = 0;
|
||||
upX = 1;
|
||||
upY = 0;
|
||||
upZ = 0;
|
||||
}
|
||||
|
||||
// Cross product for horizontal perpendicular
|
||||
@@ -98,29 +100,29 @@ public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
float outerWidth = innerWidth + laser.getOuterColorWidth() * width;
|
||||
GL11.glDepthMask(false);
|
||||
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
outerWidth, laser.getOuterColor(), alpha * 0.4f);
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
outerWidth, laser.getOuterColor(), alpha * 0.4f);
|
||||
|
||||
// Render middle layer (halfway between inner and outer)
|
||||
float midWidth = innerWidth + (outerWidth - innerWidth) * 0.5f;
|
||||
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
midWidth, laser.getOuterColor(), alpha * 0.7f);
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
midWidth, laser.getOuterColor(), alpha * 0.7f);
|
||||
GL11.glDepthMask(true);
|
||||
}
|
||||
|
||||
// Render inner core (solid)
|
||||
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
innerWidth, laser.getInnerColor(), alpha);
|
||||
renderEndX, renderEndY, renderEndZ,
|
||||
horzX, horzY, horzZ, vertX, vertY, vertZ,
|
||||
innerWidth, laser.getInnerColor(), alpha);
|
||||
|
||||
// Render lightning along the laser beam
|
||||
if (laser.hasLightningEffect() && laser.getCurrentLength() > 0.1f) {
|
||||
renderLaserLightning(laser, renderStartX, renderStartY, renderStartZ,
|
||||
renderEndX, renderEndY, renderEndZ, width);
|
||||
renderEndX, renderEndY, renderEndZ, width);
|
||||
}
|
||||
|
||||
restoreRenderState();
|
||||
@@ -179,8 +181,8 @@ public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
* Render lightning effects along the laser beam at multiple points.
|
||||
*/
|
||||
private void renderLaserLightning(EntityAbilityLaser laser,
|
||||
double startX, double startY, double startZ,
|
||||
double endX, double endY, double endZ, float width) {
|
||||
double startX, double startY, double startZ,
|
||||
double endX, double endY, double endZ, float width) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(laser);
|
||||
|
||||
float density = laser.getLightningDensity();
|
||||
@@ -229,10 +231,10 @@ public class RenderAbilityLaser extends RenderEnergyAbility {
|
||||
* Render a beam as a 3D rectangular prism (box along a line).
|
||||
*/
|
||||
private void renderBeamRectangle(double x1, double y1, double z1,
|
||||
double x2, double y2, double z2,
|
||||
double horzX, double horzY, double horzZ,
|
||||
double vertX, double vertY, double vertZ,
|
||||
float width, int color, float alpha) {
|
||||
double x2, double y2, double z2,
|
||||
double horzX, double horzY, double horzZ,
|
||||
double vertX, double vertY, double vertZ,
|
||||
float width, int color, float alpha) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
|
||||
|
||||
@@ -104,8 +104,8 @@ public class RenderAbilitySweeper extends Render {
|
||||
* Uses the same approach as RenderAbilityBeam.renderBeamRectangle.
|
||||
*/
|
||||
private void renderBeamSegment(double x1, double y1, double z1,
|
||||
double x2, double y2, double z2,
|
||||
float width, float r, float g, float b, float a) {
|
||||
double x2, double y2, double z2,
|
||||
float width, float r, float g, float b, float a) {
|
||||
// Calculate direction
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
@@ -121,7 +121,9 @@ public class RenderAbilitySweeper extends Render {
|
||||
// Calculate perpendicular vectors
|
||||
double upX = 0, upY = 1, upZ = 0;
|
||||
if (Math.abs(dy) > 0.9) {
|
||||
upX = 1; upY = 0; upZ = 0;
|
||||
upX = 1;
|
||||
upY = 0;
|
||||
upZ = 0;
|
||||
}
|
||||
|
||||
// Cross product for horizontal perpendicular
|
||||
|
||||
@@ -8,13 +8,13 @@ import kamkeel.npcs.entity.EntityAbilityZone.AccentStyle;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ParticleMotion;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ZoneShape;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ZoneType;
|
||||
import noppes.npcs.client.fx.CustomFX;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import noppes.npcs.client.fx.CustomFX;
|
||||
import noppes.npcs.client.fx.ZoneParticleFX;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@@ -373,11 +373,21 @@ public class RenderAbilityZone extends Render {
|
||||
}
|
||||
}
|
||||
|
||||
private float ringR(Ctx c) { return c.outerEnabled ? c.outerR : c.ir; }
|
||||
private float ringG(Ctx c) { return c.outerEnabled ? c.outerG : c.ig; }
|
||||
private float ringB(Ctx c) { return c.outerEnabled ? c.outerB : c.ib; }
|
||||
private float ringR(Ctx c) {
|
||||
return c.outerEnabled ? c.outerR : c.ir;
|
||||
}
|
||||
|
||||
private static float sin(double v) { return (float) Math.sin(v); }
|
||||
private float ringG(Ctx c) {
|
||||
return c.outerEnabled ? c.outerG : c.ig;
|
||||
}
|
||||
|
||||
private float ringB(Ctx c) {
|
||||
return c.outerEnabled ? c.outerB : c.ib;
|
||||
}
|
||||
|
||||
private static float sin(double v) {
|
||||
return (float) Math.sin(v);
|
||||
}
|
||||
|
||||
private void renderSwayingAccents(Ctx c, float r, float g, float b, float a, float height) {
|
||||
if (height <= 0.1f) return;
|
||||
@@ -413,10 +423,22 @@ public class RenderAbilityZone extends Render {
|
||||
float frac = (j + 0.5f) / perSide;
|
||||
double lx, lz;
|
||||
switch (side) {
|
||||
case 0: lx = -c.radius + frac * 2 * c.radius; lz = -c.radius; break;
|
||||
case 1: lx = c.radius; lz = -c.radius + frac * 2 * c.radius; break;
|
||||
case 2: lx = c.radius - frac * 2 * c.radius; lz = c.radius; break;
|
||||
default: lx = -c.radius; lz = c.radius - frac * 2 * c.radius; break;
|
||||
case 0:
|
||||
lx = -c.radius + frac * 2 * c.radius;
|
||||
lz = -c.radius;
|
||||
break;
|
||||
case 1:
|
||||
lx = c.radius;
|
||||
lz = -c.radius + frac * 2 * c.radius;
|
||||
break;
|
||||
case 2:
|
||||
lx = c.radius - frac * 2 * c.radius;
|
||||
lz = c.radius;
|
||||
break;
|
||||
default:
|
||||
lx = -c.radius;
|
||||
lz = c.radius - frac * 2 * c.radius;
|
||||
break;
|
||||
}
|
||||
float swayX = 0.15f * sin(c.time * 0.08f + idx * 1.7f);
|
||||
float swayZ = 0.15f * sin(c.time * 0.06f + idx * 2.3f);
|
||||
@@ -467,10 +489,22 @@ public class RenderAbilityZone extends Render {
|
||||
float frac = (j + 0.5f) / perSide;
|
||||
double lx, lz;
|
||||
switch (side) {
|
||||
case 0: lx = -c.radius + frac * 2 * c.radius; lz = -c.radius; break;
|
||||
case 1: lx = c.radius; lz = -c.radius + frac * 2 * c.radius; break;
|
||||
case 2: lx = c.radius - frac * 2 * c.radius; lz = c.radius; break;
|
||||
default: lx = -c.radius; lz = c.radius - frac * 2 * c.radius; break;
|
||||
case 0:
|
||||
lx = -c.radius + frac * 2 * c.radius;
|
||||
lz = -c.radius;
|
||||
break;
|
||||
case 1:
|
||||
lx = c.radius;
|
||||
lz = -c.radius + frac * 2 * c.radius;
|
||||
break;
|
||||
case 2:
|
||||
lx = c.radius - frac * 2 * c.radius;
|
||||
lz = c.radius;
|
||||
break;
|
||||
default:
|
||||
lx = -c.radius;
|
||||
lz = c.radius - frac * 2 * c.radius;
|
||||
break;
|
||||
}
|
||||
float flicker = 0.3f + 0.7f * Math.abs(sin(c.time * 0.7f + idx * 3.14f));
|
||||
float lineAlpha = baseAlpha * flicker;
|
||||
@@ -506,10 +540,14 @@ public class RenderAbilityZone extends Render {
|
||||
int side = RANDOM.nextInt(4);
|
||||
double frac = RANDOM.nextDouble() * 2 - 1;
|
||||
switch (side) {
|
||||
case 0: return new double[]{frac * c.radius, -c.radius};
|
||||
case 1: return new double[]{frac * c.radius, c.radius};
|
||||
case 2: return new double[]{-c.radius, frac * c.radius};
|
||||
default: return new double[]{c.radius, frac * c.radius};
|
||||
case 0:
|
||||
return new double[]{frac * c.radius, -c.radius};
|
||||
case 1:
|
||||
return new double[]{frac * c.radius, c.radius};
|
||||
case 2:
|
||||
return new double[]{-c.radius, frac * c.radius};
|
||||
default:
|
||||
return new double[]{c.radius, frac * c.radius};
|
||||
}
|
||||
} else {
|
||||
double angle = RANDOM.nextDouble() * Math.PI * 2;
|
||||
@@ -519,9 +557,9 @@ public class RenderAbilityZone extends Render {
|
||||
}
|
||||
|
||||
private void spawnParticle(EntityAbilityZone zone, double offsetX, double offsetY, double offsetZ,
|
||||
double mx, double my, double mz,
|
||||
float r, float g, float b, float alpha,
|
||||
float scale, int maxAge, float gravity, boolean glow) {
|
||||
double mx, double my, double mz,
|
||||
float r, float g, float b, float alpha,
|
||||
float scale, int maxAge, float gravity, boolean glow) {
|
||||
ZoneParticleFX particle = new ZoneParticleFX(
|
||||
zone.worldObj,
|
||||
zone.posX + offsetX, zone.posY + offsetY, zone.posZ + offsetZ,
|
||||
@@ -587,7 +625,7 @@ public class RenderAbilityZone extends Render {
|
||||
}
|
||||
|
||||
private void renderRingLine(ZoneShape shape, float radius,
|
||||
float r, float g, float b, float a, float yOffset) {
|
||||
float r, float g, float b, float a, float yOffset) {
|
||||
switch (shape) {
|
||||
case CIRCLE:
|
||||
renderCircleRingLine(radius, r, g, b, a, yOffset);
|
||||
@@ -621,8 +659,8 @@ public class RenderAbilityZone extends Render {
|
||||
}
|
||||
|
||||
private void renderRotatingBorder(ZoneShape shape, float radius,
|
||||
float r, float g, float b, float a,
|
||||
float rotationDeg, float yOffset) {
|
||||
float r, float g, float b, float a,
|
||||
float rotationDeg, float yOffset) {
|
||||
int dashCount = 16;
|
||||
|
||||
if (shape == ZoneShape.SQUARE) {
|
||||
@@ -688,8 +726,8 @@ public class RenderAbilityZone extends Render {
|
||||
}
|
||||
|
||||
private void renderVerticalAccents(ZoneShape shape, float radius,
|
||||
float r, float g, float b, float a,
|
||||
float height, float rotationDeg) {
|
||||
float r, float g, float b, float a,
|
||||
float height, float rotationDeg) {
|
||||
if (height <= 0.1f) return;
|
||||
|
||||
Tessellator tess = Tessellator.instance;
|
||||
@@ -701,10 +739,22 @@ public class RenderAbilityZone extends Render {
|
||||
float frac = (j + 0.5f) / perSide;
|
||||
double lx, lz;
|
||||
switch (side) {
|
||||
case 0: lx = -radius + frac * 2 * radius; lz = -radius; break;
|
||||
case 1: lx = radius; lz = -radius + frac * 2 * radius; break;
|
||||
case 2: lx = radius - frac * 2 * radius; lz = radius; break;
|
||||
default: lx = -radius; lz = radius - frac * 2 * radius; break;
|
||||
case 0:
|
||||
lx = -radius + frac * 2 * radius;
|
||||
lz = -radius;
|
||||
break;
|
||||
case 1:
|
||||
lx = radius;
|
||||
lz = -radius + frac * 2 * radius;
|
||||
break;
|
||||
case 2:
|
||||
lx = radius - frac * 2 * radius;
|
||||
lz = radius;
|
||||
break;
|
||||
default:
|
||||
lx = -radius;
|
||||
lz = radius - frac * 2 * radius;
|
||||
break;
|
||||
}
|
||||
tess.startDrawing(GL11.GL_LINES);
|
||||
tess.setColorRGBA_F(r, g, b, a);
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.lwjgl.opengl.GL12;
|
||||
/**
|
||||
* Base renderer for ability projectiles.
|
||||
* Provides common GL state setup and rendering utilities.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy rendering system.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -212,8 +212,8 @@ public abstract class RenderEnergyAbility extends Render {
|
||||
* Render a line segment as a quad billboard facing the camera.
|
||||
*/
|
||||
protected void renderLineSegment(double x1, double y1, double z1,
|
||||
double x2, double y2, double z2,
|
||||
float width, int color, float alpha) {
|
||||
double x2, double y2, double z2,
|
||||
float width, int color, float alpha) {
|
||||
float[] rgb = extractRGB(color);
|
||||
float r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
|
||||
@@ -270,9 +270,10 @@ public abstract class RenderEnergyAbility extends Render {
|
||||
|
||||
/**
|
||||
* Render attached lightning arcs around an energy entity.
|
||||
* @param entity the 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
|
||||
* @param baseSize the entity's current render size/scale
|
||||
*/
|
||||
protected void renderAttachedLightning(EntityEnergyAbility entity, float innerScale, float baseSize) {
|
||||
AttachedLightningRenderer.LightningState state = getLightningState(entity);
|
||||
|
||||
@@ -95,7 +95,11 @@ public class RenderEnergyDome extends RenderEnergyBarrier {
|
||||
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; }
|
||||
if (nLen > 0) {
|
||||
nx /= nLen;
|
||||
ny /= nLen;
|
||||
nz /= nLen;
|
||||
}
|
||||
|
||||
tess.setNormal(nx, ny, nz);
|
||||
tess.addVertex(x1, y1, z1);
|
||||
|
||||
@@ -299,8 +299,8 @@ public class TelegraphRenderer {
|
||||
* @param partialTicks Partial ticks for interpolation
|
||||
*/
|
||||
public void renderTelegraphInGUI(TelegraphInstance instance,
|
||||
double centerX, double centerY, double centerZ,
|
||||
float scale, float partialTicks) {
|
||||
double centerX, double centerY, double centerZ,
|
||||
float scale, float partialTicks) {
|
||||
if (instance == null) return;
|
||||
|
||||
Telegraph telegraph = instance.getTelegraph();
|
||||
|
||||
@@ -165,8 +165,8 @@ public class AttachedLightningRenderer {
|
||||
* Generate a jagged lightning path between two points.
|
||||
*/
|
||||
private static List<double[]> generateLightningPath(double x1, double y1, double z1,
|
||||
double x2, double y2, double z2,
|
||||
int segments, float displacement) {
|
||||
double x2, double y2, double z2,
|
||||
int segments, float displacement) {
|
||||
List<double[]> points = new ArrayList<>();
|
||||
points.add(new double[]{x1, y1, z1});
|
||||
|
||||
@@ -257,8 +257,8 @@ public class AttachedLightningRenderer {
|
||||
* Create a lightning arc between two arbitrary points.
|
||||
*/
|
||||
public static LightningArc createArcBetween(double x1, double y1, double z1,
|
||||
double x2, double y2, double z2,
|
||||
float displacement, int outerColor, int innerColor, int maxAge) {
|
||||
double x2, double y2, double z2,
|
||||
float displacement, int outerColor, int innerColor, int maxAge) {
|
||||
int segments = 4 + rand.nextInt(3);
|
||||
List<double[]> points = generateLightningPath(x1, y1, z1, x2, y2, z2, segments, displacement);
|
||||
return new LightningArc(points, maxAge, outerColor, innerColor);
|
||||
|
||||
@@ -243,7 +243,7 @@ public class LightningBolt {
|
||||
|
||||
public Segment(Vec3d start, Vec3d end) {
|
||||
this(new BoltPoint(start, new Vec3d(0, 0, 0)),
|
||||
new BoltPoint(end, new Vec3d(0, 0, 0)), 1, 0, 0);
|
||||
new BoltPoint(end, new Vec3d(0, 0, 0)), 1, 0, 0);
|
||||
}
|
||||
|
||||
public void calcDiff() {
|
||||
|
||||
@@ -5,7 +5,6 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.client.renderer.lightning.LightningBolt.Segment;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -19,7 +18,7 @@ import java.awt.Color;
|
||||
/**
|
||||
* Handles rendering of lightning bolts in the world.
|
||||
* Adapted from Botania's LightningHandler by Vazkii/ChickenBones.
|
||||
*
|
||||
* <p>
|
||||
* Register this handler with: MinecraftForge.EVENT_BUS.register(new LightningHandler());
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -168,13 +167,13 @@ public class LightningHandler {
|
||||
/**
|
||||
* Spawn a lightning bolt between two points.
|
||||
*
|
||||
* @param world The world
|
||||
* @param start Start position
|
||||
* @param end End position
|
||||
* @param world The world
|
||||
* @param start Start position
|
||||
* @param end End position
|
||||
* @param ticksPerMeter Speed of bolt expansion
|
||||
* @param seed Random seed for consistent appearance
|
||||
* @param colorOuter Outer glow color (ARGB)
|
||||
* @param colorInner Inner core color (ARGB)
|
||||
* @param seed Random seed for consistent appearance
|
||||
* @param colorOuter Outer glow color (ARGB)
|
||||
* @param colorInner Inner core color (ARGB)
|
||||
*/
|
||||
public static void spawnLightningBolt(World world, Vec3d start, Vec3d end, float ticksPerMeter, long seed, int colorOuter, int colorInner) {
|
||||
LightningBolt bolt = new LightningBolt(world, start, end, ticksPerMeter, seed, colorOuter, colorInner);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package kamkeel.npcs.command;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
|
||||
import kamkeel.npcs.controllers.data.ability.UserType;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
import noppes.npcs.controllers.PlayerDataController;
|
||||
import noppes.npcs.controllers.data.PlayerAbilityData;
|
||||
import noppes.npcs.controllers.data.PlayerData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -77,7 +79,7 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
)
|
||||
public void reload(ICommandSender sender, String[] args) {
|
||||
AbilityController.Instance.load();
|
||||
sendResult(sender, "Abilities reloaded from disk.");
|
||||
sendResult(sender, "Abilities and chained abilities reloaded from disk.");
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
@@ -110,14 +112,15 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
return;
|
||||
}
|
||||
|
||||
String key = args[0];
|
||||
String key = joinArgs(args, 0);
|
||||
Ability ability = AbilityController.Instance.resolveAbility(key);
|
||||
if (ability == null) {
|
||||
sendError(sender, "No ability found for: " + key);
|
||||
return;
|
||||
}
|
||||
|
||||
sendResult(sender, "Ability: \u00A7b" + ability.getName());
|
||||
sendResult(sender, "Ability: \u00A7b" + ability.getDisplayName());
|
||||
sendResult(sender, " Name: \u00A77" + ability.getName());
|
||||
sendResult(sender, " Type: \u00A7d" + ability.getTypeId());
|
||||
sendResult(sender, " Cooldown: \u00A7e" + ability.getCooldownTicks() + " ticks");
|
||||
sendResult(sender, " Wind Up: \u00A7e" + ability.getWindUpTicks() + " ticks");
|
||||
@@ -162,46 +165,42 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
desc = "Unlock an ability for a player",
|
||||
desc = "Give an ability to a player",
|
||||
usage = "<player> <ability>"
|
||||
)
|
||||
public void unlock(ICommandSender sender, String[] args) {
|
||||
public void give(ICommandSender sender, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sendError(sender, "Usage: /kam ability unlock <player> <ability>");
|
||||
sendError(sender, "Usage: /kam ability give <player> <ability>");
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
String abilityKey = joinArgs(args, 1);
|
||||
|
||||
// Find player
|
||||
EntityPlayerMP player = (EntityPlayerMP) NoppesUtilServer.getPlayerByName(playerName);
|
||||
if (player == null) {
|
||||
sendError(sender, "Player not found: " + playerName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve ability
|
||||
Ability ability = AbilityController.Instance.resolveAbility(abilityKey);
|
||||
if (ability == null) {
|
||||
sendError(sender, "Ability not found: " + abilityKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the ability's canonical ID for storage (registry key for built-in, name for custom)
|
||||
// Use the ability's canonical ID for storage (registry key for built-in, UUID for custom)
|
||||
String canonicalKey = ability.getId();
|
||||
if (canonicalKey == null || canonicalKey.isEmpty()) {
|
||||
canonicalKey = abilityKey; // Fallback to user-provided key
|
||||
canonicalKey = abilityKey;
|
||||
}
|
||||
String displayName = ability.getName() != null ? ability.getName() : canonicalKey;
|
||||
String displayName = ability.getDisplayName();
|
||||
|
||||
// Check if ability allows players
|
||||
if (!ability.getAllowedBy().allowsPlayer()) {
|
||||
sendError(sender, "Ability '\u00A7b" + displayName + "\u00A7c' is NPC-only and cannot be given to players.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get player data and unlock
|
||||
PlayerData data = PlayerDataController.Instance.getPlayerData(player);
|
||||
if (data.abilityData.hasUnlockedAbility(canonicalKey)) {
|
||||
sendError(sender, "Player already has ability: " + displayName);
|
||||
@@ -209,39 +208,36 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
}
|
||||
|
||||
data.abilityData.unlockAbility(canonicalKey);
|
||||
sendResult(sender, "Unlocked ability '\u00A7b" + displayName + "\u00A77' for player \u00A7a" + playerName);
|
||||
sendResult(sender, "Gave ability '\u00A7b" + displayName + "\u00A77' to player \u00A7a" + playerName);
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
desc = "Lock (revoke) an ability from a player",
|
||||
desc = "Remove an ability from a player",
|
||||
usage = "<player> <ability>"
|
||||
)
|
||||
public void lock(ICommandSender sender, String[] args) {
|
||||
public void remove(ICommandSender sender, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sendError(sender, "Usage: /kam ability lock <player> <ability>");
|
||||
sendError(sender, "Usage: /kam ability remove <player> <ability>");
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
String abilityKey = joinArgs(args, 1);
|
||||
|
||||
// Find player
|
||||
EntityPlayerMP player = (EntityPlayerMP) NoppesUtilServer.getPlayerByName(playerName);
|
||||
if (player == null) {
|
||||
sendError(sender, "Player not found: " + playerName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve ability to get canonical key
|
||||
Ability ability = AbilityController.Instance.resolveAbility(abilityKey);
|
||||
String canonicalKey = abilityKey;
|
||||
String displayName = abilityKey;
|
||||
if (ability != null) {
|
||||
canonicalKey = ability.getId() != null ? ability.getId() : abilityKey;
|
||||
displayName = ability.getName() != null ? ability.getName() : canonicalKey;
|
||||
displayName = ability.getDisplayName();
|
||||
}
|
||||
|
||||
// Get player data and lock
|
||||
PlayerData data = PlayerDataController.Instance.getPlayerData(player);
|
||||
if (!data.abilityData.hasUnlockedAbility(canonicalKey)) {
|
||||
sendError(sender, "Player doesn't have ability: " + displayName);
|
||||
@@ -249,7 +245,98 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
}
|
||||
|
||||
data.abilityData.lockAbility(canonicalKey);
|
||||
sendResult(sender, "Locked ability '\u00A7b" + displayName + "\u00A77' from player \u00A7a" + playerName);
|
||||
sendResult(sender, "Removed ability '\u00A7b" + displayName + "\u00A77' from player \u00A7a" + playerName);
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
desc = "Give a chained ability to a player",
|
||||
usage = "<player> <chain>"
|
||||
)
|
||||
public void giveChain(ICommandSender sender, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sendError(sender, "Usage: /kam ability giveChain <player> <chain>");
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
String chainKey = joinArgs(args, 1);
|
||||
|
||||
EntityPlayerMP player = (EntityPlayerMP) NoppesUtilServer.getPlayerByName(playerName);
|
||||
if (player == null) {
|
||||
sendError(sender, "Player not found: " + playerName);
|
||||
return;
|
||||
}
|
||||
|
||||
ChainedAbility chain = AbilityController.Instance.resolveChainedAbility(chainKey);
|
||||
if (chain == null) {
|
||||
sendError(sender, "Chained ability not found: " + chainKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chain.getAllowedBy().allowsPlayer()) {
|
||||
sendError(sender, "Chained ability '\u00A7b" + chain.getDisplayName() + "\u00A7c' is NPC-only and cannot be given to players.");
|
||||
return;
|
||||
}
|
||||
|
||||
String chainId = chain.getId();
|
||||
if (chainId == null || chainId.isEmpty()) {
|
||||
sendError(sender, "Chained ability has no ID: " + chain.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Store by UUID: chain:<uuid>
|
||||
String storageKey = PlayerAbilityData.CHAIN_PREFIX + chainId;
|
||||
PlayerData data = PlayerDataController.Instance.getPlayerData(player);
|
||||
if (data.abilityData.hasUnlockedAbility(storageKey)) {
|
||||
sendError(sender, "Player already has chained ability: " + chain.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
data.abilityData.unlockAbility(storageKey);
|
||||
sendResult(sender, "Gave chained ability '\u00A7b" + chain.getDisplayName() + "\u00A77' to player \u00A7a" + playerName);
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
desc = "Remove a chained ability from a player",
|
||||
usage = "<player> <chain>"
|
||||
)
|
||||
public void removeChain(ICommandSender sender, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sendError(sender, "Usage: /kam ability removeChain <player> <chain>");
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = args[0];
|
||||
String chainKey = joinArgs(args, 1);
|
||||
|
||||
EntityPlayerMP player = (EntityPlayerMP) NoppesUtilServer.getPlayerByName(playerName);
|
||||
if (player == null) {
|
||||
sendError(sender, "Player not found: " + playerName);
|
||||
return;
|
||||
}
|
||||
|
||||
ChainedAbility chain = AbilityController.Instance.resolveChainedAbility(chainKey);
|
||||
if (chain == null) {
|
||||
sendError(sender, "Chained ability not found: " + chainKey);
|
||||
return;
|
||||
}
|
||||
|
||||
String chainId = chain.getId();
|
||||
if (chainId == null || chainId.isEmpty()) {
|
||||
sendError(sender, "Chained ability has no ID: " + chain.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Storage uses UUID: chain:<uuid>
|
||||
String storageKey = PlayerAbilityData.CHAIN_PREFIX + chainId;
|
||||
PlayerData data = PlayerDataController.Instance.getPlayerData(player);
|
||||
if (!data.abilityData.hasUnlockedAbility(storageKey)) {
|
||||
sendError(sender, "Player doesn't have chained ability: " + chain.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
data.abilityData.lockAbility(storageKey);
|
||||
sendResult(sender, "Removed chained ability '\u00A7b" + chain.getDisplayName() + "\u00A77' from player \u00A7a" + playerName);
|
||||
}
|
||||
|
||||
@SubCommand(
|
||||
@@ -283,14 +370,23 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
int selected = data.abilityData.getSelectedIndex();
|
||||
for (int i = 0; i < abilityKeys.length; i++) {
|
||||
String key = abilityKeys[i];
|
||||
Ability ability = AbilityController.Instance.resolveAbility(key);
|
||||
String displayName = ability != null && ability.getName() != null ? ability.getName() : key;
|
||||
String prefix = (i == selected) ? "\u00A7e> " : " ";
|
||||
// Show display name and key if different
|
||||
if (!displayName.equals(key)) {
|
||||
sendResult(sender, prefix + "\u00A7b" + displayName + " \u00A78[" + key + "]");
|
||||
|
||||
if (key.startsWith(PlayerAbilityData.CHAIN_PREFIX)) {
|
||||
// Chained ability
|
||||
String chainName = key.substring(PlayerAbilityData.CHAIN_PREFIX.length());
|
||||
ChainedAbility chain = AbilityController.Instance.resolveChainedAbility(chainName);
|
||||
String displayName = chain != null ? chain.getDisplayName() : chainName;
|
||||
sendResult(sender, prefix + "\u00A7d[Chain] \u00A7b" + displayName);
|
||||
} else {
|
||||
sendResult(sender, prefix + "\u00A7b" + displayName);
|
||||
// Regular ability
|
||||
Ability ability = AbilityController.Instance.resolveAbility(key);
|
||||
String displayName = ability != null ? ability.getDisplayName() : key;
|
||||
if (!displayName.equals(key)) {
|
||||
sendResult(sender, prefix + "\u00A7b" + displayName + " \u00A78[" + key + "]");
|
||||
} else {
|
||||
sendResult(sender, prefix + "\u00A7b" + displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,12 +402,33 @@ public class AbilityCommand extends CommandKamkeelBase {
|
||||
|
||||
/**
|
||||
* Get list of player-usable ability names (for tab completion).
|
||||
* Uses registry keys for built-in abilities and display names for custom abilities.
|
||||
* Used by CommandKamkeel for <ability> usage token.
|
||||
* Resolves UUIDs to names so tab completion shows human-readable names.
|
||||
* Used by CommandKamkeel for {@code <ability>} usage token.
|
||||
*/
|
||||
public static List<String> getPlayerAbilityNames() {
|
||||
List<String> keys = new ArrayList<>(AbilityController.Instance.getPlayerAbilityKeys());
|
||||
Collections.sort(keys);
|
||||
return keys;
|
||||
Set<String> keys = AbilityController.Instance.getPlayerAbilityKeys();
|
||||
List<String> names = new ArrayList<>();
|
||||
for (String key : keys) {
|
||||
Ability a = AbilityController.Instance.resolveAbility(key);
|
||||
names.add(a != null ? a.getName() : key);
|
||||
}
|
||||
Collections.sort(names);
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of player-usable chained ability names (for tab completion).
|
||||
* Used by CommandKamkeel for {@code <chain>} usage token.
|
||||
*/
|
||||
public static List<String> getPlayerChainNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (String chainName : AbilityController.Instance.getChainedAbilityNamesSet()) {
|
||||
ChainedAbility chain = AbilityController.Instance.getChainedAbility(chainName);
|
||||
if (chain != null && chain.getAllowedBy().allowsPlayer()) {
|
||||
names.add(chainName);
|
||||
}
|
||||
}
|
||||
Collections.sort(names);
|
||||
return names;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import static kamkeel.npcs.util.ColorUtil.sendMessage;
|
||||
import static kamkeel.npcs.util.ColorUtil.sendResult;
|
||||
|
||||
public class AuctionCommand extends CommandKamkeelBase {
|
||||
private static final int COMMAND_PAGE_SIZE = 10;
|
||||
|
||||
public AuctionCommand() {
|
||||
super();
|
||||
@@ -62,9 +63,10 @@ public class AuctionCommand extends CommandKamkeelBase {
|
||||
}
|
||||
}
|
||||
|
||||
List<AuctionListing> listings = controller.getActiveListings(null, page - 1, 10);
|
||||
page = Math.max(1, page);
|
||||
List<AuctionListing> listings = controller.getActiveListings(null, page - 1, COMMAND_PAGE_SIZE);
|
||||
int total = controller.getTotalActiveListings(null);
|
||||
int totalPages = Math.max(1, (int) Math.ceil((double) total / 10));
|
||||
int totalPages = Math.max(1, (int) Math.ceil((double) total / COMMAND_PAGE_SIZE));
|
||||
|
||||
if (listings.isEmpty()) {
|
||||
sendMessage(sender, "\u00A77No active auctions found");
|
||||
@@ -98,6 +100,10 @@ public class AuctionCommand extends CommandKamkeelBase {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
throw new CommandException("Usage: /auction view <player>");
|
||||
}
|
||||
|
||||
String playername = args[0];
|
||||
List<PlayerData> dataList = PlayerDataController.Instance.getPlayersData(sender, playername);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static kamkeel.npcs.command.AbilityCommand.getPlayerAbilityNames;
|
||||
import static kamkeel.npcs.command.AbilityCommand.getPlayerChainNames;
|
||||
import static kamkeel.npcs.command.EffectCommand.getSortedEffectNames;
|
||||
|
||||
public class CommandKamkeel extends CommandBase {
|
||||
@@ -139,6 +140,9 @@ public class CommandKamkeel extends CommandBase {
|
||||
} else if (usage.equals("<ability>")) {
|
||||
List<String> keys = getPlayerAbilityNames();
|
||||
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
|
||||
} else if (usage.equals("<chain>")) {
|
||||
List<String> keys = getPlayerChainNames();
|
||||
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,13 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class CommandKamkeelBase extends CommandBase {
|
||||
public Map<String, Method> subcommands = new HashMap<String, Method>();
|
||||
|
||||
+411
-49
@@ -1,7 +1,27 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
package kamkeel.npcs.controllers;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.type.*;
|
||||
import kamkeel.npcs.controllers.SyncController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPhase;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
|
||||
import kamkeel.npcs.controllers.data.ability.IAbilityAction;
|
||||
import kamkeel.npcs.controllers.data.ability.IAbilityExtender;
|
||||
import kamkeel.npcs.controllers.data.ability.IAbilityFieldProvider;
|
||||
import kamkeel.npcs.controllers.data.ability.IChainedAbilityFieldProvider;
|
||||
import kamkeel.npcs.controllers.data.ability.UserType;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCharge;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCutter;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityDash;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityGuard;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityHazard;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityHeal;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityHeavyHit;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityProjectile;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityShockwave;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilitySlam;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityTeleport;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityTrap;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityVortex;
|
||||
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;
|
||||
@@ -12,16 +32,22 @@ 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.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.CustomNpcs;
|
||||
import noppes.npcs.LogWriter;
|
||||
import noppes.npcs.api.handler.IAbilityHandler;
|
||||
import noppes.npcs.util.NBTJsonUtil;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -33,11 +59,13 @@ public class AbilityController implements IAbilityHandler {
|
||||
// ── Core Registries ──────────────────────────────────────────────────────
|
||||
private final Map<String, Supplier<Ability>> abilityTypes = new LinkedHashMap<>();
|
||||
private final Map<String, Ability> builtAbilities = new LinkedHashMap<>();
|
||||
private final Map<String, Ability> customAbilities = new LinkedHashMap<>();
|
||||
private final Map<String, Ability> customAbilities = new LinkedHashMap<>(); // name → Ability
|
||||
private final Map<String, Ability> customAbilitiesById = new LinkedHashMap<>(); // UUID → Ability
|
||||
|
||||
// ── Extension Points ─────────────────────────────────────────────────────
|
||||
private final Map<String, List<AbilityVariant>> externalVariants = new LinkedHashMap<>();
|
||||
private final List<IAbilityFieldProvider> fieldProviders = new ArrayList<>();
|
||||
private final List<IChainedAbilityFieldProvider> chainedFieldProviders = new ArrayList<>();
|
||||
private final List<IAbilityExtender> extenders = new ArrayList<>();
|
||||
private final List<Predicate<EntityPlayer>> flightCheckers = new ArrayList<>();
|
||||
|
||||
@@ -46,6 +74,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
// ── Chained Abilities ──────────────────────────────────────────────────
|
||||
private final Map<String, ChainedAbility> chainedAbilities = new LinkedHashMap<>(); // name → ChainedAbility
|
||||
private final Map<String, ChainedAbility> chainedAbilitiesById = new LinkedHashMap<>(); // UUID → ChainedAbility
|
||||
private int chainedAbilityRevision = 0;
|
||||
|
||||
// ── Derived State ────────────────────────────────────────────────────────
|
||||
private final Set<String> builtInTypeIds = new HashSet<>();
|
||||
|
||||
@@ -162,6 +195,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
public void load() {
|
||||
customAbilities.clear();
|
||||
customAbilitiesById.clear();
|
||||
int migrated = 0;
|
||||
|
||||
File dir = getDir();
|
||||
@@ -177,6 +211,13 @@ public class AbilityController implements IAbilityHandler {
|
||||
Ability ability = fromNBT(nbt);
|
||||
if (ability == null) continue;
|
||||
|
||||
// Skip built-in abilities that were erroneously saved as custom files
|
||||
if (ability.isBuiltIn()) {
|
||||
file.delete();
|
||||
LogWriter.info("Removed stale built-in ability file: " + filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Legacy migration: UUID-named files get renamed to name-based
|
||||
if (UUID_PATTERN.matcher(key).matches()) {
|
||||
String name = ability.getName();
|
||||
@@ -202,8 +243,24 @@ public class AbilityController implements IAbilityHandler {
|
||||
migrated++;
|
||||
}
|
||||
|
||||
ability.setId(key);
|
||||
// Ensure ability has a UUID; generate one for legacy abilities
|
||||
String uuid = ability.getId();
|
||||
if (uuid == null || uuid.isEmpty() || uuid.equals(key)) {
|
||||
// Legacy: id was the name or empty — generate a real UUID
|
||||
uuid = UUID.randomUUID().toString();
|
||||
ability.setId(uuid);
|
||||
// Re-save file with the new UUID
|
||||
try {
|
||||
NBTJsonUtil.SaveFile(file, ability.writeNBT());
|
||||
} catch (Exception ex) {
|
||||
LogWriter.error("Failed to save UUID for ability: " + key, ex);
|
||||
}
|
||||
migrated++;
|
||||
}
|
||||
|
||||
ability.setName(key);
|
||||
customAbilities.put(key, ability);
|
||||
customAbilitiesById.put(uuid, ability);
|
||||
} catch (Exception e) {
|
||||
LogWriter.error("Error loading custom ability: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
@@ -212,9 +269,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
customAbilityRevision++;
|
||||
if (migrated > 0) {
|
||||
LogWriter.info("Migrated " + migrated + " UUID-named abilities to name-based files");
|
||||
LogWriter.info("Migrated " + migrated + " abilities (UUID-named files or missing UUIDs)");
|
||||
}
|
||||
LogWriter.info("Loaded " + customAbilities.size() + " custom abilities");
|
||||
|
||||
loadChainedAbilities();
|
||||
}
|
||||
|
||||
private boolean nameFileExists(File dir, String name) {
|
||||
@@ -223,42 +282,50 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
public boolean saveCustomAbility(Ability ability) {
|
||||
if (ability == null) return false;
|
||||
if (ability.isBuiltIn()) return false;
|
||||
|
||||
String name = ability.getName();
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
|
||||
// Ensure unique name for new abilities (no existing id)
|
||||
String oldName = ability.getId();
|
||||
boolean isNew = oldName == null || oldName.isEmpty();
|
||||
String uuid = ability.getId();
|
||||
boolean isNew = (uuid == null || uuid.isEmpty());
|
||||
|
||||
if (isNew) {
|
||||
// Generate UUID for new ability
|
||||
uuid = UUID.randomUUID().toString();
|
||||
ability.setId(uuid);
|
||||
|
||||
// Ensure unique name
|
||||
while (hasCustomAbilityName(name)) {
|
||||
name = name + "_";
|
||||
}
|
||||
ability.setName(name);
|
||||
} else {
|
||||
// Existing ability — check for rename via UUID lookup
|
||||
Ability existing = customAbilitiesById.get(uuid);
|
||||
if (existing != null) {
|
||||
String oldName = existing.getName();
|
||||
if (!oldName.equals(name)) {
|
||||
// Name changed! Ensure new name is unique (excluding self)
|
||||
String testName = name;
|
||||
while (customAbilities.containsKey(testName) && !testName.equals(oldName)) {
|
||||
testName = testName + "_";
|
||||
}
|
||||
if (!testName.equals(name)) {
|
||||
name = testName;
|
||||
ability.setName(name);
|
||||
}
|
||||
|
||||
// Delete old file and remove old map entry
|
||||
File oldFile = new File(getDir(), oldName + ".json");
|
||||
if (oldFile.exists()) {
|
||||
oldFile.delete();
|
||||
}
|
||||
customAbilities.remove(oldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle rename: old id (previous name) differs from current name
|
||||
if (!isNew && !oldName.equals(name)) {
|
||||
// Check uniqueness of new name (excluding the entry being renamed)
|
||||
String testName = name;
|
||||
while (customAbilities.containsKey(testName) && !testName.equals(oldName)) {
|
||||
testName = testName + "_";
|
||||
}
|
||||
if (!testName.equals(name)) {
|
||||
name = testName;
|
||||
ability.setName(name);
|
||||
}
|
||||
|
||||
// Delete old file and remove old map entry
|
||||
File oldFile = new File(getDir(), oldName + ".json");
|
||||
if (oldFile.exists()) {
|
||||
oldFile.delete();
|
||||
}
|
||||
customAbilities.remove(oldName);
|
||||
}
|
||||
|
||||
ability.setId(name);
|
||||
|
||||
File dir = getDir();
|
||||
File fileNew = new File(dir, name + ".json_new");
|
||||
File fileCurrent = new File(dir, name + ".json");
|
||||
@@ -276,8 +343,9 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
|
||||
customAbilities.put(name, ability);
|
||||
customAbilitiesById.put(uuid, ability);
|
||||
customAbilityRevision++;
|
||||
LogWriter.info("Saved custom ability: " + name);
|
||||
LogWriter.info("Saved custom ability: " + name + " [" + uuid + "]");
|
||||
SyncController.syncAllCustomAbilities();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -292,6 +360,12 @@ public class AbilityController implements IAbilityHandler {
|
||||
Ability removed = customAbilities.remove(name);
|
||||
if (removed == null) return false;
|
||||
|
||||
// Also remove from UUID index
|
||||
String uuid = removed.getId();
|
||||
if (uuid != null && !uuid.isEmpty()) {
|
||||
customAbilitiesById.remove(uuid);
|
||||
}
|
||||
|
||||
File dir = getDir();
|
||||
File file = new File(dir, name + ".json");
|
||||
if (file.exists()) {
|
||||
@@ -318,7 +392,14 @@ public class AbilityController implements IAbilityHandler {
|
||||
|
||||
public void setCustomAbilities(Map<String, Ability> synced) {
|
||||
customAbilities.clear();
|
||||
customAbilitiesById.clear();
|
||||
customAbilities.putAll(synced);
|
||||
for (Ability ability : synced.values()) {
|
||||
String uuid = ability.getId();
|
||||
if (uuid != null && !uuid.isEmpty()) {
|
||||
customAbilitiesById.put(uuid, ability);
|
||||
}
|
||||
}
|
||||
customAbilityRevision++;
|
||||
}
|
||||
|
||||
@@ -334,6 +415,229 @@ public class AbilityController implements IAbilityHandler {
|
||||
return dir;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// CHAINED ABILITIES
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
private void loadChainedAbilities() {
|
||||
chainedAbilities.clear();
|
||||
chainedAbilitiesById.clear();
|
||||
|
||||
File dir = getChainedDir();
|
||||
File[] files = dir.exists() ? dir.listFiles() : null;
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (!file.isFile() || !file.getName().endsWith(".json")) continue;
|
||||
try {
|
||||
String filename = file.getName();
|
||||
String key = filename.substring(0, filename.length() - 5);
|
||||
|
||||
NBTTagCompound nbt = NBTJsonUtil.LoadFile(file);
|
||||
ChainedAbility chain = new ChainedAbility();
|
||||
chain.readNBT(nbt);
|
||||
|
||||
chain.setName(key);
|
||||
chainedAbilities.put(key, chain);
|
||||
|
||||
String uuid = chain.getId();
|
||||
if (uuid != null && !uuid.isEmpty()) {
|
||||
chainedAbilitiesById.put(uuid, chain);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogWriter.error("Error loading chained ability: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chainedAbilityRevision++;
|
||||
LogWriter.info("Loaded " + chainedAbilities.size() + " chained abilities");
|
||||
}
|
||||
|
||||
public boolean saveChainedAbility(ChainedAbility chain) {
|
||||
if (chain == null) return false;
|
||||
|
||||
String name = chain.getName();
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
|
||||
String uuid = chain.getId();
|
||||
boolean isNew = (uuid == null || uuid.isEmpty());
|
||||
|
||||
if (isNew) {
|
||||
uuid = UUID.randomUUID().toString();
|
||||
chain.setId(uuid);
|
||||
|
||||
while (hasChainedAbilityName(name)) {
|
||||
name = name + "_";
|
||||
}
|
||||
chain.setName(name);
|
||||
} else {
|
||||
ChainedAbility existing = chainedAbilitiesById.get(uuid);
|
||||
if (existing != null) {
|
||||
String oldName = existing.getName();
|
||||
if (!oldName.equals(name)) {
|
||||
String testName = name;
|
||||
while (chainedAbilities.containsKey(testName) && !testName.equals(oldName)) {
|
||||
testName = testName + "_";
|
||||
}
|
||||
if (!testName.equals(name)) {
|
||||
name = testName;
|
||||
chain.setName(name);
|
||||
}
|
||||
|
||||
File oldFile = new File(getChainedDir(), oldName + ".json");
|
||||
if (oldFile.exists()) {
|
||||
oldFile.delete();
|
||||
}
|
||||
chainedAbilities.remove(oldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File dir = getChainedDir();
|
||||
File fileNew = new File(dir, name + ".json_new");
|
||||
File fileCurrent = new File(dir, name + ".json");
|
||||
|
||||
try {
|
||||
NBTTagCompound nbt = chain.writeNBT();
|
||||
NBTJsonUtil.SaveFile(fileNew, nbt);
|
||||
|
||||
if (fileCurrent.exists()) {
|
||||
fileCurrent.delete();
|
||||
}
|
||||
fileNew.renameTo(fileCurrent);
|
||||
if (fileNew.exists()) {
|
||||
fileNew.delete();
|
||||
}
|
||||
|
||||
chainedAbilities.put(name, chain);
|
||||
chainedAbilitiesById.put(uuid, chain);
|
||||
chainedAbilityRevision++;
|
||||
LogWriter.info("Saved chained ability: " + name + " [" + uuid + "]");
|
||||
SyncController.syncAllChainedAbilities();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogWriter.error("Error saving chained ability: " + name, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteChainedAbility(String name) {
|
||||
if (name == null || name.isEmpty()) return false;
|
||||
|
||||
ChainedAbility removed = chainedAbilities.remove(name);
|
||||
if (removed == null) return false;
|
||||
|
||||
String uuid = removed.getId();
|
||||
if (uuid != null && !uuid.isEmpty()) {
|
||||
chainedAbilitiesById.remove(uuid);
|
||||
}
|
||||
|
||||
File dir = getChainedDir();
|
||||
File file = new File(dir, name + ".json");
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
|
||||
chainedAbilityRevision++;
|
||||
LogWriter.info("Deleted chained ability: " + name);
|
||||
SyncController.syncAllChainedAbilities();
|
||||
return true;
|
||||
}
|
||||
|
||||
public ChainedAbility resolveChainedAbility(String key) {
|
||||
if (key == null || key.isEmpty()) return null;
|
||||
|
||||
ChainedAbility byId = chainedAbilitiesById.get(key);
|
||||
if (byId != null) return byId.deepCopy();
|
||||
|
||||
ChainedAbility chain = chainedAbilities.get(key);
|
||||
if (chain != null) return chain.deepCopy();
|
||||
|
||||
for (Map.Entry<String, ChainedAbility> entry : chainedAbilities.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(key)) {
|
||||
return entry.getValue().deepCopy();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canResolveChainedAbility(String key) {
|
||||
if (key == null || key.isEmpty()) return false;
|
||||
if (chainedAbilitiesById.containsKey(key)) return true;
|
||||
if (chainedAbilities.containsKey(key)) return true;
|
||||
for (String name : chainedAbilities.keySet()) {
|
||||
if (name.equalsIgnoreCase(key)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChainedAbility getChainedAbility(String name) {
|
||||
ChainedAbility chain = chainedAbilities.get(name);
|
||||
return chain != null ? chain.deepCopy() : null;
|
||||
}
|
||||
|
||||
public ChainedAbility getChainedAbilityByUUID(String uuid) {
|
||||
return chainedAbilitiesById.get(uuid);
|
||||
}
|
||||
|
||||
public Set<String> getChainedAbilityNamesSet() {
|
||||
return new LinkedHashSet<>(chainedAbilities.keySet());
|
||||
}
|
||||
|
||||
public Map<String, ChainedAbility> getChainedAbilities() {
|
||||
return chainedAbilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getChainedAbilityNames() {
|
||||
return chainedAbilities.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChainedAbilityName(String name) {
|
||||
return chainedAbilities.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteChainedAbilityByName(String name) {
|
||||
return deleteChainedAbility(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveChainedAbility(noppes.npcs.api.ability.IChainedAbility chain) {
|
||||
if (chain instanceof ChainedAbility) {
|
||||
return saveChainedAbility((ChainedAbility) chain);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getChainedAbilityRevision() {
|
||||
return chainedAbilityRevision;
|
||||
}
|
||||
|
||||
public void setChainedAbilities(Map<String, ChainedAbility> synced) {
|
||||
chainedAbilities.clear();
|
||||
chainedAbilitiesById.clear();
|
||||
chainedAbilities.putAll(synced);
|
||||
for (ChainedAbility chain : synced.values()) {
|
||||
String uuid = chain.getId();
|
||||
if (uuid != null && !uuid.isEmpty()) {
|
||||
chainedAbilitiesById.put(uuid, chain);
|
||||
}
|
||||
}
|
||||
chainedAbilityRevision++;
|
||||
}
|
||||
|
||||
private File getChainedDir() {
|
||||
File dir = new File(CustomNpcs.getWorldSaveDirectory(), "abilities" + File.separator + "chained");
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// RESOLUTION
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -341,17 +645,28 @@ public class AbilityController implements IAbilityHandler {
|
||||
public Ability resolveAbility(String key) {
|
||||
if (key == null || key.isEmpty()) return null;
|
||||
|
||||
// Custom: UUID lookup (most common for persistent references)
|
||||
Ability byUuid = customAbilitiesById.get(key);
|
||||
if (byUuid != null) return byUuid.deepCopy();
|
||||
|
||||
// Built-in: exact name
|
||||
Ability builtIn = builtAbilities.get(key);
|
||||
if (builtIn != null) return builtIn.deepCopy();
|
||||
|
||||
// Built-in: case-insensitive name
|
||||
// Built-in: case-insensitive map key
|
||||
for (Map.Entry<String, Ability> entry : builtAbilities.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(key)) {
|
||||
return entry.getValue().deepCopy();
|
||||
}
|
||||
}
|
||||
|
||||
// Built-in: by ability name (name may differ from map key, e.g. "Ki Fist" vs "ki_fist")
|
||||
for (Ability ability : builtAbilities.values()) {
|
||||
if (ability.getName() != null && ability.getName().equalsIgnoreCase(key)) {
|
||||
return ability.deepCopy();
|
||||
}
|
||||
}
|
||||
|
||||
// Built-in: registry key / ID
|
||||
for (Ability ability : builtAbilities.values()) {
|
||||
if (ability.getId() != null && ability.getId().equalsIgnoreCase(key)) {
|
||||
@@ -359,7 +674,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom: exact name
|
||||
// Custom: exact name (fallback for legacy references)
|
||||
Ability custom = customAbilities.get(key);
|
||||
if (custom != null) return custom.deepCopy();
|
||||
|
||||
@@ -381,11 +696,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
keys.add(id);
|
||||
}
|
||||
}
|
||||
// Custom abilities keyed by name
|
||||
// Custom abilities keyed by UUID (stable references)
|
||||
for (Ability ability : customAbilities.values()) {
|
||||
String name = ability.getName();
|
||||
if (name != null && !name.isEmpty()) {
|
||||
keys.add(name);
|
||||
String id = ability.getId();
|
||||
if (id != null && !id.isEmpty()) {
|
||||
keys.add(id);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
@@ -401,12 +716,12 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Custom abilities keyed by name
|
||||
// Custom abilities keyed by UUID (stable references)
|
||||
for (Ability ability : customAbilities.values()) {
|
||||
if (ability.getAllowedBy().allowsPlayer()) {
|
||||
String name = ability.getName();
|
||||
if (name != null && !name.isEmpty()) {
|
||||
keys.add(name);
|
||||
String id = ability.getId();
|
||||
if (id != null && !id.isEmpty()) {
|
||||
keys.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,7 +729,16 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
|
||||
public boolean hasAbility(String key) {
|
||||
return builtAbilities.containsKey(key) || customAbilities.containsKey(key);
|
||||
return builtAbilities.containsKey(key) || customAbilities.containsKey(key)
|
||||
|| customAbilitiesById.containsKey(key);
|
||||
}
|
||||
|
||||
public Ability getCustomAbilityByUUID(String uuid) {
|
||||
return customAbilitiesById.get(uuid);
|
||||
}
|
||||
|
||||
public Ability getCustomAbilityByName(String name) {
|
||||
return customAbilities.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,6 +748,9 @@ public class AbilityController implements IAbilityHandler {
|
||||
public boolean canResolveAbility(String key) {
|
||||
if (key == null || key.isEmpty()) return false;
|
||||
|
||||
// Custom: UUID lookup (most common for persistent references)
|
||||
if (customAbilitiesById.containsKey(key)) return true;
|
||||
|
||||
// Built-in: exact name
|
||||
if (builtAbilities.containsKey(key)) return true;
|
||||
|
||||
@@ -437,7 +764,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
if (ability.getId() != null && ability.getId().equalsIgnoreCase(key)) return true;
|
||||
}
|
||||
|
||||
// Custom: exact name
|
||||
// Custom: exact name (fallback for legacy references)
|
||||
if (customAbilities.containsKey(key)) return true;
|
||||
|
||||
// Custom: case-insensitive name
|
||||
@@ -448,6 +775,31 @@ public class AbilityController implements IAbilityHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// UNIFIED ACTION RESOLUTION
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Resolve any action key to an IAbilityAction.
|
||||
* Checks abilities first, then chained abilities.
|
||||
*/
|
||||
public IAbilityAction resolveAction(String key) {
|
||||
if (key == null || key.isEmpty()) return null;
|
||||
|
||||
Ability ability = resolveAbility(key);
|
||||
if (ability != null) return ability;
|
||||
|
||||
return resolveChainedAbility(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a key can be resolved as any action (ability or chain).
|
||||
*/
|
||||
public boolean canResolveAction(String key) {
|
||||
if (canResolveAbility(key)) return true;
|
||||
return canResolveChainedAbility(key);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// EXTENSION POINTS
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -467,7 +819,8 @@ public class AbilityController implements IAbilityHandler {
|
||||
// If no built-in variants exist but external ones do,
|
||||
// inject a "Base" variant so the user always gets a choice
|
||||
if (result.isEmpty()) {
|
||||
result.add(new AbilityVariant("ability.variant.base", a -> {}));
|
||||
result.add(new AbilityVariant("ability.variant.base", a -> {
|
||||
}));
|
||||
}
|
||||
result.addAll(ext);
|
||||
}
|
||||
@@ -482,6 +835,14 @@ public class AbilityController implements IAbilityHandler {
|
||||
return fieldProviders;
|
||||
}
|
||||
|
||||
public void registerChainedFieldProvider(IChainedAbilityFieldProvider provider) {
|
||||
chainedFieldProviders.add(provider);
|
||||
}
|
||||
|
||||
public List<IChainedAbilityFieldProvider> getChainedFieldProviders() {
|
||||
return chainedFieldProviders;
|
||||
}
|
||||
|
||||
public void registerExtender(IAbilityExtender extender) {
|
||||
extenders.add(extender);
|
||||
}
|
||||
@@ -545,7 +906,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
double knockbackDirX, double knockbackDirZ) {
|
||||
for (IAbilityExtender ext : extenders) {
|
||||
if (ext.onAbilityDamage(ability, caster, target, damage, knockback, knockbackUp,
|
||||
knockbackDirX, knockbackDirZ)) {
|
||||
knockbackDirX, knockbackDirZ)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -621,4 +982,5 @@ public class AbilityController implements IAbilityHandler {
|
||||
public boolean deleteCustomAbilityByName(String name) {
|
||||
return deleteCustomAbility(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import kamkeel.npcs.addon.DBCAddon;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
|
||||
import kamkeel.npcs.network.LargeAbstractPacket;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.enums.EnumSyncAction;
|
||||
@@ -39,8 +41,6 @@ import noppes.npcs.controllers.data.Quest;
|
||||
import noppes.npcs.controllers.data.QuestCategory;
|
||||
import noppes.npcs.controllers.data.RecipeAnvil;
|
||||
import noppes.npcs.controllers.data.RecipeCarpentry;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
@@ -76,7 +76,8 @@ public class SyncController {
|
||||
EnumSyncType.CUSTOM_EFFECTS,
|
||||
EnumSyncType.MAGIC,
|
||||
EnumSyncType.MAGIC_CYCLE,
|
||||
EnumSyncType.CUSTOM_ABILITY
|
||||
EnumSyncType.CUSTOM_ABILITY,
|
||||
EnumSyncType.CHAINED_ABILITY
|
||||
};
|
||||
|
||||
public static void load() {
|
||||
@@ -93,6 +94,7 @@ public class SyncController {
|
||||
registerCache(EnumSyncType.MAGIC, SyncController::magicsNBT);
|
||||
registerCache(EnumSyncType.MAGIC_CYCLE, SyncController::magicCyclesNBT);
|
||||
registerCache(EnumSyncType.CUSTOM_ABILITY, SyncController::customAbilitiesNBT);
|
||||
registerCache(EnumSyncType.CHAINED_ABILITY, SyncController::chainedAbilitiesNBT);
|
||||
}
|
||||
|
||||
public static void syncPlayer(EntityPlayerMP player) {
|
||||
@@ -349,6 +351,27 @@ public class SyncController {
|
||||
updateAllPlayerRevisions(EnumSyncType.CUSTOM_ABILITY, payload.getRevision());
|
||||
}
|
||||
|
||||
public static NBTTagCompound chainedAbilitiesNBT() {
|
||||
NBTTagList list = new NBTTagList();
|
||||
NBTTagCompound compound = new NBTTagCompound();
|
||||
for (Map.Entry<String, ChainedAbility> entry : AbilityController.Instance.getChainedAbilities().entrySet()) {
|
||||
NBTTagCompound chainNBT = entry.getValue().writeNBT();
|
||||
chainNBT.setString("ChainedAbilityId", entry.getKey());
|
||||
list.appendTag(chainNBT);
|
||||
}
|
||||
compound.setTag("Data", list);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public static void syncAllChainedAbilities() {
|
||||
CachedSyncPayload payload = rebuildNow(EnumSyncType.CHAINED_ABILITY);
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
PacketHandler.Instance.sendToAll(new SyncPacket(EnumSyncType.CHAINED_ABILITY, payload));
|
||||
updateAllPlayerRevisions(EnumSyncType.CHAINED_ABILITY, payload.getRevision());
|
||||
}
|
||||
|
||||
public static void syncPlayerData(EntityPlayerMP player, boolean update) {
|
||||
PlayerData data = PlayerData.get(player);
|
||||
if (data != null) {
|
||||
@@ -626,16 +649,30 @@ public class SyncController {
|
||||
LinkedHashMap<String, Ability> sync = new LinkedHashMap<>();
|
||||
for (int i = 0; i < list.tagCount(); i++) {
|
||||
NBTTagCompound nbt = list.getCompoundTagAt(i);
|
||||
String uuid = nbt.getString("CustomAbilityId");
|
||||
String name = nbt.getString("CustomAbilityId");
|
||||
Ability ability = AbilityController.Instance.fromNBT(nbt);
|
||||
if (ability != null) {
|
||||
ability.setId(uuid);
|
||||
sync.put(uuid, ability);
|
||||
ability.setName(name);
|
||||
sync.put(name, ability);
|
||||
}
|
||||
}
|
||||
AbilityController.Instance.setCustomAbilities(sync);
|
||||
break;
|
||||
}
|
||||
case CHAINED_ABILITY: {
|
||||
NBTTagList list = fullCompound.getTagList("Data", 10);
|
||||
LinkedHashMap<String, ChainedAbility> sync = new LinkedHashMap<>();
|
||||
for (int i = 0; i < list.tagCount(); i++) {
|
||||
NBTTagCompound nbt = list.getCompoundTagAt(i);
|
||||
String id = nbt.getString("ChainedAbilityId");
|
||||
ChainedAbility chain = new ChainedAbility();
|
||||
chain.readNBT(nbt);
|
||||
chain.setName(id);
|
||||
sync.put(id, chain);
|
||||
}
|
||||
AbilityController.Instance.setChainedAbilities(sync);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClientCacheHandler.updateClientRevision(enumSyncType, revision);
|
||||
@@ -886,6 +923,8 @@ public class SyncController {
|
||||
return EnumSet.of(EnumSyncType.CUSTOM_EFFECTS);
|
||||
case CUSTOM_ABILITY:
|
||||
return EnumSet.of(EnumSyncType.CUSTOM_ABILITY);
|
||||
case CHAINED_ABILITY:
|
||||
return EnumSet.of(EnumSyncType.CHAINED_ABILITY);
|
||||
default:
|
||||
return EnumSet.noneOf(EnumSyncType.class);
|
||||
}
|
||||
|
||||
@@ -2,51 +2,53 @@ package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.StatCollector;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.DataAbilities;
|
||||
import noppes.npcs.NpcDamageSource;
|
||||
import noppes.npcs.api.INbt;
|
||||
import noppes.npcs.api.ability.IAbility;
|
||||
import noppes.npcs.api.entity.IPlayer;
|
||||
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import noppes.npcs.controllers.data.Frame;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
import noppes.npcs.api.entity.IPlayer;
|
||||
import noppes.npcs.controllers.ScriptController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
import noppes.npcs.controllers.data.Frame;
|
||||
import noppes.npcs.controllers.data.PlayerDataScript;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
import noppes.npcs.scripted.NpcAPI;
|
||||
import noppes.npcs.scripted.event.AbilityEvent;
|
||||
import noppes.npcs.scripted.event.player.PlayerAbilityEvent;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
public abstract class Ability implements IAbility {
|
||||
public abstract class Ability implements IAbility, IAbilityAction {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CONFIGURATION (saved to NBT)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String typeId; // e.g., "ability.cnpc.slam" (also used as lang key)
|
||||
protected String id = ""; // UUID for custom, registry key for built-in
|
||||
protected String name = ""; // Unique file key / identifier
|
||||
protected String displayName = ""; // Cosmetic name (falls back to name when empty)
|
||||
protected String typeId = ""; // e.g., "ability.cnpc.slam" (also used as lang key)
|
||||
|
||||
// Selection
|
||||
protected int weight = 10;
|
||||
@@ -102,6 +104,35 @@ public abstract class Ability implements IAbility {
|
||||
// Cooldown override
|
||||
protected boolean ignoreCooldown = false;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// BUILT-IN (set in constructor via configureAsBuiltIn, NOT persisted)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
protected transient boolean builtIn = false;
|
||||
protected transient String registryKey;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// TOGGLE CONFIGURATION (saved to NBT for custom abilities)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Number of toggle states. 0 = not toggleable, 1 = binary on/off, 2+ = multi-state cycling.
|
||||
* Cycling order: Off(0) -> State 1 -> State 2 -> ... -> State N -> Off(0)
|
||||
*/
|
||||
protected int toggleStates = 0;
|
||||
|
||||
/**
|
||||
* Whether the toggled-ON state ticks each game tick (e.g., Kaioken drains ki per tick)
|
||||
*/
|
||||
protected boolean hasActiveToggle = false;
|
||||
|
||||
/**
|
||||
* Optional display labels for each toggle state (1-indexed).
|
||||
* Used in ability wheel/hotbar to show current state name.
|
||||
* Null means no labels. Array length should match toggleStates.
|
||||
*/
|
||||
protected String[] toggleStateLabels;
|
||||
|
||||
// Configurable potion effects
|
||||
protected List<AbilityPotionEffect> effects = new ArrayList<>();
|
||||
|
||||
@@ -205,9 +236,50 @@ public abstract class Ability implements IAbility {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// TOGGLE CALLBACKS (optional overrides for toggleable abilities)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Called when this toggle ability is first activated (state goes from 0 to any active state).
|
||||
* Override to apply effects (e.g., set a DBC flag, apply a buff).
|
||||
*/
|
||||
public void onToggleOn(EntityLivingBase caster) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this toggle ability is fully deactivated (state goes to 0).
|
||||
* Override to remove effects (e.g., clear a DBC flag, remove a buff).
|
||||
*/
|
||||
public void onToggleOff(EntityLivingBase caster) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever the toggle state changes (including on/off transitions and mid-cycling).
|
||||
* For multi-state toggles, this fires on every state transition.
|
||||
*
|
||||
* @param caster The entity
|
||||
* @param oldState Previous state (0 = was off)
|
||||
* @param newState New state (0 = now off, 1+ = active state)
|
||||
*/
|
||||
public void onToggleStateChanged(EntityLivingBase caster, int oldState, int newState) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every tick while this toggle is active (only if hasActiveToggle is true).
|
||||
* Override for per-tick effects (e.g., ki drain for Kaioken).
|
||||
*
|
||||
* @param state Current toggle state (1-based)
|
||||
* @return true to keep the toggle active, false to auto-deactivate
|
||||
*/
|
||||
public boolean onToggleTick(EntityLivingBase caster, int tickCount, int state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this ability is ready for auto-completion during burst overlap mode.
|
||||
* Override to delay auto-completion until all staggered projectiles have been fired.
|
||||
*
|
||||
* @param activeTick the current tick within the ACTIVE phase
|
||||
*/
|
||||
public boolean isReadyForBurstCompletion(int activeTick) {
|
||||
@@ -231,6 +303,17 @@ public abstract class Ability implements IAbility {
|
||||
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the ability enters BURST_DELAY between burst iterations.
|
||||
* Override in subclasses to reset transient state that should not carry
|
||||
* across burst repetitions (e.g., movement direction, hit entity lists).
|
||||
* <p>
|
||||
* Unlike {@link #cleanup()}, this does NOT kill spawned entities (they may
|
||||
* still be in flight for overlap mode).
|
||||
*/
|
||||
public void resetForBurst() {
|
||||
}
|
||||
|
||||
public void onDamageTaken(EntityLivingBase caster, EntityLivingBase attacker, DamageSource source, float damage) {
|
||||
}
|
||||
|
||||
@@ -483,6 +566,12 @@ public abstract class Ability implements IAbility {
|
||||
// ── General tab ──────────────────────────────────────────────
|
||||
defs.add(FieldDef.stringField("gui.name", this::getName, this::setName)
|
||||
.tab("General"));
|
||||
defs.add(FieldDef.stringField("gui.displayName", this::getRawDisplayName, this::setDisplayName)
|
||||
.tab("General"));
|
||||
defs.add(FieldDef.labelField("ability.validFor", () ->
|
||||
StatCollector.translateToLocal("ability.validFor") + ": \u00A7e"
|
||||
+ StatCollector.translateToLocal("ability.userType." + getAllowedBy().name()))
|
||||
.tab("General"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.intField("ability.weight", this::getWeight, this::setWeight).range(1, 1000),
|
||||
FieldDef.boolField("gui.enabled", this::isEnabled, this::setEnabled)
|
||||
@@ -508,27 +597,36 @@ public abstract class Ability implements IAbility {
|
||||
() -> this.getLockMovement().getDisplayKey(),
|
||||
v -> {
|
||||
for (LockMovementType t : LockMovementType.values()) {
|
||||
if (t.getDisplayKey().equals(v)) { this.setLockMovement(t); break; }
|
||||
if (t.getDisplayKey().equals(v)) {
|
||||
this.setLockMovement(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.hover("ability.hover.lockMovement")
|
||||
.tab("General"));
|
||||
.hover("ability.hover.lockMovement")
|
||||
.tab("General"));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.stringEnumField("ability.rotationMode", RotationMode.getDisplayKeys(),
|
||||
() -> this.getRotationMode().getDisplayKey(),
|
||||
v -> {
|
||||
for (RotationMode m : RotationMode.values()) {
|
||||
if (m.getDisplayKey().equals(v)) { this.setRotationMode(m); break; }
|
||||
}
|
||||
})
|
||||
() -> this.getRotationMode().getDisplayKey(),
|
||||
v -> {
|
||||
for (RotationMode m : RotationMode.values()) {
|
||||
if (m.getDisplayKey().equals(v)) {
|
||||
this.setRotationMode(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.hover("ability.hover.rotationMode"),
|
||||
FieldDef.stringEnumField("ability.rotationPhase", getRotationPhaseKeys(),
|
||||
() -> this.getRotationPhase().getDisplayKey(),
|
||||
v -> {
|
||||
for (LockMovementType t : LockMovementType.values()) {
|
||||
if (t.getDisplayKey().equals(v)) { this.setRotationPhase(t); break; }
|
||||
}
|
||||
})
|
||||
() -> this.getRotationPhase().getDisplayKey(),
|
||||
v -> {
|
||||
for (LockMovementType t : LockMovementType.values()) {
|
||||
if (t.getDisplayKey().equals(v)) {
|
||||
this.setRotationPhase(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.hover("ability.hover.rotationPhase")
|
||||
.visibleWhen(() -> this.rotationMode != RotationMode.FREE)
|
||||
).tab("General"));
|
||||
@@ -571,15 +669,17 @@ public abstract class Ability implements IAbility {
|
||||
allowedKeys[i] = allowed[i].name();
|
||||
}
|
||||
defs.add(FieldDef.stringEnumField("ability.targetingMode", allowedKeys,
|
||||
() -> this.getTargetingMode().name(),
|
||||
v -> {
|
||||
try { this.setTargetingMode(TargetingMode.valueOf(v)); }
|
||||
catch (Exception ignored) {}
|
||||
})
|
||||
() -> this.getTargetingMode().name(),
|
||||
v -> {
|
||||
try {
|
||||
this.setTargetingMode(TargetingMode.valueOf(v));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
})
|
||||
.tab("Target").hover("ability.hover.targeting"));
|
||||
} else {
|
||||
defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class,
|
||||
this::getTargetingMode, this::setTargetingMode)
|
||||
this::getTargetingMode, this::setTargetingMode)
|
||||
.tab("Target").hover("ability.hover.targeting"));
|
||||
}
|
||||
}
|
||||
@@ -592,12 +692,12 @@ public abstract class Ability implements IAbility {
|
||||
.tab("Effects"));
|
||||
defs.add(FieldDef.section("ability.section.animations").tab("Effects"));
|
||||
defs.add(FieldDef.animSubGui("ability.windUpAnimation",
|
||||
this::getWindUpAnimationId, this::setWindUpAnimationId,
|
||||
this::getWindUpAnimationName, this::setWindUpAnimationName)
|
||||
this::getWindUpAnimationId, this::setWindUpAnimationId,
|
||||
this::getWindUpAnimationName, this::setWindUpAnimationName)
|
||||
.tab("Effects"));
|
||||
defs.add(FieldDef.animSubGui("ability.activeAnimation",
|
||||
this::getActiveAnimationId, this::setActiveAnimationId,
|
||||
this::getActiveAnimationName, this::setActiveAnimationName)
|
||||
this::getActiveAnimationId, this::setActiveAnimationId,
|
||||
this::getActiveAnimationName, this::setActiveAnimationName)
|
||||
.tab("Effects"));
|
||||
defs.add(FieldDef.animSubGui("ability.dazedAnimation",
|
||||
this::getDazedAnimationId, this::setDazedAnimationId,
|
||||
@@ -653,7 +753,7 @@ public abstract class Ability implements IAbility {
|
||||
* Create a telegraph instance for this ability.
|
||||
* Override for custom telegraph shapes.
|
||||
*
|
||||
* @param caster The caster
|
||||
* @param caster The caster
|
||||
* @param target The target (for position calculation)
|
||||
* @return The telegraph instance, or null if no telegraph
|
||||
*/
|
||||
@@ -916,9 +1016,9 @@ public abstract class Ability implements IAbility {
|
||||
if (phase == AbilityPhase.ACTIVE) {
|
||||
// Check if more burst iterations remain
|
||||
if (burstEnabled && burstAmount > 0 && burstIndex < burstAmount) {
|
||||
// Don't cleanup here - entities may still be in flight
|
||||
// For non-overlap: cleaned up when next burst starts (in onExecute)
|
||||
// For overlap: entities continue flying indefinitely
|
||||
// Reset transient state for next burst iteration (e.g., movement direction, hit lists)
|
||||
// Does NOT kill entities - they may still be in flight (overlap mode)
|
||||
resetForBurst();
|
||||
burstIndex++;
|
||||
phase = AbilityPhase.BURST_DELAY;
|
||||
currentTick = 0;
|
||||
@@ -1119,6 +1219,7 @@ public abstract class Ability implements IAbility {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setString("id", id);
|
||||
nbt.setString("name", name);
|
||||
nbt.setString("displayName", displayName);
|
||||
nbt.setString("typeId", typeId);
|
||||
nbt.setInteger("weight", weight);
|
||||
nbt.setBoolean("enabled", enabled);
|
||||
@@ -1150,6 +1251,17 @@ public abstract class Ability implements IAbility {
|
||||
nbt.setInteger("allowedBy", allowedBy.ordinal());
|
||||
nbt.setBoolean("ignoreCooldown", ignoreCooldown);
|
||||
|
||||
// Toggle
|
||||
nbt.setInteger("toggleStates", toggleStates);
|
||||
nbt.setBoolean("hasActiveToggle", hasActiveToggle);
|
||||
if (toggleStateLabels != null && toggleStateLabels.length > 0) {
|
||||
NBTTagList labelList = new NBTTagList();
|
||||
for (String label : toggleStateLabels) {
|
||||
labelList.appendTag(new NBTTagString(label != null ? label : ""));
|
||||
}
|
||||
nbt.setTag("toggleStateLabels", labelList);
|
||||
}
|
||||
|
||||
// Burst
|
||||
nbt.setBoolean("burstEnabled", burstEnabled);
|
||||
nbt.setInteger("burstAmount", burstAmount);
|
||||
@@ -1180,17 +1292,22 @@ public abstract class Ability implements IAbility {
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
id = nbt.getString("id");
|
||||
name = nbt.getString("name");
|
||||
displayName = nbt.getString("displayName");
|
||||
typeId = nbt.getString("typeId");
|
||||
weight = nbt.getInteger("weight");
|
||||
enabled = nbt.getBoolean("enabled");
|
||||
targetingMode = TargetingMode.valueOf(nbt.getString("targetingMode"));
|
||||
weight = nbt.hasKey("weight") ? nbt.getInteger("weight") : 10;
|
||||
enabled = nbt.hasKey("enabled") ? nbt.getBoolean("enabled") : true;
|
||||
try {
|
||||
targetingMode = TargetingMode.valueOf(nbt.getString("targetingMode"));
|
||||
} catch (Exception e) {
|
||||
targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
}
|
||||
minRange = nbt.getFloat("minRange");
|
||||
maxRange = nbt.getFloat("maxRange");
|
||||
cooldownTicks = nbt.getInteger("cooldown");
|
||||
windUpTicks = nbt.getInteger("windUp");
|
||||
syncWindupWithAnimation = nbt.getBoolean("syncWindup");
|
||||
dazedTicks = nbt.getInteger("recovery");
|
||||
interruptible = nbt.getBoolean("interruptible");
|
||||
syncWindupWithAnimation = nbt.hasKey("syncWindup") ? nbt.getBoolean("syncWindup") : true;
|
||||
dazedTicks = nbt.hasKey("recovery") ? nbt.getInteger("recovery") : 80;
|
||||
interruptible = nbt.hasKey("interruptible") ? nbt.getBoolean("interruptible") : true;
|
||||
lockMovement = LockMovementType.fromOrdinal(nbt.getInteger("lockMovement"));
|
||||
rotationMode = RotationMode.fromOrdinal(nbt.getInteger("rotationMode"));
|
||||
rotationPhase = LockMovementType.fromOrdinal(nbt.getInteger("rotationPhase"));
|
||||
@@ -1204,7 +1321,7 @@ public abstract class Ability implements IAbility {
|
||||
windUpAnimationName = nbt.getString("windUpAnimationName");
|
||||
activeAnimationName = nbt.getString("activeAnimationName");
|
||||
dazedAnimationName = nbt.getString("dazedAnimationName");
|
||||
showTelegraph = nbt.getBoolean("showTelegraph");
|
||||
showTelegraph = nbt.hasKey("showTelegraph") ? nbt.getBoolean("showTelegraph") : true;
|
||||
try {
|
||||
telegraphType = TelegraphType.valueOf(nbt.getString("telegraphType"));
|
||||
} catch (Exception e) {
|
||||
@@ -1215,6 +1332,20 @@ public abstract class Ability implements IAbility {
|
||||
allowedBy = UserType.fromOrdinal(nbt.getInteger("allowedBy"));
|
||||
ignoreCooldown = nbt.getBoolean("ignoreCooldown");
|
||||
|
||||
// Toggle
|
||||
toggleStates = nbt.getInteger("toggleStates");
|
||||
hasActiveToggle = nbt.getBoolean("hasActiveToggle");
|
||||
if (nbt.hasKey("toggleStateLabels")) {
|
||||
NBTTagList labelList = nbt.getTagList("toggleStateLabels", 8);
|
||||
toggleStateLabels = new String[labelList.tagCount()];
|
||||
for (int i = 0; i < labelList.tagCount(); i++) {
|
||||
String label = labelList.getStringTagAt(i);
|
||||
toggleStateLabels[i] = (label != null && !label.isEmpty()) ? label : null;
|
||||
}
|
||||
} else {
|
||||
toggleStateLabels = null;
|
||||
}
|
||||
|
||||
// Burst
|
||||
burstEnabled = nbt.getBoolean("burstEnabled");
|
||||
burstAmount = nbt.getInteger("burstAmount");
|
||||
@@ -1242,7 +1373,10 @@ public abstract class Ability implements IAbility {
|
||||
}
|
||||
}
|
||||
|
||||
readTypeNBT(nbt.getCompoundTag("typeData"));
|
||||
// Type-specific
|
||||
if (nbt.hasKey("typeData")) {
|
||||
readTypeNBT(nbt.getCompoundTag("typeData"));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
@@ -1265,18 +1399,70 @@ public abstract class Ability implements IAbility {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display name for this ability.
|
||||
* Returns displayName if set, otherwise falls back to name.
|
||||
* Converts & color codes to § for rendering.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
String result = (displayName != null && !displayName.isEmpty()) ? displayName : name;
|
||||
return result != null ? result.replaceAll("&([0-9a-fk-or])", "\u00A7$1") : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw display name (may be empty).
|
||||
*/
|
||||
public String getRawDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName != null ? displayName : "";
|
||||
}
|
||||
|
||||
public String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
public boolean isBuiltIn() {
|
||||
return false;
|
||||
return builtIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registry key for built-in abilities.
|
||||
* Returns null for custom abilities.
|
||||
*/
|
||||
public String getRegistryKey() {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure this ability as a built-in ability with fixed config.
|
||||
* Sets builtIn flag, assigns registry key, id, name, and derives typeId.
|
||||
* Call this in the constructor of any ability that should be non-customizable.
|
||||
*/
|
||||
protected void configureAsBuiltIn(String registryKey) {
|
||||
this.builtIn = true;
|
||||
this.registryKey = registryKey;
|
||||
this.id = registryKey;
|
||||
this.name = registryKey;
|
||||
this.typeId = "ability." + registryKey.replace(':', '.');
|
||||
}
|
||||
|
||||
public Ability deepCopy() {
|
||||
return AbilityController.Instance.fromNBT(this.writeNBT());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChain() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAbilityAction deepCopyAction() {
|
||||
return deepCopy();
|
||||
}
|
||||
|
||||
public boolean isNpcInlineEdit() {
|
||||
return npcInlineEdit;
|
||||
}
|
||||
@@ -1399,6 +1585,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Get lock movement type as integer.
|
||||
*
|
||||
* @return 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE
|
||||
*/
|
||||
@Override
|
||||
@@ -1408,6 +1595,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Set lock movement type from integer.
|
||||
*
|
||||
* @param type 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE
|
||||
*/
|
||||
@Override
|
||||
@@ -1417,6 +1605,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Get rotation mode as integer.
|
||||
*
|
||||
* @return 0=FREE, 1=LOCKED, 2=TRACK
|
||||
*/
|
||||
@Override
|
||||
@@ -1426,6 +1615,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Set rotation mode from integer.
|
||||
*
|
||||
* @param type 0=FREE, 1=LOCKED, 2=TRACK
|
||||
*/
|
||||
@Override
|
||||
@@ -1435,6 +1625,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Get rotation phase as integer.
|
||||
*
|
||||
* @return 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE
|
||||
*/
|
||||
@Override
|
||||
@@ -1444,6 +1635,7 @@ public abstract class Ability implements IAbility {
|
||||
|
||||
/**
|
||||
* API method: Set rotation phase from integer.
|
||||
*
|
||||
* @param type 0=NO, 1=WINDUP, 2=ACTIVE, 3=WINDUP_AND_ACTIVE
|
||||
*/
|
||||
@Override
|
||||
@@ -1727,6 +1919,46 @@ public abstract class Ability implements IAbility {
|
||||
this.ignoreCooldown = ignoreCooldown;
|
||||
}
|
||||
|
||||
public boolean isToggleable() {
|
||||
return toggleStates > 0;
|
||||
}
|
||||
|
||||
public int getToggleStates() {
|
||||
return toggleStates;
|
||||
}
|
||||
|
||||
public void setToggleStates(int toggleStates) {
|
||||
this.toggleStates = Math.max(0, toggleStates);
|
||||
}
|
||||
|
||||
public boolean hasActiveToggle() {
|
||||
return hasActiveToggle;
|
||||
}
|
||||
|
||||
public void setHasActiveToggle(boolean hasActiveToggle) {
|
||||
this.hasActiveToggle = hasActiveToggle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display label for a specific toggle state.
|
||||
* @param state 1-based state index
|
||||
* @return the label, or null if none set
|
||||
*/
|
||||
public String getToggleStateLabel(int state) {
|
||||
if (toggleStateLabels != null && state >= 1 && state <= toggleStateLabels.length) {
|
||||
return toggleStateLabels[state - 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set display labels for toggle states (1-indexed).
|
||||
* @param labels one label per state, null entries allowed
|
||||
*/
|
||||
public void setToggleStateLabels(String... labels) {
|
||||
this.toggleStateLabels = (labels != null && labels.length > 0) ? labels : null;
|
||||
}
|
||||
|
||||
public List<AbilityPotionEffect> getEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* Unified slot for storing any combat action: inline ability, ability reference, or chain reference.
|
||||
* Replaces {@link AbilitySlot} with support for all {@link IAbilityAction} types.
|
||||
* <p>
|
||||
* References are lazy-resolved via their respective controllers and cached until
|
||||
* the controller revision changes.
|
||||
*/
|
||||
public class AbilityAction {
|
||||
|
||||
public enum SlotType {
|
||||
INLINE_ABILITY,
|
||||
ABILITY_REFERENCE,
|
||||
CHAIN_REFERENCE,
|
||||
INLINE_CHAIN
|
||||
}
|
||||
|
||||
private SlotType slotType;
|
||||
private Ability inlineAbility;
|
||||
private ChainedAbility inlineChain;
|
||||
private String referenceId;
|
||||
|
||||
/**
|
||||
* Per-slot enabled override for reference slots (null = use master's default).
|
||||
*/
|
||||
private Boolean enabledOverride;
|
||||
|
||||
// Cache
|
||||
private transient IAbilityAction cachedAction;
|
||||
private transient int cachedRevision = -1;
|
||||
|
||||
private AbilityAction() {
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// FACTORY METHODS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public static AbilityAction inline(Ability ability) {
|
||||
AbilityAction slot = new AbilityAction();
|
||||
slot.slotType = SlotType.INLINE_ABILITY;
|
||||
slot.inlineAbility = ability;
|
||||
return slot;
|
||||
}
|
||||
|
||||
public static AbilityAction abilityReference(String referenceId) {
|
||||
AbilityAction slot = new AbilityAction();
|
||||
slot.slotType = SlotType.ABILITY_REFERENCE;
|
||||
slot.referenceId = referenceId;
|
||||
return slot;
|
||||
}
|
||||
|
||||
public static AbilityAction chainReference(String referenceId) {
|
||||
AbilityAction slot = new AbilityAction();
|
||||
slot.slotType = SlotType.CHAIN_REFERENCE;
|
||||
slot.referenceId = referenceId;
|
||||
return slot;
|
||||
}
|
||||
|
||||
public static AbilityAction inlineChain(ChainedAbility chain) {
|
||||
AbilityAction slot = new AbilityAction();
|
||||
slot.slotType = SlotType.INLINE_CHAIN;
|
||||
slot.inlineChain = chain;
|
||||
return slot;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// QUERIES
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public SlotType getSlotType() {
|
||||
return slotType;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return slotType == SlotType.ABILITY_REFERENCE || slotType == SlotType.CHAIN_REFERENCE;
|
||||
}
|
||||
|
||||
public boolean isChainReference() {
|
||||
return slotType == SlotType.CHAIN_REFERENCE;
|
||||
}
|
||||
|
||||
public boolean isInlineChain() {
|
||||
return slotType == SlotType.INLINE_CHAIN;
|
||||
}
|
||||
|
||||
public boolean isChain() {
|
||||
return slotType == SlotType.CHAIN_REFERENCE || slotType == SlotType.INLINE_CHAIN;
|
||||
}
|
||||
|
||||
public boolean isAbilityReference() {
|
||||
return slotType == SlotType.ABILITY_REFERENCE;
|
||||
}
|
||||
|
||||
public String getReferenceId() {
|
||||
return referenceId;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// RESOLUTION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Resolve the action. Inline returns directly; references resolve
|
||||
* from the appropriate controller with version-based caching.
|
||||
*/
|
||||
public IAbilityAction getAction() {
|
||||
switch (slotType) {
|
||||
case INLINE_ABILITY:
|
||||
return inlineAbility;
|
||||
|
||||
case INLINE_CHAIN:
|
||||
return inlineChain;
|
||||
|
||||
case ABILITY_REFERENCE: {
|
||||
AbilityController ctrl = AbilityController.Instance;
|
||||
if (ctrl == null) return null;
|
||||
int rev = ctrl.getCustomAbilityRevision();
|
||||
if (cachedAction != null && cachedRevision == rev) {
|
||||
return cachedAction;
|
||||
}
|
||||
Ability resolved = ctrl.resolveAbility(referenceId);
|
||||
if (resolved != null && enabledOverride != null) {
|
||||
resolved.setEnabled(enabledOverride);
|
||||
}
|
||||
cachedAction = resolved;
|
||||
cachedRevision = rev;
|
||||
return cachedAction;
|
||||
}
|
||||
|
||||
case CHAIN_REFERENCE: {
|
||||
AbilityController ctrl = AbilityController.Instance;
|
||||
if (ctrl == null) return null;
|
||||
int rev = ctrl.getChainedAbilityRevision();
|
||||
if (cachedAction != null && cachedRevision == rev) {
|
||||
return cachedAction;
|
||||
}
|
||||
ChainedAbility resolved = ctrl.resolveChainedAbility(referenceId);
|
||||
if (resolved != null && enabledOverride != null) {
|
||||
resolved.setEnabled(enabledOverride);
|
||||
}
|
||||
cachedAction = resolved;
|
||||
cachedRevision = rev;
|
||||
return cachedAction;
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get as Ability (returns null if this is a chain slot or resolution fails).
|
||||
*/
|
||||
public Ability getAbility() {
|
||||
IAbilityAction action = getAction();
|
||||
return (action instanceof Ability) ? (Ability) action : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get as ChainedAbility (returns null if this is an ability slot or resolution fails).
|
||||
*/
|
||||
public ChainedAbility getChainedAbility() {
|
||||
IAbilityAction action = getAction();
|
||||
return (action instanceof ChainedAbility) ? (ChainedAbility) action : null;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// ENABLED OVERRIDE
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (slotType == SlotType.INLINE_ABILITY) {
|
||||
if (inlineAbility != null) {
|
||||
inlineAbility.setEnabled(enabled);
|
||||
}
|
||||
} else if (slotType == SlotType.INLINE_CHAIN) {
|
||||
if (inlineChain != null) {
|
||||
inlineChain.setEnabled(enabled);
|
||||
}
|
||||
} else {
|
||||
this.enabledOverride = enabled;
|
||||
if (cachedAction != null) {
|
||||
cachedAction.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// INLINE CONVERSION (ability references only)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public Ability getInlineAbility() {
|
||||
return inlineAbility;
|
||||
}
|
||||
|
||||
public ChainedAbility getInlineChain() {
|
||||
return inlineChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this reference slot to an inline slot by copying the resolved data.
|
||||
* Works for ability references (→ INLINE_ABILITY) and chain references (→ INLINE_CHAIN).
|
||||
* Chain entries are kept as-is (not auto-converted to inline).
|
||||
*/
|
||||
public boolean convertToInline() {
|
||||
if (slotType == SlotType.ABILITY_REFERENCE) {
|
||||
Ability resolved = getAbility();
|
||||
if (resolved == null) return false;
|
||||
|
||||
inlineAbility = AbilityController.Instance.fromNBT(resolved.writeNBT());
|
||||
slotType = SlotType.INLINE_ABILITY;
|
||||
referenceId = null;
|
||||
cachedAction = null;
|
||||
cachedRevision = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (slotType == SlotType.CHAIN_REFERENCE) {
|
||||
ChainedAbility resolved = getChainedAbility();
|
||||
if (resolved == null) return false;
|
||||
|
||||
inlineChain = resolved.deepCopy();
|
||||
slotType = SlotType.INLINE_CHAIN;
|
||||
referenceId = null;
|
||||
cachedAction = null;
|
||||
cachedRevision = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// NBT
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public NBTTagCompound writeNBT() {
|
||||
switch (slotType) {
|
||||
case INLINE_CHAIN: {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
if (inlineChain != null) {
|
||||
nbt.setTag("InlineChain", inlineChain.writeNBT());
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
case CHAIN_REFERENCE: {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setString("ChainReference", referenceId);
|
||||
if (enabledOverride != null) {
|
||||
nbt.setBoolean("RefEnabled", enabledOverride);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
case ABILITY_REFERENCE: {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setString("Reference", referenceId);
|
||||
if (enabledOverride != null) {
|
||||
nbt.setBoolean("RefEnabled", enabledOverride);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
case INLINE_ABILITY:
|
||||
default:
|
||||
return inlineAbility != null ? inlineAbility.writeNBT() : new NBTTagCompound();
|
||||
}
|
||||
}
|
||||
|
||||
public static AbilityAction fromNBT(NBTTagCompound nbt) {
|
||||
if (nbt == null) return null;
|
||||
|
||||
// Inline chain (new format)
|
||||
if (nbt.hasKey("InlineChain")) {
|
||||
ChainedAbility chain = new ChainedAbility();
|
||||
chain.readNBT(nbt.getCompoundTag("InlineChain"));
|
||||
return inlineChain(chain);
|
||||
}
|
||||
|
||||
// Chain reference
|
||||
if (nbt.hasKey("ChainReference")) {
|
||||
AbilityAction slot = chainReference(nbt.getString("ChainReference"));
|
||||
if (nbt.hasKey("RefEnabled")) {
|
||||
slot.enabledOverride = nbt.getBoolean("RefEnabled");
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
// Ability reference
|
||||
if (nbt.hasKey("Reference")) {
|
||||
AbilityAction slot = abilityReference(nbt.getString("Reference"));
|
||||
if (nbt.hasKey("RefEnabled")) {
|
||||
slot.enabledOverride = nbt.getBoolean("RefEnabled");
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
// Inline ability
|
||||
Ability ability = AbilityController.Instance.fromNBT(nbt);
|
||||
if (ability == null) return null;
|
||||
return inline(ability);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
@@ -8,19 +9,25 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
* <p>
|
||||
* References are lazy-resolved via {@link AbilityController#resolveAbility(String)}
|
||||
* and cached until the controller version changes.
|
||||
*
|
||||
* @deprecated Use {@link AbilityAction} instead, which supports abilities and chained abilities.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AbilitySlot {
|
||||
|
||||
private Ability inlineAbility;
|
||||
private String referenceId;
|
||||
|
||||
/** Per-slot enabled override for reference slots (null = use master's default). */
|
||||
/**
|
||||
* Per-slot enabled override for reference slots (null = use master's default).
|
||||
*/
|
||||
private Boolean enabledOverride;
|
||||
|
||||
private transient Ability cachedAbility;
|
||||
private transient int cachedVersion = -1;
|
||||
|
||||
private AbilitySlot() {}
|
||||
private AbilitySlot() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a slot with an inline (embedded) ability.
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.function.Consumer;
|
||||
* Represents a variant/template for an ability type.
|
||||
* When a user creates an ability that has registered variants,
|
||||
* they are presented with a selection dialog before the ability is created.
|
||||
*
|
||||
* <p>
|
||||
* Each variant has a display name (lang key) and a configurator that
|
||||
* applies preset values to the newly created ability.
|
||||
*/
|
||||
|
||||
@@ -50,14 +50,22 @@ public enum AnchorPoint {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case FRONT: return "ability.anchor.front";
|
||||
case CENTER: return "ability.anchor.center";
|
||||
case RIGHT_HAND: return "ability.anchor.rightHand";
|
||||
case LEFT_HAND: return "ability.anchor.leftHand";
|
||||
case ABOVE_HEAD: return "ability.anchor.aboveHead";
|
||||
case CHEST: return "ability.anchor.chest";
|
||||
case EYE: return "ability.anchor.eye";
|
||||
default: return name();
|
||||
case FRONT:
|
||||
return "ability.anchor.front";
|
||||
case CENTER:
|
||||
return "ability.anchor.center";
|
||||
case RIGHT_HAND:
|
||||
return "ability.anchor.rightHand";
|
||||
case LEFT_HAND:
|
||||
return "ability.anchor.leftHand";
|
||||
case ABOVE_HEAD:
|
||||
return "ability.anchor.aboveHead";
|
||||
case CHEST:
|
||||
return "ability.anchor.chest";
|
||||
case EYE:
|
||||
return "ability.anchor.eye";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* Abstract base class for built-in (non-customizable) abilities.
|
||||
* Built-in abilities are registered by key, have fixed configurations,
|
||||
* and cannot be modified through the preset GUI system.
|
||||
* <p>
|
||||
* Examples: simple utility abilities like Jump, Sprint, etc.
|
||||
* Third-party mods can extend this class to create their own built-in abilities.
|
||||
*/
|
||||
public abstract class BuiltInAbility extends Ability {
|
||||
|
||||
/**
|
||||
* The registry key used to look up this ability (e.g., "cnpc:jump", "dbc:ki_blast").
|
||||
*/
|
||||
private final String registryKey;
|
||||
|
||||
public BuiltInAbility(String registryKey) {
|
||||
this.registryKey = registryKey;
|
||||
this.id = registryKey;
|
||||
this.name = registryKey;
|
||||
// Convert "namespace:name" to "ability.namespace.name" for GUI filter compatibility
|
||||
this.typeId = "ability." + registryKey.replace(':', '.');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltIn() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registry key for this built-in ability.
|
||||
*/
|
||||
public String getRegistryKey() {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in abilities do not write type-specific NBT (they have fixed configs).
|
||||
*/
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
// No-op: built-in abilities have fixed configurations
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in abilities do not read type-specific NBT.
|
||||
*/
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
// No-op: built-in abilities have fixed configurations
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration of the active phase in ticks.
|
||||
* Built-in abilities must define their own active duration.
|
||||
*/
|
||||
public abstract int getActiveDurationTicks();
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import noppes.npcs.api.ability.IChainedAbility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A chained ability is an ordered sequence of ability references that execute
|
||||
* one after another. It has its own conditions, cooldown, weight, and per-entry
|
||||
* delay configuration. Individual ability conditions are skipped during chain execution.
|
||||
* <p>
|
||||
* All entries must be ability references (by name/key). Inline abilities are not supported.
|
||||
* When saving, all references are validated against {@link AbilityController}.
|
||||
*/
|
||||
public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CONFIGURATION (saved to NBT)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
private String id = ""; // UUID (stable persistent reference)
|
||||
private String name = ""; // Unique file key / identifier
|
||||
private String displayName = ""; // Cosmetic name (falls back to name when empty)
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Weight for NPC weighted random selection.
|
||||
*/
|
||||
private int weight = 10;
|
||||
|
||||
/**
|
||||
* Whether each ability in the chain uses its own windup phase.
|
||||
*/
|
||||
private boolean windUpAll = true;
|
||||
|
||||
/**
|
||||
* Chain-level cooldown in ticks (applied after entire chain completes).
|
||||
*/
|
||||
private int cooldownTicks = 100;
|
||||
|
||||
/**
|
||||
* Minimum range for NPC eligibility check.
|
||||
*/
|
||||
private float minRange = 0;
|
||||
|
||||
/**
|
||||
* Maximum range for NPC eligibility check.
|
||||
*/
|
||||
private float maxRange = 20;
|
||||
|
||||
/**
|
||||
* Chain-level conditions (individual ability conditions are ignored).
|
||||
*/
|
||||
private List<Condition> conditions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Ordered list of ability entries to execute.
|
||||
*/
|
||||
private List<ChainedAbilityEntry> entries = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Extension data for external mods (e.g., icons, DBC stats).
|
||||
*/
|
||||
private NBTTagCompound customData = new NBTTagCompound();
|
||||
|
||||
public ChainedAbility() {
|
||||
}
|
||||
|
||||
public ChainedAbility(String name) {
|
||||
this.name = name != null ? name : "";
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// GETTERS / SETTERS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id != null ? id : "";
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name != null ? name : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display name for this chained ability.
|
||||
* Returns displayName if set, otherwise falls back to name.
|
||||
* Converts & color codes to § for rendering.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
String result = (displayName != null && !displayName.isEmpty()) ? displayName : name;
|
||||
return result != null ? result.replaceAll("&([0-9a-fk-or])", "\u00A7$1") : "";
|
||||
}
|
||||
|
||||
public String getRawDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName != null ? displayName : "";
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {
|
||||
this.weight = Math.max(1, weight);
|
||||
}
|
||||
|
||||
public boolean isWindUpAll() {
|
||||
return windUpAll;
|
||||
}
|
||||
|
||||
public void setWindUpAll(boolean windUpAll) {
|
||||
this.windUpAll = windUpAll;
|
||||
}
|
||||
|
||||
public int getCooldownTicks() {
|
||||
return cooldownTicks;
|
||||
}
|
||||
|
||||
public void setCooldownTicks(int cooldownTicks) {
|
||||
this.cooldownTicks = Math.max(0, cooldownTicks);
|
||||
}
|
||||
|
||||
public float getMinRange() {
|
||||
return minRange;
|
||||
}
|
||||
|
||||
public void setMinRange(float minRange) {
|
||||
this.minRange = Math.max(0, minRange);
|
||||
}
|
||||
|
||||
public float getMaxRange() {
|
||||
return maxRange;
|
||||
}
|
||||
|
||||
public void setMaxRange(float maxRange) {
|
||||
this.maxRange = Math.max(0, maxRange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the allowed user type from child abilities.
|
||||
* A chain allows players if ALL resolved entries allow players.
|
||||
* A chain allows NPCs if ALL resolved entries allow NPCs.
|
||||
* Unresolvable entries are skipped (don't restrict).
|
||||
*/
|
||||
public UserType getAllowedBy() {
|
||||
if (entries.isEmpty()) return UserType.BOTH;
|
||||
boolean allAllowPlayer = true;
|
||||
boolean allAllowNpc = true;
|
||||
for (ChainedAbilityEntry entry : entries) {
|
||||
Ability a = entry.resolve();
|
||||
if (a == null) continue;
|
||||
UserType ut = a.getAllowedBy();
|
||||
if (!ut.allowsPlayer()) allAllowPlayer = false;
|
||||
if (!ut.allowsNpc()) allAllowNpc = false;
|
||||
}
|
||||
if (allAllowPlayer && allAllowNpc) return UserType.BOTH;
|
||||
if (allAllowPlayer) return UserType.PLAYER_ONLY;
|
||||
if (allAllowNpc) return UserType.NPC_ONLY;
|
||||
return UserType.NPC_ONLY;
|
||||
}
|
||||
|
||||
public List<Condition> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void setConditions(List<Condition> conditions) {
|
||||
this.conditions = conditions != null ? conditions : new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<ChainedAbilityEntry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void setEntries(List<ChainedAbilityEntry> entries) {
|
||||
this.entries = entries != null ? entries : new ArrayList<>();
|
||||
}
|
||||
|
||||
public NBTTagCompound getCustomData() {
|
||||
return customData;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// IChainedAbility INTERFACE
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
@Override
|
||||
public int getEntryCount() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryReference(int index) {
|
||||
if (index < 0 || index >= entries.size()) return null;
|
||||
ChainedAbilityEntry entry = entries.get(index);
|
||||
if (entry.isInline()) {
|
||||
Ability a = entry.getInlineAbility();
|
||||
return a != null ? a.getName() : "";
|
||||
}
|
||||
return entry.getAbilityReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEntryInline(int index) {
|
||||
if (index < 0 || index >= entries.size()) return false;
|
||||
return entries.get(index).isInline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntryDelay(int index) {
|
||||
if (index < 0 || index >= entries.size()) return 0;
|
||||
return entries.get(index).getDelayTicks();
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// ENTRY MANAGEMENT
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public void addEntry(ChainedAbilityEntry entry) {
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void addEntry(String abilityReference, int delayTicks) {
|
||||
entries.add(new ChainedAbilityEntry(abilityReference, delayTicks));
|
||||
}
|
||||
|
||||
public void removeEntry(int index) {
|
||||
if (index >= 0 && index < entries.size()) {
|
||||
entries.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveEntryUp(int index) {
|
||||
if (index > 0 && index < entries.size()) {
|
||||
ChainedAbilityEntry entry = entries.remove(index);
|
||||
entries.add(index - 1, entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveEntryDown(int index) {
|
||||
if (index >= 0 && index < entries.size() - 1) {
|
||||
ChainedAbilityEntry entry = entries.remove(index);
|
||||
entries.add(index + 1, entry);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CONDITIONS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Check all chain-level conditions against the caster and target.
|
||||
*/
|
||||
public boolean checkConditions(EntityLivingBase caster, EntityLivingBase target) {
|
||||
for (Condition c : conditions) {
|
||||
if (!c.check(caster, target)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check conditions for player use (skip target-requiring conditions).
|
||||
*/
|
||||
public boolean checkConditionsForPlayer(EntityLivingBase caster) {
|
||||
for (Condition c : conditions) {
|
||||
if (c.requiresTarget()) continue;
|
||||
if (!c.check(caster, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// VALIDATION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Validate this chained ability. Returns a list of error messages.
|
||||
* An empty list means valid.
|
||||
*/
|
||||
public List<String> validate() {
|
||||
List<String> errors = new ArrayList<>();
|
||||
|
||||
if (name == null || name.isEmpty()) {
|
||||
errors.add("Name is required");
|
||||
}
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
errors.add("At least one ability entry is required");
|
||||
}
|
||||
|
||||
AbilityController controller = AbilityController.Instance;
|
||||
if (controller != null) {
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
ChainedAbilityEntry entry = entries.get(i);
|
||||
if (entry.isInline()) {
|
||||
if (entry.getInlineAbility() == null) {
|
||||
errors.add("Entry " + (i + 1) + ": inline ability is null");
|
||||
}
|
||||
} else {
|
||||
String ref = entry.getAbilityReference();
|
||||
if (ref == null || ref.isEmpty()) {
|
||||
errors.add("Entry " + (i + 1) + ": ability reference is empty");
|
||||
} else if (!controller.canResolveAbility(ref)) {
|
||||
errors.add("Entry " + (i + 1) + ": cannot resolve ability '" + ref + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// DEEP COPY
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Create a deep copy via NBT round-trip.
|
||||
*/
|
||||
public ChainedAbility deepCopy() {
|
||||
ChainedAbility copy = new ChainedAbility();
|
||||
copy.readNBT(this.writeNBT());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChain() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAbilityAction deepCopyAction() {
|
||||
return deepCopy();
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// NBT SERIALIZATION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public NBTTagCompound writeNBT() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setString("Id", id);
|
||||
nbt.setString("Name", name);
|
||||
nbt.setString("DisplayName", displayName);
|
||||
nbt.setBoolean("Enabled", enabled);
|
||||
nbt.setInteger("Weight", weight);
|
||||
nbt.setBoolean("WindUpAll", windUpAll);
|
||||
nbt.setInteger("CooldownTicks", cooldownTicks);
|
||||
nbt.setFloat("MinRange", minRange);
|
||||
nbt.setFloat("MaxRange", maxRange);
|
||||
|
||||
// Conditions
|
||||
NBTTagList condList = new NBTTagList();
|
||||
for (Condition c : conditions) {
|
||||
condList.appendTag(c.writeNBT());
|
||||
}
|
||||
nbt.setTag("Conditions", condList);
|
||||
|
||||
// Entries
|
||||
NBTTagList entryList = new NBTTagList();
|
||||
for (ChainedAbilityEntry entry : entries) {
|
||||
entryList.appendTag(entry.writeNBT());
|
||||
}
|
||||
nbt.setTag("Entries", entryList);
|
||||
|
||||
// Custom data (for external mods)
|
||||
nbt.setTag("customData", (NBTTagCompound) customData.copy());
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
id = nbt.getString("Id");
|
||||
name = nbt.getString("Name");
|
||||
displayName = nbt.getString("DisplayName");
|
||||
enabled = !nbt.hasKey("Enabled") || nbt.getBoolean("Enabled");
|
||||
weight = nbt.hasKey("Weight") ? nbt.getInteger("Weight") : 10;
|
||||
windUpAll = !nbt.hasKey("WindUpAll") || nbt.getBoolean("WindUpAll");
|
||||
cooldownTicks = nbt.hasKey("CooldownTicks") ? nbt.getInteger("CooldownTicks") : 100;
|
||||
minRange = nbt.getFloat("MinRange");
|
||||
maxRange = nbt.hasKey("MaxRange") ? nbt.getFloat("MaxRange") : 20;
|
||||
// AllowedBy is computed from child abilities — old NBT data silently ignored
|
||||
|
||||
// Conditions
|
||||
conditions.clear();
|
||||
NBTTagList condList = nbt.getTagList("Conditions", 10);
|
||||
for (int i = 0; i < condList.tagCount(); i++) {
|
||||
Condition c = Condition.fromNBT(condList.getCompoundTagAt(i));
|
||||
if (c != null) {
|
||||
conditions.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Entries
|
||||
entries.clear();
|
||||
NBTTagList entryList = nbt.getTagList("Entries", 10);
|
||||
for (int i = 0; i < entryList.tagCount(); i++) {
|
||||
ChainedAbilityEntry entry = ChainedAbilityEntry.fromNBT(entryList.getCompoundTagAt(i));
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Custom data (for external mods)
|
||||
customData = nbt.getCompoundTag("customData");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* A single entry in a {@link ChainedAbility}, representing one ability
|
||||
* to execute in sequence along with its delay configuration.
|
||||
* <p>
|
||||
* Entries can be either a <b>reference</b> to a registered ability (by name/key)
|
||||
* or an <b>inline</b> ability that is owned directly by this entry.
|
||||
*/
|
||||
public class ChainedAbilityEntry {
|
||||
|
||||
public enum EntryType {REFERENCE, INLINE}
|
||||
|
||||
private EntryType entryType = EntryType.REFERENCE;
|
||||
|
||||
/**
|
||||
* Reference key (built-in name or custom ability name). Used when entryType == REFERENCE.
|
||||
*/
|
||||
private String abilityReference = "";
|
||||
|
||||
/**
|
||||
* Inline ability data. Used when entryType == INLINE.
|
||||
*/
|
||||
private Ability inlineAbility = null;
|
||||
|
||||
/**
|
||||
* Delay in ticks BEFORE this ability starts (after previous entry completes).
|
||||
*/
|
||||
private int delayTicks = 0;
|
||||
|
||||
public ChainedAbilityEntry() {
|
||||
}
|
||||
|
||||
public ChainedAbilityEntry(String abilityReference, int delayTicks) {
|
||||
this.entryType = EntryType.REFERENCE;
|
||||
this.abilityReference = abilityReference != null ? abilityReference : "";
|
||||
this.delayTicks = Math.max(0, delayTicks);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// FACTORY METHODS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public static ChainedAbilityEntry reference(String ref, int delay) {
|
||||
ChainedAbilityEntry entry = new ChainedAbilityEntry();
|
||||
entry.entryType = EntryType.REFERENCE;
|
||||
entry.abilityReference = ref != null ? ref : "";
|
||||
entry.delayTicks = Math.max(0, delay);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public static ChainedAbilityEntry inline(Ability ability, int delay) {
|
||||
ChainedAbilityEntry entry = new ChainedAbilityEntry();
|
||||
entry.entryType = EntryType.INLINE;
|
||||
entry.inlineAbility = ability;
|
||||
entry.delayTicks = Math.max(0, delay);
|
||||
return entry;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// TYPE QUERIES
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public EntryType getEntryType() {
|
||||
return entryType;
|
||||
}
|
||||
|
||||
public boolean isInline() {
|
||||
return entryType == EntryType.INLINE;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return entryType == EntryType.REFERENCE;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// GETTERS / SETTERS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public String getAbilityReference() {
|
||||
return abilityReference;
|
||||
}
|
||||
|
||||
public void setAbilityReference(String abilityReference) {
|
||||
this.abilityReference = abilityReference != null ? abilityReference : "";
|
||||
}
|
||||
|
||||
public Ability getInlineAbility() {
|
||||
return inlineAbility;
|
||||
}
|
||||
|
||||
public void setInlineAbility(Ability ability) {
|
||||
this.inlineAbility = ability;
|
||||
}
|
||||
|
||||
public int getDelayTicks() {
|
||||
return delayTicks;
|
||||
}
|
||||
|
||||
public void setDelayTicks(int delayTicks) {
|
||||
this.delayTicks = Math.max(0, delayTicks);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// RESOLUTION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Resolve this entry to an Ability instance.
|
||||
* Inline entries return their ability directly.
|
||||
* Reference entries resolve via AbilityController.
|
||||
*/
|
||||
public Ability resolve() {
|
||||
if (entryType == EntryType.INLINE) {
|
||||
return inlineAbility;
|
||||
}
|
||||
AbilityController ctrl = AbilityController.Instance;
|
||||
if (ctrl == null) return null;
|
||||
return ctrl.resolveAbility(abilityReference);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// CONVERSION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Convert a reference entry to inline by cloning the resolved ability.
|
||||
* Returns false if already inline or the reference cannot be resolved.
|
||||
*/
|
||||
public boolean convertToInline() {
|
||||
if (entryType != EntryType.REFERENCE) return false;
|
||||
|
||||
AbilityController ctrl = AbilityController.Instance;
|
||||
if (ctrl == null) return false;
|
||||
|
||||
Ability resolved = ctrl.resolveAbility(abilityReference);
|
||||
if (resolved == null) return false;
|
||||
|
||||
inlineAbility = ctrl.fromNBT(resolved.writeNBT());
|
||||
entryType = EntryType.INLINE;
|
||||
abilityReference = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// DEEP COPY
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Create a deep copy of this entry. Inline abilities are copied via NBT round-trip.
|
||||
*/
|
||||
public ChainedAbilityEntry deepCopy() {
|
||||
ChainedAbilityEntry copy = new ChainedAbilityEntry();
|
||||
copy.entryType = this.entryType;
|
||||
copy.abilityReference = this.abilityReference;
|
||||
copy.delayTicks = this.delayTicks;
|
||||
if (this.inlineAbility != null) {
|
||||
copy.inlineAbility = AbilityController.Instance.fromNBT(this.inlineAbility.writeNBT());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// NBT (backwards compatible)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public NBTTagCompound writeNBT() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setInteger("Delay", delayTicks);
|
||||
|
||||
if (entryType == EntryType.INLINE && inlineAbility != null) {
|
||||
nbt.setTag("InlineAbility", inlineAbility.writeNBT());
|
||||
} else {
|
||||
nbt.setString("Reference", abilityReference);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static ChainedAbilityEntry fromNBT(NBTTagCompound nbt) {
|
||||
if (nbt == null) return null;
|
||||
|
||||
ChainedAbilityEntry entry = new ChainedAbilityEntry();
|
||||
entry.delayTicks = Math.max(0, nbt.getInteger("Delay"));
|
||||
|
||||
// Inline entry (new format)
|
||||
if (nbt.hasKey("InlineAbility")) {
|
||||
NBTTagCompound abilityNBT = nbt.getCompoundTag("InlineAbility");
|
||||
entry.entryType = EntryType.INLINE;
|
||||
entry.inlineAbility = AbilityController.Instance != null
|
||||
? AbilityController.Instance.fromNBT(abilityNBT) : null;
|
||||
} else {
|
||||
// Reference entry (old + new format)
|
||||
entry.entryType = EntryType.REFERENCE;
|
||||
entry.abilityReference = nbt.getString("Reference");
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common interface for all combat actions that can be assigned to NPCs or players.
|
||||
* Implemented by {@link Ability} (individual ability) and {@link ChainedAbility} (sequence).
|
||||
* <p>
|
||||
* This enables unified storage via {@link AbilityAction}, unified weighted random selection,
|
||||
* and unified eligibility checking without instanceof or separate codepaths.
|
||||
*/
|
||||
public interface IAbilityAction {
|
||||
|
||||
String getName();
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
int getWeight();
|
||||
|
||||
int getCooldownTicks();
|
||||
|
||||
float getMinRange();
|
||||
|
||||
float getMaxRange();
|
||||
|
||||
UserType getAllowedBy();
|
||||
|
||||
List<Condition> getConditions();
|
||||
|
||||
boolean checkConditions(EntityLivingBase caster, EntityLivingBase target);
|
||||
|
||||
boolean checkConditionsForPlayer(EntityLivingBase caster);
|
||||
|
||||
/**
|
||||
* Whether this action is a chained ability (sequence of abilities) vs an individual ability.
|
||||
*/
|
||||
boolean isChain();
|
||||
|
||||
/**
|
||||
* Create a deep copy of this action.
|
||||
*/
|
||||
IAbilityAction deepCopyAction();
|
||||
|
||||
NBTTagCompound writeNBT();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* External field definition provider for chained abilities.
|
||||
* Called during GUI initialization to allow mods to inject custom tabs/fields
|
||||
* into the chained ability configuration GUI.
|
||||
* <p>
|
||||
* Note: Although this interface references FieldDef (client-only), it is safe to
|
||||
* register on both sides because the generic type is erased at bytecode level.
|
||||
* The addFieldDefinitions method is only ever called from client-side GUI code.
|
||||
*/
|
||||
public interface IChainedAbilityFieldProvider {
|
||||
/**
|
||||
* Add field definitions to the chained ability's GUI.
|
||||
* Fields added here should use .tab() to assign them to a custom tab.
|
||||
*
|
||||
* @param chain The chained ability being configured
|
||||
* @param defs The mutable list of field definitions to add to
|
||||
*/
|
||||
void addFieldDefinitions(ChainedAbility chain, List<FieldDef> defs);
|
||||
}
|
||||
@@ -9,5 +9,6 @@ import net.minecraft.entity.Entity;
|
||||
*/
|
||||
public interface PreviewEntityHandler {
|
||||
void onEntitySpawned(Entity entity);
|
||||
|
||||
void onEntityRemoved(Entity entity);
|
||||
}
|
||||
@@ -27,11 +27,16 @@ public enum TargetingMode {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case AGGRO_TARGET: return "ability.target.aggro_target";
|
||||
case SELF: return "ability.target.self";
|
||||
case AOE_SELF: return "ability.target.aoe_self";
|
||||
case AOE_TARGET: return "ability.target.aoe_target";
|
||||
default: return name();
|
||||
case AGGRO_TARGET:
|
||||
return "ability.target.aggro_target";
|
||||
case SELF:
|
||||
return "ability.target.self";
|
||||
case AOE_SELF:
|
||||
return "ability.target.aoe_self";
|
||||
case AOE_TARGET:
|
||||
return "ability.target.aoe_target";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
/**
|
||||
* Tracks the state of a single active toggle for an entity.
|
||||
* Stored in AbstractDataAbilities.activeToggles map.
|
||||
* <p>
|
||||
* State is 1-based: state 1 = first ON state, state 2 = second, etc.
|
||||
* State 0 means OFF (entry should not exist in the map).
|
||||
*/
|
||||
public class ToggleEntry {
|
||||
private final Ability ability;
|
||||
private int tickCount;
|
||||
private int state;
|
||||
|
||||
public ToggleEntry(Ability ability, int state) {
|
||||
this.ability = ability;
|
||||
this.tickCount = 0;
|
||||
this.state = Math.max(1, state);
|
||||
}
|
||||
|
||||
public Ability getAbility() {
|
||||
return ability;
|
||||
}
|
||||
|
||||
public int getTickCount() {
|
||||
return tickCount;
|
||||
}
|
||||
|
||||
public void incrementTick() {
|
||||
tickCount++;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = Math.max(1, state);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,9 @@ public class EnergyBarrierData {
|
||||
// Knockback settings
|
||||
public boolean knockbackEnabled = false;
|
||||
public float knockbackStrength = 1.0f;
|
||||
/** 0=Both, 1=Player only, 2=NPC only */
|
||||
/**
|
||||
* 0=Both, 1=Player only, 2=NPC only
|
||||
*/
|
||||
public int knockbackTarget = 0;
|
||||
|
||||
// Melee settings
|
||||
@@ -36,7 +38,8 @@ public class EnergyBarrierData {
|
||||
*/
|
||||
private Map<String, Float> damageMultipliers = new HashMap<>();
|
||||
|
||||
public EnergyBarrierData() {}
|
||||
public EnergyBarrierData() {
|
||||
}
|
||||
|
||||
public EnergyBarrierData(float maxHealth, boolean useHealth, int durationTicks, boolean useDuration) {
|
||||
this.maxHealth = maxHealth;
|
||||
@@ -70,23 +73,50 @@ public class EnergyBarrierData {
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getMaxHealth() { return maxHealth; }
|
||||
public void setMaxHealth(float maxHealth) { this.maxHealth = Math.max(0, maxHealth); }
|
||||
public float getMaxHealth() {
|
||||
return maxHealth;
|
||||
}
|
||||
|
||||
public boolean isUseHealth() { return useHealth; }
|
||||
public void setUseHealth(boolean useHealth) { this.useHealth = useHealth; }
|
||||
public void setMaxHealth(float maxHealth) {
|
||||
this.maxHealth = Math.max(0, maxHealth);
|
||||
}
|
||||
|
||||
public int getDurationTicks() { return durationTicks; }
|
||||
public void setDurationTicks(int durationTicks) { this.durationTicks = Math.max(1, durationTicks); }
|
||||
public boolean isUseHealth() {
|
||||
return useHealth;
|
||||
}
|
||||
|
||||
public boolean isUseDuration() { return useDuration; }
|
||||
public void setUseDuration(boolean useDuration) { this.useDuration = useDuration; }
|
||||
public void setUseHealth(boolean useHealth) {
|
||||
this.useHealth = useHealth;
|
||||
}
|
||||
|
||||
public float getDefaultMultiplier() { return defaultMultiplier; }
|
||||
public void setDefaultMultiplier(float defaultMultiplier) { this.defaultMultiplier = defaultMultiplier; }
|
||||
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 static String[] getKnockbackTargetKeys() {
|
||||
return KNOCKBACK_TARGET_KEYS;
|
||||
}
|
||||
|
||||
public String getKnockbackTargetKey() {
|
||||
return KNOCKBACK_TARGET_KEYS[Math.max(0, Math.min(knockbackTarget, 2))];
|
||||
|
||||
@@ -15,7 +15,8 @@ public class EnergyCombatData implements IEnergyCombatData {
|
||||
public float explosionRadius = 3.0f;
|
||||
public float explosionDamageFalloff = 0.5f;
|
||||
|
||||
public EnergyCombatData() {}
|
||||
public EnergyCombatData() {
|
||||
}
|
||||
|
||||
public EnergyCombatData(float damage, float knockback, float knockbackUp,
|
||||
boolean explosive, float explosionRadius, float explosionDamageFalloff) {
|
||||
|
||||
@@ -20,7 +20,8 @@ public class EnergyDisplayData implements IEnergyDisplayData {
|
||||
// public boolean skyboxEnabled = false;
|
||||
// public String skyboxTexture = "";
|
||||
|
||||
public EnergyDisplayData() {}
|
||||
public EnergyDisplayData() {
|
||||
}
|
||||
|
||||
public EnergyDisplayData(int innerColor, int outerColor) {
|
||||
this.innerColor = innerColor;
|
||||
|
||||
@@ -14,7 +14,8 @@ public class EnergyHomingData implements IEnergyHomingData {
|
||||
public float homingStrength = 0.15f;
|
||||
public float homingRange = 20.0f;
|
||||
|
||||
public EnergyHomingData() {}
|
||||
public EnergyHomingData() {
|
||||
}
|
||||
|
||||
public EnergyHomingData(float speed, boolean homing, float homingStrength, float homingRange) {
|
||||
this.speed = speed;
|
||||
|
||||
@@ -8,10 +8,11 @@ import noppes.npcs.api.ability.data.IEnergyLifespanData;
|
||||
* Used as a parameter object for entity constructors and ability configuration.
|
||||
*/
|
||||
public class EnergyLifespanData implements IEnergyLifespanData {
|
||||
public float maxDistance = 30.0f;
|
||||
public float maxDistance = 150.0f;
|
||||
public int maxLifetime = 200;
|
||||
|
||||
public EnergyLifespanData() {}
|
||||
public EnergyLifespanData() {
|
||||
}
|
||||
|
||||
public EnergyLifespanData(float maxDistance, int maxLifetime) {
|
||||
this.maxDistance = maxDistance;
|
||||
|
||||
@@ -13,7 +13,8 @@ public class EnergyLightningData implements IEnergyLightningData {
|
||||
public float lightningRadius = 0.5f;
|
||||
public int lightningFadeTime = 6;
|
||||
|
||||
public EnergyLightningData() {}
|
||||
public EnergyLightningData() {
|
||||
}
|
||||
|
||||
public EnergyLightningData(boolean lightningEffect, float lightningDensity,
|
||||
float lightningRadius, int lightningFadeTime) {
|
||||
|
||||
@@ -17,7 +17,8 @@ public class EnergyPanelData {
|
||||
public float launchDamage = 8.0f;
|
||||
public float launchKnockback = 2.0f;
|
||||
|
||||
public EnergyPanelData() {}
|
||||
public EnergyPanelData() {
|
||||
}
|
||||
|
||||
public EnergyPanelData(float panelWidth, float panelHeight, float heightOffset) {
|
||||
this.panelWidth = panelWidth;
|
||||
@@ -27,26 +28,61 @@ public class EnergyPanelData {
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getPanelWidth() { return panelWidth; }
|
||||
public void setPanelWidth(float panelWidth) { this.panelWidth = Math.max(0.5f, panelWidth); }
|
||||
public float getPanelWidth() {
|
||||
return panelWidth;
|
||||
}
|
||||
|
||||
public float getPanelHeight() { return panelHeight; }
|
||||
public void setPanelHeight(float panelHeight) { this.panelHeight = Math.max(0.5f, panelHeight); }
|
||||
public void setPanelWidth(float panelWidth) {
|
||||
this.panelWidth = Math.max(0.5f, panelWidth);
|
||||
}
|
||||
|
||||
public float getHeightOffset() { return heightOffset; }
|
||||
public void setHeightOffset(float heightOffset) { this.heightOffset = heightOffset; }
|
||||
public float getPanelHeight() {
|
||||
return panelHeight;
|
||||
}
|
||||
|
||||
public boolean isLaunching() { return launching; }
|
||||
public void setLaunching(boolean launching) { this.launching = launching; }
|
||||
public void setPanelHeight(float panelHeight) {
|
||||
this.panelHeight = Math.max(0.5f, panelHeight);
|
||||
}
|
||||
|
||||
public float getLaunchSpeed() { return launchSpeed; }
|
||||
public void setLaunchSpeed(float launchSpeed) { this.launchSpeed = Math.max(0.1f, launchSpeed); }
|
||||
public float getHeightOffset() {
|
||||
return heightOffset;
|
||||
}
|
||||
|
||||
public float getLaunchDamage() { return launchDamage; }
|
||||
public void setLaunchDamage(float launchDamage) { this.launchDamage = Math.max(0, launchDamage); }
|
||||
public void setHeightOffset(float heightOffset) {
|
||||
this.heightOffset = heightOffset;
|
||||
}
|
||||
|
||||
public float getLaunchKnockback() { return launchKnockback; }
|
||||
public void setLaunchKnockback(float launchKnockback) { this.launchKnockback = Math.max(0, launchKnockback); }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ public class EnergyTrajectoryData implements IEnergyTrajectoryData {
|
||||
public int currentPath = 0;
|
||||
private final List<Path> trajectory = new ArrayList<>();
|
||||
|
||||
public EnergyTrajectoryData() {}
|
||||
public EnergyTrajectoryData() {
|
||||
}
|
||||
|
||||
public EnergyTrajectoryData(int startingPath, Path... paths) {
|
||||
trajectory.addAll(Arrays.asList(paths));
|
||||
@@ -85,6 +86,7 @@ public class EnergyTrajectoryData implements IEnergyTrajectoryData {
|
||||
IPath p = getPath(path);
|
||||
return p == null ? 0 : p.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(int path, double x) {
|
||||
IPath p = getPath(path);
|
||||
@@ -126,8 +128,8 @@ public class EnergyTrajectoryData implements IEnergyTrajectoryData {
|
||||
@Override
|
||||
public void setPath(int path, double x, double y, double z, int delay) {
|
||||
Path newPath = new Path(
|
||||
NpcAPI.Instance().getIPos(x, y, z),
|
||||
delay
|
||||
NpcAPI.Instance().getIPos(x, y, z),
|
||||
delay
|
||||
);
|
||||
|
||||
while (trajectory.size() <= path) {
|
||||
@@ -196,7 +198,7 @@ public class EnergyTrajectoryData implements IEnergyTrajectoryData {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Path implements IEnergyTrajectoryData.IPath{
|
||||
public static class Path implements IEnergyTrajectoryData.IPath {
|
||||
public IPos pos;
|
||||
public int delayTicks;
|
||||
public boolean concluded;
|
||||
|
||||
@@ -199,5 +199,7 @@ public class AbilityFieldBuilder extends GuiFieldBuilder {
|
||||
return super.handleTextFieldEvent(textFieldId, field);
|
||||
}
|
||||
|
||||
public Map<Integer, int[]> getEffectWidgetMeta() { return effectWidgetMeta; }
|
||||
public Map<Integer, int[]> getEffectWidgetMeta() {
|
||||
return effectWidgetMeta;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
@@ -11,10 +12,8 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import noppes.npcs.api.ability.type.IAbilityCharge;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -172,6 +171,12 @@ public class AbilityCharge extends AbilityMovement implements IAbilityCharge {
|
||||
hitEntities.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForBurst() {
|
||||
super.resetForBurst();
|
||||
hitEntities.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTelegraphLength() {
|
||||
return maxRange;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
@@ -11,15 +14,8 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilityCutter;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -40,9 +36,12 @@ public class AbilityCutter extends Ability implements IAbilityCutter {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case SWIPE: return "ability.sweep.swipe";
|
||||
case SPIN: return "ability.sweep.spin";
|
||||
default: return name();
|
||||
case SWIPE:
|
||||
return "ability.sweep.swipe";
|
||||
case SPIN:
|
||||
return "ability.sweep.spin";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +231,7 @@ public class AbilityCutter extends Ability implements IAbilityCutter {
|
||||
* For SWIPE mode, this covers the continuous arc from startAngle to endAngle.
|
||||
*/
|
||||
private void performSweepDamageRange(EntityLivingBase caster, World world, float minDist, float maxDist,
|
||||
float startAngle, float endAngle) {
|
||||
float startAngle, float endAngle) {
|
||||
// Calculate the angular range covered this tick
|
||||
float minAngle = Math.min(startAngle, endAngle);
|
||||
float maxAngle = Math.max(startAngle, endAngle);
|
||||
|
||||
@@ -8,9 +8,8 @@ import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.api.ability.type.IAbilityDash;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -32,9 +31,12 @@ public class AbilityDash extends AbilityMovement implements IAbilityDash {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case AGGRESSIVE: return "ability.dash.aggressive";
|
||||
case DEFENSIVE: return "ability.dash.defensive";
|
||||
default: return name();
|
||||
case AGGRESSIVE:
|
||||
return "ability.dash.aggressive";
|
||||
case DEFENSIVE:
|
||||
return "ability.dash.defensive";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,6 +196,12 @@ public class AbilityDash extends AbilityMovement implements IAbilityDash {
|
||||
chosenDirection = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForBurst() {
|
||||
super.resetForBurst();
|
||||
chosenDirection = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPreviewDuration() {
|
||||
return (int) Math.ceil(dashDistance / dashSpeed) + 5;
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.*;
|
||||
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.AbilityPhase;
|
||||
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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
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.api.ability.type.IAbilityGuard;
|
||||
import noppes.npcs.api.handler.data.IAnimation;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
import noppes.npcs.controllers.data.PlayerData;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilityGuard;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import noppes.npcs.util.ValueUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -77,9 +78,12 @@ public class AbilityGuard extends Ability implements IAbilityGuard {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case FLAT: return "ability.counter.flat";
|
||||
case PERCENT: return "ability.counter.percent";
|
||||
default: return name();
|
||||
case FLAT:
|
||||
return "ability.counter.flat";
|
||||
case PERCENT:
|
||||
return "ability.counter.percent";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ZoneShape;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilityHazard;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -106,20 +102,45 @@ public class AbilityHazard extends AbilityZone implements IAbilityHazard {
|
||||
this.affectsCaster = nbt.getBoolean("affectsCaster");
|
||||
}
|
||||
|
||||
public float getRadius() { return radius; }
|
||||
public void setRadius(float radius) { this.radius = radius; }
|
||||
public float getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public float getDamagePerSecond() { return damagePerSecond; }
|
||||
public void setDamagePerSecond(float damagePerSecond) { this.damagePerSecond = damagePerSecond; }
|
||||
public void setRadius(float radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public int getDamageInterval() { return damageInterval; }
|
||||
public void setDamageInterval(int damageInterval) { this.damageInterval = damageInterval; }
|
||||
public float getDamagePerSecond() {
|
||||
return damagePerSecond;
|
||||
}
|
||||
|
||||
public boolean isIgnoreInvulnFrames() { return ignoreInvulnFrames; }
|
||||
public void setIgnoreInvulnFrames(boolean ignoreInvulnFrames) { this.ignoreInvulnFrames = ignoreInvulnFrames; }
|
||||
public void setDamagePerSecond(float damagePerSecond) {
|
||||
this.damagePerSecond = damagePerSecond;
|
||||
}
|
||||
|
||||
public boolean isAffectsCaster() { return affectsCaster; }
|
||||
public void setAffectsCaster(boolean affectsCaster) { this.affectsCaster = affectsCaster; }
|
||||
public int getDamageInterval() {
|
||||
return damageInterval;
|
||||
}
|
||||
|
||||
public void setDamageInterval(int damageInterval) {
|
||||
this.damageInterval = damageInterval;
|
||||
}
|
||||
|
||||
public boolean isIgnoreInvulnFrames() {
|
||||
return ignoreInvulnFrames;
|
||||
}
|
||||
|
||||
public void setIgnoreInvulnFrames(boolean ignoreInvulnFrames) {
|
||||
this.ignoreInvulnFrames = ignoreInvulnFrames;
|
||||
}
|
||||
|
||||
public boolean isAffectsCaster() {
|
||||
return affectsCaster;
|
||||
}
|
||||
|
||||
public void setAffectsCaster(boolean affectsCaster) {
|
||||
this.affectsCaster = affectsCaster;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
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;
|
||||
@@ -9,13 +11,9 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.api.ability.type.IAbilityHeal;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -5,13 +5,13 @@ 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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import noppes.npcs.api.ability.type.IAbilityHeavyHit;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -53,6 +53,12 @@ public abstract class AbilityMovement extends Ability {
|
||||
maxActiveTicks = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForBurst() {
|
||||
movementDirection = null;
|
||||
maxActiveTicks = 0;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// DIRECTION HELPERS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -5,18 +5,15 @@ 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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilityProjectile;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -94,7 +91,11 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile {
|
||||
double dy = (target.posY + target.height / 2) - (caster.posY + caster.getEyeHeight());
|
||||
double dz = target.posZ - caster.posZ;
|
||||
double len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (len > 0) { dx /= len; dy /= len; dz /= len; }
|
||||
if (len > 0) {
|
||||
dx /= len;
|
||||
dy /= len;
|
||||
dz /= len;
|
||||
}
|
||||
|
||||
applyAbilityDamageWithDirection(caster, target, damage, knockback, dx, dz);
|
||||
world.playSoundAtEntity(caster, "random.bow", 1.0f, 0.8f);
|
||||
@@ -167,7 +168,7 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile {
|
||||
* Apply explosion splash damage around a point.
|
||||
*/
|
||||
private void applyExplosionDamage(EntityLivingBase caster, EntityLivingBase primaryTarget, World world,
|
||||
double x, double y, double z) {
|
||||
double x, double y, double z) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Entity> entities = world.getEntitiesWithinAABBExcludingEntity(primaryTarget,
|
||||
primaryTarget.boundingBox.expand(explosionRadius, explosionRadius, explosionRadius));
|
||||
|
||||
@@ -5,16 +5,13 @@ 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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import noppes.npcs.api.ability.type.IAbilityShockwave;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -5,6 +5,7 @@ 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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
@@ -13,13 +14,10 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.api.ability.type.IAbilitySlam;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilitySlam;
|
||||
import somehussar.gui.annotationHandling.GuiEditable;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
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.UserType;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -13,15 +16,8 @@ import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.api.ability.type.IAbilityTeleport;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -43,10 +39,14 @@ public class AbilityTeleport extends Ability implements IAbilityTeleport {
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case BLINK: return "ability.teleport.blink";
|
||||
case BEHIND: return "ability.teleport.behind";
|
||||
case SINGLE: return "ability.teleport.single";
|
||||
default: return name();
|
||||
case BLINK:
|
||||
return "ability.teleport.blink";
|
||||
case BEHIND:
|
||||
return "ability.teleport.behind";
|
||||
case SINGLE:
|
||||
return "ability.teleport.single";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
@@ -12,9 +14,6 @@ import noppes.npcs.client.gui.SubGuiTrapPresetSelector;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.constants.EnumPotionType;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -115,51 +114,80 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
switch (preset) {
|
||||
case "VENOM":
|
||||
groundAlpha = 0.04f;
|
||||
particles = true; particleDensity = 0.3f; particleScale = 0.5f;
|
||||
particleMotion = 1; particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44; colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44; activeColor = 0xC044FF44;
|
||||
particles = true;
|
||||
particleDensity = 0.3f;
|
||||
particleScale = 0.5f;
|
||||
particleMotion = 1;
|
||||
particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44;
|
||||
colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44;
|
||||
activeColor = 0xC044FF44;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Poison, 100, 0));
|
||||
break;
|
||||
case "EXPLOSIVE":
|
||||
groundAlpha = 0.04f;
|
||||
particles = true; particleDensity = 0.3f; particleScale = 0.6f;
|
||||
particleMotion = 0; particleDir = "mc:smoke";
|
||||
colorData.innerColor = 0xFF6611; colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611; activeColor = 0xC0FF4400;
|
||||
particles = true;
|
||||
particleDensity = 0.3f;
|
||||
particleScale = 0.6f;
|
||||
particleMotion = 0;
|
||||
particleDir = "mc:smoke";
|
||||
colorData.innerColor = 0xFF6611;
|
||||
colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611;
|
||||
activeColor = 0xC0FF4400;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Fire, 60, 0));
|
||||
break;
|
||||
case "CURSED":
|
||||
groundAlpha = 0.04f;
|
||||
particles = true; particleDensity = 0.3f; particleScale = 0.5f;
|
||||
particleMotion = 1; particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF; colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF; activeColor = 0xC0CC66FF;
|
||||
particles = true;
|
||||
particleDensity = 0.3f;
|
||||
particleScale = 0.5f;
|
||||
particleMotion = 1;
|
||||
particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF;
|
||||
colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF;
|
||||
activeColor = 0xC0CC66FF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Weakness, 100, 0));
|
||||
break;
|
||||
case "SHOCK":
|
||||
groundAlpha = 0.04f;
|
||||
particles = true; particleDensity = 0.3f; particleScale = 0.4f;
|
||||
particleMotion = 2; particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF; colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF; activeColor = 0xC066AAFF;
|
||||
particles = true;
|
||||
particleDensity = 0.3f;
|
||||
particleScale = 0.4f;
|
||||
particleMotion = 2;
|
||||
particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF;
|
||||
colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF;
|
||||
activeColor = 0xC066AAFF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
break;
|
||||
case "SNARE":
|
||||
groundAlpha = 0.04f;
|
||||
particles = true; particleDensity = 0.3f; particleScale = 0.5f;
|
||||
particleMotion = 1; particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF; colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF; activeColor = 0xC0AADDFF;
|
||||
particles = true;
|
||||
particleDensity = 0.3f;
|
||||
particleScale = 0.5f;
|
||||
particleMotion = 1;
|
||||
particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF;
|
||||
colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF;
|
||||
activeColor = 0xC0AADDFF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Slowness, 100, 1));
|
||||
break;
|
||||
case "HIDDEN":
|
||||
default:
|
||||
groundAlpha = 0.03f;
|
||||
particles = false; particleDensity = 0.0f; particleScale = 1.0f;
|
||||
particles = false;
|
||||
particleDensity = 0.0f;
|
||||
particleScale = 1.0f;
|
||||
particleMotion = 0;
|
||||
colorData.innerColor = 0x888888; colorData.outerColor = 0x444444;
|
||||
windUpColor = 0x60888888; activeColor = 0xC0AAAAAA;
|
||||
colorData.innerColor = 0x888888;
|
||||
colorData.outerColor = 0x444444;
|
||||
windUpColor = 0x60888888;
|
||||
activeColor = 0xC0AAAAAA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -190,22 +218,69 @@ public class AbilityTrap extends AbilityZone implements IAbilityTrap {
|
||||
this.visible = nbt.getBoolean("visible");
|
||||
}
|
||||
|
||||
public float getTriggerRadius() { return triggerRadius; }
|
||||
public void setTriggerRadius(float triggerRadius) { this.triggerRadius = triggerRadius; }
|
||||
public int getArmTime() { return armTime; }
|
||||
public void setArmTime(int armTime) { this.armTime = armTime; }
|
||||
public int getMaxTriggers() { return maxTriggers; }
|
||||
public void setMaxTriggers(int maxTriggers) { this.maxTriggers = maxTriggers; }
|
||||
public int getTriggerCooldown() { return triggerCooldown; }
|
||||
public void setTriggerCooldown(int triggerCooldown) { this.triggerCooldown = triggerCooldown; }
|
||||
public float getDamage() { return damage; }
|
||||
public void setDamage(float damage) { this.damage = damage; }
|
||||
public float getDamageRadius() { return damageRadius; }
|
||||
public void setDamageRadius(float damageRadius) { this.damageRadius = damageRadius; }
|
||||
public float getKnockback() { return knockback; }
|
||||
public void setKnockback(float knockback) { this.knockback = knockback; }
|
||||
public boolean isVisible() { return visible; }
|
||||
public void setVisible(boolean visible) { this.visible = visible; }
|
||||
public float getTriggerRadius() {
|
||||
return triggerRadius;
|
||||
}
|
||||
|
||||
public void setTriggerRadius(float triggerRadius) {
|
||||
this.triggerRadius = triggerRadius;
|
||||
}
|
||||
|
||||
public int getArmTime() {
|
||||
return armTime;
|
||||
}
|
||||
|
||||
public void setArmTime(int armTime) {
|
||||
this.armTime = armTime;
|
||||
}
|
||||
|
||||
public int getMaxTriggers() {
|
||||
return maxTriggers;
|
||||
}
|
||||
|
||||
public void setMaxTriggers(int maxTriggers) {
|
||||
this.maxTriggers = maxTriggers;
|
||||
}
|
||||
|
||||
public int getTriggerCooldown() {
|
||||
return triggerCooldown;
|
||||
}
|
||||
|
||||
public void setTriggerCooldown(int triggerCooldown) {
|
||||
this.triggerCooldown = triggerCooldown;
|
||||
}
|
||||
|
||||
public float getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
public void setDamage(float damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
public float getDamageRadius() {
|
||||
return damageRadius;
|
||||
}
|
||||
|
||||
public void setDamageRadius(float damageRadius) {
|
||||
this.damageRadius = damageRadius;
|
||||
}
|
||||
|
||||
public float getKnockback() {
|
||||
return knockback;
|
||||
}
|
||||
|
||||
public void setKnockback(float knockback) {
|
||||
this.knockback = knockback;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
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.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import noppes.npcs.api.ability.type.IAbilityVortex;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kamkeel.npcs.controllers.data.ability.type;
|
||||
|
||||
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.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
@@ -14,15 +16,10 @@ import kamkeel.npcs.entity.EntityAbilityZone.ParticleMotion;
|
||||
import kamkeel.npcs.entity.EntityAbilityZone.ZoneShape;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.constants.EnumPotionType;
|
||||
import net.minecraft.util.DamageSource;
|
||||
|
||||
|
||||
import noppes.npcs.client.gui.SubGuiZonePresetSelector;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import noppes.npcs.constants.EnumPotionType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -213,57 +210,134 @@ public abstract class AbilityZone extends Ability {
|
||||
particleDir = "";
|
||||
switch (styleName) {
|
||||
case "TOXIC":
|
||||
groundFill = true; groundAlpha = 0.30f; rings = true; ringCount = 3;
|
||||
border = false; borderSpeed = 1.0f; accents = true; accentStyle = 1;
|
||||
lightning = false; particles = true; particleDensity = 1.5f; particleScale = 0.8f;
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44; colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44; activeColor = 0xC044FF44;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.30f;
|
||||
rings = true;
|
||||
ringCount = 3;
|
||||
border = false;
|
||||
borderSpeed = 1.0f;
|
||||
accents = true;
|
||||
accentStyle = 1;
|
||||
lightning = false;
|
||||
particles = true;
|
||||
particleDensity = 1.5f;
|
||||
particleScale = 0.8f;
|
||||
particleMotion = 1;
|
||||
particleGlow = true;
|
||||
particleDir = "mc:mobSpell";
|
||||
colorData.innerColor = 0x44DD44;
|
||||
colorData.outerColor = 0x116611;
|
||||
windUpColor = 0x6044DD44;
|
||||
activeColor = 0xC044FF44;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Poison, 100, 0));
|
||||
break;
|
||||
case "INFERNO":
|
||||
groundFill = true; groundAlpha = 0.35f; rings = true; ringCount = 3;
|
||||
border = true; borderSpeed = 2.0f; accents = true; accentStyle = 2;
|
||||
lightning = false; particles = true; particleDensity = 2.0f; particleScale = 1.2f;
|
||||
particleMotion = 0; particleGlow = true; particleDir = "mc:flame";
|
||||
colorData.innerColor = 0xFF6611; colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611; activeColor = 0xC0FF4400;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.35f;
|
||||
rings = true;
|
||||
ringCount = 3;
|
||||
border = true;
|
||||
borderSpeed = 2.0f;
|
||||
accents = true;
|
||||
accentStyle = 2;
|
||||
lightning = false;
|
||||
particles = true;
|
||||
particleDensity = 2.0f;
|
||||
particleScale = 1.2f;
|
||||
particleMotion = 0;
|
||||
particleGlow = true;
|
||||
particleDir = "mc:flame";
|
||||
colorData.innerColor = 0xFF6611;
|
||||
colorData.outerColor = 0xCC2200;
|
||||
windUpColor = 0x60FF6611;
|
||||
activeColor = 0xC0FF4400;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Fire, 60, 0));
|
||||
break;
|
||||
case "ARCANE":
|
||||
groundFill = true; groundAlpha = 0.20f; rings = true; ringCount = 1;
|
||||
border = true; borderSpeed = 0.8f; accents = true; accentStyle = 0;
|
||||
lightning = false; particles = true; particleDensity = 1.0f; particleScale = 1.0f;
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF; colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF; activeColor = 0xC0CC66FF;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.20f;
|
||||
rings = true;
|
||||
ringCount = 1;
|
||||
border = true;
|
||||
borderSpeed = 0.8f;
|
||||
accents = true;
|
||||
accentStyle = 0;
|
||||
lightning = false;
|
||||
particles = true;
|
||||
particleDensity = 1.0f;
|
||||
particleScale = 1.0f;
|
||||
particleMotion = 1;
|
||||
particleGlow = true;
|
||||
particleDir = "mc:portal";
|
||||
colorData.innerColor = 0xAA44FF;
|
||||
colorData.outerColor = 0x6622BB;
|
||||
windUpColor = 0x60AA44FF;
|
||||
activeColor = 0xC0CC66FF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Weakness, 100, 0));
|
||||
break;
|
||||
case "ELECTRIC":
|
||||
groundFill = true; groundAlpha = 0.15f; rings = false; ringCount = 1;
|
||||
border = false; borderSpeed = 1.0f; accents = false; accentStyle = 0;
|
||||
lightning = true; particles = true; particleDensity = 0.8f; particleScale = 0.6f;
|
||||
particleMotion = 2; particleGlow = true; particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF; colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF; activeColor = 0xC066AAFF;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.15f;
|
||||
rings = false;
|
||||
ringCount = 1;
|
||||
border = false;
|
||||
borderSpeed = 1.0f;
|
||||
accents = false;
|
||||
accentStyle = 0;
|
||||
lightning = true;
|
||||
particles = true;
|
||||
particleDensity = 0.8f;
|
||||
particleScale = 0.6f;
|
||||
particleMotion = 2;
|
||||
particleGlow = true;
|
||||
particleDir = "mc:enchantmenttable";
|
||||
colorData.innerColor = 0x4488FF;
|
||||
colorData.outerColor = 0x2244BB;
|
||||
windUpColor = 0x604488FF;
|
||||
activeColor = 0xC066AAFF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.MiningFatigue, 80, 1));
|
||||
break;
|
||||
case "FROST":
|
||||
groundFill = true; groundAlpha = 0.25f; rings = true; ringCount = 3;
|
||||
border = true; borderSpeed = 0.3f; accents = true; accentStyle = 0;
|
||||
lightning = false; particles = true; particleDensity = 1.5f; particleScale = 1.0f;
|
||||
particleMotion = 1; particleGlow = true; particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF; colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF; activeColor = 0xC0AADDFF;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.25f;
|
||||
rings = true;
|
||||
ringCount = 3;
|
||||
border = true;
|
||||
borderSpeed = 0.3f;
|
||||
accents = true;
|
||||
accentStyle = 0;
|
||||
lightning = false;
|
||||
particles = true;
|
||||
particleDensity = 1.5f;
|
||||
particleScale = 1.0f;
|
||||
particleMotion = 1;
|
||||
particleGlow = true;
|
||||
particleDir = "mc:snowshovel";
|
||||
colorData.innerColor = 0x88CCFF;
|
||||
colorData.outerColor = 0x4488CC;
|
||||
windUpColor = 0x6088CCFF;
|
||||
activeColor = 0xC0AADDFF;
|
||||
effects.add(new AbilityPotionEffect(EnumPotionType.Slowness, 100, 1));
|
||||
break;
|
||||
case "DEFAULT":
|
||||
groundFill = true; groundAlpha = 0.25f; rings = true; ringCount = 3;
|
||||
border = true; borderSpeed = 1.0f; accents = true; accentStyle = 0;
|
||||
lightning = false; particles = false; particleDensity = 1.0f; particleScale = 1.0f;
|
||||
particleMotion = 0; particleGlow = true;
|
||||
colorData.innerColor = 0xCCCCCC; colorData.outerColor = 0x666666;
|
||||
windUpColor = 0x60CCCCCC; activeColor = 0xC0FFFFFF;
|
||||
groundFill = true;
|
||||
groundAlpha = 0.25f;
|
||||
rings = true;
|
||||
ringCount = 3;
|
||||
border = true;
|
||||
borderSpeed = 1.0f;
|
||||
accents = true;
|
||||
accentStyle = 0;
|
||||
lightning = false;
|
||||
particles = false;
|
||||
particleDensity = 1.0f;
|
||||
particleScale = 1.0f;
|
||||
particleMotion = 0;
|
||||
particleGlow = true;
|
||||
colorData.innerColor = 0xCCCCCC;
|
||||
colorData.outerColor = 0x666666;
|
||||
windUpColor = 0x60CCCCCC;
|
||||
activeColor = 0xC0FFFFFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -310,8 +384,11 @@ public abstract class AbilityZone extends Ability {
|
||||
|
||||
protected void readZoneNBT(NBTTagCompound nbt, int defaultDuration) {
|
||||
this.durationTicks = nbt.getInteger("durationTicks");
|
||||
try { this.zoneShape = ZoneShape.valueOf(nbt.getString("zoneShape")); }
|
||||
catch (Exception e) { this.zoneShape = ZoneShape.CIRCLE; }
|
||||
try {
|
||||
this.zoneShape = ZoneShape.valueOf(nbt.getString("zoneShape"));
|
||||
} catch (Exception e) {
|
||||
this.zoneShape = ZoneShape.CIRCLE;
|
||||
}
|
||||
this.spawnRadius = nbt.getFloat("spawnRadius");
|
||||
this.zoneCount = nbt.getInteger("zoneCount");
|
||||
this.zoneHeight = nbt.getFloat("zoneHeight");
|
||||
@@ -337,73 +414,238 @@ public abstract class AbilityZone extends Ability {
|
||||
this.particleGlow = nbt.getBoolean("particleGlow");
|
||||
}
|
||||
|
||||
public int getDurationTicks() { return durationTicks; }
|
||||
public void setDurationTicks(int durationTicks) { this.durationTicks = Math.max(1, durationTicks); }
|
||||
public int getDurationTicks() {
|
||||
return durationTicks;
|
||||
}
|
||||
|
||||
public ZoneShape getZoneShapeEnum() { return zoneShape; }
|
||||
public void setZoneShapeEnum(ZoneShape shape) { this.zoneShape = shape; }
|
||||
public void setDurationTicks(int durationTicks) {
|
||||
this.durationTicks = Math.max(1, durationTicks);
|
||||
}
|
||||
|
||||
public ZoneShape getZoneShapeEnum() {
|
||||
return zoneShape;
|
||||
}
|
||||
|
||||
public void setZoneShapeEnum(ZoneShape shape) {
|
||||
this.zoneShape = shape;
|
||||
}
|
||||
|
||||
public int getZoneShapeOrdinal() {
|
||||
return zoneShape.ordinal();
|
||||
}
|
||||
|
||||
public int getZoneShapeOrdinal() { return zoneShape.ordinal(); }
|
||||
public void setZoneShapeOrdinal(int shape) {
|
||||
ZoneShape[] values = ZoneShape.values();
|
||||
this.zoneShape = shape >= 0 && shape < values.length ? values[shape] : ZoneShape.CIRCLE;
|
||||
}
|
||||
|
||||
public float getSpawnRadius() { return spawnRadius; }
|
||||
public void setSpawnRadius(float spawnRadius) { this.spawnRadius = Math.max(0, spawnRadius); }
|
||||
public int getZoneCount() { return zoneCount; }
|
||||
public void setZoneCount(int zoneCount) { this.zoneCount = Math.max(1, zoneCount); }
|
||||
public float getZoneHeight() { return zoneHeight; }
|
||||
public void setZoneHeight(float zoneHeight) { this.zoneHeight = Math.max(0.5f, zoneHeight); }
|
||||
public float getSpawnRadius() {
|
||||
return spawnRadius;
|
||||
}
|
||||
|
||||
public float getParticleDensity() { return particleDensity; }
|
||||
public void setParticleDensity(float v) { this.particleDensity = Math.max(0, Math.min(5, v)); }
|
||||
public float getParticleScale() { return particleScale; }
|
||||
public void setParticleScale(float v) { this.particleScale = Math.max(0.1f, Math.min(5, v)); }
|
||||
public float getAnimSpeed() { return animSpeed; }
|
||||
public void setAnimSpeed(float v) { this.animSpeed = Math.max(0.1f, Math.min(5, v)); }
|
||||
public float getLightningDensity() { return lightningDensity; }
|
||||
public void setLightningDensity(float v) { this.lightningDensity = Math.max(0, Math.min(3, v)); }
|
||||
public void setSpawnRadius(float spawnRadius) {
|
||||
this.spawnRadius = Math.max(0, spawnRadius);
|
||||
}
|
||||
|
||||
public int getInnerColor() { return colorData.innerColor; }
|
||||
public void setInnerColor(int color) { colorData.innerColor = color; }
|
||||
public int getOuterColor() { return colorData.outerColor; }
|
||||
public void setOuterColor(int color) { colorData.outerColor = color; }
|
||||
public boolean isOuterColorEnabled() { return colorData.outerColorEnabled; }
|
||||
public void setOuterColorEnabled(boolean enabled) { colorData.outerColorEnabled = enabled; }
|
||||
public int getZoneCount() {
|
||||
return zoneCount;
|
||||
}
|
||||
|
||||
public boolean isGroundFill() { return groundFill; }
|
||||
public void setGroundFill(boolean v) { this.groundFill = v; }
|
||||
public float getGroundAlpha() { return groundAlpha; }
|
||||
public void setGroundAlpha(float v) { this.groundAlpha = Math.max(0, Math.min(1, v)); }
|
||||
public boolean isRings() { return rings; }
|
||||
public void setRings(boolean v) { this.rings = v; }
|
||||
public int getRingCount() { return ringCount; }
|
||||
public void setRingCount(int v) { this.ringCount = Math.max(1, Math.min(5, v)); }
|
||||
public boolean isBorder() { return border; }
|
||||
public void setBorder(boolean v) { this.border = v; }
|
||||
public float getBorderSpeed() { return borderSpeed; }
|
||||
public void setBorderSpeed(float v) { this.borderSpeed = Math.max(0.1f, Math.min(5, v)); }
|
||||
public boolean isAccents() { return accents; }
|
||||
public void setAccents(boolean v) { this.accents = v; }
|
||||
public int getAccentStyle() { return accentStyle; }
|
||||
public void setAccentStyle(int v) { this.accentStyle = Math.max(0, Math.min(AccentStyle.values().length - 1, v)); }
|
||||
public AccentStyle getAccentStyleEnum() { return AccentStyle.values()[Math.max(0, Math.min(accentStyle, AccentStyle.values().length - 1))]; }
|
||||
public void setAccentStyleEnum(AccentStyle s) { this.accentStyle = s.ordinal(); }
|
||||
public boolean isLightning() { return lightning; }
|
||||
public void setLightning(boolean v) { this.lightning = v; }
|
||||
public boolean isParticles() { return particles; }
|
||||
public void setParticles(boolean v) { this.particles = v; }
|
||||
public int getParticleMotion() { return particleMotion; }
|
||||
public void setParticleMotion(int v) { this.particleMotion = Math.max(0, Math.min(ParticleMotion.values().length - 1, v)); }
|
||||
public ParticleMotion getParticleMotionEnum() { return ParticleMotion.values()[Math.max(0, Math.min(particleMotion, ParticleMotion.values().length - 1))]; }
|
||||
public void setParticleMotionEnum(ParticleMotion m) { this.particleMotion = m.ordinal(); }
|
||||
public String getParticleDir() { return particleDir; }
|
||||
public void setParticleDir(String v) { this.particleDir = v != null ? v : ""; }
|
||||
public int getParticleSize() { return particleSize; }
|
||||
public void setParticleSize(int v) { this.particleSize = Math.max(1, Math.min(256, v)); }
|
||||
public boolean isParticleGlow() { return particleGlow; }
|
||||
public void setParticleGlow(boolean v) { this.particleGlow = v; }
|
||||
public void setZoneCount(int zoneCount) {
|
||||
this.zoneCount = Math.max(1, zoneCount);
|
||||
}
|
||||
|
||||
public float getZoneHeight() {
|
||||
return zoneHeight;
|
||||
}
|
||||
|
||||
public void setZoneHeight(float zoneHeight) {
|
||||
this.zoneHeight = Math.max(0.5f, zoneHeight);
|
||||
}
|
||||
|
||||
public float getParticleDensity() {
|
||||
return particleDensity;
|
||||
}
|
||||
|
||||
public void setParticleDensity(float v) {
|
||||
this.particleDensity = Math.max(0, Math.min(5, v));
|
||||
}
|
||||
|
||||
public float getParticleScale() {
|
||||
return particleScale;
|
||||
}
|
||||
|
||||
public void setParticleScale(float v) {
|
||||
this.particleScale = Math.max(0.1f, Math.min(5, v));
|
||||
}
|
||||
|
||||
public float getAnimSpeed() {
|
||||
return animSpeed;
|
||||
}
|
||||
|
||||
public void setAnimSpeed(float v) {
|
||||
this.animSpeed = Math.max(0.1f, Math.min(5, v));
|
||||
}
|
||||
|
||||
public float getLightningDensity() {
|
||||
return lightningDensity;
|
||||
}
|
||||
|
||||
public void setLightningDensity(float v) {
|
||||
this.lightningDensity = Math.max(0, Math.min(3, v));
|
||||
}
|
||||
|
||||
public int getInnerColor() {
|
||||
return colorData.innerColor;
|
||||
}
|
||||
|
||||
public void setInnerColor(int color) {
|
||||
colorData.innerColor = color;
|
||||
}
|
||||
|
||||
public int getOuterColor() {
|
||||
return colorData.outerColor;
|
||||
}
|
||||
|
||||
public void setOuterColor(int color) {
|
||||
colorData.outerColor = color;
|
||||
}
|
||||
|
||||
public boolean isOuterColorEnabled() {
|
||||
return colorData.outerColorEnabled;
|
||||
}
|
||||
|
||||
public void setOuterColorEnabled(boolean enabled) {
|
||||
colorData.outerColorEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isGroundFill() {
|
||||
return groundFill;
|
||||
}
|
||||
|
||||
public void setGroundFill(boolean v) {
|
||||
this.groundFill = v;
|
||||
}
|
||||
|
||||
public float getGroundAlpha() {
|
||||
return groundAlpha;
|
||||
}
|
||||
|
||||
public void setGroundAlpha(float v) {
|
||||
this.groundAlpha = Math.max(0, Math.min(1, v));
|
||||
}
|
||||
|
||||
public boolean isRings() {
|
||||
return rings;
|
||||
}
|
||||
|
||||
public void setRings(boolean v) {
|
||||
this.rings = v;
|
||||
}
|
||||
|
||||
public int getRingCount() {
|
||||
return ringCount;
|
||||
}
|
||||
|
||||
public void setRingCount(int v) {
|
||||
this.ringCount = Math.max(1, Math.min(5, v));
|
||||
}
|
||||
|
||||
public boolean isBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
public void setBorder(boolean v) {
|
||||
this.border = v;
|
||||
}
|
||||
|
||||
public float getBorderSpeed() {
|
||||
return borderSpeed;
|
||||
}
|
||||
|
||||
public void setBorderSpeed(float v) {
|
||||
this.borderSpeed = Math.max(0.1f, Math.min(5, v));
|
||||
}
|
||||
|
||||
public boolean isAccents() {
|
||||
return accents;
|
||||
}
|
||||
|
||||
public void setAccents(boolean v) {
|
||||
this.accents = v;
|
||||
}
|
||||
|
||||
public int getAccentStyle() {
|
||||
return accentStyle;
|
||||
}
|
||||
|
||||
public void setAccentStyle(int v) {
|
||||
this.accentStyle = Math.max(0, Math.min(AccentStyle.values().length - 1, v));
|
||||
}
|
||||
|
||||
public AccentStyle getAccentStyleEnum() {
|
||||
return AccentStyle.values()[Math.max(0, Math.min(accentStyle, AccentStyle.values().length - 1))];
|
||||
}
|
||||
|
||||
public void setAccentStyleEnum(AccentStyle s) {
|
||||
this.accentStyle = s.ordinal();
|
||||
}
|
||||
|
||||
public boolean isLightning() {
|
||||
return lightning;
|
||||
}
|
||||
|
||||
public void setLightning(boolean v) {
|
||||
this.lightning = v;
|
||||
}
|
||||
|
||||
public boolean isParticles() {
|
||||
return particles;
|
||||
}
|
||||
|
||||
public void setParticles(boolean v) {
|
||||
this.particles = v;
|
||||
}
|
||||
|
||||
public int getParticleMotion() {
|
||||
return particleMotion;
|
||||
}
|
||||
|
||||
public void setParticleMotion(int v) {
|
||||
this.particleMotion = Math.max(0, Math.min(ParticleMotion.values().length - 1, v));
|
||||
}
|
||||
|
||||
public ParticleMotion getParticleMotionEnum() {
|
||||
return ParticleMotion.values()[Math.max(0, Math.min(particleMotion, ParticleMotion.values().length - 1))];
|
||||
}
|
||||
|
||||
public void setParticleMotionEnum(ParticleMotion m) {
|
||||
this.particleMotion = m.ordinal();
|
||||
}
|
||||
|
||||
public String getParticleDir() {
|
||||
return particleDir;
|
||||
}
|
||||
|
||||
public void setParticleDir(String v) {
|
||||
this.particleDir = v != null ? v : "";
|
||||
}
|
||||
|
||||
public int getParticleSize() {
|
||||
return particleSize;
|
||||
}
|
||||
|
||||
public void setParticleSize(int v) {
|
||||
this.particleSize = Math.max(1, Math.min(256, v));
|
||||
}
|
||||
|
||||
public boolean isParticleGlow() {
|
||||
return particleGlow;
|
||||
}
|
||||
|
||||
public void setParticleGlow(boolean v) {
|
||||
this.particleGlow = v;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
protected void addPresetFieldDef(List<FieldDef> defs) {
|
||||
|
||||
@@ -6,7 +6,11 @@ import kamkeel.npcs.controllers.data.ability.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.RotationMode;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
@@ -34,7 +38,7 @@ public class AbilityBeam extends AbilityEnergyProjectile<EntityAbilityBeam> impl
|
||||
new EnergyDisplayData(0xFFFFFF, 0x00AAFF, true, 0.4f, 0.5f, 6.0f),
|
||||
new EnergyCombatData(10.0f, 1.5f, 0.2f, false, 4.0f, 0.5f),
|
||||
new EnergyHomingData(0.4f, true, 0.1f, 15.0f),
|
||||
new EnergyLifespanData(25.0f, 200)
|
||||
new EnergyLifespanData(150.0f, 200)
|
||||
);
|
||||
this.typeId = "ability.cnpc.beam";
|
||||
this.name = "Beam";
|
||||
@@ -56,7 +60,7 @@ public class AbilityBeam extends AbilityEnergyProjectile<EntityAbilityBeam> impl
|
||||
|
||||
@Override
|
||||
protected EntityAbilityBeam createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityAbilityBeam(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
@@ -81,7 +85,7 @@ public class AbilityBeam extends AbilityEnergyProjectile<EntityAbilityBeam> impl
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityAbilityBeam beam, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
beam.setupPreview(caster, beamWidth, headSize, resolved, lightningData, projData.anchor, windUpTicks, 1.0f);
|
||||
}
|
||||
|
||||
@@ -139,14 +143,29 @@ public class AbilityBeam extends AbilityEnergyProjectile<EntityAbilityBeam> impl
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
|
||||
public float getSpeed() { return homingData.speed; }
|
||||
public void setSpeed(float speed) { homingData.speed = speed; }
|
||||
public float getSpeed() {
|
||||
return homingData.speed;
|
||||
}
|
||||
|
||||
public float getBeamWidth() { return beamWidth; }
|
||||
public void setBeamWidth(float beamWidth) { this.beamWidth = beamWidth; }
|
||||
public void setSpeed(float speed) {
|
||||
homingData.speed = speed;
|
||||
}
|
||||
|
||||
public float getHeadSize() { return headSize; }
|
||||
public void setHeadSize(float headSize) { this.headSize = headSize; }
|
||||
public float getBeamWidth() {
|
||||
return beamWidth;
|
||||
}
|
||||
|
||||
public void setBeamWidth(float beamWidth) {
|
||||
this.beamWidth = beamWidth;
|
||||
}
|
||||
|
||||
public float getHeadSize() {
|
||||
return headSize;
|
||||
}
|
||||
|
||||
public void setHeadSize(float headSize) {
|
||||
this.headSize = headSize;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ 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.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilityDisc;
|
||||
@@ -36,7 +40,7 @@ public class AbilityDisc extends AbilityEnergyProjectile<EntityAbilityDisc> impl
|
||||
new EnergyDisplayData(0xFFFFFF, 0xFF8800, true, 0.4f, 0.5f, 5.0f),
|
||||
new EnergyCombatData(8.0f, 1.2f, 0.15f, false, 3.0f, 0.5f),
|
||||
new EnergyHomingData(0.6f, true, 0.12f, 18.0f),
|
||||
new EnergyLifespanData(35.0f, 200)
|
||||
new EnergyLifespanData(150.0f, 200)
|
||||
);
|
||||
this.typeId = "ability.cnpc.disc";
|
||||
this.name = "Disc";
|
||||
@@ -56,7 +60,7 @@ public class AbilityDisc extends AbilityEnergyProjectile<EntityAbilityDisc> impl
|
||||
|
||||
@Override
|
||||
protected EntityAbilityDisc createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityAbilityDisc(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
@@ -81,7 +85,7 @@ public class AbilityDisc extends AbilityEnergyProjectile<EntityAbilityDisc> impl
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityAbilityDisc disc, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
disc.setupPreview(caster, discRadius, discThickness, resolved, lightningData, projData.anchor, windUpTicks, vertical);
|
||||
}
|
||||
|
||||
@@ -139,23 +143,53 @@ public class AbilityDisc extends AbilityEnergyProjectile<EntityAbilityDisc> impl
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
|
||||
public float getSpeed() { return homingData.speed; }
|
||||
public void setSpeed(float speed) { homingData.speed = speed; }
|
||||
public float getSpeed() {
|
||||
return homingData.speed;
|
||||
}
|
||||
|
||||
public float getDiscRadius() { return discRadius; }
|
||||
public void setDiscRadius(float discRadius) { this.discRadius = discRadius; }
|
||||
public void setSpeed(float speed) {
|
||||
homingData.speed = speed;
|
||||
}
|
||||
|
||||
public float getDiscThickness() { return discThickness; }
|
||||
public void setDiscThickness(float discThickness) { this.discThickness = discThickness; }
|
||||
public float getDiscRadius() {
|
||||
return discRadius;
|
||||
}
|
||||
|
||||
public boolean isVertical() { return vertical; }
|
||||
public void setVertical(boolean vertical) { this.vertical = vertical; }
|
||||
public void setDiscRadius(float discRadius) {
|
||||
this.discRadius = discRadius;
|
||||
}
|
||||
|
||||
public boolean isBoomerang() { return boomerang; }
|
||||
public void setBoomerang(boolean boomerang) { this.boomerang = boomerang; }
|
||||
public float getDiscThickness() {
|
||||
return discThickness;
|
||||
}
|
||||
|
||||
public int getBoomerangDelay() { return boomerangDelay; }
|
||||
public void setBoomerangDelay(int boomerangDelay) { this.boomerangDelay = boomerangDelay; }
|
||||
public void setDiscThickness(float discThickness) {
|
||||
this.discThickness = discThickness;
|
||||
}
|
||||
|
||||
public boolean isVertical() {
|
||||
return vertical;
|
||||
}
|
||||
|
||||
public void setVertical(boolean vertical) {
|
||||
this.vertical = vertical;
|
||||
}
|
||||
|
||||
public boolean isBoomerang() {
|
||||
return boomerang;
|
||||
}
|
||||
|
||||
public void setBoomerang(boolean boomerang) {
|
||||
this.boomerang = boomerang;
|
||||
}
|
||||
|
||||
public int getBoomerangDelay() {
|
||||
return boomerangDelay;
|
||||
}
|
||||
|
||||
public void setBoomerangDelay(int boomerangDelay) {
|
||||
this.boomerangDelay = boomerangDelay;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ 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;
|
||||
@@ -111,11 +110,21 @@ public class AbilityDome extends AbilityEnergyBarrier {
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getDomeRadius() { return domeRadius; }
|
||||
public void setDomeRadius(float radius) { this.domeRadius = Math.max(1.0f, radius); }
|
||||
public float getDomeRadius() {
|
||||
return domeRadius;
|
||||
}
|
||||
|
||||
public boolean isFollowCaster() { return followCaster; }
|
||||
public void setFollowCaster(boolean follow) { this.followCaster = follow; }
|
||||
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 ====================
|
||||
|
||||
|
||||
+77
-22
@@ -26,40 +26,95 @@ public abstract class AbilityEnergy extends Ability {
|
||||
|
||||
// ==================== DISPLAY DATA ====================
|
||||
|
||||
public int getInnerColor() { return displayData.innerColor; }
|
||||
public void setInnerColor(int color) { displayData.innerColor = color; }
|
||||
public int getInnerColor() {
|
||||
return displayData.innerColor;
|
||||
}
|
||||
|
||||
public float getInnerAlpha() { return displayData.innerAlpha; }
|
||||
public void setInnerAlpha(float alpha) { displayData.innerAlpha = alpha; }
|
||||
public void setInnerColor(int color) {
|
||||
displayData.innerColor = color;
|
||||
}
|
||||
|
||||
public int getOuterColor() { return displayData.outerColor; }
|
||||
public void setOuterColor(int color) { displayData.outerColor = color; }
|
||||
public float getInnerAlpha() {
|
||||
return displayData.innerAlpha;
|
||||
}
|
||||
|
||||
public boolean isOuterColorEnabled() { return displayData.outerColorEnabled; }
|
||||
public void setOuterColorEnabled(boolean enabled) { displayData.outerColorEnabled = enabled; }
|
||||
public void setInnerAlpha(float alpha) {
|
||||
displayData.innerAlpha = alpha;
|
||||
}
|
||||
|
||||
public float getOuterColorWidth() { return displayData.outerColorWidth; }
|
||||
public void setOuterColorWidth(float width) { displayData.outerColorWidth = width; }
|
||||
public int getOuterColor() {
|
||||
return displayData.outerColor;
|
||||
}
|
||||
|
||||
public float getOuterColorAlpha() { return displayData.outerColorAlpha; }
|
||||
public void setOuterColorAlpha(float alpha) { displayData.outerColorAlpha = alpha; }
|
||||
public void setOuterColor(int color) {
|
||||
displayData.outerColor = color;
|
||||
}
|
||||
|
||||
public float getRotationSpeed() { return displayData.rotationSpeed; }
|
||||
public void setRotationSpeed(float speed) { displayData.rotationSpeed = speed; }
|
||||
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 boolean hasLightningEffect() {
|
||||
return lightningData.lightningEffect;
|
||||
}
|
||||
|
||||
public float getLightningDensity() { return lightningData.lightningDensity; }
|
||||
public void setLightningDensity(float density) { lightningData.lightningDensity = density; }
|
||||
public void setLightningEffect(boolean enabled) {
|
||||
lightningData.lightningEffect = enabled;
|
||||
}
|
||||
|
||||
public float getLightningRadius() { return lightningData.lightningRadius; }
|
||||
public void setLightningRadius(float radius) { lightningData.lightningRadius = radius; }
|
||||
public float getLightningDensity() {
|
||||
return lightningData.lightningDensity;
|
||||
}
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.lightningFadeTime; }
|
||||
public void setLightningFadeTime(int fadeTime) { lightningData.lightningFadeTime = fadeTime; }
|
||||
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 ====================
|
||||
|
||||
|
||||
+81
-23
@@ -142,37 +142,95 @@ public abstract class AbilityEnergyBarrier extends AbilityEnergy {
|
||||
// Display and lightning data inherited from AbilityEnergy
|
||||
|
||||
// Barrier data
|
||||
public float getBarrierMaxHealth() { return barrierData.maxHealth; }
|
||||
public void setBarrierMaxHealth(float maxHealth) { barrierData.setMaxHealth(maxHealth); }
|
||||
public float getBarrierMaxHealth() {
|
||||
return barrierData.maxHealth;
|
||||
}
|
||||
|
||||
public boolean isUseHealth() { return barrierData.useHealth; }
|
||||
public void setUseHealth(boolean useHealth) { barrierData.useHealth = useHealth; }
|
||||
public void setBarrierMaxHealth(float maxHealth) {
|
||||
barrierData.setMaxHealth(maxHealth);
|
||||
}
|
||||
|
||||
public int getBarrierDuration() { return barrierData.durationTicks; }
|
||||
public void setBarrierDuration(int ticks) { barrierData.setDurationTicks(ticks); }
|
||||
public boolean isUseHealth() {
|
||||
return barrierData.useHealth;
|
||||
}
|
||||
|
||||
public boolean isUseDuration() { return barrierData.useDuration; }
|
||||
public void setUseDuration(boolean useDuration) { barrierData.useDuration = useDuration; }
|
||||
public void setUseHealth(boolean useHealth) {
|
||||
barrierData.useHealth = useHealth;
|
||||
}
|
||||
|
||||
public float getDefaultMultiplier() { return barrierData.defaultMultiplier; }
|
||||
public void setDefaultMultiplier(float mult) { barrierData.defaultMultiplier = mult; }
|
||||
public int getBarrierDuration() {
|
||||
return barrierData.durationTicks;
|
||||
}
|
||||
|
||||
public void setDamageMultiplier(String typeId, float mult) { barrierData.setMultiplier(typeId, mult); }
|
||||
public float getDamageMultiplier(String typeId) { return barrierData.getMultiplier(typeId); }
|
||||
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); }
|
||||
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; }
|
||||
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 ====================
|
||||
|
||||
@@ -199,7 +257,7 @@ public abstract class AbilityEnergyBarrier extends AbilityEnergy {
|
||||
FieldDef.floatField("ability.knockbackStrength", this::getKnockbackStrength, this::setKnockbackStrength)
|
||||
.range(0, 10).visibleWhen(this::isKnockbackEnabled),
|
||||
FieldDef.stringEnumField("ability.knockbackTarget", EnergyBarrierData.getKnockbackTargetKeys(),
|
||||
this::getKnockbackTargetKey, this::setKnockbackTargetKey)
|
||||
this::getKnockbackTargetKey, this::setKnockbackTargetKey)
|
||||
.visibleWhen(this::isKnockbackEnabled)
|
||||
));
|
||||
|
||||
|
||||
+192
-54
@@ -2,10 +2,14 @@ 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.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
@@ -24,7 +28,7 @@ import java.util.List;
|
||||
* Abstract base for energy projectile abilities (Orb, Disc, Beam, LaserShot).
|
||||
* Handles shared lifecycle (windup → execute → active → completion), multi-projectile
|
||||
* support with staggered firing, telegraph creation, NBT persistence, and GUI definitions.
|
||||
*
|
||||
* <p>
|
||||
* Subclasses provide entity creation/firing/charging logic and type-specific fields.
|
||||
*
|
||||
* @param <E> The entity type this ability spawns
|
||||
@@ -64,6 +68,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
this.homingData = homingData;
|
||||
this.lifespanData = lifespanData;
|
||||
this.trajectoryData = new EnergyTrajectoryData();
|
||||
this.burstOverlap = true;
|
||||
initProjectiles(1);
|
||||
}
|
||||
|
||||
@@ -74,7 +79,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
* Called during windup (tick 1) and burst refire (onExecute when entities are null).
|
||||
*/
|
||||
protected abstract E createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index);
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index);
|
||||
|
||||
/**
|
||||
* Fire an entity (start moving toward target). Entity is guaranteed non-null and alive.
|
||||
@@ -90,7 +95,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
* Setup entity for preview mode during windup.
|
||||
*/
|
||||
protected abstract void setupEntityPreview(E entity, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index);
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index);
|
||||
|
||||
/**
|
||||
* Create typed array (Java generics can't create generic arrays).
|
||||
@@ -129,9 +134,12 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
*/
|
||||
protected AnchorPoint getDefaultAnchor(int index) {
|
||||
switch (index) {
|
||||
case 0: return AnchorPoint.RIGHT_HAND;
|
||||
case 1: return AnchorPoint.LEFT_HAND;
|
||||
default: return AnchorPoint.FRONT;
|
||||
case 0:
|
||||
return AnchorPoint.RIGHT_HAND;
|
||||
case 1:
|
||||
return AnchorPoint.LEFT_HAND;
|
||||
default:
|
||||
return AnchorPoint.FRONT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,15 +176,31 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
}
|
||||
}
|
||||
|
||||
public int getProjectileCount() { return projectileCount; }
|
||||
public int getProjectileCount() {
|
||||
return projectileCount;
|
||||
}
|
||||
|
||||
public int getFireDelay() { return fireDelay; }
|
||||
public void setFireDelay(int delay) { this.fireDelay = Math.max(0, delay); }
|
||||
public int getFireDelay() {
|
||||
return fireDelay;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link #getFireDelay()} */
|
||||
public int getDualFireDelay() { return fireDelay; }
|
||||
/** @deprecated Use {@link #setFireDelay(int)} */
|
||||
public void setDualFireDelay(int delay) { setFireDelay(delay); }
|
||||
public void setFireDelay(int delay) {
|
||||
this.fireDelay = Math.max(0, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getFireDelay()}
|
||||
*/
|
||||
public int getDualFireDelay() {
|
||||
return fireDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #setFireDelay(int)}
|
||||
*/
|
||||
public void setDualFireDelay(int delay) {
|
||||
setFireDelay(delay);
|
||||
}
|
||||
|
||||
protected int clampIndex(int index) {
|
||||
return Math.max(0, Math.min(index, projectileCount - 1));
|
||||
@@ -317,7 +341,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
// Check if entity was removed from world (chunk unload, etc.)
|
||||
// Skip this check for preview entities - they're not registered in the world
|
||||
if (!isPreview() && tick > 5 && entity.worldObj != null
|
||||
&& entity.worldObj.getEntityByID(entity.getEntityId()) != entity) {
|
||||
&& entity.worldObj.getEntityByID(entity.getEntityId()) != entity) {
|
||||
entity.setDead();
|
||||
continue;
|
||||
}
|
||||
@@ -449,64 +473,163 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
// ==================== API GETTERS & SETTERS ====================
|
||||
|
||||
// Combat data
|
||||
@Override public float getDamage() { return combatData.damage; }
|
||||
@Override public void setDamage(float damage) { combatData.damage = damage; }
|
||||
@Override
|
||||
public float getDamage() {
|
||||
return combatData.damage;
|
||||
}
|
||||
|
||||
@Override public float getKnockback() { return combatData.knockback; }
|
||||
@Override public void setKnockback(float knockback) { combatData.knockback = knockback; }
|
||||
@Override
|
||||
public void setDamage(float damage) {
|
||||
combatData.damage = damage;
|
||||
}
|
||||
|
||||
@Override public float getKnockbackUp() { return combatData.knockbackUp; }
|
||||
@Override public void setKnockbackUp(float knockbackUp) { combatData.knockbackUp = knockbackUp; }
|
||||
@Override
|
||||
public float getKnockback() {
|
||||
return combatData.knockback;
|
||||
}
|
||||
|
||||
@Override public boolean isExplosive() { return combatData.explosive; }
|
||||
@Override public void setExplosive(boolean explosive) { combatData.explosive = explosive; }
|
||||
@Override
|
||||
public void setKnockback(float knockback) {
|
||||
combatData.knockback = knockback;
|
||||
}
|
||||
|
||||
@Override public float getExplosionRadius() { return combatData.explosionRadius; }
|
||||
@Override public void setExplosionRadius(float explosionRadius) { combatData.explosionRadius = explosionRadius; }
|
||||
@Override
|
||||
public float getKnockbackUp() {
|
||||
return combatData.knockbackUp;
|
||||
}
|
||||
|
||||
@Override public float getExplosionDamageFalloff() { return combatData.explosionDamageFalloff; }
|
||||
@Override public void setExplosionDamageFalloff(float falloff) { combatData.explosionDamageFalloff = falloff; }
|
||||
@Override
|
||||
public void setKnockbackUp(float knockbackUp) {
|
||||
combatData.knockbackUp = knockbackUp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplosive() {
|
||||
return combatData.explosive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplosive(boolean explosive) {
|
||||
combatData.explosive = explosive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExplosionRadius() {
|
||||
return combatData.explosionRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplosionRadius(float explosionRadius) {
|
||||
combatData.explosionRadius = explosionRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExplosionDamageFalloff() {
|
||||
return combatData.explosionDamageFalloff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplosionDamageFalloff(float falloff) {
|
||||
combatData.explosionDamageFalloff = falloff;
|
||||
}
|
||||
|
||||
// Lifespan data
|
||||
@Override public float getMaxDistance() { return lifespanData.maxDistance; }
|
||||
@Override public void setMaxDistance(float maxDistance) { lifespanData.maxDistance = maxDistance; }
|
||||
@Override
|
||||
public float getMaxDistance() {
|
||||
return lifespanData.maxDistance;
|
||||
}
|
||||
|
||||
@Override public int getMaxLifetime() { return lifespanData.maxLifetime; }
|
||||
@Override public void setMaxLifetime(int maxLifetime) { lifespanData.maxLifetime = maxLifetime; }
|
||||
@Override
|
||||
public void setMaxDistance(float maxDistance) {
|
||||
lifespanData.maxDistance = maxDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLifetime() {
|
||||
return lifespanData.maxLifetime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxLifetime(int maxLifetime) {
|
||||
lifespanData.maxLifetime = maxLifetime;
|
||||
}
|
||||
|
||||
// Homing data
|
||||
public boolean isHoming() { return homingData.homing; }
|
||||
public void setHoming(boolean homing) { homingData.homing = homing; }
|
||||
public boolean isHoming() {
|
||||
return homingData.homing;
|
||||
}
|
||||
|
||||
public float getHomingStrength() { return homingData.homingStrength; }
|
||||
public void setHomingStrength(float strength) { homingData.homingStrength = strength; }
|
||||
public void setHoming(boolean homing) {
|
||||
homingData.homing = homing;
|
||||
}
|
||||
|
||||
public float getHomingRange() { return homingData.homingRange; }
|
||||
public void setHomingRange(float range) { homingData.homingRange = range; }
|
||||
public float getHomingStrength() {
|
||||
return homingData.homingStrength;
|
||||
}
|
||||
|
||||
public void setHomingStrength(float strength) {
|
||||
homingData.homingStrength = strength;
|
||||
}
|
||||
|
||||
public float getHomingRange() {
|
||||
return homingData.homingRange;
|
||||
}
|
||||
|
||||
public void setHomingRange(float range) {
|
||||
homingData.homingRange = range;
|
||||
}
|
||||
|
||||
// Display and lightning data inherited from AbilityEnergy
|
||||
|
||||
// Anchor - default to projectile 0
|
||||
public AnchorPoint getAnchorPointEnum() { return projectiles[0].anchor.anchorPoint; }
|
||||
public void setAnchorPointEnum(AnchorPoint point) { projectiles[0].anchor.anchorPoint = point; }
|
||||
public AnchorPoint getAnchorPointEnum() {
|
||||
return projectiles[0].anchor.anchorPoint;
|
||||
}
|
||||
|
||||
public float getAnchorOffsetX() { return projectiles[0].anchor.anchorOffsetX; }
|
||||
public void setAnchorOffsetX(float x) { projectiles[0].anchor.anchorOffsetX = x; }
|
||||
public void setAnchorPointEnum(AnchorPoint point) {
|
||||
projectiles[0].anchor.anchorPoint = point;
|
||||
}
|
||||
|
||||
public float getAnchorOffsetY() { return projectiles[0].anchor.anchorOffsetY; }
|
||||
public void setAnchorOffsetY(float y) { projectiles[0].anchor.anchorOffsetY = y; }
|
||||
public float getAnchorOffsetX() {
|
||||
return projectiles[0].anchor.anchorOffsetX;
|
||||
}
|
||||
|
||||
public float getAnchorOffsetZ() { return projectiles[0].anchor.anchorOffsetZ; }
|
||||
public void setAnchorOffsetZ(float z) { projectiles[0].anchor.anchorOffsetZ = z; }
|
||||
public void setAnchorOffsetX(float x) {
|
||||
projectiles[0].anchor.anchorOffsetX = x;
|
||||
}
|
||||
|
||||
@Override public int getAnchorPoint() { return projectiles[0].anchor.anchorPoint.ordinal(); }
|
||||
@Override public void setAnchorPoint(int point) { projectiles[0].anchor.anchorPoint = AnchorPoint.fromOrdinal(point); }
|
||||
public float getAnchorOffsetY() {
|
||||
return projectiles[0].anchor.anchorOffsetY;
|
||||
}
|
||||
|
||||
public void setAnchorOffsetY(float y) {
|
||||
projectiles[0].anchor.anchorOffsetY = y;
|
||||
}
|
||||
|
||||
public float getAnchorOffsetZ() {
|
||||
return projectiles[0].anchor.anchorOffsetZ;
|
||||
}
|
||||
|
||||
public void setAnchorOffsetZ(float z) {
|
||||
projectiles[0].anchor.anchorOffsetZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnchorPoint() {
|
||||
return projectiles[0].anchor.anchorPoint.ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnchorPoint(int point) {
|
||||
projectiles[0].anchor.anchorPoint = AnchorPoint.fromOrdinal(point);
|
||||
}
|
||||
|
||||
// Indexed API methods
|
||||
public int getInnerColor(int index) {
|
||||
ProjectileData p = projectiles[clampIndex(index)];
|
||||
return p.colorOverride ? p.innerColor : displayData.innerColor;
|
||||
}
|
||||
|
||||
public void setInnerColor(int index, int color) {
|
||||
ProjectileData p = projectiles[clampIndex(index)];
|
||||
p.colorOverride = true;
|
||||
@@ -517,17 +640,32 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
ProjectileData p = projectiles[clampIndex(index)];
|
||||
return p.colorOverride ? p.outerColor : displayData.outerColor;
|
||||
}
|
||||
|
||||
public void setOuterColor(int index, int color) {
|
||||
ProjectileData p = projectiles[clampIndex(index)];
|
||||
p.colorOverride = true;
|
||||
p.outerColor = color;
|
||||
}
|
||||
|
||||
public int getAnchorPoint(int index) { return projectiles[clampIndex(index)].anchor.anchorPoint.ordinal(); }
|
||||
public void setAnchorPoint(int index, int point) { projectiles[clampIndex(index)].anchor.anchorPoint = AnchorPoint.fromOrdinal(point); }
|
||||
public void setAnchorOffsetX(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetX = offset; }
|
||||
public void setAnchorOffsetY(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetY = offset; }
|
||||
public void setAnchorOffsetZ(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetZ = offset; }
|
||||
public int getAnchorPoint(int index) {
|
||||
return projectiles[clampIndex(index)].anchor.anchorPoint.ordinal();
|
||||
}
|
||||
|
||||
public void setAnchorPoint(int index, int point) {
|
||||
projectiles[clampIndex(index)].anchor.anchorPoint = AnchorPoint.fromOrdinal(point);
|
||||
}
|
||||
|
||||
public void setAnchorOffsetX(int index, float offset) {
|
||||
projectiles[clampIndex(index)].anchor.anchorOffsetX = offset;
|
||||
}
|
||||
|
||||
public void setAnchorOffsetY(int index, float offset) {
|
||||
projectiles[clampIndex(index)].anchor.anchorOffsetY = offset;
|
||||
}
|
||||
|
||||
public void setAnchorOffsetZ(int index, float offset) {
|
||||
projectiles[clampIndex(index)].anchor.anchorOffsetZ = offset;
|
||||
}
|
||||
|
||||
// ==================== GUI FIELD DEFINITIONS ====================
|
||||
|
||||
@@ -555,7 +693,7 @@ public abstract class AbilityEnergyProjectile<E extends EntityEnergyProjectile>
|
||||
.visibleWhen(() -> idx < projectileCount));
|
||||
|
||||
defs.add(FieldDef.enumField("ability.anchorPoint", AnchorPoint.class,
|
||||
() -> projectiles[idx].anchor.anchorPoint, v -> projectiles[idx].anchor.anchorPoint = v)
|
||||
() -> projectiles[idx].anchor.anchorPoint, v -> projectiles[idx].anchor.anchorPoint = v)
|
||||
.tab("ability.tab.visual").visibleWhen(() -> idx < projectileCount));
|
||||
defs.add(FieldDef.row(
|
||||
FieldDef.floatField("ability.anchor.offsetX", () -> projectiles[idx].anchor.anchorOffsetX, v -> projectiles[idx].anchor.anchorOffsetX = v)
|
||||
|
||||
+44
-11
@@ -6,7 +6,11 @@ import kamkeel.npcs.controllers.data.ability.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.LockMovementType;
|
||||
import kamkeel.npcs.controllers.data.ability.RotationMode;
|
||||
import kamkeel.npcs.controllers.data.ability.TargetingMode;
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
@@ -30,13 +34,14 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
private float laserWidth = 0.3f;
|
||||
private float expansionSpeed = 3.0f;
|
||||
private int lingerTicks = 8;
|
||||
private boolean dieOnImpact = false;
|
||||
|
||||
public AbilityLaserShot() {
|
||||
super(
|
||||
new EnergyDisplayData(0xFFFFFF, 0xFF0000, true, 0.4f, 0.5f, 0.0f),
|
||||
new EnergyCombatData(6.0f, 0.5f, 0.05f, false, 2.0f, 0.5f),
|
||||
new EnergyHomingData(),
|
||||
new EnergyLifespanData(40.0f, 100)
|
||||
new EnergyLifespanData(150.0f, 100)
|
||||
);
|
||||
this.typeId = "ability.cnpc.laser_shot";
|
||||
this.name = "Laser Shot";
|
||||
@@ -111,13 +116,15 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
|
||||
@Override
|
||||
protected EntityAbilityLaser createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityAbilityLaser(
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
EntityAbilityLaser laser = new EntityAbilityLaser(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
laserWidth,
|
||||
resolved, combatData, lightningData, lifespanData, trajectoryData,
|
||||
expansionSpeed, lingerTicks);
|
||||
laser.setDieOnImpact(dieOnImpact);
|
||||
return laser;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,7 +140,7 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityAbilityLaser laser, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
laser.setupPreview(caster, laserWidth, resolved, lightningData, expansionSpeed, lifespanData.maxDistance);
|
||||
}
|
||||
|
||||
@@ -154,6 +161,7 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
nbt.setFloat("laserWidth", laserWidth);
|
||||
nbt.setFloat("expansionSpeed", expansionSpeed);
|
||||
nbt.setInteger("lingerTicks", lingerTicks);
|
||||
nbt.setBoolean("dieOnImpact", dieOnImpact);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,18 +169,42 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
this.laserWidth = nbt.getFloat("laserWidth");
|
||||
this.expansionSpeed = nbt.getFloat("expansionSpeed");
|
||||
this.lingerTicks = nbt.getInteger("lingerTicks");
|
||||
this.dieOnImpact = nbt.getBoolean("dieOnImpact");
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
|
||||
public float getLaserWidth() { return laserWidth; }
|
||||
public void setLaserWidth(float laserWidth) { this.laserWidth = laserWidth; }
|
||||
public float getLaserWidth() {
|
||||
return laserWidth;
|
||||
}
|
||||
|
||||
public float getExpansionSpeed() { return expansionSpeed; }
|
||||
public void setExpansionSpeed(float expansionSpeed) { this.expansionSpeed = expansionSpeed; }
|
||||
public void setLaserWidth(float laserWidth) {
|
||||
this.laserWidth = laserWidth;
|
||||
}
|
||||
|
||||
public int getLingerTicks() { return lingerTicks; }
|
||||
public void setLingerTicks(int lingerTicks) { this.lingerTicks = lingerTicks; }
|
||||
public float getExpansionSpeed() {
|
||||
return expansionSpeed;
|
||||
}
|
||||
|
||||
public void setExpansionSpeed(float expansionSpeed) {
|
||||
this.expansionSpeed = expansionSpeed;
|
||||
}
|
||||
|
||||
public int getLingerTicks() {
|
||||
return lingerTicks;
|
||||
}
|
||||
|
||||
public void setLingerTicks(int lingerTicks) {
|
||||
this.lingerTicks = lingerTicks;
|
||||
}
|
||||
|
||||
public boolean isDieOnImpact() {
|
||||
return dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDieOnImpact(boolean dieOnImpact) {
|
||||
this.dieOnImpact = dieOnImpact;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
@@ -194,6 +226,7 @@ public class AbilityLaserShot extends AbilityEnergyProjectile<EntityAbilityLaser
|
||||
FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime)
|
||||
));
|
||||
defs.add(FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance));
|
||||
defs.add(FieldDef.boolField("ability.dieOnImpact", this::isDieOnImpact, this::setDieOnImpact));
|
||||
defs.add(FieldDef.section("ability.section.explosive"));
|
||||
defs.add(FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive"));
|
||||
defs.add(FieldDef.floatField("gui.radius", this::getExplosionRadius, this::setExplosionRadius).visibleWhen(this::isExplosive));
|
||||
|
||||
@@ -5,7 +5,11 @@ 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.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityAbilityOrb;
|
||||
@@ -51,7 +55,7 @@ public class AbilityOrb extends AbilityEnergyProjectile<EntityAbilityOrb> implem
|
||||
|
||||
@Override
|
||||
protected EntityAbilityOrb createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityAbilityOrb(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, orbSize,
|
||||
@@ -74,7 +78,7 @@ public class AbilityOrb extends AbilityEnergyProjectile<EntityAbilityOrb> implem
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityAbilityOrb orb, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
orb.setupPreview(caster, orbSize, resolved, lightningData, projData.anchor, windUpTicks);
|
||||
}
|
||||
|
||||
@@ -137,11 +141,21 @@ public class AbilityOrb extends AbilityEnergyProjectile<EntityAbilityOrb> implem
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
|
||||
public float getOrbSpeed() { return homingData.speed; }
|
||||
public void setOrbSpeed(float speed) { homingData.speed = speed; }
|
||||
public float getOrbSpeed() {
|
||||
return homingData.speed;
|
||||
}
|
||||
|
||||
public float getOrbSize() { return orbSize; }
|
||||
public void setOrbSize(float size) { this.orbSize = size; }
|
||||
public void setOrbSpeed(float speed) {
|
||||
homingData.speed = speed;
|
||||
}
|
||||
|
||||
public float getOrbSize() {
|
||||
return orbSize;
|
||||
}
|
||||
|
||||
public void setOrbSize(float size) {
|
||||
this.orbSize = size;
|
||||
}
|
||||
|
||||
// ==================== TYPE-SPECIFIC GUI ====================
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ 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;
|
||||
@@ -124,11 +123,21 @@ public class AbilityShield extends AbilityEnergyBarrier {
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public float getShieldWidth() { return shieldWidth; }
|
||||
public void setShieldWidth(float width) { this.shieldWidth = Math.max(0.5f, width); }
|
||||
public float getShieldWidth() {
|
||||
return shieldWidth;
|
||||
}
|
||||
|
||||
public float getShieldHeight() { return shieldHeight; }
|
||||
public void setShieldHeight(float height) { this.shieldHeight = Math.max(0.5f, height); }
|
||||
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 ====================
|
||||
|
||||
|
||||
+36
-12
@@ -5,7 +5,11 @@ 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.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ProjectileData;
|
||||
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
import kamkeel.npcs.entity.EntityEnergySlicer;
|
||||
@@ -33,7 +37,7 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
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)
|
||||
new EnergyLifespanData(150.0f, 100)
|
||||
);
|
||||
this.typeId = "ability.cnpc.slicer";
|
||||
this.name = "Slicer";
|
||||
@@ -53,7 +57,7 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
|
||||
@Override
|
||||
protected EntityEnergySlicer createEntity(EntityLivingBase caster, EntityLivingBase target,
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
Vec3 spawnPos, EnergyDisplayData resolved, int index) {
|
||||
return new EntityEnergySlicer(
|
||||
caster.worldObj, caster, target,
|
||||
spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord,
|
||||
@@ -79,7 +83,7 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
|
||||
@Override
|
||||
protected void setupEntityPreview(EntityEnergySlicer slicer, EntityLivingBase caster,
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
EnergyDisplayData resolved, ProjectileData projData, int index) {
|
||||
slicer.setupPreview(caster, sliceWidth, sliceThickness, resolved, lightningData, projData.anchor, windUpTicks);
|
||||
}
|
||||
|
||||
@@ -130,17 +134,37 @@ public class AbilitySlicer extends AbilityEnergyProjectile<EntityEnergySlicer> {
|
||||
|
||||
// ==================== TYPE-SPECIFIC GETTERS ====================
|
||||
|
||||
public float getSlicerSpeed() { return homingData.speed; }
|
||||
public void setSlicerSpeed(float speed) { homingData.speed = speed; }
|
||||
public float getSlicerSpeed() {
|
||||
return homingData.speed;
|
||||
}
|
||||
|
||||
public float getSliceWidth() { return sliceWidth; }
|
||||
public void setSliceWidth(float width) { this.sliceWidth = Math.max(0.5f, width); }
|
||||
public void setSlicerSpeed(float speed) {
|
||||
homingData.speed = speed;
|
||||
}
|
||||
|
||||
public float getSliceThickness() { return sliceThickness; }
|
||||
public void setSliceThickness(float thickness) { this.sliceThickness = Math.max(0.05f, thickness); }
|
||||
public float getSliceWidth() {
|
||||
return sliceWidth;
|
||||
}
|
||||
|
||||
public boolean isPiercing() { return piercing; }
|
||||
public void setPiercing(boolean piercing) { this.piercing = piercing; }
|
||||
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 ====================
|
||||
|
||||
|
||||
+72
-19
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
* Sweeper ability: A low sweeping beam that rotates around the NPC.
|
||||
* Players can jump over it. The beam completes a set number of rotations before ending.
|
||||
* Telegraph shows a large circle on the ground indicating range.
|
||||
*
|
||||
* <p>
|
||||
* All damage logic is handled by the EntityAbilitySweeper entity to ensure
|
||||
* visual and damage hitbox alignment.
|
||||
*/
|
||||
@@ -173,24 +173,77 @@ public class AbilitySweeper extends AbilityEnergy implements IAbilitySweeper {
|
||||
}
|
||||
|
||||
// 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; }
|
||||
public void setBeamWidth(float beamWidth) { this.beamWidth = beamWidth; }
|
||||
public float getBeamHeight() { return beamHeight; }
|
||||
public void setBeamHeight(float beamHeight) { this.beamHeight = beamHeight; }
|
||||
public float getDamage() { return damage; }
|
||||
public void setDamage(float damage) { this.damage = damage; }
|
||||
public int getDamageInterval() { return damageInterval; }
|
||||
public void setDamageInterval(int damageInterval) { this.damageInterval = damageInterval; }
|
||||
public boolean isPiercing() { return piercing; }
|
||||
public void setPiercing(boolean piercing) { this.piercing = piercing; }
|
||||
public float getSweepSpeed() { return sweepSpeed; }
|
||||
public void setSweepSpeed(float sweepSpeed) { this.sweepSpeed = sweepSpeed; }
|
||||
public int getNumberOfRotations() { return numberOfRotations; }
|
||||
public void setNumberOfRotations(int numberOfRotations) { this.numberOfRotations = numberOfRotations; }
|
||||
public boolean isLockOnTarget() { return lockOnTarget; }
|
||||
public void setLockOnTarget(boolean lockOnTarget) { this.lockOnTarget = lockOnTarget; }
|
||||
public float getBeamLength() {
|
||||
return beamLength;
|
||||
}
|
||||
|
||||
public void setBeamLength(float beamLength) {
|
||||
this.beamLength = beamLength;
|
||||
}
|
||||
|
||||
public float getBeamWidth() {
|
||||
return beamWidth;
|
||||
}
|
||||
|
||||
public void setBeamWidth(float beamWidth) {
|
||||
this.beamWidth = beamWidth;
|
||||
}
|
||||
|
||||
public float getBeamHeight() {
|
||||
return beamHeight;
|
||||
}
|
||||
|
||||
public void setBeamHeight(float beamHeight) {
|
||||
this.beamHeight = beamHeight;
|
||||
}
|
||||
|
||||
public float getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
public void setDamage(float damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
public int getDamageInterval() {
|
||||
return damageInterval;
|
||||
}
|
||||
|
||||
public void setDamageInterval(int damageInterval) {
|
||||
this.damageInterval = damageInterval;
|
||||
}
|
||||
|
||||
public boolean isPiercing() {
|
||||
return piercing;
|
||||
}
|
||||
|
||||
public void setPiercing(boolean piercing) {
|
||||
this.piercing = piercing;
|
||||
}
|
||||
|
||||
public float getSweepSpeed() {
|
||||
return sweepSpeed;
|
||||
}
|
||||
|
||||
public void setSweepSpeed(float sweepSpeed) {
|
||||
this.sweepSpeed = sweepSpeed;
|
||||
}
|
||||
|
||||
public int getNumberOfRotations() {
|
||||
return numberOfRotations;
|
||||
}
|
||||
|
||||
public void setNumberOfRotations(int numberOfRotations) {
|
||||
this.numberOfRotations = numberOfRotations;
|
||||
}
|
||||
|
||||
public boolean isLockOnTarget() {
|
||||
return lockOnTarget;
|
||||
}
|
||||
|
||||
public void setLockOnTarget(boolean lockOnTarget) {
|
||||
this.lockOnTarget = lockOnTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPreviewDuration() {
|
||||
|
||||
@@ -11,7 +11,6 @@ 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;
|
||||
@@ -139,28 +138,65 @@ public class AbilityWall extends AbilityEnergyBarrier {
|
||||
|
||||
// ==================== GETTERS & SETTERS ====================
|
||||
|
||||
public EnergyPanelData getPanelData() { return panelData; }
|
||||
public EnergyPanelData getPanelData() {
|
||||
return panelData;
|
||||
}
|
||||
|
||||
public float getPanelWidth() { return panelData.panelWidth; }
|
||||
public void setPanelWidth(float width) { panelData.setPanelWidth(width); }
|
||||
public float getPanelWidth() {
|
||||
return panelData.panelWidth;
|
||||
}
|
||||
|
||||
public float getPanelHeight() { return panelData.panelHeight; }
|
||||
public void setPanelHeight(float height) { panelData.setPanelHeight(height); }
|
||||
public void setPanelWidth(float width) {
|
||||
panelData.setPanelWidth(width);
|
||||
}
|
||||
|
||||
public float getHeightOffset() { return panelData.heightOffset; }
|
||||
public void setHeightOffset(float offset) { panelData.heightOffset = offset; }
|
||||
public float getPanelHeight() {
|
||||
return panelData.panelHeight;
|
||||
}
|
||||
|
||||
public boolean isLaunching() { return panelData.launching; }
|
||||
public void setLaunching(boolean launching) { panelData.launching = launching; }
|
||||
public void setPanelHeight(float height) {
|
||||
panelData.setPanelHeight(height);
|
||||
}
|
||||
|
||||
public float getLaunchSpeed() { return panelData.launchSpeed; }
|
||||
public void setLaunchSpeed(float speed) { panelData.setLaunchSpeed(speed); }
|
||||
public float getHeightOffset() {
|
||||
return panelData.heightOffset;
|
||||
}
|
||||
|
||||
public float getLaunchDamage() { return panelData.launchDamage; }
|
||||
public void setLaunchDamage(float damage) { panelData.setLaunchDamage(damage); }
|
||||
public void setHeightOffset(float offset) {
|
||||
panelData.heightOffset = offset;
|
||||
}
|
||||
|
||||
public float getLaunchKnockback() { return panelData.launchKnockback; }
|
||||
public void setLaunchKnockback(float kb) { panelData.setLaunchKnockback(kb); }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import noppes.npcs.EventHooks;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
@@ -11,6 +16,7 @@ import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.LogWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -19,10 +25,10 @@ import java.util.List;
|
||||
/**
|
||||
* Beam projectile - head with trailing path that curves with homing.
|
||||
* Stays attached to origin point, trail shows path of head.
|
||||
*
|
||||
* <p>
|
||||
* IMPORTANT: Trail points are stored RELATIVE to startX/Y/Z (origin).
|
||||
* This ensures rendering is stable regardless of entity position interpolation.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
@@ -63,6 +69,7 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
|
||||
/**
|
||||
* Full constructor with all parameters using data classes.
|
||||
*
|
||||
* @param anchoredMode If true, origin follows owner and tail orb is rendered.
|
||||
* If false, beam is free-moving with trailing length (no tail orb).
|
||||
*/
|
||||
@@ -214,7 +221,7 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
/**
|
||||
* Start the beam firing (exit charging mode).
|
||||
* Called by ability when windup ends.
|
||||
*
|
||||
* <p>
|
||||
* For anchored beams: origin follows owner, head starts at charged position
|
||||
* For non-anchored beams: origin fixed at charged position, head starts there
|
||||
*/
|
||||
@@ -281,8 +288,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
// Check distance using head offset (distance from origin)
|
||||
double distFromOrigin = Math.sqrt(
|
||||
headOffsetX * headOffsetX +
|
||||
headOffsetY * headOffsetY +
|
||||
headOffsetZ * headOffsetZ
|
||||
headOffsetY * headOffsetY +
|
||||
headOffsetZ * headOffsetZ
|
||||
);
|
||||
boolean exceeded = distFromOrigin >= getMaxDistance();
|
||||
if (exceeded && !worldObj.isRemote && DEBUG_LOGGING) {
|
||||
@@ -440,8 +447,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
Vec3 lastPoint = trailPoints.get(trailPoints.size() - 1);
|
||||
double dist = Math.sqrt(
|
||||
(headOffsetX - lastPoint.xCoord) * (headOffsetX - lastPoint.xCoord) +
|
||||
(headOffsetY - lastPoint.yCoord) * (headOffsetY - lastPoint.yCoord) +
|
||||
(headOffsetZ - lastPoint.zCoord) * (headOffsetZ - lastPoint.zCoord)
|
||||
(headOffsetY - lastPoint.yCoord) * (headOffsetY - lastPoint.yCoord) +
|
||||
(headOffsetZ - lastPoint.zCoord) * (headOffsetZ - lastPoint.zCoord)
|
||||
);
|
||||
|
||||
if (dist >= MIN_POINT_DISTANCE) {
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import noppes.npcs.EventHooks;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Disc projectile - flat spinning disc with optional boomerang behavior.
|
||||
* Has a wider, thinner hitbox compared to Orb.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
@@ -252,8 +258,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
protected boolean checkMaxDistance() {
|
||||
double distTraveled = Math.sqrt(
|
||||
(posX - startX) * (posX - startX) +
|
||||
(posY - startY) * (posY - startY) +
|
||||
(posZ - startZ) * (posZ - startZ)
|
||||
(posY - startY) * (posY - startY) +
|
||||
(posZ - startZ) * (posZ - startZ)
|
||||
);
|
||||
|
||||
if (boomerang) {
|
||||
@@ -270,8 +276,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
if (owner != null) {
|
||||
double distToOwner = Math.sqrt(
|
||||
(posX - owner.posX) * (posX - owner.posX) +
|
||||
(posY - owner.posY) * (posY - owner.posY) +
|
||||
(posZ - owner.posZ) * (posZ - owner.posZ)
|
||||
(posY - owner.posY) * (posY - owner.posY) +
|
||||
(posZ - owner.posZ) * (posZ - owner.posZ)
|
||||
);
|
||||
return distToOwner < 1.5;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import noppes.npcs.EventHooks;
|
||||
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.HashSet;
|
||||
import java.util.List;
|
||||
@@ -18,7 +22,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Laser projectile - fast expanding thin line that pierces through multiple targets.
|
||||
* No homing, travels in a straight line from origin to max distance.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
@@ -39,6 +43,9 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
// Lock vertical direction after firing (only update yaw, keep pitch fixed)
|
||||
private boolean lockVerticalDirection = false;
|
||||
|
||||
// Whether to die on first entity impact (hit-scan mode)
|
||||
private boolean dieOnImpact = false;
|
||||
|
||||
// Track hit entities to avoid double-damage
|
||||
private Set<Integer> hitEntities = new HashSet<>();
|
||||
|
||||
@@ -246,8 +253,8 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
// Laser stops at block
|
||||
currentLength = (float) Math.sqrt(
|
||||
(blockHit.hitVec.xCoord - startX) * (blockHit.hitVec.xCoord - startX) +
|
||||
(blockHit.hitVec.yCoord - startY) * (blockHit.hitVec.yCoord - startY) +
|
||||
(blockHit.hitVec.zCoord - startZ) * (blockHit.hitVec.zCoord - startZ)
|
||||
(blockHit.hitVec.yCoord - startY) * (blockHit.hitVec.yCoord - startY) +
|
||||
(blockHit.hitVec.zCoord - startZ) * (blockHit.hitVec.zCoord - startZ)
|
||||
);
|
||||
endX = blockHit.hitVec.xCoord;
|
||||
endY = blockHit.hitVec.yCoord;
|
||||
@@ -294,6 +301,20 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
hitEntities.add(entity.getEntityId());
|
||||
applyDamage(entity);
|
||||
|
||||
if (dieOnImpact) {
|
||||
// Stop at impact point and begin linger/fade
|
||||
double dx = entity.posX - startX;
|
||||
double dy = (entity.posY + entity.height * 0.5) - startY;
|
||||
double dz = entity.posZ - startZ;
|
||||
float impactDist = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
currentLength = Math.min(impactDist, currentLength);
|
||||
endX = startX + dirX * currentLength;
|
||||
endY = startY + dirY * currentLength;
|
||||
endZ = startZ + dirZ * currentLength;
|
||||
fullyExtended = true;
|
||||
return; // Stop checking further entities
|
||||
}
|
||||
|
||||
// Piercing - don't stop, continue to next entity
|
||||
}
|
||||
}
|
||||
@@ -382,6 +403,14 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.lingerTicks = ticks;
|
||||
}
|
||||
|
||||
public boolean isDieOnImpact() {
|
||||
return dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDieOnImpact(boolean dieOnImpact) {
|
||||
this.dieOnImpact = dieOnImpact;
|
||||
}
|
||||
|
||||
public void setDirection(double x, double y, double z) {
|
||||
this.dirX = x;
|
||||
this.dirY = y;
|
||||
@@ -447,6 +476,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
this.laserWidth = nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f;
|
||||
this.expansionSpeed = nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f;
|
||||
this.lingerTicks = nbt.hasKey("LingerTicks") ? nbt.getInteger("LingerTicks") : 10;
|
||||
this.dieOnImpact = nbt.getBoolean("DieOnImpact");
|
||||
this.dirX = nbt.getDouble("DirX");
|
||||
this.dirY = nbt.getDouble("DirY");
|
||||
this.dirZ = nbt.getDouble("DirZ");
|
||||
@@ -464,6 +494,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
nbt.setFloat("LaserWidth", laserWidth);
|
||||
nbt.setFloat("ExpansionSpeed", expansionSpeed);
|
||||
nbt.setInteger("LingerTicks", lingerTicks);
|
||||
nbt.setBoolean("DieOnImpact", dieOnImpact);
|
||||
nbt.setDouble("DirX", dirX);
|
||||
nbt.setDouble("DirY", dirY);
|
||||
nbt.setDouble("DirZ", dirZ);
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import noppes.npcs.EventHooks;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import noppes.npcs.EventHooks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Orb projectile - spherical homing energy ball.
|
||||
* Extends EntityEnergyAbility for shared functionality.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public class EntityAbilityOrb extends EntityEnergyProjectile {
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.Set;
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* Design: Similar to Beam trail visuals but rotating around origin.
|
||||
*/
|
||||
public class EntityAbilitySweeper extends EntityEnergyAbility {
|
||||
@@ -65,11 +65,11 @@ public class EntityAbilitySweeper extends EntityEnergyAbility {
|
||||
}
|
||||
|
||||
public EntityAbilitySweeper(World world, EntityLivingBase owner, EntityLivingBase target,
|
||||
float beamLength, float beamWidth, float beamHeight,
|
||||
EnergyDisplayData displayData,
|
||||
float sweepSpeed, int numberOfRotations,
|
||||
float damage, int damageInterval, boolean piercing,
|
||||
boolean lockOnTarget) {
|
||||
float beamLength, float beamWidth, float beamHeight,
|
||||
EnergyDisplayData displayData,
|
||||
float sweepSpeed, int numberOfRotations,
|
||||
float damage, int damageInterval, boolean piercing,
|
||||
boolean lockOnTarget) {
|
||||
this(world);
|
||||
|
||||
this.ownerEntityId = owner.getEntityId();
|
||||
|
||||
@@ -34,16 +34,20 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
// ENUMS
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public enum ZoneType { TRAP, HAZARD }
|
||||
public enum ZoneType {TRAP, HAZARD}
|
||||
|
||||
public enum ZoneShape {
|
||||
CIRCLE, SQUARE;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case CIRCLE: return "ability.shape.circle";
|
||||
case SQUARE: return "ability.shape.square";
|
||||
default: return name();
|
||||
case CIRCLE:
|
||||
return "ability.shape.circle";
|
||||
case SQUARE:
|
||||
return "ability.shape.square";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,10 +58,14 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case STATIC: return "ability.accentStyle.static";
|
||||
case SWAYING: return "ability.accentStyle.swaying";
|
||||
case FLICKERING: return "ability.accentStyle.flickering";
|
||||
default: return name();
|
||||
case STATIC:
|
||||
return "ability.accentStyle.static";
|
||||
case SWAYING:
|
||||
return "ability.accentStyle.swaying";
|
||||
case FLICKERING:
|
||||
return "ability.accentStyle.flickering";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,10 +76,14 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case RISING: return "ability.particleMotion.rising";
|
||||
case DRIFTING: return "ability.particleMotion.drifting";
|
||||
case SPARKS: return "ability.particleMotion.sparks";
|
||||
default: return name();
|
||||
case RISING:
|
||||
return "ability.particleMotion.rising";
|
||||
case DRIFTING:
|
||||
return "ability.particleMotion.drifting";
|
||||
case SPARKS:
|
||||
return "ability.particleMotion.sparks";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +186,7 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
}
|
||||
|
||||
private EntityAbilityZone(World world, ZoneType type, EntityLivingBase owner,
|
||||
double x, double y, double z) {
|
||||
double x, double y, double z) {
|
||||
this(world);
|
||||
this.zoneType = type;
|
||||
this.ownerEntityId = owner.getEntityId();
|
||||
@@ -184,17 +196,17 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
}
|
||||
|
||||
public static EntityAbilityZone createTrap(World world, EntityLivingBase owner,
|
||||
double x, double y, double z,
|
||||
ZoneShape shape,
|
||||
float triggerRadius, int armTime, int maxTriggers,
|
||||
int triggerCooldown, float damage, float damageRadius,
|
||||
float knockback, int durationTicks,
|
||||
int innerColor, int outerColor, boolean outerColorEnabled,
|
||||
float zoneHeight,
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
boolean visible,
|
||||
List<AbilityPotionEffect> effects) {
|
||||
double x, double y, double z,
|
||||
ZoneShape shape,
|
||||
float triggerRadius, int armTime, int maxTriggers,
|
||||
int triggerCooldown, float damage, float damageRadius,
|
||||
float knockback, int durationTicks,
|
||||
int innerColor, int outerColor, boolean outerColorEnabled,
|
||||
float zoneHeight,
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
boolean visible,
|
||||
List<AbilityPotionEffect> effects) {
|
||||
EntityAbilityZone zone = new EntityAbilityZone(world, ZoneType.TRAP, owner, x, y, z);
|
||||
zone.shape = shape;
|
||||
zone.radius = triggerRadius;
|
||||
@@ -226,17 +238,17 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
}
|
||||
|
||||
public static EntityAbilityZone createHazard(World world, EntityLivingBase owner,
|
||||
double x, double y, double z,
|
||||
ZoneShape shape,
|
||||
float radius,
|
||||
float damagePerSecond, int damageInterval,
|
||||
boolean ignoreInvulnFrames, boolean affectsCaster,
|
||||
int durationTicks,
|
||||
int innerColor, int outerColor, boolean outerColorEnabled,
|
||||
float zoneHeight,
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
List<AbilityPotionEffect> effects) {
|
||||
double x, double y, double z,
|
||||
ZoneShape shape,
|
||||
float radius,
|
||||
float damagePerSecond, int damageInterval,
|
||||
boolean ignoreInvulnFrames, boolean affectsCaster,
|
||||
int durationTicks,
|
||||
int innerColor, int outerColor, boolean outerColorEnabled,
|
||||
float zoneHeight,
|
||||
float particleDensity, float particleScale,
|
||||
float animSpeed, float lightningDensity,
|
||||
List<AbilityPotionEffect> effects) {
|
||||
EntityAbilityZone zone = new EntityAbilityZone(world, ZoneType.HAZARD, owner, x, y, z);
|
||||
zone.shape = shape;
|
||||
zone.radius = radius;
|
||||
@@ -268,7 +280,8 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
@Override
|
||||
protected void entityInit() {}
|
||||
protected void entityInit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleHealthUpdate(byte id) {
|
||||
@@ -549,45 +562,133 @@ public class EntityAbilityZone extends Entity implements IEntityAdditionalSpawnD
|
||||
// GETTERS FOR RENDERER
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public ZoneType getZoneType() { return zoneType; }
|
||||
public ZoneShape getShape() { return shape; }
|
||||
public float getRadius() { return radius; }
|
||||
public int getInnerColor() { return innerColor; }
|
||||
public int getOuterColor() { return outerColor; }
|
||||
public boolean isOuterColorEnabled() { return outerColorEnabled; }
|
||||
public float getZoneHeight() { return zoneHeight; }
|
||||
public boolean isArmed() { return armed || ticksExisted >= armTime; }
|
||||
public boolean isVisible() { return visible; }
|
||||
public int getTriggerFlashTick() { return triggerFlashTick; }
|
||||
public int getDurationTicks() { return durationTicks; }
|
||||
public int getMaxTicks() { return maxTicks; }
|
||||
public float getParticleDensity() { return particleDensity; }
|
||||
public float getParticleScale() { return particleScale; }
|
||||
public float getAnimSpeed() { return animSpeed; }
|
||||
public float getLightningDensity() { return lightningDensity; }
|
||||
public ZoneType getZoneType() {
|
||||
return zoneType;
|
||||
}
|
||||
|
||||
public boolean isGroundFill() { return groundFill; }
|
||||
public float getGroundAlpha() { return groundAlpha; }
|
||||
public boolean isRings() { return rings; }
|
||||
public int getRingCount() { return ringCount; }
|
||||
public boolean isBorder() { return border; }
|
||||
public float getBorderSpeed() { return borderSpeed; }
|
||||
public boolean isAccents() { return accents; }
|
||||
public int getAccentStyle() { return accentStyle; }
|
||||
public boolean isLightning() { return lightning; }
|
||||
public boolean isParticles() { return particles; }
|
||||
public int getParticleMotion() { return particleMotion; }
|
||||
public String getParticleDir() { return particleDir; }
|
||||
public int getParticleSize() { return particleSize; }
|
||||
public boolean isParticleGlow() { return particleGlow; }
|
||||
public ZoneShape getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
public float getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public int getInnerColor() {
|
||||
return innerColor;
|
||||
}
|
||||
|
||||
public int getOuterColor() {
|
||||
return outerColor;
|
||||
}
|
||||
|
||||
public boolean isOuterColorEnabled() {
|
||||
return outerColorEnabled;
|
||||
}
|
||||
|
||||
public float getZoneHeight() {
|
||||
return zoneHeight;
|
||||
}
|
||||
|
||||
public boolean isArmed() {
|
||||
return armed || ticksExisted >= armTime;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public int getTriggerFlashTick() {
|
||||
return triggerFlashTick;
|
||||
}
|
||||
|
||||
public int getDurationTicks() {
|
||||
return durationTicks;
|
||||
}
|
||||
|
||||
public int getMaxTicks() {
|
||||
return maxTicks;
|
||||
}
|
||||
|
||||
public float getParticleDensity() {
|
||||
return particleDensity;
|
||||
}
|
||||
|
||||
public float getParticleScale() {
|
||||
return particleScale;
|
||||
}
|
||||
|
||||
public float getAnimSpeed() {
|
||||
return animSpeed;
|
||||
}
|
||||
|
||||
public float getLightningDensity() {
|
||||
return lightningDensity;
|
||||
}
|
||||
|
||||
public boolean isGroundFill() {
|
||||
return groundFill;
|
||||
}
|
||||
|
||||
public float getGroundAlpha() {
|
||||
return groundAlpha;
|
||||
}
|
||||
|
||||
public boolean isRings() {
|
||||
return rings;
|
||||
}
|
||||
|
||||
public int getRingCount() {
|
||||
return ringCount;
|
||||
}
|
||||
|
||||
public boolean isBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
public float getBorderSpeed() {
|
||||
return borderSpeed;
|
||||
}
|
||||
|
||||
public boolean isAccents() {
|
||||
return accents;
|
||||
}
|
||||
|
||||
public int getAccentStyle() {
|
||||
return accentStyle;
|
||||
}
|
||||
|
||||
public boolean isLightning() {
|
||||
return lightning;
|
||||
}
|
||||
|
||||
public boolean isParticles() {
|
||||
return particles;
|
||||
}
|
||||
|
||||
public int getParticleMotion() {
|
||||
return particleMotion;
|
||||
}
|
||||
|
||||
public String getParticleDir() {
|
||||
return particleDir;
|
||||
}
|
||||
|
||||
public int getParticleSize() {
|
||||
return particleSize;
|
||||
}
|
||||
|
||||
public boolean isParticleGlow() {
|
||||
return particleGlow;
|
||||
}
|
||||
|
||||
public void applyVisual(boolean groundFill, float groundAlpha,
|
||||
boolean rings, int ringCount,
|
||||
boolean border, float borderSpeed,
|
||||
boolean accents, int accentStyle,
|
||||
boolean lightning,
|
||||
boolean particles, int particleMotion,
|
||||
String particleDir, int particleSize, boolean particleGlow) {
|
||||
boolean rings, int ringCount,
|
||||
boolean border, float borderSpeed,
|
||||
boolean accents, int accentStyle,
|
||||
boolean lightning,
|
||||
boolean particles, int particleMotion,
|
||||
String particleDir, int particleSize, boolean particleGlow) {
|
||||
this.groundFill = groundFill;
|
||||
this.groundAlpha = groundAlpha;
|
||||
this.rings = rings;
|
||||
|
||||
@@ -30,7 +30,9 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
|
||||
protected int ownerEntityId = -1;
|
||||
|
||||
// ==================== STATE ====================
|
||||
/** The ability that spawned this entity. Transient, not saved to NBT. */
|
||||
/**
|
||||
* The ability that spawned this entity. Transient, not saved to NBT.
|
||||
*/
|
||||
protected transient Ability sourceAbility = null;
|
||||
protected boolean previewMode = false;
|
||||
protected EntityLivingBase previewOwner = null;
|
||||
@@ -98,59 +100,137 @@ public abstract class EntityEnergyAbility extends Entity implements IEntityAddit
|
||||
return worldObj.getEntityByID(ownerEntityId);
|
||||
}
|
||||
|
||||
public int getOwnerEntityId() { return ownerEntityId; }
|
||||
public void setOwnerEntityId(int id) { this.ownerEntityId = id; }
|
||||
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; }
|
||||
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; }
|
||||
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 EnergyDisplayData getDisplayData() {
|
||||
return displayData;
|
||||
}
|
||||
|
||||
public int getInnerColor() { return displayData.getInnerColor(); }
|
||||
public void setInnerColor(int color) { displayData.setInnerColor(color); }
|
||||
public EnergyLightningData getLightningData() {
|
||||
return lightningData;
|
||||
}
|
||||
|
||||
public float getInnerAlpha() { return displayData.getInnerAlpha(); }
|
||||
public void setInnerAlpha(float alpha) { displayData.setInnerAlpha(alpha); }
|
||||
public int getInnerColor() {
|
||||
return displayData.getInnerColor();
|
||||
}
|
||||
|
||||
public int getOuterColor() { return displayData.getOuterColor(); }
|
||||
public void setOuterColor(int color) { displayData.setOuterColor(color); }
|
||||
public void setInnerColor(int color) {
|
||||
displayData.setInnerColor(color);
|
||||
}
|
||||
|
||||
public boolean isOuterColorEnabled() { return displayData.isOuterColorEnabled(); }
|
||||
public void setOuterColorEnabled(boolean enabled) { displayData.setOuterColorEnabled(enabled); }
|
||||
public float getInnerAlpha() {
|
||||
return displayData.getInnerAlpha();
|
||||
}
|
||||
|
||||
public float getOuterColorWidth() { return displayData.getOuterColorWidth(); }
|
||||
public void setOuterColorWidth(float width) { displayData.setOuterColorWidth(width); }
|
||||
public void setInnerAlpha(float alpha) {
|
||||
displayData.setInnerAlpha(alpha);
|
||||
}
|
||||
|
||||
public float getOuterColorAlpha() { return displayData.getOuterColorAlpha(); }
|
||||
public void setOuterColorAlpha(float alpha) { displayData.setOuterColorAlpha(alpha); }
|
||||
public int getOuterColor() {
|
||||
return displayData.getOuterColor();
|
||||
}
|
||||
|
||||
public float getRotationSpeed() { return displayData.getRotationSpeed(); }
|
||||
public void setRotationSpeed(float speed) { displayData.setRotationSpeed(speed); }
|
||||
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 boolean hasLightningEffect() {
|
||||
return lightningData.isLightningEffect();
|
||||
}
|
||||
|
||||
public float getLightningDensity() { return lightningData.getLightningDensity(); }
|
||||
public void setLightningDensity(float density) { lightningData.setLightningDensity(density); }
|
||||
public void setLightningEffect(boolean enabled) {
|
||||
lightningData.setLightningEffect(enabled);
|
||||
}
|
||||
|
||||
public float getLightningRadius() { return lightningData.getLightningRadius(); }
|
||||
public void setLightningRadius(float radius) { lightningData.setLightningRadius(radius); }
|
||||
public float getLightningDensity() {
|
||||
return lightningData.getLightningDensity();
|
||||
}
|
||||
|
||||
public int getLightningFadeTime() { return lightningData.getLightningFadeTime(); }
|
||||
public void setLightningFadeTime(int ticks) { lightningData.setLightningFadeTime(ticks); }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
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;
|
||||
@@ -144,6 +140,7 @@ public abstract class EntityEnergyBarrier extends EntityEnergyAbility {
|
||||
* 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() {
|
||||
@@ -223,18 +220,33 @@ public abstract class EntityEnergyBarrier extends EntityEnergyAbility {
|
||||
|
||||
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;
|
||||
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; }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -195,10 +195,21 @@ public class EntityEnergyDome extends EntityEnergyBarrier {
|
||||
|
||||
// ==================== 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; }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -343,9 +343,17 @@ public class EntityEnergyPanel extends EntityEnergyBarrier {
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public PanelMode getMode() { return mode; }
|
||||
public float getPanelYaw() { return panelYaw; }
|
||||
public EnergyPanelData getPanelData() { return panelData; }
|
||||
public PanelMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public float getPanelYaw() {
|
||||
return panelYaw;
|
||||
}
|
||||
|
||||
public EnergyPanelData getPanelData() {
|
||||
return panelData;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
|
||||
@@ -2,10 +2,16 @@ package kamkeel.npcs.entity;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityPotionEffect;
|
||||
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import kamkeel.npcs.util.AnchorPointHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
@@ -37,7 +43,7 @@ import java.util.Map;
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* Design inspired by LouisXIV's energy attack system.
|
||||
*/
|
||||
public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
@@ -56,6 +62,10 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
refs.add(new WeakReference<>(projectile));
|
||||
}
|
||||
|
||||
public static void clearAllProjectiles() {
|
||||
activeProjectiles.clear();
|
||||
}
|
||||
|
||||
public static List<EntityEnergyProjectile> getActiveProjectiles(int ownerEntityId) {
|
||||
List<WeakReference<EntityEnergyProjectile>> refs = activeProjectiles.get(ownerEntityId);
|
||||
if (refs == null) return Collections.emptyList();
|
||||
@@ -270,13 +280,14 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
/**
|
||||
* Check if projectile has exceeded max distance.
|
||||
*
|
||||
* @return true if should die
|
||||
*/
|
||||
protected boolean checkMaxDistance() {
|
||||
double distTraveled = Math.sqrt(
|
||||
(posX - startX) * (posX - startX) +
|
||||
(posY - startY) * (posY - startY) +
|
||||
(posZ - startZ) * (posZ - startZ)
|
||||
(posY - startY) * (posY - startY) +
|
||||
(posZ - startZ) * (posZ - startZ)
|
||||
);
|
||||
return distTraveled >= getMaxDistance();
|
||||
}
|
||||
@@ -291,6 +302,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
/**
|
||||
* 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() {
|
||||
@@ -451,12 +463,13 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
double dist = Math.sqrt(
|
||||
Math.pow(target.posX - posX, 2) +
|
||||
Math.pow(target.posY - posY, 2) +
|
||||
Math.pow(target.posZ - posZ, 2)
|
||||
Math.pow(target.posY - posY, 2) +
|
||||
Math.pow(target.posZ - posZ, 2)
|
||||
);
|
||||
|
||||
if (dist <= getExplosionRadius()) {
|
||||
float falloff = 1.0f - (float) (dist / getExplosionRadius()) * getExplosionDamageFalloff();
|
||||
float radius = getExplosionRadius();
|
||||
if (radius > 0 && dist <= radius) {
|
||||
float falloff = 1.0f - (float) (dist / radius) * getExplosionDamageFalloff();
|
||||
applyDamage(target, getDamage() * falloff, getKnockback() * falloff);
|
||||
}
|
||||
}
|
||||
@@ -513,7 +526,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
* Update during charging state - grow size and follow anchor.
|
||||
* Default implementation grows {@code size} from 0 to {@code targetSize}.
|
||||
* Override in subclasses for type-specific charging (Disc, Beam).
|
||||
*
|
||||
* <p>
|
||||
* Note: Owner death checks are handled by onUpdate() before this is called.
|
||||
*/
|
||||
protected void updateCharging() {
|
||||
@@ -575,7 +588,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
* Call from subclass constructors after initProjectile().
|
||||
*/
|
||||
protected void calculateInitialVelocity(EntityLivingBase owner, EntityLivingBase target,
|
||||
double x, double y, double z) {
|
||||
double x, double y, double z) {
|
||||
if (target != null) {
|
||||
double dx = target.posX - x;
|
||||
double dy = (target.posY + target.getEyeHeight()) - y;
|
||||
@@ -696,7 +709,10 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
// ==================== VISUAL GETTERS & SETTERS ====================
|
||||
|
||||
public float getSize() { return size; }
|
||||
public float getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setProjectileSize(float size) {
|
||||
this.size = size;
|
||||
this.renderCurrentSize = size;
|
||||
@@ -733,64 +749,147 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
|
||||
|
||||
// ==================== LIFESPAN GETTERS & SETTERS ====================
|
||||
|
||||
public float getMaxDistance() { return lifespanData.getMaxDistance(); }
|
||||
public void setMaxDistance(float distance) { lifespanData.setMaxDistance(distance); }
|
||||
public float getMaxDistance() {
|
||||
return lifespanData.getMaxDistance();
|
||||
}
|
||||
|
||||
public int getMaxLifetime() { return lifespanData.getMaxLifetime(); }
|
||||
public void setMaxLifetime(int ticks) { lifespanData.setMaxLifetime(ticks); }
|
||||
public void setMaxDistance(float distance) {
|
||||
lifespanData.setMaxDistance(distance);
|
||||
}
|
||||
|
||||
public int getMaxLifetime() {
|
||||
return lifespanData.getMaxLifetime();
|
||||
}
|
||||
|
||||
public void setMaxLifetime(int ticks) {
|
||||
lifespanData.setMaxLifetime(ticks);
|
||||
}
|
||||
|
||||
// ==================== COMBAT GETTERS & SETTERS ====================
|
||||
|
||||
public float getDamage() { return combatData.getDamage(); }
|
||||
public void setCombatDamage(float damage) { combatData.setDamage(damage); }
|
||||
public float getDamage() {
|
||||
return combatData.getDamage();
|
||||
}
|
||||
|
||||
public float getKnockback() { return combatData.knockback; }
|
||||
public void setCombatKnockback(float knockback) { combatData.setKnockback(knockback); }
|
||||
public void setCombatDamage(float damage) {
|
||||
combatData.setDamage(damage);
|
||||
}
|
||||
|
||||
public float getKnockbackUp() { return combatData.knockbackUp; }
|
||||
public void setCombatKnockbackUp(float knockbackUp) { combatData.setKnockbackUp(knockbackUp); }
|
||||
public float getKnockback() {
|
||||
return combatData.knockback;
|
||||
}
|
||||
|
||||
public boolean isExplosive() { return combatData.isExplosive(); }
|
||||
public void setExplosive(boolean explosive) { combatData.setExplosive(explosive); }
|
||||
public void setCombatKnockback(float knockback) {
|
||||
combatData.setKnockback(knockback);
|
||||
}
|
||||
|
||||
public float getExplosionRadius() { return combatData.explosionRadius; }
|
||||
public void setExplosionRadius(float radius) { combatData.setExplosionRadius(radius); }
|
||||
public float getKnockbackUp() {
|
||||
return combatData.knockbackUp;
|
||||
}
|
||||
|
||||
public float getExplosionDamageFalloff() { return combatData.explosionDamageFalloff; }
|
||||
public void setExplosionDamageFalloff(float falloff) { combatData.setExplosionDamageFalloff(falloff); }
|
||||
public void setCombatKnockbackUp(float knockbackUp) {
|
||||
combatData.setKnockbackUp(knockbackUp);
|
||||
}
|
||||
|
||||
public boolean isExplosive() {
|
||||
return combatData.isExplosive();
|
||||
}
|
||||
|
||||
public void setExplosive(boolean explosive) {
|
||||
combatData.setExplosive(explosive);
|
||||
}
|
||||
|
||||
public float getExplosionRadius() {
|
||||
return combatData.explosionRadius;
|
||||
}
|
||||
|
||||
public void setExplosionRadius(float radius) {
|
||||
combatData.setExplosionRadius(radius);
|
||||
}
|
||||
|
||||
public float getExplosionDamageFalloff() {
|
||||
return combatData.explosionDamageFalloff;
|
||||
}
|
||||
|
||||
public void setExplosionDamageFalloff(float falloff) {
|
||||
combatData.setExplosionDamageFalloff(falloff);
|
||||
}
|
||||
|
||||
// ==================== HOMING GETTERS & SETTERS ====================
|
||||
|
||||
public boolean isHoming() { return homingData.isHoming(); }
|
||||
public void setHomingEnabled(boolean homing) { homingData.setHoming(homing); }
|
||||
public boolean isHoming() {
|
||||
return homingData.isHoming();
|
||||
}
|
||||
|
||||
public float getHomingStrength() { return homingData.getHomingStrength(); }
|
||||
public void setHomingStrength(float strength) { homingData.setHomingStrength(strength); }
|
||||
public void setHomingEnabled(boolean homing) {
|
||||
homingData.setHoming(homing);
|
||||
}
|
||||
|
||||
public float getHomingRange() { return homingData.getHomingRange(); }
|
||||
public void setHomingRange(float range) { homingData.setHomingRange(range); }
|
||||
public float getHomingStrength() {
|
||||
return homingData.getHomingStrength();
|
||||
}
|
||||
|
||||
public void setHomingStrength(float strength) {
|
||||
homingData.setHomingStrength(strength);
|
||||
}
|
||||
|
||||
public float getHomingRange() {
|
||||
return homingData.getHomingRange();
|
||||
}
|
||||
|
||||
public void setHomingRange(float range) {
|
||||
homingData.setHomingRange(range);
|
||||
}
|
||||
|
||||
// ==================== SPEED & ANCHOR GETTERS & SETTERS ====================
|
||||
|
||||
public float getSpeed() { return homingData.getSpeed(); }
|
||||
public void setSpeed(float speed) { homingData.setSpeed(speed); }
|
||||
public float getSpeed() {
|
||||
return homingData.getSpeed();
|
||||
}
|
||||
|
||||
public AnchorPoint getAnchorPoint() { return anchorData.getAnchorPoint(); }
|
||||
public void setSpeed(float speed) {
|
||||
homingData.setSpeed(speed);
|
||||
}
|
||||
|
||||
public int getAnchor() { return anchorData.getAnchor(); }
|
||||
public float getAnchorOffsetX() { return anchorData.getAnchorOffsetX(); }
|
||||
public float getAnchorOffsetY() { return anchorData.getAnchorOffsetY(); }
|
||||
public float getAnchorOffsetZ() { return anchorData.getAnchorOffsetZ(); }
|
||||
public AnchorPoint getAnchorPoint() {
|
||||
return anchorData.getAnchorPoint();
|
||||
}
|
||||
|
||||
public int getAnchor() {
|
||||
return anchorData.getAnchor();
|
||||
}
|
||||
|
||||
public float getAnchorOffsetX() {
|
||||
return anchorData.getAnchorOffsetX();
|
||||
}
|
||||
|
||||
public float getAnchorOffsetY() {
|
||||
return anchorData.getAnchorOffsetY();
|
||||
}
|
||||
|
||||
public float getAnchorOffsetZ() {
|
||||
return anchorData.getAnchorOffsetZ();
|
||||
}
|
||||
|
||||
// ==================== MOVEMENT GETTERS ====================
|
||||
|
||||
public double getStartX() { return startX; }
|
||||
public double getStartY() { return startY; }
|
||||
public double getStartZ() { return startZ; }
|
||||
public double getStartX() {
|
||||
return startX;
|
||||
}
|
||||
|
||||
public double getStartY() {
|
||||
return startY;
|
||||
}
|
||||
|
||||
public double getStartZ() {
|
||||
return startZ;
|
||||
}
|
||||
|
||||
// ==================== STATE GETTERS ====================
|
||||
|
||||
public boolean getHasHit() { return hasHit; }
|
||||
public boolean getHasHit() {
|
||||
return hasHit;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package kamkeel.npcs.entity;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.data.*;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyAnchorData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyCombatData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyDisplayData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyHomingData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLifespanData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyLightningData;
|
||||
import kamkeel.npcs.controllers.data.ability.data.EnergyTrajectoryData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -293,14 +299,29 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public float getSliceWidth() { return sliceWidth; }
|
||||
public void setSliceWidth(float width) { this.sliceWidth = width; }
|
||||
public float getSliceWidth() {
|
||||
return sliceWidth;
|
||||
}
|
||||
|
||||
public float getSliceThickness() { return sliceThickness; }
|
||||
public void setSliceThickness(float thickness) { this.sliceThickness = thickness; }
|
||||
public void setSliceWidth(float width) {
|
||||
this.sliceWidth = width;
|
||||
}
|
||||
|
||||
public boolean isPiercing() { return piercing; }
|
||||
public void setPiercing(boolean piercing) { this.piercing = piercing; }
|
||||
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 ====================
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ import kamkeel.npcs.network.packets.data.UpdateAnimationsPacket;
|
||||
import kamkeel.npcs.network.packets.data.VillagerListPacket;
|
||||
import kamkeel.npcs.network.packets.data.ability.PlayerAbilityStatePacket;
|
||||
import kamkeel.npcs.network.packets.data.ability.PlayerAbilitySyncPacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphRemovePacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphSpawnPacket;
|
||||
import kamkeel.npcs.network.packets.data.gui.GuiClosePacket;
|
||||
import kamkeel.npcs.network.packets.data.gui.GuiErrorPacket;
|
||||
import kamkeel.npcs.network.packets.data.gui.GuiOpenBookPacket;
|
||||
@@ -53,6 +51,9 @@ import kamkeel.npcs.network.packets.data.npc.WeaponNpcPacket;
|
||||
import kamkeel.npcs.network.packets.data.script.ScriptOverlayClosePacket;
|
||||
import kamkeel.npcs.network.packets.data.script.ScriptOverlayDataPacket;
|
||||
import kamkeel.npcs.network.packets.data.script.ScriptedParticlePacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphRemovePacket;
|
||||
import kamkeel.npcs.network.packets.data.telegraph.TelegraphSpawnPacket;
|
||||
import kamkeel.npcs.network.packets.player.AuctionActionPacket;
|
||||
import kamkeel.npcs.network.packets.player.BankActionPacket;
|
||||
import kamkeel.npcs.network.packets.player.CheckPlayerValue;
|
||||
import kamkeel.npcs.network.packets.player.CompanionActionPacket;
|
||||
@@ -61,7 +62,6 @@ import kamkeel.npcs.network.packets.player.FollowerPacket;
|
||||
import kamkeel.npcs.network.packets.player.GetNPCRole;
|
||||
import kamkeel.npcs.network.packets.player.GetTraderData;
|
||||
import kamkeel.npcs.network.packets.player.InputDevicePacket;
|
||||
import kamkeel.npcs.network.packets.player.AuctionActionPacket;
|
||||
import kamkeel.npcs.network.packets.player.MailActionPacket;
|
||||
import kamkeel.npcs.network.packets.player.SaveBookPacket;
|
||||
import kamkeel.npcs.network.packets.player.SaveSignPacket;
|
||||
@@ -94,10 +94,14 @@ import kamkeel.npcs.network.packets.request.TraderMarketSavePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesGetAllPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcSavePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.BuiltInAbilityGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.ChainedAbilitiesGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.ChainedAbilityGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.ChainedAbilityRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.ChainedAbilitySavePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilitiesGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilityGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilityRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.BuiltInAbilityGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilitySavePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationRemovePacket;
|
||||
@@ -112,8 +116,8 @@ import kamkeel.npcs.network.packets.request.clone.CloneAllTagsPacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneAllTagsShortPacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneFolderCrudPacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneFolderListPacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneMovePacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneListPacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneMovePacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.ClonePreSavePacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.clone.CloneSavePacket;
|
||||
@@ -519,6 +523,10 @@ public class PacketHandler {
|
||||
REQUEST_PACKET.registerPacket(new CustomAbilityRemovePacket());
|
||||
REQUEST_PACKET.registerPacket(new CustomAbilitySavePacket());
|
||||
REQUEST_PACKET.registerPacket(new BuiltInAbilityGetPacket());
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilitiesGetPacket());
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilityGetPacket());
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilitySavePacket());
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilityRemovePacket());
|
||||
|
||||
// Other Packets
|
||||
REQUEST_PACKET.registerPacket(new IsGuiOpenInform());
|
||||
|
||||
@@ -206,6 +206,10 @@ public enum EnumRequestPacket {
|
||||
CustomAbilityRemove,
|
||||
CustomAbilitySave,
|
||||
BuiltInAbilityGet,
|
||||
ChainedAbilitiesGet,
|
||||
ChainedAbilityGet,
|
||||
ChainedAbilitySave,
|
||||
ChainedAbilityRemove,
|
||||
Hammer,
|
||||
|
||||
RecipeScript,
|
||||
|
||||
@@ -13,5 +13,6 @@ public enum EnumSyncType {
|
||||
CARPENTRY_RECIPES,
|
||||
ANVIL_RECIPES,
|
||||
CUSTOM_EFFECTS,
|
||||
CUSTOM_ABILITY
|
||||
CUSTOM_ABILITY,
|
||||
CHAINED_ABILITY
|
||||
}
|
||||
@@ -15,8 +15,8 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.AuctionClientConfig;
|
||||
import noppes.npcs.client.ClientCacheHandler;
|
||||
import noppes.npcs.config.ConfigMain;
|
||||
import noppes.npcs.client.ScriptClientConfig;
|
||||
import noppes.npcs.config.ConfigMain;
|
||||
import noppes.npcs.controllers.AuctionConfigSync;
|
||||
import noppes.npcs.controllers.ScriptConfigSync;
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* Lightweight packet syncing ability lock state from server to client.
|
||||
* Sent every tick during ability execution when flags change, and once when ability ends.
|
||||
*
|
||||
* <p>
|
||||
* Flags byte layout:
|
||||
* bit 0: movement locked (suppress WASD, zero motion)
|
||||
* bit 1: rotation locked (freeze yaw/pitch)
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
import noppes.npcs.config.ConfigMarket;
|
||||
import noppes.npcs.constants.EnumAuctionPage;
|
||||
import noppes.npcs.constants.EnumGuiType;
|
||||
import noppes.npcs.constants.EnumRoleType;
|
||||
import noppes.npcs.controllers.AuctionController;
|
||||
@@ -39,7 +40,8 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
private long amount;
|
||||
private NBTTagCompound data;
|
||||
|
||||
public AuctionActionPacket() {}
|
||||
public AuctionActionPacket() {
|
||||
}
|
||||
|
||||
private AuctionActionPacket(Action action) {
|
||||
this.action = action;
|
||||
@@ -57,7 +59,9 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsNPC() { return false; } // Allow opening via command without NPC
|
||||
public boolean needsNPC() {
|
||||
return false;
|
||||
} // Allow opening via command without NPC
|
||||
|
||||
// =========================================
|
||||
// Client-side static methods
|
||||
@@ -116,7 +120,9 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
PacketClient.sendClient(packet);
|
||||
}
|
||||
|
||||
/** Request listings from server with filter and page */
|
||||
/**
|
||||
* Request listings from server with filter and page
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void requestListings(AuctionFilter filter, int page) {
|
||||
AuctionActionPacket packet = new AuctionActionPacket(Action.RequestListings);
|
||||
@@ -130,10 +136,14 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
// =========================================
|
||||
|
||||
@Override
|
||||
public Enum getType() { return EnumPlayerPacket.AuctionAction; }
|
||||
public Enum getType() {
|
||||
return EnumPlayerPacket.AuctionAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() { return PacketHandler.PLAYER_PACKET; }
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.PLAYER_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
@@ -290,7 +300,10 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
long startingPrice = in.readLong();
|
||||
String buyoutStr = ByteBufUtils.readString(in);
|
||||
long buyoutPrice = 0;
|
||||
try { buyoutPrice = Long.parseLong(buyoutStr); } catch (NumberFormatException ignored) {}
|
||||
try {
|
||||
buyoutPrice = Long.parseLong(buyoutStr);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
|
||||
NBTTagCompound itemNBT = ByteBufUtils.readNBT(in);
|
||||
if (itemNBT == null) return "No item data received.";
|
||||
@@ -315,13 +328,8 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
|
||||
private void handleOpenPage(ByteBuf in, EntityPlayerMP player) {
|
||||
int page = in.readInt();
|
||||
EnumGuiType guiType;
|
||||
switch (page) {
|
||||
case 0: guiType = EnumGuiType.PlayerAuction; break;
|
||||
case 1: guiType = EnumGuiType.PlayerAuctionSell; break;
|
||||
case 2: guiType = EnumGuiType.PlayerAuctionTrades; break;
|
||||
default: guiType = EnumGuiType.PlayerAuction; break;
|
||||
}
|
||||
EnumAuctionPage auctionPage = EnumAuctionPage.fromOrdinal(page);
|
||||
EnumGuiType guiType = auctionPage.getGuiType();
|
||||
NoppesUtilServer.sendOpenGui(player, guiType, npc);
|
||||
|
||||
// Send trades data when opening the trades page
|
||||
@@ -333,7 +341,9 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
}
|
||||
}
|
||||
|
||||
/** Send full trades data to player (listings, bids, claims) */
|
||||
/**
|
||||
* Send full trades data to player (listings, bids, claims)
|
||||
*/
|
||||
private void sendTradesData(EntityPlayerMP player, AuctionController controller) {
|
||||
NBTTagCompound response = new NBTTagCompound();
|
||||
response.setBoolean("TradesData", true);
|
||||
@@ -481,6 +491,9 @@ public class AuctionActionPacket extends AbstractPacket {
|
||||
} else {
|
||||
// Need only part of stack
|
||||
stack.splitStack(needed);
|
||||
if (stack.stackSize <= 0) {
|
||||
player.inventory.setInventorySlotContents(i, null);
|
||||
}
|
||||
needed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package kamkeel.npcs.network.packets.request.ability;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package kamkeel.npcs.network.packets.request.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to get list of all chained ability names.
|
||||
*/
|
||||
public final class ChainedAbilitiesGetPacket extends AbstractPacket {
|
||||
public static String packetName = "Request|ChainedAbilitiesGet";
|
||||
|
||||
public ChainedAbilitiesGetPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.ChainedAbilitiesGet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
NoppesUtilServer.sendChainedAbilitiesData((EntityPlayerMP) player);
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package kamkeel.npcs.network.packets.request.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to get a specific chained ability by name.
|
||||
*/
|
||||
public final class ChainedAbilityGetPacket extends AbstractPacket {
|
||||
public static String packetName = "Request|ChainedAbilityGet";
|
||||
|
||||
private String name;
|
||||
|
||||
public ChainedAbilityGetPacket() {
|
||||
}
|
||||
|
||||
public ChainedAbilityGetPacket(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.ChainedAbilityGet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
ByteBufUtils.writeString(out, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
String chainName = ByteBufUtils.readString(in);
|
||||
ChainedAbility chain = AbilityController.Instance.getChainedAbility(chainName);
|
||||
if (chain != null) {
|
||||
NBTTagCompound compound = chain.writeNBT();
|
||||
GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package kamkeel.npcs.network.packets.request.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import noppes.npcs.CustomNpcsPermissions;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to remove a chained ability by name.
|
||||
*/
|
||||
public final class ChainedAbilityRemovePacket extends AbstractPacket {
|
||||
public static String packetName = "Request|ChainedAbilityRemove";
|
||||
|
||||
private String name;
|
||||
|
||||
public ChainedAbilityRemovePacket() {
|
||||
}
|
||||
|
||||
public ChainedAbilityRemovePacket(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.ChainedAbilityRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomNpcsPermissions.Permission getPermission() {
|
||||
return CustomNpcsPermissions.GLOBAL_ABILITY;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
ByteBufUtils.writeString(out, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
String chainName = ByteBufUtils.readString(in);
|
||||
AbilityController.Instance.deleteChainedAbility(chainName);
|
||||
NoppesUtilServer.sendChainedAbilitiesData((EntityPlayerMP) player);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package kamkeel.npcs.network.packets.request.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.CustomNpcsPermissions;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Request packet to save a chained ability.
|
||||
*/
|
||||
public final class ChainedAbilitySavePacket extends AbstractPacket {
|
||||
public static String packetName = "Request|ChainedAbilitySave";
|
||||
|
||||
private NBTTagCompound chainNBT;
|
||||
|
||||
public ChainedAbilitySavePacket() {
|
||||
}
|
||||
|
||||
public ChainedAbilitySavePacket(NBTTagCompound chainNBT) {
|
||||
this.chainNBT = chainNBT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.ChainedAbilitySave;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomNpcsPermissions.Permission getPermission() {
|
||||
return CustomNpcsPermissions.GLOBAL_ABILITY;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
ByteBufUtils.writeNBT(out, chainNBT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
NBTTagCompound compound = ByteBufUtils.readNBT(in);
|
||||
if (compound == null) return;
|
||||
ChainedAbility chain = new ChainedAbility();
|
||||
chain.readNBT(compound);
|
||||
|
||||
if (chain.getName() != null && !chain.getName().isEmpty()) {
|
||||
AbilityController.Instance.saveChainedAbility(chain);
|
||||
NoppesUtilServer.sendChainedAbilitiesData((EntityPlayerMP) player);
|
||||
GuiDataPacket.sendGuiData((EntityPlayerMP) player, chain.writeNBT());
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,8 +3,8 @@ package kamkeel.npcs.network.packets.request.ability;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package kamkeel.npcs.network.packets.request.ability;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package kamkeel.npcs.network.packets.request.ability;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
|
||||
-1
@@ -15,7 +15,6 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
import noppes.npcs.controllers.data.BuiltInAnimation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -10,10 +10,10 @@ import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import noppes.npcs.controllers.ServerTagMapController;
|
||||
import noppes.npcs.controllers.data.TagMap;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package kamkeel.npcs.network.packets.request.script;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
|
||||
@@ -411,6 +411,7 @@ public class AnchorPointHelper {
|
||||
/**
|
||||
* Rotate an offset vector by the entity's body yaw so offsets are entity-relative.
|
||||
* +X = entity's right, +Y = up, +Z = entity's forward.
|
||||
*
|
||||
* @param bodyYawRad body yaw in radians
|
||||
*/
|
||||
private static Vec3 rotateOffsetByYaw(double offsetX, double offsetY, double offsetZ, float bodyYawRad) {
|
||||
@@ -444,19 +445,19 @@ public class AnchorPointHelper {
|
||||
* Apply FULL_MODEL rotation to a world-space offset from entity position.
|
||||
* Converts the offset to model space, applies FULL_MODEL rotation and pivots,
|
||||
* then converts back to world space.
|
||||
*
|
||||
* <p>
|
||||
* The rendering pipeline is: entity_pos * body_yaw * scale(-1,-1,1) * FULL_MODEL * parts
|
||||
* Combined body_yaw + scale maps model space to world space:
|
||||
* worldX = mx*cos(yaw) + mz*sin(yaw)
|
||||
* worldY = -my (model Y-down → world Y-up)
|
||||
* worldZ = mx*sin(yaw) - mz*cos(yaw)
|
||||
* worldX = mx*cos(yaw) + mz*sin(yaw)
|
||||
* worldY = -my (model Y-down → world Y-up)
|
||||
* worldZ = mx*sin(yaw) - mz*cos(yaw)
|
||||
* This transform is its own inverse for X,Z.
|
||||
*
|
||||
* <p>
|
||||
* FULL_MODEL rotation order matches renderer: vertex sees Z, then Y, then X.
|
||||
*/
|
||||
private static Vec3 applyFullModelToWorldOffset(FramePart fullModel, EntityLivingBase entity,
|
||||
double worldDX, double worldDY, double worldDZ,
|
||||
float bodyYaw, float scale) {
|
||||
double worldDX, double worldDY, double worldDZ,
|
||||
float bodyYaw, float scale) {
|
||||
float[] rotations = getRotations(fullModel, entity);
|
||||
float[] pivots = getPivots(fullModel, entity);
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ public class BukkitUtil {
|
||||
|
||||
/**
|
||||
* Checks if a specific Bukkit plugin is enabled.
|
||||
*
|
||||
* @param pluginName the plugin name to check
|
||||
* @return true if the plugin is enabled
|
||||
*/
|
||||
@@ -115,6 +116,7 @@ public class BukkitUtil {
|
||||
|
||||
/**
|
||||
* Gets a Bukkit OfflinePlayer by name.
|
||||
*
|
||||
* @param playerName the player name
|
||||
* @return the OfflinePlayer object, or null if not available
|
||||
*/
|
||||
@@ -131,6 +133,7 @@ public class BukkitUtil {
|
||||
|
||||
/**
|
||||
* Gets a Bukkit Player by name (online players only).
|
||||
*
|
||||
* @param playerName the player name
|
||||
* @return the Player object, or null if not online or not available
|
||||
*/
|
||||
@@ -147,6 +150,7 @@ public class BukkitUtil {
|
||||
|
||||
/**
|
||||
* Gets a service provider from Bukkit's ServicesManager.
|
||||
*
|
||||
* @param serviceClass the service class to get
|
||||
* @return the service provider, or null if not available
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package kamkeel.npcs.util;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityVariant;
|
||||
import noppes.npcs.LogWriter;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -68,8 +74,7 @@ public class Register<T> {
|
||||
}
|
||||
|
||||
public AbilityVariant registerVariant(String typeId, String variantName, String group, Consumer<Ability> configurator) {
|
||||
registerVariant(typeId, variantName, () -> new AbilityVariant(variantName, group, configurator));
|
||||
return new AbilityVariant(variantName, group, configurator);
|
||||
return registerVariant(typeId, variantName, () -> new AbilityVariant(variantName, group, configurator));
|
||||
}
|
||||
|
||||
public AbilityVariant registerVariant(String typeId, String factoryName, Supplier<AbilityVariant> factory) {
|
||||
|
||||
Loaded 100 of 207 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user