Added Dual Disc Ability

This commit is contained in:
Vidal committed 2026-01-31 22:36:12 -03:00
1 parent e9f22dab2a
commit 71065fc520
7 files changed
+784 -4

No files matched your search

@@ -364,7 +364,8 @@ public class AbilityController implements IAbilityHandler {
registerType("cnpc:projectile", AbilityProjectile::new);
registerType("cnpc:orb", AbilityOrb::new);
registerType("cnpc:dual_orb", AbilityDualOrb::new);
registerType("cnpc:disc", AbilityDisc::new);
registerType("cnpc:dual_disc", AbilityDisc::new);
registerType("cnpc:dual_disc", AbilityDualDisc::new);
registerType("cnpc:laser_shot", AbilityLaserShot::new);
registerType("cnpc:beam", AbilityEnergyBeam::new);
registerType("cnpc:dual_beam", AbilityDualBeam::new);
@@ -0,0 +1,410 @@
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.AnchorPoint;
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.telegraph.Telegraph;
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
import kamkeel.npcs.entity.EntityAbilityDisc;
import kamkeel.npcs.util.AnchorPointHelper;
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.client.gui.advanced.SubGuiAbilityConfig;
import noppes.npcs.client.gui.advanced.ability.SubGuiAbilityDualDisc;
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
import noppes.npcs.entity.EntityNPCInterface;
import noppes.npcs.util.ValueUtil;
public class AbilityDualDisc extends Ability {
// Disc geometry
private float discRadius = 1.0f;
private float discThickness = 0.2f;
// Boomerang properties
private boolean boomerang = false;
private int boomerangDelay = 40;
// Dual properties
private boolean dualFire= true;
private int dualFireDelay = 10;
// Energy data classes
private EnergyColorData[] colorData = new EnergyColorData[]{
new EnergyColorData(0xFFFFFF, 0xFF8800, true, 0.4f, 0.5f, 5.0f),
new EnergyColorData(0xFFFFFF, 0x8800FF, true, 0.4f, 0.5f, 5.0f)
};
private EnergyCombatData combatData = new EnergyCombatData(8.0f, 1.2f, 0.15f, false, 3.0f, 0.5f);
private EnergyHomingData homingData = new EnergyHomingData(0.6f, true, 0.12f, 18.0f);
public final EnergyLightningData[] lightningData = new EnergyLightningData[]{
new EnergyLightningData(), new EnergyLightningData()
};
private EnergyLifespanData lifespanData = new EnergyLifespanData(35.0f, 200);
private EnergyAnchorData[] anchorData = new EnergyAnchorData[]{
new EnergyAnchorData(AnchorPoint.RIGHT_HAND), new EnergyAnchorData(AnchorPoint.LEFT_HAND)
};
// Transient state for disc entity (used during windup charging)
private transient EntityAbilityDisc discEntity = null;
private transient EntityAbilityDisc discEntity2 = null;
public AbilityDualDisc() {
this.typeId = "ability.cnpc.dual_disc";
this.name = "Dual Disc";
this.targetingMode = TargetingMode.AGGRO_TARGET;
this.maxRange = 30.0f;
this.minRange = 5.0f;
this.cooldownTicks = 0;
this.windUpTicks = 60;
this.lockMovement = LockMovementType.WINDUP;
this.telegraphType = TelegraphType.CIRCLE;
this.showTelegraph = true;
// Default built-in animations
this.windUpAnimationName = "Ability_DualBeam_Windup";
this.activeAnimationName = "Ability_DualBeam_Active";
}
@Override
public boolean hasTypeSettings() {
return true;
}
@Override
@SideOnly(Side.CLIENT)
public SubGuiAbilityConfig createConfigGui(IAbilityConfigCallback callback) {
return new SubGuiAbilityDualDisc(this, callback);
}
@Override
public boolean isTargetingModeLocked() {
return true;
}
@Override
public TargetingMode[] getAllowedTargetingModes() {
return new TargetingMode[]{TargetingMode.AGGRO_TARGET};
}
@Override
public void onExecute(EntityLivingBase caster, EntityLivingBase target, World world) {
if (world.isRemote) {
signalCompletion();
return;
}
// Start moving the orb that was spawned during windup
if (discEntity != null && !discEntity.isDead) {
discEntity.startMoving(target);
}
if (dualFire) {
if (discEntity2 != null && !discEntity2.isDead && dualFireDelay <= 0) {
discEntity2.startMoving(target);
}
} else {
discEntity2.setDead();
}
// Ability stays active until entity dies (prevents firing another while projectile is alive)
// Movement locking is handled separately by the base class
}
@Override
public void onWindUpTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) {
if (world.isRemote) return;
// Spawn disc in charging mode on first tick of windup
if (tick == 1) {
// Create disc in charging mode - follows caster based on anchor point during windup
Vec3 spawnPos1 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[0]);
discEntity = new EntityAbilityDisc(
world, caster, target,
spawnPos1.xCoord, spawnPos1.yCoord, spawnPos1.zCoord,
discRadius, discThickness,
colorData[0], combatData, homingData, lightningData[0], lifespanData,
boomerang, boomerangDelay);
Vec3 spawnPos2 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[1]);
discEntity2 = new EntityAbilityDisc(
world, caster, target,
spawnPos2.xCoord, spawnPos2.yCoord, spawnPos2.zCoord,
discRadius, discThickness,
colorData[1], combatData, homingData, lightningData[1], lifespanData,
boomerang, boomerangDelay);
discEntity.setSiblingUUID(discEntity2.getPersistentID());
discEntity2.setSiblingUUID(discEntity.getPersistentID());
discEntity.setupCharging(anchorData[0], windUpTicks);
discEntity2.setupCharging(anchorData[1], windUpTicks);
discEntity.setEffects(this.effects);
if (dualFire) {
discEntity2.setEffects(this.effects);
}
world.spawnEntityInWorld(discEntity);
world.spawnEntityInWorld(discEntity2);
}
}
@Override
public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) {
// Signal completion when entity dies
if (dualFire) {
if ((discEntity == null || discEntity.isDead) && (discEntity2 == null || discEntity2.isDead)) {
discEntity = null;
discEntity2 = null;
signalCompletion();
}
if (tick == dualFireDelay && discEntity2 != null && !discEntity2.isDead) {
discEntity2.startMoving(target);
}
} else {
if (discEntity == null || discEntity.isDead) {
discEntity = null;
signalCompletion();
}
}
}
@Override
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
}
@Override
public void cleanup() {
// Despawn disc entity if still alive
if (discEntity != null && !discEntity.isDead) {
discEntity.setDead();
}
if (discEntity2 != null && !discEntity2.isDead) {
discEntity2.setDead();
}
discEntity = null;
discEntity2 = null;
}
@Override
public TelegraphInstance createTelegraph(EntityLivingBase caster, EntityLivingBase target) {
if (!showTelegraph || telegraphType == TelegraphType.NONE || target == null) {
return null;
}
// Create circle telegraph at target position
Telegraph telegraph = Telegraph.circle(discRadius * 1.5f);
telegraph.setDurationTicks(windUpTicks);
telegraph.setColor(windUpColor);
telegraph.setWarningColor(activeColor);
telegraph.setWarningStartTick(Math.max(5, windUpTicks / 4));
telegraph.setHeightOffset(telegraphHeightOffset);
// Position at target and follow target during windup
TelegraphInstance instance = new TelegraphInstance(telegraph, target.posX, target.posY, target.posZ, caster.rotationYaw);
instance.setCasterEntityId(caster.getEntityId());
instance.setEntityIdToFollow(target.getEntityId());
return instance;
}
@Override
public float getTelegraphRadius() {
return discRadius * 1.5f;
}
@Override
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setFloat("discRadius", discRadius);
nbt.setFloat("discThickness", discThickness);
nbt.setBoolean("boomerang", boomerang);
nbt.setInteger("boomerangDelay", boomerangDelay);
nbt.setBoolean("dualFire", dualFire);
nbt.setInteger("dualFireDelay", dualFireDelay);
combatData.writeNBT(nbt);
homingData.writeNBT(nbt);
lifespanData.writeNBT(nbt);
NBTTagCompound disc1 = new NBTTagCompound();
NBTTagCompound disc2 = new NBTTagCompound();
anchorData[0].writeNBT(disc1);
anchorData[1].writeNBT(disc2);
colorData[0].writeNBT(disc1);
colorData[1].writeNBT(disc2);
lightningData[0].writeNBT(disc1);
lightningData[1].writeNBT(disc2);
nbt.setTag("Disc_1", disc1);
nbt.setTag("Disc_2", disc2);
}
@Override
public void readTypeNBT(NBTTagCompound nbt) {
NBTTagCompound disc1 = nbt.hasKey("Disc_1") ? nbt.getCompoundTag("Disc_1") : new NBTTagCompound();
NBTTagCompound disc2 = nbt.hasKey("Disc_2") ? nbt.getCompoundTag("Disc_2") : new NBTTagCompound();
this.discRadius = nbt.hasKey("discRadius") ? nbt.getFloat("discRadius") : 1.0f;
this.discThickness = nbt.hasKey("discThickness") ? nbt.getFloat("discThickness") : 0.2f;
this.boomerang = nbt.hasKey("boomerang") && nbt.getBoolean("boomerang");
this.boomerangDelay = nbt.hasKey("boomerangDelay") ? nbt.getInteger("boomerangDelay") : 40;
this.dualFire = !nbt.hasKey("dualFire") || nbt.getBoolean("dualFire");
this.dualFireDelay = nbt.hasKey("dualFireDelay") ? nbt.getInteger("dualFireDelay") : 0;
combatData.readNBT(nbt);
homingData.readNBT(nbt);
lifespanData.readNBT(nbt);
anchorData[0].readNBT(disc1);
anchorData[1].readNBT(disc2);
colorData[0].readNBT(disc1);
colorData[1].readNBT(disc2);
lightningData[0].readNBT(disc1);
lightningData[1].readNBT(disc2);
}
// Getters & Setters
private EnergyColorData getColorData(int orb) {
orb = ValueUtil.clamp(orb, 0, 1);
return colorData[orb];
}
private EnergyLightningData getLightningData(int orb) {
orb = ValueUtil.clamp(orb, 0, 1);
return lightningData[orb];
}
private EnergyAnchorData getAnchorData(int orb) {
orb = ValueUtil.clamp(orb, 0, 1);
return anchorData[orb];
}
public boolean isDualFire() { return dualFire; }
public void setDualFire(boolean dualFire) { this.dualFire = dualFire; }
public int getDualFireDelay() { return dualFireDelay; }
public void setDualFireDelay(int dualFireDelay) { this.dualFireDelay = dualFireDelay; }
public float getSpeed() { return homingData.speed; }
public void setSpeed(float speed) { homingData.speed = speed; }
public float getDiscRadius() { return discRadius; }
public void setDiscRadius(float discRadius) { this.discRadius = discRadius; }
public float getDiscThickness() { return discThickness; }
public void setDiscThickness(float discThickness) { this.discThickness = discThickness; }
public float getMaxDistance() { return lifespanData.maxDistance; }
public void setMaxDistance(float maxDistance) { lifespanData.maxDistance = maxDistance; }
public int getMaxLifetime() { return lifespanData.maxLifetime; }
public void setMaxLifetime(int maxLifetime) { lifespanData.maxLifetime = maxLifetime; }
public float getDamage() { return combatData.damage; }
public void setDamage(float damage) { combatData.damage = damage; }
public float getKnockback() { return combatData.knockback; }
public void setKnockback(float knockback) { combatData.knockback = knockback; }
public float getKnockbackUp() { return combatData.knockbackUp; }
public void setKnockbackUp(float knockbackUp) { combatData.knockbackUp = knockbackUp; }
public boolean isHoming() { return homingData.homing; }
public void setHoming(boolean homing) { homingData.homing = homing; }
public float getHomingStrength() { return homingData.homingStrength; }
public void setHomingStrength(float homingStrength) { homingData.homingStrength = homingStrength; }
public float getHomingRange() { return homingData.homingRange; }
public void setHomingRange(float homingRange) { homingData.homingRange = homingRange; }
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; }
public boolean isExplosive() { return combatData.explosive; }
public void setExplosive(boolean explosive) { combatData.explosive = explosive; }
public float getExplosionRadius() { return combatData.explosionRadius; }
public void setExplosionRadius(float explosionRadius) { combatData.explosionRadius = explosionRadius; }
public float getExplosionDamageFalloff() { return combatData.explosionDamageFalloff; }
public void setExplosionDamageFalloff(float explosionDamageFalloff) { combatData.explosionDamageFalloff = explosionDamageFalloff; }
public int getInnerColor(int orb) { return getColorData(orb).innerColor; }
public void setInnerColor(int orb, int innerColor) { getColorData(orb).innerColor = innerColor; }
public int getOuterColor(int orb) { return getColorData(orb).outerColor; }
public void setOuterColor(int orb, int outerColor) { getColorData(orb).outerColor = outerColor; }
public boolean isOuterColorEnabled(int orb) { return getColorData(orb).outerColorEnabled; }
public void setOuterColorEnabled(int orb, boolean enabled) { getColorData(orb).outerColorEnabled = enabled; }
public float getOuterColorWidth(int orb) { return getColorData(orb).outerColorWidth; }
public void setOuterColorWidth(int orb, float width) { getColorData(orb).outerColorWidth = width; }
public float getOuterColorAlpha(int orb) { return getColorData(orb).outerColorAlpha; }
public void setOuterColorAlpha(int orb, float alpha) { getColorData(orb).outerColorAlpha = alpha; }
public float getRotationSpeed(int orb) { return getColorData(orb).rotationSpeed; }
public void setRotationSpeed(int orb, float speed) { getColorData(orb).rotationSpeed = speed; }
public int getInnerColor() { return getInnerColor(0); }
public void setInnerColor(int innerColor) { setInnerColor(0, innerColor); }
public int getOuterColor() { return getOuterColor(0); }
public void setOuterColor(int outerColor) { setOuterColor(0, outerColor); }
public boolean isOuterColorEnabled() { return isOuterColorEnabled(0); }
public void setOuterColorEnabled(boolean enabled) { setOuterColorEnabled(0, enabled); }
public float getOuterColorWidth() { return getOuterColorWidth(0); }
public void setOuterColorWidth(float width) { setOuterColorWidth(0, width); }
public float getOuterColorAlpha() { return getOuterColorAlpha(0); }
public void setOuterColorAlpha(float alpha) { setOuterColorAlpha(0, alpha); }
public float getRotationSpeed() { return getRotationSpeed(0); }
public void setRotationSpeed(float speed) { setRotationSpeed(0, speed); }
public boolean hasLightningEffect(int orb) { return getLightningData(orb).lightningEffect; }
public void setLightningEffect(int orb, boolean lightningEffect) { getLightningData(orb).lightningEffect = lightningEffect; }
public float getLightningDensity(int orb) { return getLightningData(orb).lightningDensity; }
public void setLightningDensity(int orb, float lightningDensity) { getLightningData(orb).lightningDensity = lightningDensity; }
public float getLightningRadius(int orb) { return getLightningData(orb).lightningRadius; }
public void setLightningRadius(int orb, float lightningRadius) { getLightningData(orb).lightningRadius = lightningRadius; }
public boolean hasLightningEffect() { return hasLightningEffect(0); }
public void setLightningEffect(boolean lightningEffect) { setLightningEffect(0, lightningEffect); }
public float getLightningDensity() { return getLightningDensity(0); }
public void setLightningDensity(float lightningDensity) { setLightningDensity(0, lightningDensity); }
public float getLightningRadius() { return getLightningRadius(0); }
public void setLightningRadius(float lightningRadius) { setLightningRadius(0, lightningRadius); }
public AnchorPoint getAnchorPointEnum(int orb) { return getAnchorData(orb).anchorPoint; }
public void setAnchorPointEnum(int orb, AnchorPoint anchorPoint) { getAnchorData(orb).anchorPoint = anchorPoint; }
public float getAnchorOffsetX(int orb) { return getAnchorData(orb).anchorOffsetX; }
public void setAnchorOffsetX(int orb, float x) { getAnchorData(orb).anchorOffsetX = x; }
public float getAnchorOffsetY(int orb) { return getAnchorData(orb).anchorOffsetY; }
public void setAnchorOffsetY(int orb, float y) { getAnchorData(orb).anchorOffsetY = y; }
public float getAnchorOffsetZ(int orb) { return getAnchorData(orb).anchorOffsetZ; }
public void setAnchorOffsetZ(int orb, float z) { getAnchorData(orb).anchorOffsetZ = z; }
public AnchorPoint getAnchorPointEnum() { return getAnchorPointEnum(0); }
public void setAnchorPointEnum(AnchorPoint anchorPoint) { setAnchorPointEnum(0, anchorPoint); }
public float getAnchorOffsetX() { return getAnchorOffsetX(0); }
public void setAnchorOffsetX(float x) { setAnchorOffsetX(0, x); }
public float getAnchorOffsetY() { return getAnchorOffsetY(0); }
public void setAnchorOffsetY(float y) { setAnchorOffsetY(0, y); }
public float getAnchorOffsetZ() { return getAnchorOffsetZ(0); }
public void setAnchorOffsetZ(float z) { setAnchorOffsetZ(0, z); }
//@Override
public int getAnchorPoint(int orb) { return getAnchorData(orb).anchorPoint.ordinal(); }
public int getAnchorPoint() { return getAnchorData(0).anchorPoint.ordinal(); }
//@Override
public void setAnchorPoint(int orb, int point) { getAnchorData(orb).anchorPoint = AnchorPoint.fromOrdinal(point); }
public void setAnchorPoint(int point) { getAnchorData(0).anchorPoint = AnchorPoint.fromOrdinal(point); }
@Override
@SideOnly(Side.CLIENT)
public Entity createPreviewEntity(EntityNPCInterface npc) {
if (npc == null || npc.worldObj == null) return null;
EntityAbilityDisc disc = new EntityAbilityDisc(npc.worldObj);
disc.setupPreview(npc, discRadius, discThickness, colorData[0], lightningData[0], anchorData[0], windUpTicks);
return disc;
}
@Override
public int getPreviewActiveDuration() {
return lifespanData.maxLifetime > 0 ? Math.min(lifespanData.maxLifetime, 100) : 100;
}
}
@@ -12,6 +12,7 @@ import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import java.util.List;
import java.util.UUID;
/**
* Disc projectile - flat spinning disc with optional boomerang behavior.
@@ -48,6 +49,8 @@ public class EntityAbilityDisc extends EntityAbilityProjectile {
// Data watcher index for charging state (synced to clients)
private static final int DW_CHARGING = 20;
private UUID siblingUUID = null;
public EntityAbilityDisc(World world) {
super(world);
}
@@ -565,6 +568,18 @@ public class EntityAbilityDisc extends EntityAbilityProjectile {
return returning;
}
public UUID getSiblingUUID() {
return siblingUUID;
}
public void setSiblingUUID(UUID siblingUUID) {
if (siblingUUID == null)
return;
if (this.siblingUUID == null)
this.siblingUUID = siblingUUID;
}
// ==================== NBT ====================
@Override
@@ -587,6 +602,7 @@ public class EntityAbilityDisc extends EntityAbilityProjectile {
this.targetDiscRadius = nbt.hasKey("TargetDiscRadius") ? nbt.getFloat("TargetDiscRadius") : this.discRadius;
this.targetDiscThickness = nbt.hasKey("TargetDiscThickness") ? nbt.getFloat("TargetDiscThickness") : this.discThickness;
this.anchorData.readNBT(nbt);
this.siblingUUID = nbt.hasKey("SiblingUUID") ? UUID.fromString(nbt.getString("SiblingUUID")) : null;
}
@Override
@@ -609,5 +625,6 @@ public class EntityAbilityDisc extends EntityAbilityProjectile {
// Anchor data
this.anchorData.writeNBT(nbt);
nbt.setString("SiblingUUID", siblingUUID.toString());
}
}
@@ -473,6 +473,8 @@ public class EntityAbilityOrb extends EntityAbilityProjectile {
this.targetSize = nbt.hasKey("TargetSize") ? nbt.getFloat("TargetSize") : this.size;
// Anchor data
this.anchorData.readNBT(nbt);
this.siblingUUID = nbt.hasKey("SiblingUUID") ? UUID.fromString(nbt.getString("SiblingUUID")) : null;
}
@Override
@@ -487,5 +489,7 @@ public class EntityAbilityOrb extends EntityAbilityProjectile {
nbt.setInteger("ChargeTick", chargeTick);
anchorData.writeNBT(nbt);
nbt.setFloat("TargetSize", targetSize);
nbt.setString("SiblingUUID", siblingUUID.toString());
}
}
@@ -0,0 +1,342 @@
package noppes.npcs.client.gui.advanced.ability;
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
import kamkeel.npcs.controllers.data.ability.type.AbilityDisc;
import kamkeel.npcs.controllers.data.ability.type.AbilityDualDisc;
import noppes.npcs.client.gui.SubGuiColorSelector;
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
import noppes.npcs.client.gui.util.*;
import java.util.List;
public class SubGuiAbilityDualDisc extends SubGuiAbilityConfig {
private final AbilityDualDisc disc;
private int editingVisualColorId = 0;
private int editingDisc = 0;
public SubGuiAbilityDualDisc(AbilityDualDisc ability, IAbilityConfigCallback callback) {
super(ability, callback);
this.disc = ability;
}
@Override
protected boolean hasVisualSettings() {
return true;
}
@Override
protected void initTypeTab(int startY) {
int y = startY;
int labelX = guiLeft + 8;
int fieldX = guiLeft + 85;
int col2LabelX = guiLeft + 145;
int col2FieldX = guiLeft + 205;
// Row 1: Damage + Speed
addLabel(new GuiNpcLabel(100, "enchantment.damage", labelX, y + 5));
addTextField(createFloatField(100, fieldX, y, 50, disc.getDamage()));
addLabel(new GuiNpcLabel(101, "stats.speed", col2LabelX, y + 5));
addTextField(createFloatField(101, col2FieldX, y, 50, disc.getSpeed()));
y += 24;
// Row 2: Disc Radius + Disc Thickness
addLabel(new GuiNpcLabel(102, "ability.discRadius", labelX, y + 5));
addTextField(createFloatField(102, fieldX, y, 50, disc.getDiscRadius()));
addLabel(new GuiNpcLabel(103, "ability.discThickness", col2LabelX, y + 5));
addTextField(createFloatField(103, col2FieldX, y, 50, disc.getDiscThickness()));
y += 24;
// Row 3: Homing + Homing Strength (only show strength if homing)
addLabel(new GuiNpcLabel(104, "ability.homing", labelX, y + 5));
GuiNpcButton homingBtn = new GuiNpcButton(104, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, disc.isHoming() ? 1 : 0);
homingBtn.setHoverText("ability.hover.homing");
addButton(homingBtn);
if (disc.isHoming()) {
addLabel(new GuiNpcLabel(105, "ability.homingStr", col2LabelX, y + 5));
addTextField(createFloatField(105, col2FieldX, y, 50, disc.getHomingStrength()));
}
y += 24;
// Row 4: Boomerang + Boomerang Delay (only show delay if boomerang)
addLabel(new GuiNpcLabel(106, "ability.boomerang", labelX, y + 5));
GuiNpcButton boomerangBtn = new GuiNpcButton(106, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, disc.isBoomerang() ? 1 : 0);
boomerangBtn.setHoverText("ability.hover.boomerang");
addButton(boomerangBtn);
if (disc.isBoomerang()) {
addLabel(new GuiNpcLabel(107, "ability.boomerangDelay", col2LabelX, y + 5));
addTextField(createIntField(107, col2FieldX, y, 50, disc.getBoomerangDelay()));
}
y += 24;
// Row 5: Explosive + Explosion Radius (only show radius if explosive)
addLabel(new GuiNpcLabel(108, "ability.explosive", labelX, y + 5));
GuiNpcButton explosiveBtn = new GuiNpcButton(108, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, disc.isExplosive() ? 1 : 0);
explosiveBtn.setHoverText("ability.hover.explosive");
addButton(explosiveBtn);
if (disc.isExplosive()) {
addLabel(new GuiNpcLabel(109, "ability.explosionRad", col2LabelX, y + 5));
addTextField(createFloatField(109, col2FieldX, y, 50, disc.getExplosionRadius()));
}
y += 24;
// Row 6: Knockback + Max Distance
addLabel(new GuiNpcLabel(110, "ability.knockback", labelX, y + 5));
addTextField(createFloatField(110, fieldX, y, 50, disc.getKnockback()));
addLabel(new GuiNpcLabel(111, "ability.maxDist", col2LabelX, y + 5));
addTextField(createFloatField(111, col2FieldX, y, 50, disc.getMaxDistance()));
y += 24;
// Row 7: Max Lifetime + Effects button
addLabel(new GuiNpcLabel(112, "ability.lifetime", labelX, y + 5));
addTextField(createIntField(112, fieldX, y, 50, disc.getMaxLifetime()));
y += 24;
addLabel(new GuiNpcLabel(113, "ability.dualFire", labelX, y + 5));
addButton(new GuiNpcButtonYesNo(113, fieldX, y, disc.isDualFire()));
if (disc.isDualFire()) {
addLabel(new GuiNpcLabel(114, "ability.dualFireDelay", col2LabelX, y + 5));
addTextField(createIntField(114, col2FieldX, y, 50, disc.getDualFireDelay()));
}
addButton(new GuiNpcButton(150, col2LabelX + 120, y, 80, 20, "ability.effects"));
}
@Override
protected void initVisualTab(int startY) {
int y = startY;
int labelX = guiLeft + 8;
int fieldX = guiLeft + 85;
int col2LabelX = guiLeft + 180;
int col2FieldX = guiLeft + 260;
// Row 1: Anchor Point
addLabel(new GuiNpcLabel(210, "ability.anchorPoint", labelX, y + 5));
GuiNpcButton anchorBtn = new GuiNpcButton(210, fieldX, y, 80, 20, AnchorPoint.getDisplayNames(), disc.getAnchorPointEnum(editingDisc).ordinal());
anchorBtn.setHoverText("ability.hover.anchorPoint");
addButton(anchorBtn);
y += 24;
// Row 2: Inner Color + Outer Color
addLabel(new GuiNpcLabel(200, "ability.innerColor", labelX, y + 5));
String innerHex = String.format("%06X", disc.getInnerColor(editingDisc) & 0xFFFFFF);
GuiNpcButton innerColorBtn = new GuiNpcButton(200, fieldX, y, 55, 20, innerHex);
innerColorBtn.setTextColor(disc.getInnerColor(editingDisc) & 0xFFFFFF);
addButton(innerColorBtn);
addLabel(new GuiNpcLabel(201, "ability.outerColor", col2LabelX, y + 5));
String outerHex = String.format("%06X", disc.getOuterColor(editingDisc) & 0xFFFFFF);
GuiNpcButton outerColorBtn = new GuiNpcButton(201, col2FieldX, y, 55, 20, outerHex);
outerColorBtn.setTextColor(disc.getOuterColor(editingDisc) & 0xFFFFFF);
outerColorBtn.setEnabled(disc.isOuterColorEnabled(editingDisc));
addButton(outerColorBtn);
y += 24;
// Row 2: Outer Color Enabled + Outer Color Width
addLabel(new GuiNpcLabel(202, "ability.outerEnabled", labelX, y + 5));
addButton(new GuiNpcButton(202, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, disc.isOuterColorEnabled(editingDisc) ? 1 : 0));
addLabel(new GuiNpcLabel(203, "ability.outerWidth", col2LabelX, y + 5));
GuiNpcTextField widthField = createFloatField(203, col2FieldX, y, 55, disc.getOuterColorWidth(editingDisc));
widthField.setEnabled(disc.isOuterColorEnabled(editingDisc));
addTextField(widthField);
y += 24;
// Row 3: Outer Color Alpha
addLabel(new GuiNpcLabel(204, "ability.outerAlpha", labelX, y + 5));
GuiNpcTextField alphaField = createFloatField(204, fieldX, y, 55, disc.getOuterColorAlpha(editingDisc));
alphaField.setEnabled(disc.isOuterColorEnabled(editingDisc));
alphaField.setMinMaxDefaultFloat(0, 1, 0.5f);
addTextField(alphaField);
y += 24;
// Row 4: Rotation Speed
addLabel(new GuiNpcLabel(205, "ability.rotationSpeed", labelX, y + 5));
addTextField(createFloatField(205, fieldX, y, 50, disc.getRotationSpeed(editingDisc)));
y += 24;
// Row 5: Lightning Effect Enabled
addLabel(new GuiNpcLabel(206, "ability.lightning", labelX, y + 5));
GuiNpcButton lightningBtn = new GuiNpcButton(206, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, disc.hasLightningEffect(editingDisc) ? 1 : 0);
lightningBtn.setHoverText("ability.hover.lightning");
addButton(lightningBtn);
// Only show Lightning settings if Lightning is enabled
if (disc.hasLightningEffect(editingDisc)) {
y += 24;
// Row 6: Density + Radius
addLabel(new GuiNpcLabel(207, "ability.lightningDensity", labelX, y + 5));
GuiNpcTextField densityField = new GuiNpcTextField(207, this, fontRendererObj, fieldX, y, 55, 18, "" + disc.getLightningDensity(editingDisc));
densityField.setMinMaxDefaultFloat(0.01f, 5.0f, 0.15f);
addTextField(densityField);
addLabel(new GuiNpcLabel(208, "ability.lightningRadius", col2LabelX, y + 5));
GuiNpcTextField radiusField = new GuiNpcTextField(208, this, fontRendererObj, col2FieldX, y, 55, 18, "" + disc.getLightningRadius(editingDisc));
radiusField.setMinMaxDefaultFloat(0.1f, 10.0f, 0.5f);
addTextField(radiusField);
}
y += 24;
addButton(new GuiNpcButton(400, col2FieldX, y, 55, 20, new String[]{"Disc 1", "Disc 2"}, editingDisc));
}
@Override
protected void handleTypeButton(int id, GuiNpcButton button) {
int value = button.getValue();
switch (id) {
case 104:
disc.setHoming(value == 1);
initGui();
break;
case 106:
disc.setBoomerang(value == 1);
initGui();
break;
case 108:
disc.setExplosive(value == 1);
initGui();
break;
case 113:
disc.setDualFire(value == 1);
initGui();
break;
case 150:
setSubGui(new SubGuiAbilityEffects(disc.getEffects()));
break;
}
}
@Override
protected void handleVisualButton(int id, GuiNpcButton button) {
int value = button.getValue();
switch (id) {
case 200:
editingVisualColorId = 200;
setSubGui(new SubGuiColorSelector(disc.getInnerColor(editingDisc)));
break;
case 201:
editingVisualColorId = 201;
setSubGui(new SubGuiColorSelector(disc.getOuterColor(editingDisc)));
break;
case 202:
disc.setOuterColorEnabled(editingDisc, value == 1);
initGui();
break;
case 206:
disc.setLightningEffect(editingDisc, value == 1);
initGui();
break;
case 210:
disc.setAnchorPointEnum(editingDisc, AnchorPoint.fromOrdinal(value));
break;
case 400:
editingDisc = (editingDisc + 1) % 2;
initGui();
break;
}
}
@Override
public void subGuiClosed(SubGuiInterface subgui) {
if (subgui instanceof SubGuiColorSelector && editingVisualColorId != 0) {
SubGuiColorSelector colorSelector = (SubGuiColorSelector) subgui;
int rgb = colorSelector.color & 0x00FFFFFF;
if (editingVisualColorId == 200) {
disc.setInnerColor(editingDisc, rgb);
} else if (editingVisualColorId == 201) {
disc.setOuterColor(editingDisc, rgb);
}
editingVisualColorId = 0;
initGui();
} else if (subgui instanceof SubGuiAbilityEffects) {
SubGuiAbilityEffects effectsGui = (SubGuiAbilityEffects) subgui;
List<AbilityEffect> result = effectsGui.getResult();
if (result != null) {
disc.setEffects(result);
}
} else {
super.subGuiClosed(subgui);
}
}
@Override
protected void handleTypeTextField(int id, GuiNpcTextField field) {
switch (id) {
case 100:
disc.setDamage(parseFloat(field, disc.getDamage()));
break;
case 101:
disc.setSpeed(parseFloat(field, disc.getSpeed()));
break;
case 102:
disc.setDiscRadius(parseFloat(field, disc.getDiscRadius()));
break;
case 103:
disc.setDiscThickness(parseFloat(field, disc.getDiscThickness()));
break;
case 105:
disc.setHomingStrength(parseFloat(field, disc.getHomingStrength()));
break;
case 107:
disc.setBoomerangDelay(field.getInteger());
break;
case 109:
disc.setExplosionRadius(parseFloat(field, disc.getExplosionRadius()));
break;
case 110:
disc.setKnockback(parseFloat(field, disc.getKnockback()));
break;
case 111:
disc.setMaxDistance(parseFloat(field, disc.getMaxDistance()));
break;
case 112:
disc.setMaxLifetime(field.getInteger());
break;
case 114:
disc.setDualFireDelay(field.getInteger());
break;
}
}
@Override
protected void handleVisualTextField(int id, GuiNpcTextField field) {
switch (id) {
case 203:
disc.setOuterColorWidth(editingDisc, parseFloat(field, disc.getOuterColorWidth(editingDisc)));
break;
case 204:
disc.setOuterColorAlpha(editingDisc, parseFloat(field, disc.getOuterColorAlpha(editingDisc)));
break;
case 205:
disc.setRotationSpeed(editingDisc, parseFloat(field, disc.getRotationSpeed(editingDisc)));
break;
case 207:
disc.setLightningDensity(editingDisc, parseFloat(field, disc.getLightningDensity(editingDisc)));
break;
case 208:
disc.setLightningRadius(editingDisc, parseFloat(field, disc.getLightningRadius(editingDisc)));
break;
}
}
}
@@ -3,7 +3,6 @@ package noppes.npcs.client.gui.advanced.ability;
import kamkeel.npcs.controllers.data.ability.AbilityEffect;
import kamkeel.npcs.controllers.data.ability.AnchorPoint;
import kamkeel.npcs.controllers.data.ability.type.AbilityDualOrb;
import kamkeel.npcs.controllers.data.ability.type.AbilityOrb;
import noppes.npcs.client.gui.SubGuiColorSelector;
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
import noppes.npcs.client.gui.util.*;
@@ -240,9 +239,9 @@ public class SubGuiAbilityDualOrb extends SubGuiAbilityConfig {
SubGuiColorSelector colorSelector = (SubGuiColorSelector) subgui;
int rgb = colorSelector.color & 0x00FFFFFF;
if (editingVisualColorId == 200) {
orb.setInnerColor(rgb);
orb.setInnerColor(editingOrb, rgb);
} else if (editingVisualColorId == 201) {
orb.setOuterColor(rgb);
orb.setOuterColor(editingOrb, rgb);
}
editingVisualColorId = 0;
initGui();