Custom Ability Telegraph Controls, Inner Radius Fix

This commit is contained in:
Kam committed 2026-03-05 02:18:34 -05:00
1 parent dbca3da639
commit e309794fd7
8 files changed
+440 -43

No files matched your search

+1 -1
Submodule src/api updated: 4e96425314...5eb98d172e.
@@ -105,7 +105,7 @@ public class TelegraphRenderer {
renderLine(telegraph.getLength(), telegraph.getWidth(), red, green, blue, alpha);
break;
case CONE:
renderCone(telegraph.getLength(), telegraph.getAngle(), red, green, blue, alpha);
renderCone(telegraph.getLength(), telegraph.getAngle(), telegraph.getInnerRadius(), red, green, blue, alpha);
break;
case POINT:
renderPoint(red, green, blue, alpha);
@@ -207,42 +207,98 @@ public class TelegraphRenderer {
tessellator.draw();
}
private void renderCone(float length, float angle, float r, float g, float b, float a) {
private void renderCone(float length, float angle, float innerRadius, float r, float g, float b, float a) {
float halfAngleRad = (float) Math.toRadians(angle / 2);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawing(GL11.GL_TRIANGLE_FAN);
tessellator.setColorRGBA_F(r, g, b, a);
// Origin point
tessellator.addVertex(0, 0, 0);
if (innerRadius <= 0) {
// Standard cone: triangle fan from origin
tessellator.startDrawing(GL11.GL_TRIANGLE_FAN);
tessellator.setColorRGBA_F(r, g, b, a);
// Arc points
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
double x = Math.sin(segmentAngle) * length;
double z = Math.cos(segmentAngle) * length;
tessellator.addVertex(x, 0, z);
tessellator.addVertex(0, 0, 0);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
double x = Math.sin(segmentAngle) * length;
double z = Math.cos(segmentAngle) * length;
tessellator.addVertex(x, 0, z);
}
tessellator.draw();
// Border
tessellator.startDrawing(GL11.GL_LINE_STRIP);
tessellator.setColorRGBA_F(r, g, b, Math.min(1.0f, a * 2));
tessellator.addVertex(0, 0.01, 0);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
double x = Math.sin(segmentAngle) * length;
double z = Math.cos(segmentAngle) * length;
tessellator.addVertex(x, 0.01, z);
}
tessellator.addVertex(0, 0.01, 0);
tessellator.draw();
} else {
// Truncated cone: strip between inner and outer arcs
tessellator.startDrawing(GL11.GL_TRIANGLE_STRIP);
tessellator.setColorRGBA_F(r, g, b, a);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
double sinA = Math.sin(segmentAngle);
double cosA = Math.cos(segmentAngle);
tessellator.addVertex(sinA * length, 0, cosA * length);
tessellator.addVertex(sinA * innerRadius, 0, cosA * innerRadius);
}
tessellator.draw();
// Border: outer arc
float borderAlpha = Math.min(1.0f, a * 2);
tessellator.startDrawing(GL11.GL_LINE_STRIP);
tessellator.setColorRGBA_F(r, g, b, borderAlpha);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
tessellator.addVertex(Math.sin(segmentAngle) * length, 0.01, Math.cos(segmentAngle) * length);
}
tessellator.draw();
// Border: inner arc
tessellator.startDrawing(GL11.GL_LINE_STRIP);
tessellator.setColorRGBA_F(r, g, b, borderAlpha);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
tessellator.addVertex(Math.sin(segmentAngle) * innerRadius, 0.01, Math.cos(segmentAngle) * innerRadius);
}
tessellator.draw();
// Border: side edges connecting inner and outer arcs
tessellator.startDrawing(GL11.GL_LINES);
tessellator.setColorRGBA_F(r, g, b, borderAlpha);
double sinStart = Math.sin(-halfAngleRad);
double cosStart = Math.cos(-halfAngleRad);
tessellator.addVertex(sinStart * innerRadius, 0.01, cosStart * innerRadius);
tessellator.addVertex(sinStart * length, 0.01, cosStart * length);
double sinEnd = Math.sin(halfAngleRad);
double cosEnd = Math.cos(halfAngleRad);
tessellator.addVertex(sinEnd * innerRadius, 0.01, cosEnd * innerRadius);
tessellator.addVertex(sinEnd * length, 0.01, cosEnd * length);
tessellator.draw();
}
tessellator.draw();
// Draw border
tessellator.startDrawing(GL11.GL_LINE_STRIP);
tessellator.setColorRGBA_F(r, g, b, Math.min(1.0f, a * 2));
tessellator.addVertex(0, 0.01, 0);
for (int i = 0; i <= CONE_SEGMENTS; i++) {
float segmentAngle = -halfAngleRad + (halfAngleRad * 2 * i) / CONE_SEGMENTS;
double x = Math.sin(segmentAngle) * length;
double z = Math.cos(segmentAngle) * length;
tessellator.addVertex(x, 0.01, z);
}
tessellator.addVertex(0, 0.01, 0);
tessellator.draw();
}
private void renderPoint(float r, float g, float b, float a) {
@@ -344,7 +400,7 @@ public class TelegraphRenderer {
renderLine(telegraph.getLength(), telegraph.getWidth(), red, green, blue, alpha);
break;
case CONE:
renderCone(telegraph.getLength(), telegraph.getAngle(), red, green, blue, alpha);
renderCone(telegraph.getLength(), telegraph.getAngle(), telegraph.getInnerRadius(), red, green, blue, alpha);
break;
case POINT:
renderPoint(red, green, blue, alpha);
@@ -597,6 +597,18 @@ public abstract class Ability implements IAbility, IAbilityAction {
return 45.0f;
}
public float getTelegraphInnerRadius() {
return 0.0f;
}
/**
* Override to return true if the ability type manages its own telegraph GUI controls.
* When true, the base class will skip adding the default telegraph section.
*/
public boolean hasOwnTelegraphControls() {
return false;
}
/**
* Returns true if the caster is a player (not an NPC).
* Use this instead of checking {@code target != null} to make NPC/Player
@@ -875,7 +887,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
.tab("Effects"));
TelegraphType tType = getTelegraphType();
if (tType != null && tType != TelegraphType.NONE) {
if (tType != null && tType != TelegraphType.NONE && !hasOwnTelegraphControls()) {
defs.add(FieldDef.section("ability.section.telegraph").tab("Effects")
.hover("telegraph." + tType.name().toLowerCase()));
defs.add(FieldDef.boolField("ability.showTelegraph", this::isShowTelegraph, this::setShowTelegraph)
@@ -1015,13 +1027,13 @@ public abstract class Ability implements IAbility, IAbilityAction {
telegraph = Telegraph.circle(getTelegraphRadius());
break;
case RING:
telegraph = Telegraph.ring(getTelegraphRadius(), getTelegraphRadius() * 0.5f);
telegraph = Telegraph.ring(getTelegraphRadius(), getTelegraphInnerRadius());
break;
case LINE:
telegraph = Telegraph.line(getTelegraphLength(), getTelegraphWidth());
break;
case CONE:
telegraph = Telegraph.cone(getTelegraphLength(), getTelegraphAngle());
telegraph = Telegraph.cone(getTelegraphLength(), getTelegraphAngle(), getTelegraphInnerRadius());
break;
case POINT:
telegraph = new Telegraph("", TelegraphType.POINT);
@@ -1,8 +1,12 @@
package kamkeel.npcs.controllers.data.ability;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.data.ability.enums.LockMode;
import kamkeel.npcs.controllers.data.ability.enums.TargetingMode;
import kamkeel.npcs.controllers.data.ability.enums.UserType;
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.nbt.NBTTagCompound;
@@ -28,6 +32,17 @@ public class CustomAbility extends Ability implements ICustomAbility {
private int durationTicks = 20;
// Telegraph dimension fields
private float tRadius = 5.0f;
private float tInnerRadius = 0.0f;
private float tLength = 5.0f;
private float tWidth = 2.0f;
private float tAngle = 45.0f;
// Telegraph timing
private int telegraphActiveTicks = 0;
private boolean syncTelegraphWithDuration = true;
public CustomAbility() {
this.typeId = "ability.cnpc.custom";
this.name = "Custom";
@@ -77,6 +92,139 @@ public class CustomAbility extends Ability implements ICustomAbility {
return true;
}
@Override
public boolean hasOwnTelegraphControls() {
return true;
}
// ==================== TELEGRAPH OVERRIDES ====================
@Override
public boolean keepTelegraphDuringActive() {
return getResolvedTelegraphActiveTicks() > 0;
}
/**
* Returns the effective telegraph active ticks: synced from duration or manual value.
*/
public int getResolvedTelegraphActiveTicks() {
if (syncTelegraphWithDuration) {
return durationTicks;
}
return telegraphActiveTicks;
}
@Override
public TelegraphInstance createTelegraph(EntityLivingBase caster, EntityLivingBase target) {
if (!isShowTelegraph() || getTelegraphType() == TelegraphType.NONE) {
return null;
}
Telegraph telegraph;
double x, y, z;
float yaw = caster.rotationYaw;
TelegraphType tType = getTelegraphType();
boolean positionAtCaster = targetingMode == TargetingMode.AOE_SELF ||
targetingMode == TargetingMode.SELF ||
tType == TelegraphType.LINE ||
tType == TelegraphType.CONE;
if (positionAtCaster) {
x = caster.posX;
y = findGroundLevel(caster.worldObj, caster.posX, caster.posY, caster.posZ);
z = caster.posZ;
} else if (target != null) {
x = target.posX;
y = findGroundLevel(caster.worldObj, target.posX, target.posY, target.posZ);
z = target.posZ;
} else {
x = caster.posX;
y = findGroundLevel(caster.worldObj, caster.posX, caster.posY, caster.posZ);
z = caster.posZ;
}
switch (tType) {
case CIRCLE:
telegraph = Telegraph.circle(tRadius);
break;
case RING:
telegraph = Telegraph.ring(tRadius, tInnerRadius);
break;
case LINE:
telegraph = Telegraph.line(tLength, tWidth);
break;
case CONE:
telegraph = Telegraph.cone(tLength, tAngle, tInnerRadius);
break;
case POINT:
telegraph = new Telegraph("", TelegraphType.POINT);
break;
case SQUARE:
telegraph = Telegraph.square(tRadius);
break;
default:
return null;
}
int activeTicks = getResolvedTelegraphActiveTicks();
int totalDuration = windUpTicks + activeTicks;
telegraph.setDurationTicks(Math.max(1, totalDuration));
telegraph.setColor(windUpColor);
telegraph.setWarningColor(activeColor);
if (windUpTicks > 0) {
telegraph.setWarningStartTick(windUpTicks);
} else {
telegraph.setWarningStartTick(0);
}
telegraph.setHeightOffset(telegraphHeightOffset);
TelegraphInstance instance = new TelegraphInstance(telegraph, x, y, z, yaw);
instance.setCasterEntityId(caster.getEntityId());
if (positionAtCaster) {
instance.setEntityIdToFollow(caster.getEntityId());
if (tType == TelegraphType.LINE || tType == TelegraphType.CONE) {
if (!isRotationLockedDuringWindup()) {
if (target != null) {
instance.setTargetEntityId(target.getEntityId());
} else {
instance.setTrackFollowedEntityYaw(true);
}
}
}
} else if (target != null) {
instance.setEntityIdToFollow(target.getEntityId());
}
return instance;
}
@Override
public float getTelegraphRadius() {
return tRadius;
}
@Override
public float getTelegraphInnerRadius() {
return tInnerRadius;
}
@Override
public float getTelegraphLength() {
return tLength;
}
@Override
public float getTelegraphWidth() {
return tWidth;
}
@Override
public float getTelegraphAngle() {
return tAngle;
}
// ==================== FIELDS ====================
@Override
@@ -89,6 +237,62 @@ public class CustomAbility extends Ability implements ICustomAbility {
this.durationTicks = Math.max(0, ticks);
}
public float getTRadius() {
return tRadius;
}
public void setTRadius(float radius) {
this.tRadius = Math.max(0, radius);
}
public float getTInnerRadius() {
return tInnerRadius;
}
public void setTInnerRadius(float innerRadius) {
this.tInnerRadius = Math.max(0, innerRadius);
}
public float getTLength() {
return tLength;
}
public void setTLength(float length) {
this.tLength = Math.max(0, length);
}
public float getTWidth() {
return tWidth;
}
public void setTWidth(float width) {
this.tWidth = Math.max(0, width);
}
public float getTAngle() {
return tAngle;
}
public void setTAngle(float angle) {
this.tAngle = Math.max(0, angle);
}
public int getTelegraphActiveTicks() {
return telegraphActiveTicks;
}
public void setTelegraphActiveTicks(int ticks) {
this.telegraphActiveTicks = Math.max(0, ticks);
}
public boolean isSyncTelegraphWithDuration() {
return syncTelegraphWithDuration;
}
public void setSyncTelegraphWithDuration(boolean sync) {
this.syncTelegraphWithDuration = sync;
}
// ==================== ICustomAbility ====================
@Override
@@ -104,6 +308,31 @@ public class CustomAbility extends Ability implements ICustomAbility {
}
}
@Override
public void setTelegraphRadius(float radius) {
this.tRadius = Math.max(0, radius);
}
@Override
public void setTelegraphInnerRadius(float innerRadius) {
this.tInnerRadius = Math.max(0, innerRadius);
}
@Override
public void setTelegraphLength(float length) {
this.tLength = Math.max(0, length);
}
@Override
public void setTelegraphWidth(float width) {
this.tWidth = Math.max(0, width);
}
@Override
public void setTelegraphAngle(float angle) {
this.tAngle = Math.max(0, angle);
}
@Override
public int getTargetingModeType() {
return getTargetingMode().ordinal();
@@ -122,15 +351,30 @@ public class CustomAbility extends Ability implements ICustomAbility {
@Override
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setInteger("durationTicks", durationTicks);
nbt.setFloat("tRadius", tRadius);
nbt.setFloat("tInnerRadius", tInnerRadius);
nbt.setFloat("tLength", tLength);
nbt.setFloat("tWidth", tWidth);
nbt.setFloat("tAngle", tAngle);
nbt.setInteger("telegraphActiveTicks", telegraphActiveTicks);
nbt.setBoolean("syncTelegraphWithDuration", syncTelegraphWithDuration);
}
@Override
public void readTypeNBT(NBTTagCompound nbt) {
this.durationTicks = Math.max(0, nbt.getInteger("durationTicks"));
this.tRadius = nbt.hasKey("tRadius") ? nbt.getFloat("tRadius") : 5.0f;
this.tInnerRadius = nbt.hasKey("tInnerRadius") ? nbt.getFloat("tInnerRadius") : 0.0f;
this.tLength = nbt.hasKey("tLength") ? nbt.getFloat("tLength") : 5.0f;
this.tWidth = nbt.hasKey("tWidth") ? nbt.getFloat("tWidth") : 2.0f;
this.tAngle = nbt.hasKey("tAngle") ? nbt.getFloat("tAngle") : 45.0f;
this.telegraphActiveTicks = nbt.hasKey("telegraphActiveTicks") ? nbt.getInteger("telegraphActiveTicks") : 0;
this.syncTelegraphWithDuration = nbt.hasKey("syncTelegraphWithDuration") ? nbt.getBoolean("syncTelegraphWithDuration") : true;
}
// ==================== GUI ====================
@SideOnly(Side.CLIENT)
@Override
public void getAbilityDefinitions(List<FieldDef> defs) {
// User Type (NPC / Player / Both)
@@ -141,10 +385,6 @@ public class CustomAbility extends Ability implements ICustomAbility {
defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class,
this::getTargetingMode, this::setTargetingMode));
// Telegraph Shape
defs.add(FieldDef.enumField("ability.telegraphShape", TelegraphType.class,
this::getTelegraphType, this::setTelegraphType));
// Toggle section
defs.add(FieldDef.section("ability.section.toggle"));
defs.add(FieldDef.boolField("ability.toggleEnabled",
@@ -161,5 +401,75 @@ public class CustomAbility extends Ability implements ICustomAbility {
defs.add(FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks)
.range(0, 6000)
.visibleWhen(() -> !this.isToggleable()));
// ── Telegraph Controls (Effects tab) ─────────────────────────
defs.add(FieldDef.section("ability.section.telegraph").tab("Effects"));
defs.add(FieldDef.enumField("ability.telegraphShape", TelegraphType.class,
this::getTelegraphType, this::setTelegraphType).tab("Effects"));
defs.add(FieldDef.boolField("ability.showTelegraph", this::isShowTelegraph, this::setShowTelegraph)
.tab("Effects").visibleWhen(this::hasTelegraphShape));
defs.add(FieldDef.colorSubGui("ability.windUpColor", this::getWindUpColor, this::setWindUpColor)
.tab("Effects").visibleWhen(this::isTelegraphVisible));
defs.add(FieldDef.colorSubGui("ability.activeColor", this::getActiveColor, this::setActiveColor)
.tab("Effects").visibleWhen(this::isTelegraphVisible));
defs.add(FieldDef.floatField("ability.telegraphHeight", this::getTelegraphHeightOffset, this::setTelegraphHeightOffset)
.tab("Effects").visibleWhen(this::isTelegraphVisible));
// Telegraph active duration with sync toggle (mirrors windup sync pattern)
defs.add(FieldDef.row(
FieldDef.intField("ability.telegraphActiveTicks", this::getTelegraphActiveTicks, this::setTelegraphActiveTicks).range(0, 6000),
FieldDef.boolField("ability.syncTelegraph", this::isSyncTelegraphWithDuration, this::setSyncTelegraphWithDuration)
.hover("ability.hover.syncTelegraph")
).tab("Effects").visibleWhen(() -> isTelegraphVisible() && !isSyncTelegraphWithDuration()));
defs.add(FieldDef.row(
FieldDef.labelField("ability.telegraphActiveTicks", () -> getResolvedTelegraphActiveTicks() + "t"),
FieldDef.boolField("ability.syncTelegraph", this::isSyncTelegraphWithDuration, this::setSyncTelegraphWithDuration)
.hover("ability.hover.syncTelegraph")
).tab("Effects").visibleWhen(() -> isTelegraphVisible() && isSyncTelegraphWithDuration()));
// Shape-specific dimension fields
defs.add(FieldDef.floatField("ability.telegraphRadius", this::getTRadius, this::setTRadius)
.tab("Effects").visibleWhen(() -> isTelegraphVisible() && needsRadius()));
defs.add(FieldDef.floatField("ability.telegraphInnerRadius", this::getTInnerRadius, this::setTInnerRadius)
.tab("Effects").visibleWhen(() -> isTelegraphVisible() && needsInnerRadius()));
defs.add(FieldDef.floatField("ability.telegraphLength", this::getTLength, this::setTLength)
.tab("Effects").visibleWhen(() -> isTelegraphVisible() && needsLength()));
defs.add(FieldDef.floatField("ability.telegraphWidth", this::getTWidth, this::setTWidth)
.tab("Effects").visibleWhen(() -> isTelegraphVisible() && needsWidth()));
defs.add(FieldDef.floatField("ability.telegraphAngle", this::getTAngle, this::setTAngle)
.tab("Effects").visibleWhen(() -> isTelegraphVisible() && needsAngle()));
}
// ==================== TELEGRAPH VISIBILITY HELPERS ====================
private boolean hasTelegraphShape() {
return getTelegraphType() != TelegraphType.NONE;
}
private boolean isTelegraphVisible() {
return hasTelegraphShape() && isShowTelegraph();
}
private boolean needsRadius() {
TelegraphType t = getTelegraphType();
return t == TelegraphType.CIRCLE || t == TelegraphType.RING || t == TelegraphType.SQUARE;
}
private boolean needsInnerRadius() {
TelegraphType t = getTelegraphType();
return t == TelegraphType.RING || t == TelegraphType.CONE;
}
private boolean needsLength() {
TelegraphType t = getTelegraphType();
return t == TelegraphType.LINE || t == TelegraphType.CONE;
}
private boolean needsWidth() {
return getTelegraphType() == TelegraphType.LINE;
}
private boolean needsAngle() {
return getTelegraphType() == TelegraphType.CONE;
}
}
@@ -122,7 +122,7 @@ public class AbilityCutter extends Ability implements IAbilityCutter {
return null;
}
Telegraph telegraph = Telegraph.cone(getTelegraphLength(), getTelegraphAngle());
Telegraph telegraph = Telegraph.cone(getTelegraphLength(), getTelegraphAngle(), getTelegraphInnerRadius());
int totalDuration = windUpTicks + getActiveDurationTicks();
telegraph.setDurationTicks(totalDuration);
telegraph.setColor(windUpColor);
@@ -162,6 +162,11 @@ public class AbilityCutter extends Ability implements IAbilityCutter {
return arcAngle;
}
@Override
public float getTelegraphInnerRadius() {
return innerRadius;
}
@Override
public void onExecute(EntityLivingBase caster, EntityLivingBase target) {
hitEntities.clear();
@@ -111,9 +111,10 @@ public class AbilityDodge extends AbilityDefend implements IAbilityDodge {
@SideOnly(Side.CLIENT)
@Override
protected void getTypeDefinitions(List<FieldDef> defs) {
defs.add(FieldDef.section("ability.section.dodgeAnimations").tab("Effects"));
FieldDef.insertAfter(defs, "ability.dazedAnimation",
FieldDef.section("ability.section.dodgeAnimations").tab("Effects"));
FieldDef.insertAfter(defs, "ability.section.dodgeAnimations",
FieldDef.animSubGui("ability.dodgeAnimation1",
this::getDodgeAnimation1Id, this::setDodgeAnimation1Id,
this::getDodgeAnimation1Name, this::setDodgeAnimation1Name)
@@ -152,6 +152,14 @@ public class Telegraph {
return t;
}
public static Telegraph cone(float length, float angle, float innerRadius) {
Telegraph t = new Telegraph("", TelegraphType.CONE);
t.length = length;
t.angle = angle;
t.innerRadius = innerRadius;
return t;
}
public static Telegraph point() {
return new Telegraph("", TelegraphType.POINT);
}
@@ -1021,6 +1021,11 @@ public abstract class AbstractDataAbilities {
* Execute an ability immediately (no windup). Called when windUpTicks is 0.
*/
protected void executeImmediate(Ability ability, EntityLivingBase target) {
// Spawn telegraph for abilities that persist during active phase (e.g., Custom Ability)
if (ability.keepTelegraphDuringActive()) {
spawnTelegraph(ability, target);
}
// Play active sound and animation
playAbilitySound(ability.getActiveSound());
playAbilityAnimation(ability.getActiveAnimation());