mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 15:27:29 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
77be537de4
22 files changed
+2813
-37
No files matched your search
@@ -4,6 +4,9 @@ import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static kamkeel.npcs.util.ColorUtil.sendError;
|
||||
|
||||
@@ -369,7 +369,7 @@ public abstract class Ability implements IAbility {
|
||||
* Create a telegraph instance for this ability.
|
||||
* Override for custom telegraph shapes.
|
||||
*
|
||||
* @param npc The caster
|
||||
* @param caster The caster
|
||||
* @param target The target (for position calculation)
|
||||
* @return The telegraph instance, or null if no telegraph
|
||||
*/
|
||||
|
||||
@@ -1,23 +1,6 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilitySweeper;
|
||||
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.AbilityOrb;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityDisc;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityLaserShot;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityEnergyBeam;
|
||||
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.*;
|
||||
import kamkeel.npcs.controllers.SyncController;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.CustomNpcs;
|
||||
@@ -380,9 +363,12 @@ public class AbilityController implements IAbilityHandler {
|
||||
registerType("cnpc:sweeper", AbilitySweeper::new);
|
||||
registerType("cnpc:projectile", AbilityProjectile::new);
|
||||
registerType("cnpc:orb", AbilityOrb::new);
|
||||
registerType("cnpc:disc", AbilityDisc::new);
|
||||
registerType("cnpc:dual_orb", AbilityDualOrb::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);
|
||||
|
||||
// Movement abilities
|
||||
registerType("cnpc:charge", AbilityCharge::new);
|
||||
|
||||
@@ -31,14 +31,6 @@ public abstract class BuiltInAbility extends Ability {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in abilities are not customizable.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCustomizable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in abilities do not write type-specific NBT (they have fixed configs).
|
||||
*/
|
||||
|
||||
@@ -24,25 +24,25 @@ public class EnergyAnchorData {
|
||||
}
|
||||
|
||||
public EnergyAnchorData(int anchorPoint) {
|
||||
this.anchorPoint = AnchorPoint.fromId(anchorPoint);
|
||||
this.anchorPoint = AnchorPoint.fromOrdinal(anchorPoint);
|
||||
}
|
||||
|
||||
public EnergyAnchorData(int anchorPoint, float anchorOffsetX, float anchorOffsetY, float anchorOffsetZ) {
|
||||
this.anchorPoint = AnchorPoint.fromId(anchorPoint);
|
||||
this.anchorPoint = AnchorPoint.fromOrdinal(anchorPoint);
|
||||
this.anchorOffsetX = anchorOffsetX;
|
||||
this.anchorOffsetY = anchorOffsetY;
|
||||
this.anchorOffsetZ = anchorOffsetZ;
|
||||
}
|
||||
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setInteger("anchorPoint", anchorPoint.getId());
|
||||
nbt.setInteger("anchorPoint", anchorPoint.ordinal());
|
||||
nbt.setFloat("anchorOffsetX", anchorOffsetX);
|
||||
nbt.setFloat("anchorOffsetY", anchorOffsetY);
|
||||
nbt.setFloat("anchorOffsetZ", anchorOffsetZ);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromId(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT;
|
||||
this.anchorPoint = nbt.hasKey("anchorPoint") ? AnchorPoint.fromOrdinal(nbt.getInteger("anchorPoint")) : AnchorPoint.FRONT;
|
||||
this.anchorOffsetX = nbt.hasKey("anchorOffsetX") ? nbt.getFloat("anchorOffsetX") : 0;
|
||||
this.anchorOffsetY = nbt.hasKey("anchorOffsetY") ? nbt.getFloat("anchorOffsetY") : 0;
|
||||
this.anchorOffsetZ = nbt.hasKey("anchorOffsetZ") ? nbt.getFloat("anchorOffsetZ") : 0;
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
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.EntityAbilityBeam;
|
||||
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.SubGuiAbilityDualBeam;
|
||||
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
import noppes.npcs.util.ValueUtil;
|
||||
|
||||
public class AbilityDualBeam extends Ability {
|
||||
private float beamWidth = 0.4f;
|
||||
private float headSize = 0.6f;
|
||||
private boolean dualFire= true;
|
||||
private int dualFireDelay = 0;
|
||||
|
||||
// Data classes
|
||||
private EnergyColorData[] colorData = new EnergyColorData[]{
|
||||
new EnergyColorData(0xFFFFFF, 0x00AAFF, true, 0.4f, 0.5f, 6.0f),
|
||||
new EnergyColorData(0xFFFFFF, 0xFF0000, true, 0.4f, 0.5f, 6.0f),
|
||||
};
|
||||
private EnergyCombatData combatData = new EnergyCombatData(10.0f, 1.5f, 0.2f, false, 4.0f, 0.5f);
|
||||
private EnergyHomingData homingData = new EnergyHomingData(0.4f, true, 0.1f, 15.0f);
|
||||
private EnergyLightningData[] lightningData = new EnergyLightningData[]{
|
||||
new EnergyLightningData(), new EnergyLightningData()
|
||||
};
|
||||
private EnergyLifespanData lifespanData = new EnergyLifespanData(25.0f, 200);
|
||||
private EnergyAnchorData[] anchorData = new EnergyAnchorData[]{
|
||||
new EnergyAnchorData(AnchorPoint.RIGHT_HAND), new EnergyAnchorData(AnchorPoint.LEFT_HAND)
|
||||
};
|
||||
|
||||
// Transient state for beam entity (used during windup charging)
|
||||
private transient EntityAbilityBeam beamEntity = null;
|
||||
private transient EntityAbilityBeam beamEntity2 = null;
|
||||
|
||||
public AbilityDualBeam() {
|
||||
this.typeId = "ability.cnpc.dual_beam";
|
||||
this.name = "Dual Beam";
|
||||
this.targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
this.maxRange = 20.0f;
|
||||
this.minRange = 5.0f;
|
||||
this.cooldownTicks = 0;
|
||||
this.windUpTicks = 80;
|
||||
this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE;
|
||||
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 SubGuiAbilityDualBeam(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 firing the beam that was spawned during windup
|
||||
if (beamEntity != null && !beamEntity.isDead) {
|
||||
beamEntity.startFiring(target);
|
||||
}
|
||||
|
||||
if (dualFire) {
|
||||
if (beamEntity2 != null && !beamEntity2.isDead && dualFireDelay <= 0) {
|
||||
beamEntity2.startFiring(target);
|
||||
}
|
||||
} else {
|
||||
beamEntity2.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 beam in charging mode on first tick of windup
|
||||
if (tick == 1) {
|
||||
float offsetDist = 1.0f;
|
||||
|
||||
// Create beam in charging mode - follows caster based on anchor point during windup
|
||||
Vec3 spawnPos1 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[0], offsetDist);
|
||||
beamEntity = new EntityAbilityBeam(
|
||||
world, caster, target,
|
||||
spawnPos1.xCoord, spawnPos1.yCoord, spawnPos1.zCoord,
|
||||
beamWidth, headSize,
|
||||
colorData[0], combatData, homingData, lightningData[0], lifespanData,
|
||||
lockMovement.locksActive());
|
||||
|
||||
Vec3 spawnPos2 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[1], offsetDist);
|
||||
beamEntity2 = new EntityAbilityBeam(
|
||||
world, caster, target,
|
||||
spawnPos2.xCoord, spawnPos2.yCoord, spawnPos2.zCoord,
|
||||
beamWidth, headSize,
|
||||
colorData[1], combatData, homingData, lightningData[1], lifespanData,
|
||||
lockMovement.locksActive());
|
||||
|
||||
beamEntity.setSiblingUUID(beamEntity2.getPersistentID());
|
||||
beamEntity2.setSiblingUUID(beamEntity.getPersistentID());
|
||||
|
||||
beamEntity.setupCharging(anchorData[0], windUpTicks, offsetDist);
|
||||
beamEntity2.setupCharging(anchorData[1], windUpTicks, offsetDist);
|
||||
|
||||
beamEntity.setEffects(this.effects);
|
||||
if (dualFire) beamEntity2.setEffects(this.effects);
|
||||
|
||||
world.spawnEntityInWorld(beamEntity);
|
||||
world.spawnEntityInWorld(beamEntity2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) {
|
||||
// Signal completion when entity dies
|
||||
if (dualFire) {
|
||||
if ((beamEntity == null || beamEntity.isDead) && (beamEntity2 == null || beamEntity2.isDead)) {
|
||||
beamEntity = null;
|
||||
beamEntity2 = null;
|
||||
signalCompletion();
|
||||
}
|
||||
|
||||
if (tick == dualFireDelay && beamEntity2 != null && !beamEntity2.isDead) {
|
||||
beamEntity2.startFiring(target);
|
||||
}
|
||||
} else {
|
||||
if (beamEntity == null || beamEntity.isDead) {
|
||||
beamEntity = null;
|
||||
signalCompletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
// Despawn beam entity if still alive
|
||||
if (beamEntity != null && !beamEntity.isDead) {
|
||||
beamEntity.setDead();
|
||||
}
|
||||
|
||||
if (beamEntity2 != null && !beamEntity2.isDead) {
|
||||
beamEntity2.setDead();
|
||||
}
|
||||
|
||||
beamEntity = null;
|
||||
beamEntity2 = 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(headSize * 2.0f);
|
||||
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 headSize * 2.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("beamWidth", beamWidth);
|
||||
nbt.setFloat("headSize", headSize);
|
||||
nbt.setBoolean("dualFire", dualFire);
|
||||
nbt.setInteger("dualFireDelay", dualFireDelay);
|
||||
combatData.writeNBT(nbt);
|
||||
homingData.writeNBT(nbt);
|
||||
lifespanData.writeNBT(nbt);
|
||||
|
||||
NBTTagCompound beam1 = new NBTTagCompound();
|
||||
NBTTagCompound beam2 = new NBTTagCompound();
|
||||
|
||||
anchorData[0].writeNBT(beam1);
|
||||
anchorData[1].writeNBT(beam2);
|
||||
colorData[0].writeNBT(beam1);
|
||||
colorData[1].writeNBT(beam2);
|
||||
lightningData[0].writeNBT(beam1);
|
||||
lightningData[1].writeNBT(beam2);
|
||||
|
||||
nbt.setTag("Beam_1", beam1);
|
||||
nbt.setTag("Beam_2", beam2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
NBTTagCompound beam1 = nbt.hasKey("Beam_1") ? nbt.getCompoundTag("Beam_1") : new NBTTagCompound();
|
||||
NBTTagCompound beam2 = nbt.hasKey("Beam_2") ? nbt.getCompoundTag("Beam_2") : new NBTTagCompound();
|
||||
|
||||
this.beamWidth = nbt.hasKey("beamWidth") ? nbt.getFloat("beamWidth") : 0.4f;
|
||||
this.headSize = nbt.hasKey("headSize") ? nbt.getFloat("headSize") : 0.6f;
|
||||
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(beam1);
|
||||
anchorData[1].readNBT(beam2);
|
||||
colorData[0].readNBT(beam1);
|
||||
colorData[1].readNBT(beam2);
|
||||
lightningData[0].readNBT(beam1);
|
||||
lightningData[1].readNBT(beam2);
|
||||
}
|
||||
|
||||
// Getters & Setters - Standalone fields
|
||||
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; }
|
||||
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; }
|
||||
|
||||
private EnergyColorData getColorData(int beam) {
|
||||
beam = ValueUtil.clamp(beam, 0, 1);
|
||||
return colorData[beam];
|
||||
}
|
||||
private EnergyLightningData getLightningData(int beam) {
|
||||
beam = ValueUtil.clamp(beam, 0, 1);
|
||||
return lightningData[beam];
|
||||
}
|
||||
private EnergyAnchorData getAnchorData(int beam) {
|
||||
beam = ValueUtil.clamp(beam, 0, 1);
|
||||
return anchorData[beam];
|
||||
}
|
||||
|
||||
// Getters & Setters - Color data
|
||||
public int getInnerColor(int beam) { return getColorData(beam).innerColor; }
|
||||
public void setInnerColor(int beam, int innerColor) { getColorData(beam).innerColor = innerColor; }
|
||||
public int getOuterColor(int beam) { return getColorData(beam).outerColor; }
|
||||
public void setOuterColor(int beam, int outerColor) { getColorData(beam).outerColor = outerColor; }
|
||||
public boolean isOuterColorEnabled(int beam) { return getColorData(beam).outerColorEnabled; }
|
||||
public void setOuterColorEnabled(int beam, boolean enabled) { getColorData(beam).outerColorEnabled = enabled; }
|
||||
public float getOuterColorWidth(int beam) { return getColorData(beam).outerColorWidth; }
|
||||
public void setOuterColorWidth(int beam, float width) { getColorData(beam).outerColorWidth = width; }
|
||||
public float getOuterColorAlpha(int beam) { return getColorData(beam).outerColorAlpha; }
|
||||
public void setOuterColorAlpha(int beam, float alpha) { getColorData(beam).outerColorAlpha = alpha; }
|
||||
public float getRotationSpeed(int beam) { return getColorData(beam).rotationSpeed; }
|
||||
public void setRotationSpeed(int beam, float speed) { getColorData(beam).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); }
|
||||
|
||||
// Getters & Setters - Combat data
|
||||
public float getDamage() { return combatData.damage; }
|
||||
public void setDamage(float damage) { this.combatData.damage = damage; }
|
||||
public float getKnockback() { return combatData.knockback; }
|
||||
public void setKnockback(float knockback) { this.combatData.knockback = knockback; }
|
||||
public float getKnockbackUp() { return combatData.knockbackUp; }
|
||||
public void setKnockbackUp(float knockbackUp) { this.combatData.knockbackUp = knockbackUp; }
|
||||
public boolean isExplosive() { return combatData.explosive; }
|
||||
public void setExplosive(boolean explosive) { this.combatData.explosive = explosive; }
|
||||
public float getExplosionRadius() { return combatData.explosionRadius; }
|
||||
public void setExplosionRadius(float explosionRadius) { this.combatData.explosionRadius = explosionRadius; }
|
||||
public float getExplosionDamageFalloff() { return combatData.explosionDamageFalloff; }
|
||||
public void setExplosionDamageFalloff(float explosionDamageFalloff) { this.combatData.explosionDamageFalloff = explosionDamageFalloff; }
|
||||
|
||||
// Getters & Setters - Homing data
|
||||
public float getSpeed() { return homingData.speed; }
|
||||
public void setSpeed(float speed) { this.homingData.speed = speed; }
|
||||
public boolean isHoming() { return homingData.homing; }
|
||||
public void setHoming(boolean homing) { this.homingData.homing = homing; }
|
||||
public float getHomingStrength() { return homingData.homingStrength; }
|
||||
public void setHomingStrength(float homingStrength) { this.homingData.homingStrength = homingStrength; }
|
||||
public float getHomingRange() { return homingData.homingRange; }
|
||||
public void setHomingRange(float homingRange) { this.homingData.homingRange = homingRange; }
|
||||
|
||||
// Getters & Setters - Lightning data
|
||||
public boolean hasLightningEffect(int beam) { return getLightningData(beam).lightningEffect; }
|
||||
public void setLightningEffect(int beam, boolean lightningEffect) { getLightningData(beam).lightningEffect = lightningEffect; }
|
||||
public float getLightningDensity(int beam) { return getLightningData(beam).lightningDensity; }
|
||||
public void setLightningDensity(int beam, float lightningDensity) { getLightningData(beam).lightningDensity = lightningDensity; }
|
||||
public float getLightningRadius(int beam) { return getLightningData(beam).lightningRadius; }
|
||||
public void setLightningRadius(int beam, float lightningRadius) { getLightningData(beam).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); }
|
||||
|
||||
|
||||
// Getters & Setters - Lifespan data
|
||||
public float getMaxDistance() { return lifespanData.maxDistance; }
|
||||
public void setMaxDistance(float maxDistance) { this.lifespanData.maxDistance = maxDistance; }
|
||||
public int getMaxLifetime() { return lifespanData.maxLifetime; }
|
||||
public void setMaxLifetime(int maxLifetime) { this.lifespanData.maxLifetime = maxLifetime; }
|
||||
|
||||
// Getters & Setters - Anchor point
|
||||
public AnchorPoint getAnchorPointEnum(int beam) { return getAnchorData(beam).anchorPoint; }
|
||||
public void setAnchorPointEnum(int beam, AnchorPoint anchorPoint) { getAnchorData(beam).anchorPoint = anchorPoint; }
|
||||
public float getAnchorOffsetX(int beam) { return getAnchorData(beam).anchorOffsetX; }
|
||||
public void setAnchorOffsetX(int beam, float x) { getAnchorData(beam).anchorOffsetX = x; }
|
||||
public float getAnchorOffsetY(int beam) { return getAnchorData(beam).anchorOffsetY; }
|
||||
public void setAnchorOffsetY(int beam, float y) { getAnchorData(beam).anchorOffsetY = y; }
|
||||
public float getAnchorOffsetZ(int beam) { return getAnchorData(beam).anchorOffsetZ; }
|
||||
public void setAnchorOffsetZ(int beam, float z) { getAnchorData(beam).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 beam) { return getAnchorData(beam).anchorPoint.ordinal(); }
|
||||
public int getAnchorPoint() { return getAnchorData(0).anchorPoint.ordinal(); }
|
||||
|
||||
//@Override
|
||||
public void setAnchorPoint(int beam, int point) { getAnchorData(beam).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;
|
||||
|
||||
EntityAbilityBeam beam = new EntityAbilityBeam(npc.worldObj);
|
||||
beam.setupPreview(npc, beamWidth, headSize, colorData[0], lightningData[0], anchorData[0], windUpTicks, 1.0f);
|
||||
return beam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviewActiveDuration() {
|
||||
return lifespanData.maxLifetime > 0 ? Math.min(lifespanData.maxLifetime, 100) : 100;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
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.EntityAbilityOrb;
|
||||
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.SubGuiAbilityDualOrb;
|
||||
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
import noppes.npcs.util.ValueUtil;
|
||||
|
||||
public class AbilityDualOrb extends Ability {
|
||||
// Ability-specific properties
|
||||
private float orbSize = 1.0f;
|
||||
private boolean dualFire= true;
|
||||
private int dualFireDelay = 20;
|
||||
|
||||
// Data classes for energy properties
|
||||
public final EnergyColorData[] colorData = new EnergyColorData[]{
|
||||
new EnergyColorData(), new EnergyColorData()
|
||||
};
|
||||
public final EnergyCombatData combatData = new EnergyCombatData();
|
||||
public final EnergyHomingData homingData = new EnergyHomingData();
|
||||
public final EnergyLightningData[] lightningData = new EnergyLightningData[]{
|
||||
new EnergyLightningData(), new EnergyLightningData()
|
||||
};
|
||||
public final EnergyLifespanData lifespanData = new EnergyLifespanData();
|
||||
private EnergyAnchorData[] anchorData = new EnergyAnchorData[]{
|
||||
new EnergyAnchorData(AnchorPoint.RIGHT_HAND), new EnergyAnchorData(AnchorPoint.LEFT_HAND)
|
||||
};
|
||||
|
||||
// Transient state for orb entity (used during windup charging)
|
||||
private transient EntityAbilityOrb orbEntity = null;
|
||||
private transient EntityAbilityOrb orbEntity2 = null;
|
||||
|
||||
public AbilityDualOrb() {
|
||||
this.typeId = "ability.cnpc.dual_orb";
|
||||
this.name = "Dual Orb";
|
||||
this.targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
this.maxRange = 25.0f;
|
||||
this.minRange = 5.0f;
|
||||
this.cooldownTicks = 0;
|
||||
this.windUpTicks = 30;
|
||||
this.lockMovement = LockMovementType.WINDUP;
|
||||
this.telegraphType = TelegraphType.CIRCLE;
|
||||
this.showTelegraph = true;
|
||||
// Default built-in animation
|
||||
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 SubGuiAbilityDualOrb(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 (orbEntity != null && !orbEntity.isDead) {
|
||||
orbEntity.startMoving(target);
|
||||
}
|
||||
|
||||
if (dualFire) {
|
||||
if (orbEntity2 != null && !orbEntity2.isDead && dualFireDelay <= 0) {
|
||||
orbEntity2.startMoving(target);
|
||||
}
|
||||
} else {
|
||||
orbEntity2.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 orb in charging mode on first tick of windup
|
||||
if (tick == 1) {
|
||||
// Create orb in charging mode - follows caster based on anchor point during windup
|
||||
Vec3 spawnPos1 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[0]);
|
||||
orbEntity = new EntityAbilityOrb(
|
||||
world, caster, target,
|
||||
spawnPos1.xCoord, spawnPos1.yCoord, spawnPos1.zCoord, orbSize,
|
||||
colorData[0], combatData, homingData, lightningData[0], lifespanData);
|
||||
|
||||
Vec3 spawnPos2 = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[1]);
|
||||
orbEntity2 = new EntityAbilityOrb(
|
||||
world, caster, target,
|
||||
spawnPos2.xCoord, spawnPos2.yCoord, spawnPos2.zCoord, orbSize,
|
||||
colorData[1], combatData, homingData, lightningData[1], lifespanData);
|
||||
|
||||
orbEntity.setSiblingUUID(orbEntity2.getPersistentID());
|
||||
orbEntity2.setSiblingUUID(orbEntity.getPersistentID());
|
||||
|
||||
orbEntity.setupCharging(anchorData[0], windUpTicks);
|
||||
orbEntity2.setupCharging(anchorData[1], windUpTicks);
|
||||
|
||||
orbEntity.setEffects(this.effects);
|
||||
|
||||
if (dualFire) {
|
||||
orbEntity2.setEffects(this.effects);
|
||||
}
|
||||
|
||||
world.spawnEntityInWorld(orbEntity);
|
||||
world.spawnEntityInWorld(orbEntity2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) {
|
||||
// Signal completion when entity dies
|
||||
if (dualFire) {
|
||||
if ((orbEntity == null || orbEntity.isDead) && (orbEntity2 == null || orbEntity2.isDead)) {
|
||||
orbEntity = null;
|
||||
orbEntity2 = null;
|
||||
signalCompletion();
|
||||
}
|
||||
|
||||
if (tick == dualFireDelay && orbEntity2 != null && !orbEntity2.isDead) {
|
||||
orbEntity2.startMoving(target);
|
||||
}
|
||||
} else {
|
||||
if (orbEntity == null || orbEntity.isDead) {
|
||||
orbEntity = null;
|
||||
signalCompletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(EntityLivingBase caster, EntityLivingBase target) {
|
||||
// Nothing to clean up - entity manages itself
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
// Despawn orb entity if still alive
|
||||
if (orbEntity != null && !orbEntity.isDead) {
|
||||
orbEntity.setDead();
|
||||
}
|
||||
|
||||
if (orbEntity2 != null && !orbEntity2.isDead) {
|
||||
orbEntity2.setDead();
|
||||
}
|
||||
|
||||
orbEntity = null;
|
||||
orbEntity2 = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TelegraphInstance createTelegraph(EntityLivingBase caster, EntityLivingBase target) {
|
||||
if (!showTelegraph || telegraphType == TelegraphType.NONE || target == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create small circle telegraph at target position
|
||||
Telegraph telegraph = Telegraph.circle(orbSize * 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 orbSize * 1.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("orbSize", orbSize);
|
||||
nbt.setBoolean("dualFire", dualFire);
|
||||
nbt.setInteger("dualFireDelay", dualFireDelay);
|
||||
combatData.writeNBT(nbt);
|
||||
homingData.writeNBT(nbt);
|
||||
lifespanData.writeNBT(nbt);
|
||||
// Backward compat: old key was "orbSpeed"
|
||||
nbt.setFloat("orbSpeed", homingData.speed);
|
||||
|
||||
NBTTagCompound orb1 = new NBTTagCompound();
|
||||
NBTTagCompound orb2 = new NBTTagCompound();
|
||||
|
||||
anchorData[0].writeNBT(orb1);
|
||||
anchorData[1].writeNBT(orb2);
|
||||
colorData[0].writeNBT(orb1);
|
||||
colorData[1].writeNBT(orb2);
|
||||
lightningData[0].writeNBT(orb1);
|
||||
lightningData[1].writeNBT(orb2);
|
||||
|
||||
nbt.setTag("Orb_1", orb1);
|
||||
nbt.setTag("Orb_2", orb2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
NBTTagCompound orb1 = nbt.hasKey("Orb_1") ? nbt.getCompoundTag("Orb_1") : new NBTTagCompound();
|
||||
NBTTagCompound orb2 = nbt.hasKey("Orb_2") ? nbt.getCompoundTag("Orb_2") : new NBTTagCompound();
|
||||
|
||||
this.orbSize = nbt.hasKey("orbSize") ? nbt.getFloat("orbSize") : 1.0f;
|
||||
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);
|
||||
// Backward compat: old key was "orbSpeed"
|
||||
if (nbt.hasKey("orbSpeed")) {
|
||||
homingData.speed = nbt.getFloat("orbSpeed");
|
||||
}
|
||||
|
||||
anchorData[0].readNBT(orb1);
|
||||
anchorData[1].readNBT(orb2);
|
||||
colorData[0].readNBT(orb1);
|
||||
colorData[1].readNBT(orb2);
|
||||
lightningData[0].readNBT(orb1);
|
||||
lightningData[1].readNBT(orb2);
|
||||
}
|
||||
|
||||
// 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 float getOrbSpeed() {
|
||||
return homingData.speed;
|
||||
}
|
||||
|
||||
public void setOrbSpeed(float orbSpeed) {
|
||||
homingData.speed = orbSpeed;
|
||||
}
|
||||
|
||||
public float getOrbSize() {
|
||||
return orbSize;
|
||||
}
|
||||
|
||||
public void setOrbSize(float orbSize) {
|
||||
this.orbSize = orbSize;
|
||||
}
|
||||
|
||||
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 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 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;
|
||||
|
||||
EntityAbilityOrb orb = new EntityAbilityOrb(npc.worldObj);
|
||||
orb.setupPreview(npc, orbSize, colorData[0], lightningData[0], anchorData[0], windUpTicks);
|
||||
return orb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviewActiveDuration() {
|
||||
return lifespanData.maxLifetime > 0 ? Math.min(lifespanData.maxLifetime, 100) : 100;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import noppes.npcs.LogWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Beam projectile - head with trailing path that curves with homing.
|
||||
@@ -32,6 +33,7 @@ public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
private boolean homing = true;
|
||||
private float homingStrength = 0.35f; // Increased from 0.15 for better tracking
|
||||
private float homingRange = 20.0f;
|
||||
private UUID siblingUUID = null;
|
||||
|
||||
// Beam shape properties
|
||||
private float beamWidth = 0.3f;
|
||||
@@ -646,6 +648,12 @@ public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldIgnoreEntity(Entity entity) {
|
||||
if (entity.getPersistentID().equals(siblingUUID)) return true;
|
||||
return super.shouldIgnoreEntity(entity);
|
||||
}
|
||||
|
||||
// ==================== GETTERS FOR RENDERER ====================
|
||||
|
||||
public float getBeamWidth() {
|
||||
@@ -744,6 +752,18 @@ public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
return trailFadeTime;
|
||||
}
|
||||
|
||||
public UUID getSiblingUUID() {
|
||||
return siblingUUID;
|
||||
}
|
||||
|
||||
public void setSiblingUUID(UUID siblingUUID) {
|
||||
if (siblingUUID == null)
|
||||
return;
|
||||
|
||||
if (this.siblingUUID == null)
|
||||
this.siblingUUID = siblingUUID;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
@@ -787,6 +807,8 @@ public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
this.siblingUUID = nbt.hasKey("SiblingUUID") ? UUID.fromString(nbt.getString("SiblingUUID")) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -821,5 +843,6 @@ public class EntityAbilityBeam extends EntityAbilityProjectile {
|
||||
trailList.appendTag(pointNbt);
|
||||
}
|
||||
nbt.setTag("Trail", trailList);
|
||||
nbt.setString("SiblingUUID", siblingUUID.toString());
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Orb projectile - spherical homing energy ball.
|
||||
@@ -37,6 +38,8 @@ public class EntityAbilityOrb extends EntityAbilityProjectile {
|
||||
// Data watcher index for charging state (synced to clients)
|
||||
private static final int DW_CHARGING = 20;
|
||||
|
||||
private UUID siblingUUID = null;
|
||||
|
||||
public EntityAbilityOrb(World world) {
|
||||
super(world);
|
||||
}
|
||||
@@ -441,6 +444,18 @@ public class EntityAbilityOrb extends EntityAbilityProjectile {
|
||||
return size;
|
||||
}
|
||||
|
||||
public UUID getSiblingUUID() {
|
||||
return siblingUUID;
|
||||
}
|
||||
|
||||
public void setSiblingUUID(UUID siblingUUID) {
|
||||
if (siblingUUID == null)
|
||||
return;
|
||||
|
||||
if (this.siblingUUID == null)
|
||||
this.siblingUUID = siblingUUID;
|
||||
}
|
||||
|
||||
// ==================== NBT ====================
|
||||
|
||||
@Override
|
||||
@@ -458,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
|
||||
@@ -472,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,36 @@
|
||||
package kamkeel.npcs.util;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Register<T> {
|
||||
private final String registryKey;
|
||||
private final String namespace;
|
||||
protected final Map<String, Supplier<T>> entries = new LinkedHashMap<>();
|
||||
|
||||
public Register(String registryKey, String namespace) {
|
||||
this.registryKey = registryKey;
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public T register(String factoryName, Supplier<T> factory) {
|
||||
entries.put(registryKey + "." + namespace + ":" + factoryName, factory);
|
||||
return factory.get();
|
||||
}
|
||||
|
||||
public static class Abilities extends Register<Ability> {
|
||||
public Abilities(String namespace) {
|
||||
super("ability", namespace);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
for (Map.Entry<String, Supplier<Ability>> entry : entries.entrySet()) {
|
||||
AbilityController.Instance.registerType(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
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.AbilityDualBeam;
|
||||
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 SubGuiAbilityDualBeam extends SubGuiAbilityConfig {
|
||||
private final AbilityDualBeam beam;
|
||||
private int editingVisualColorId = 0;
|
||||
private int editingBeam = 0;
|
||||
|
||||
public SubGuiAbilityDualBeam(AbilityDualBeam ability, IAbilityConfigCallback callback) {
|
||||
super(ability, callback);
|
||||
this.beam = 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, beam.getDamage()));
|
||||
|
||||
addLabel(new GuiNpcLabel(101, "stats.speed", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(101, col2FieldX, y, 50, beam.getSpeed()));
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 2: Beam Width + Head Size
|
||||
addLabel(new GuiNpcLabel(102, "ability.beamWidth", labelX, y + 5));
|
||||
addTextField(createFloatField(102, fieldX, y, 50, beam.getBeamWidth()));
|
||||
|
||||
addLabel(new GuiNpcLabel(103, "ability.headSize", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(103, col2FieldX, y, 50, beam.getHeadSize()));
|
||||
|
||||
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"}, beam.isHoming() ? 1 : 0);
|
||||
homingBtn.setHoverText("ability.hover.homing");
|
||||
addButton(homingBtn);
|
||||
|
||||
if (beam.isHoming()) {
|
||||
addLabel(new GuiNpcLabel(105, "ability.homingStr", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(105, col2FieldX, y, 50, beam.getHomingStrength()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 4: Max Distance (+ Homing Range only if homing)
|
||||
if (beam.isHoming()) {
|
||||
addLabel(new GuiNpcLabel(106, "ability.homingRange", labelX, y + 5));
|
||||
addTextField(createFloatField(106, fieldX, y, 50, beam.getHomingRange()));
|
||||
}
|
||||
|
||||
addLabel(new GuiNpcLabel(107, "ability.maxDist", beam.isHoming() ? col2LabelX : labelX, y + 5));
|
||||
addTextField(createFloatField(107, beam.isHoming() ? col2FieldX : fieldX, y, 50, beam.getMaxDistance()));
|
||||
|
||||
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"}, beam.isExplosive() ? 1 : 0);
|
||||
explosiveBtn.setHoverText("ability.hover.explosive");
|
||||
addButton(explosiveBtn);
|
||||
|
||||
if (beam.isExplosive()) {
|
||||
addLabel(new GuiNpcLabel(109, "ability.explosionRad", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(109, col2FieldX, y, 50, beam.getExplosionRadius()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 6: Knockback + Max Lifetime
|
||||
addLabel(new GuiNpcLabel(110, "ability.knockback", labelX, y + 5));
|
||||
addTextField(createFloatField(110, fieldX, y, 50, beam.getKnockback()));
|
||||
|
||||
addLabel(new GuiNpcLabel(111, "ability.lifetime", col2LabelX, y + 5));
|
||||
addTextField(createIntField(111, col2FieldX, y, 50, beam.getMaxLifetime()));
|
||||
|
||||
y += 24;
|
||||
|
||||
addLabel(new GuiNpcLabel(112, "ability.dualFire", labelX, y + 5));
|
||||
addButton(new GuiNpcButtonYesNo(112, fieldX, y, beam.isDualFire()));
|
||||
|
||||
if (beam.isDualFire()) {
|
||||
addLabel(new GuiNpcLabel(113, "ability.dualFireDelay", col2LabelX, y + 5));
|
||||
addTextField(createIntField(113, col2FieldX, y, 50, beam.getDualFireDelay()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
addButton(new GuiNpcButton(150, labelX, 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(), beam.getAnchorPointEnum(editingBeam).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", beam.getInnerColor(editingBeam) & 0xFFFFFF);
|
||||
GuiNpcButton innerColorBtn = new GuiNpcButton(200, fieldX, y, 55, 20, innerHex);
|
||||
innerColorBtn.setTextColor(beam.getInnerColor(editingBeam) & 0xFFFFFF);
|
||||
addButton(innerColorBtn);
|
||||
|
||||
addLabel(new GuiNpcLabel(201, "ability.outerColor", col2LabelX, y + 5));
|
||||
String outerHex = String.format("%06X", beam.getOuterColor(editingBeam) & 0xFFFFFF);
|
||||
GuiNpcButton outerColorBtn = new GuiNpcButton(201, col2FieldX, y, 55, 20, outerHex);
|
||||
outerColorBtn.setTextColor(beam.getOuterColor(editingBeam) & 0xFFFFFF);
|
||||
outerColorBtn.setEnabled(beam.isOuterColorEnabled(editingBeam));
|
||||
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"}, beam.isOuterColorEnabled(editingBeam) ? 1 : 0));
|
||||
|
||||
addLabel(new GuiNpcLabel(203, "ability.outerWidth", col2LabelX, y + 5));
|
||||
GuiNpcTextField widthField = createFloatField(203, col2FieldX, y, 55, beam.getOuterColorWidth(editingBeam));
|
||||
widthField.setEnabled(beam.isOuterColorEnabled(editingBeam));
|
||||
addTextField(widthField);
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 3: Rotation Speed
|
||||
addLabel(new GuiNpcLabel(204, "ability.outerAlpha", labelX, y + 5));
|
||||
GuiNpcTextField alphaField = createFloatField(204, fieldX, y, 55, beam.getOuterColorAlpha(editingBeam));
|
||||
alphaField.setEnabled(beam.isOuterColorEnabled(editingBeam));
|
||||
alphaField.setMinMaxDefaultFloat(0, 1, 0.5f);
|
||||
addTextField(alphaField);
|
||||
|
||||
addLabel(new GuiNpcLabel(205, "ability.rotationSpeed", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(205, col2FieldX, y, 50, beam.getRotationSpeed(editingBeam)));
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 4: Lightning Effect Enabled (only affects head)
|
||||
addLabel(new GuiNpcLabel(206, "ability.lightning", labelX, y + 5));
|
||||
GuiNpcButton lightningBtn = new GuiNpcButton(206, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, beam.hasLightningEffect(editingBeam) ? 1 : 0);
|
||||
lightningBtn.setHoverText("ability.hover.lightning");
|
||||
addButton(lightningBtn);
|
||||
|
||||
// Only show Lightning settings if Lightning is enabled
|
||||
if (beam.hasLightningEffect(editingBeam)) {
|
||||
y += 24;
|
||||
|
||||
// Row 5: Density + Radius
|
||||
addLabel(new GuiNpcLabel(207, "ability.lightningDensity", labelX, y + 5));
|
||||
GuiNpcTextField densityField = new GuiNpcTextField(207, this, fontRendererObj, fieldX, y, 55, 18, "" + beam.getLightningDensity(editingBeam));
|
||||
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, "" + beam.getLightningRadius(editingBeam));
|
||||
radiusField.setMinMaxDefaultFloat(0.1f, 10.0f, 0.5f);
|
||||
addTextField(radiusField);
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
addButton(new GuiNpcButton(400, col2FieldX, y, 55, 20, new String[]{"Beam 1", "Beam 2"}, editingBeam));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTypeButton(int id, GuiNpcButton button) {
|
||||
int value = button.getValue();
|
||||
switch (id) {
|
||||
case 104:
|
||||
beam.setHoming(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 108:
|
||||
beam.setExplosive(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 112:
|
||||
beam.setDualFire(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 150:
|
||||
setSubGui(new SubGuiAbilityEffects(beam.getEffects()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleVisualButton(int id, GuiNpcButton button) {
|
||||
int value = button.getValue();
|
||||
switch (id) {
|
||||
case 200:
|
||||
editingVisualColorId = 200;
|
||||
setSubGui(new SubGuiColorSelector(beam.getInnerColor(editingBeam)));
|
||||
break;
|
||||
case 201:
|
||||
editingVisualColorId = 201;
|
||||
setSubGui(new SubGuiColorSelector(beam.getOuterColor(editingBeam)));
|
||||
break;
|
||||
case 202:
|
||||
beam.setOuterColorEnabled(editingBeam, value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 206:
|
||||
beam.setLightningEffect(editingBeam, value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 210:
|
||||
beam.setAnchorPointEnum(editingBeam, AnchorPoint.fromOrdinal(value));
|
||||
break;
|
||||
case 400:
|
||||
editingBeam = (editingBeam + 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) {
|
||||
beam.setInnerColor(editingBeam, rgb);
|
||||
} else if (editingVisualColorId == 201) {
|
||||
beam.setOuterColor(editingBeam, rgb);
|
||||
}
|
||||
editingVisualColorId = 0;
|
||||
initGui();
|
||||
} else if (subgui instanceof SubGuiAbilityEffects) {
|
||||
SubGuiAbilityEffects effectsGui = (SubGuiAbilityEffects) subgui;
|
||||
List<AbilityEffect> result = effectsGui.getResult();
|
||||
if (result != null) {
|
||||
beam.setEffects(result);
|
||||
}
|
||||
} else {
|
||||
super.subGuiClosed(subgui);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTypeTextField(int id, GuiNpcTextField field) {
|
||||
switch (id) {
|
||||
case 100:
|
||||
beam.setDamage(parseFloat(field, beam.getDamage()));
|
||||
break;
|
||||
case 101:
|
||||
beam.setSpeed(parseFloat(field, beam.getSpeed()));
|
||||
break;
|
||||
case 102:
|
||||
beam.setBeamWidth(parseFloat(field, beam.getBeamWidth()));
|
||||
break;
|
||||
case 103:
|
||||
beam.setHeadSize(parseFloat(field, beam.getHeadSize()));
|
||||
break;
|
||||
case 105:
|
||||
beam.setHomingStrength(parseFloat(field, beam.getHomingStrength()));
|
||||
break;
|
||||
case 106:
|
||||
beam.setHomingRange(parseFloat(field, beam.getHomingRange()));
|
||||
break;
|
||||
case 107:
|
||||
beam.setMaxDistance(parseFloat(field, beam.getMaxDistance()));
|
||||
break;
|
||||
case 109:
|
||||
beam.setExplosionRadius(parseFloat(field, beam.getExplosionRadius()));
|
||||
break;
|
||||
case 110:
|
||||
beam.setKnockback(parseFloat(field, beam.getKnockback()));
|
||||
break;
|
||||
case 111:
|
||||
beam.setMaxLifetime(field.getInteger());
|
||||
break;
|
||||
case 113:
|
||||
beam.setDualFireDelay(field.getInteger());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleVisualTextField(int id, GuiNpcTextField field) {
|
||||
switch (id) {
|
||||
case 203:
|
||||
beam.setOuterColorWidth(editingBeam, parseFloat(field, beam.getOuterColorWidth(editingBeam)));
|
||||
break;
|
||||
case 204:
|
||||
beam.setOuterColorAlpha(editingBeam, parseFloat(field, beam.getOuterColorAlpha(editingBeam)));
|
||||
break;
|
||||
case 205:
|
||||
beam.setRotationSpeed(editingBeam, parseFloat(field, beam.getRotationSpeed(editingBeam)));
|
||||
break;
|
||||
case 207:
|
||||
beam.setLightningDensity(editingBeam, parseFloat(field, beam.getLightningDensity(editingBeam)));
|
||||
break;
|
||||
case 208:
|
||||
beam.setLightningRadius(editingBeam, parseFloat(field, beam.getLightningRadius(editingBeam)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
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 noppes.npcs.client.gui.SubGuiColorSelector;
|
||||
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
|
||||
import noppes.npcs.client.gui.util.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SubGuiAbilityDualOrb extends SubGuiAbilityConfig {
|
||||
private final AbilityDualOrb orb;
|
||||
private int editingVisualColorId = 0;
|
||||
private int editingOrb = 0;
|
||||
|
||||
public SubGuiAbilityDualOrb(AbilityDualOrb ability, IAbilityConfigCallback callback) {
|
||||
super(ability, callback);
|
||||
this.orb = 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, orb.getDamage()));
|
||||
|
||||
addLabel(new GuiNpcLabel(101, "stats.speed", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(101, col2FieldX, y, 50, orb.getOrbSpeed()));
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 2: Orb Size + Max Distance
|
||||
addLabel(new GuiNpcLabel(102, "stats.size", labelX, y + 5));
|
||||
addTextField(createFloatField(102, fieldX, y, 50, orb.getOrbSize()));
|
||||
|
||||
addLabel(new GuiNpcLabel(103, "ability.maxDist", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(103, col2FieldX, y, 50, orb.getMaxDistance()));
|
||||
|
||||
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"}, orb.isHoming() ? 1 : 0);
|
||||
homingBtn.setHoverText("ability.hover.homing");
|
||||
addButton(homingBtn);
|
||||
|
||||
if (orb.isHoming()) {
|
||||
addLabel(new GuiNpcLabel(105, "ability.homingStr", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(105, col2FieldX, y, 50, orb.getHomingStrength()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 4: Explosive + Explosion Radius (only show radius if explosive)
|
||||
addLabel(new GuiNpcLabel(106, "ability.explosive", labelX, y + 5));
|
||||
GuiNpcButton explosiveBtn = new GuiNpcButton(106, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, orb.isExplosive() ? 1 : 0);
|
||||
explosiveBtn.setHoverText("ability.hover.explosive");
|
||||
addButton(explosiveBtn);
|
||||
|
||||
if (orb.isExplosive()) {
|
||||
addLabel(new GuiNpcLabel(107, "ability.explosionRad", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(107, col2FieldX, y, 50, orb.getExplosionRadius()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 5: Knockback + Max Lifetime
|
||||
addLabel(new GuiNpcLabel(108, "ability.knockback", labelX, y + 5));
|
||||
addTextField(createFloatField(108, fieldX, y, 50, orb.getKnockback()));
|
||||
|
||||
addLabel(new GuiNpcLabel(109, "ability.lifetime", col2LabelX, y + 5));
|
||||
addTextField(createIntField(109, col2FieldX, y, 50, orb.getMaxLifetime()));
|
||||
|
||||
y += 24;
|
||||
|
||||
addLabel(new GuiNpcLabel(110, "ability.dualFire", labelX, y + 5));
|
||||
addButton(new GuiNpcButtonYesNo(110, fieldX, y, orb.isDualFire()));
|
||||
|
||||
if (orb.isDualFire()) {
|
||||
addLabel(new GuiNpcLabel(111, "ability.dualFireDelay", col2LabelX, y + 5));
|
||||
addTextField(createIntField(111, col2FieldX, y, 50, orb.getDualFireDelay()));
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 7: Effects button
|
||||
addButton(new GuiNpcButton(150, labelX, 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(), orb.getAnchorPointEnum(editingOrb).ordinal());
|
||||
anchorBtn.setHoverText("ability.hover.anchorPoint");
|
||||
addButton(anchorBtn);
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 2: Inner Color + Rotation Speed
|
||||
addLabel(new GuiNpcLabel(200, "ability.innerColor", labelX, y + 5));
|
||||
String innerHex = String.format("%06X", orb.getInnerColor(editingOrb) & 0xFFFFFF);
|
||||
GuiNpcButton innerColorBtn = new GuiNpcButton(200, fieldX, y, 55, 20, innerHex);
|
||||
innerColorBtn.setTextColor(orb.getInnerColor(editingOrb) & 0xFFFFFF);
|
||||
addButton(innerColorBtn);
|
||||
|
||||
addLabel(new GuiNpcLabel(205, "ability.rotationSpeed", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(205, col2FieldX, y, 55, orb.getRotationSpeed(editingOrb)));
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 3: Outer Glow Enabled
|
||||
addLabel(new GuiNpcLabel(202, "ability.outerEnabled", labelX, y + 5));
|
||||
addButton(new GuiNpcButton(202, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, orb.isOuterColorEnabled(editingOrb) ? 1 : 0));
|
||||
|
||||
// Only show Outer Color and Width if Outer Glow is enabled
|
||||
if (orb.isOuterColorEnabled()) {
|
||||
addLabel(new GuiNpcLabel(204, "ability.outerAlpha", col2LabelX, y + 5));
|
||||
GuiNpcTextField alphaField = createFloatField(204, col2FieldX, y, 55, orb.getOuterColorAlpha(editingOrb));
|
||||
alphaField.setEnabled(orb.isOuterColorEnabled(editingOrb));
|
||||
alphaField.setMinMaxDefaultFloat(0, 1, 0.5f);
|
||||
addTextField(alphaField);
|
||||
|
||||
y += 24;
|
||||
|
||||
// Row 4: Outer Color + Outer Width
|
||||
addLabel(new GuiNpcLabel(201, "ability.outerColor", labelX, y + 5));
|
||||
String outerHex = String.format("%06X", orb.getOuterColor(editingOrb) & 0xFFFFFF);
|
||||
GuiNpcButton outerColorBtn = new GuiNpcButton(201, fieldX, y, 55, 20, outerHex);
|
||||
outerColorBtn.setTextColor(orb.getOuterColor(editingOrb) & 0xFFFFFF);
|
||||
addButton(outerColorBtn);
|
||||
|
||||
addLabel(new GuiNpcLabel(203, "ability.outerWidth", col2LabelX, y + 5));
|
||||
addTextField(createFloatField(203, col2FieldX, y, 55, orb.getOuterColorWidth(editingOrb)));
|
||||
}
|
||||
|
||||
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"}, orb.hasLightningEffect(editingOrb) ? 1 : 0);
|
||||
lightningBtn.setHoverText("ability.hover.lightning");
|
||||
addButton(lightningBtn);
|
||||
|
||||
// Only show Lightning settings if Lightning is enabled
|
||||
if (orb.hasLightningEffect(editingOrb)) {
|
||||
y += 24;
|
||||
|
||||
// Row 61: Density + Radius
|
||||
addLabel(new GuiNpcLabel(207, "ability.lightningDensity", labelX, y + 5));
|
||||
GuiNpcTextField densityField = new GuiNpcTextField(207, this, fontRendererObj, fieldX, y, 55, 18, "" + orb.getLightningDensity(editingOrb));
|
||||
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, "" + orb.getLightningRadius(editingOrb));
|
||||
radiusField.setMinMaxDefaultFloat(0.1f, 10.0f, 0.5f);
|
||||
addTextField(radiusField);
|
||||
}
|
||||
|
||||
y += 24;
|
||||
|
||||
addButton(new GuiNpcButton(400, col2FieldX, y, 55, 20, new String[]{"Orb 1", "Orb 2"}, editingOrb));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTypeButton(int id, GuiNpcButton button) {
|
||||
int value = button.getValue();
|
||||
switch (id) {
|
||||
case 104:
|
||||
orb.setHoming(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 106:
|
||||
orb.setExplosive(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 110:
|
||||
orb.setDualFire(value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 150:
|
||||
setSubGui(new SubGuiAbilityEffects(orb.getEffects()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleVisualButton(int id, GuiNpcButton button) {
|
||||
int value = button.getValue();
|
||||
switch (id) {
|
||||
case 200:
|
||||
editingVisualColorId = 200;
|
||||
setSubGui(new SubGuiColorSelector(orb.getInnerColor(editingOrb)));
|
||||
break;
|
||||
case 201:
|
||||
editingVisualColorId = 201;
|
||||
setSubGui(new SubGuiColorSelector(orb.getOuterColor(editingOrb)));
|
||||
break;
|
||||
case 202:
|
||||
orb.setOuterColorEnabled(editingOrb, value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 206:
|
||||
orb.setLightningEffect(editingOrb, value == 1);
|
||||
initGui();
|
||||
break;
|
||||
case 210:
|
||||
orb.setAnchorPointEnum(editingOrb, AnchorPoint.fromOrdinal(value));
|
||||
break;
|
||||
case 400:
|
||||
editingOrb = (editingOrb + 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) {
|
||||
orb.setInnerColor(editingOrb, rgb);
|
||||
} else if (editingVisualColorId == 201) {
|
||||
orb.setOuterColor(editingOrb, rgb);
|
||||
}
|
||||
editingVisualColorId = 0;
|
||||
initGui();
|
||||
} else if (subgui instanceof SubGuiAbilityEffects) {
|
||||
SubGuiAbilityEffects effectsGui = (SubGuiAbilityEffects) subgui;
|
||||
List<AbilityEffect> result = effectsGui.getResult();
|
||||
if (result != null) {
|
||||
orb.setEffects(result);
|
||||
}
|
||||
} else {
|
||||
super.subGuiClosed(subgui);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTypeTextField(int id, GuiNpcTextField field) {
|
||||
switch (id) {
|
||||
case 100:
|
||||
orb.setDamage(parseFloat(field, orb.getDamage()));
|
||||
break;
|
||||
case 101:
|
||||
orb.setOrbSpeed(parseFloat(field, orb.getOrbSpeed()));
|
||||
break;
|
||||
case 102:
|
||||
orb.setOrbSize(parseFloat(field, orb.getOrbSize()));
|
||||
break;
|
||||
case 103:
|
||||
orb.setMaxDistance(parseFloat(field, orb.getMaxDistance()));
|
||||
break;
|
||||
case 105:
|
||||
orb.setHomingStrength(parseFloat(field, orb.getHomingStrength()));
|
||||
break;
|
||||
case 107:
|
||||
orb.setExplosionRadius(parseFloat(field, orb.getExplosionRadius()));
|
||||
break;
|
||||
case 108:
|
||||
orb.setKnockback(parseFloat(field, orb.getKnockback()));
|
||||
break;
|
||||
case 109:
|
||||
orb.setMaxLifetime(field.getInteger());
|
||||
break;
|
||||
case 111:
|
||||
orb.setDualFireDelay(field.getInteger());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleVisualTextField(int id, GuiNpcTextField field) {
|
||||
switch (id) {
|
||||
case 203:
|
||||
orb.setOuterColorWidth(editingOrb, parseFloat(field, orb.getOuterColorWidth(editingOrb)));
|
||||
break;
|
||||
case 204:
|
||||
orb.setOuterColorAlpha(editingOrb, parseFloat(field, orb.getOuterColorAlpha(editingOrb)));
|
||||
break;
|
||||
case 205:
|
||||
orb.setRotationSpeed(editingOrb, parseFloat(field, orb.getRotationSpeed(editingOrb)));
|
||||
break;
|
||||
case 207:
|
||||
orb.setLightningDensity(editingOrb, parseFloat(field, orb.getLightningDensity(editingOrb)));
|
||||
break;
|
||||
case 208:
|
||||
orb.setLightningRadius(editingOrb, parseFloat(field, orb.getLightningRadius(editingOrb)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.item.ItemStack;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
import noppes.npcs.api.IPos;
|
||||
import noppes.npcs.api.ITimers;
|
||||
import noppes.npcs.api.ability.IDataAbilities;
|
||||
import noppes.npcs.api.entity.ICustomNpc;
|
||||
import noppes.npcs.api.entity.IEntityLivingBase;
|
||||
import noppes.npcs.api.entity.IPlayer;
|
||||
@@ -51,6 +52,7 @@ import noppes.npcs.scripted.roles.ScriptRoleInterface;
|
||||
import noppes.npcs.scripted.roles.ScriptRoleMailman;
|
||||
import noppes.npcs.scripted.roles.ScriptRoleTrader;
|
||||
import noppes.npcs.scripted.roles.ScriptRoleTransporter;
|
||||
import noppes.npcs.scripted.wrapper.ScriptDataAbilities;
|
||||
import noppes.npcs.util.ValueUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -1458,7 +1460,7 @@ public class ScriptNpc<T extends EntityNPCInterface> extends ScriptLiving<T> imp
|
||||
return npc.stats.magicData;
|
||||
}
|
||||
|
||||
public noppes.npcs.api.ability.IDataAbilities getAbilityData() {
|
||||
return new noppes.npcs.scripted.wrapper.ScriptDataAbilities(npc);
|
||||
public IDataAbilities getAbilityData() {
|
||||
return new ScriptDataAbilities(npc);
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,15 @@ package noppes.npcs.scripted.wrapper;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.AbilitySlot;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import noppes.npcs.DataAbilities;
|
||||
import noppes.npcs.api.ability.IAbility;
|
||||
import noppes.npcs.api.ability.IDataAbilities;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Script wrapper for DataAbilities providing API access to NPC abilities.
|
||||
*/
|
||||
@@ -65,7 +68,7 @@ public class ScriptDataAbilities implements IDataAbilities {
|
||||
|
||||
@Override
|
||||
public boolean isAbilityReference(String abilityId) {
|
||||
List<kamkeel.npcs.controllers.data.ability.AbilitySlot> slots = data.getAbilitySlots();
|
||||
List<AbilitySlot> slots = data.getAbilitySlots();
|
||||
for (int i = 0; i < slots.size(); i++) {
|
||||
kamkeel.npcs.controllers.data.ability.AbilitySlot slot = slots.get(i);
|
||||
if (slot.isReference()) {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class ScriptPlayerAbilityData implements IPlayerAbilityData {
|
||||
|
||||
@Override
|
||||
public String[] getUnlockedAbilities() {
|
||||
return data.getUnlockedAbilities().toArray(new String[0]);
|
||||
return data.getUnlockedAbilities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,6 +79,11 @@ public class ScriptPlayerAbilityData implements IPlayerAbilityData {
|
||||
data.interruptCurrentAbility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnCooldown() {
|
||||
return data.isOnCooldown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnCooldown(String key) {
|
||||
EntityPlayer player = playerData.player;
|
||||
@@ -86,6 +91,11 @@ public class ScriptPlayerAbilityData implements IPlayerAbilityData {
|
||||
return data.isOnCooldown(key, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCooldown() {
|
||||
data.resetCooldown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCooldown(String key) {
|
||||
data.resetCooldown(key);
|
||||
|
||||
Reference in new issue
Block a user