Revise ability logic and configs

This commit is contained in:
Kam committed 2026-01-11 16:04:49 -05:00
1 parent 3dc56aba06
commit 828e99d427
26 files changed
+553 -473

No files matched your search

@@ -117,9 +117,16 @@ public abstract class Ability implements IAbility {
* @param hitEntity The entity being hit
* @param damage The damage amount
* @param knockback The horizontal knockback
* @param knockbackUp The vertical knockback
* @return true if damage was applied (not cancelled), false if cancelled
*/
protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hitEntity,
float damage, float knockback) {
return applyAbilityDamage(npc, hitEntity, damage, knockback, 0.0f);
}
/**
* Backward-compatible signature (vertical knockback is ignored).
*/
protected boolean applyAbilityDamage(EntityNPCInterface npc, EntityLivingBase hitEntity,
float damage, float knockback, float knockbackUp) {
DataAbilities dataAbilities = npc.abilities;
@@ -133,7 +140,6 @@ public abstract class Ability implements IAbility {
// Apply damage with potentially modified values
float finalDamage = event.getDamage();
float finalKnockback = event.getKnockback();
float finalKnockbackUp = event.getKnockbackUp();
// Apply damage
if (finalDamage > 0) {
@@ -141,18 +147,10 @@ public abstract class Ability implements IAbility {
}
// Apply knockback if any
if (finalKnockback > 0 || finalKnockbackUp > 0) {
if (finalKnockback > 0) {
double dx = hitEntity.posX - npc.posX;
double dz = hitEntity.posZ - npc.posZ;
double len = Math.sqrt(dx * dx + dz * dz);
if (len > 0 && finalKnockback > 0) {
dx /= len;
dz /= len;
hitEntity.motionX += dx * finalKnockback;
hitEntity.motionZ += dz * finalKnockback;
}
hitEntity.motionY += finalKnockbackUp;
hitEntity.velocityChanged = true;
applyNpcKnockback(hitEntity, dx, dz, finalKnockback);
}
return true;
@@ -166,17 +164,16 @@ public abstract class Ability implements IAbility {
* @param hitEntity The entity being hit
* @param damage The damage amount
* @param knockback The horizontal knockback
* @param knockbackUp The vertical knockback
* @param knockbackDirX The X component of knockback direction (normalized)
* @param knockbackDirZ The Z component of knockback direction (normalized)
* @return true if damage was applied (not cancelled), false if cancelled
*/
protected boolean applyAbilityDamageWithDirection(EntityNPCInterface npc, EntityLivingBase hitEntity,
float damage, float knockback, float knockbackUp,
float damage, float knockback,
double knockbackDirX, double knockbackDirZ) {
DataAbilities dataAbilities = npc.abilities;
AbilityEvent.HitEvent event = dataAbilities.fireHitEvent(
this, currentTarget, hitEntity, damage, knockback, knockbackUp);
this, currentTarget, hitEntity, damage, knockback, 0.0f);
if (event == null) {
return false; // Cancelled
@@ -185,7 +182,6 @@ public abstract class Ability implements IAbility {
// Apply damage with potentially modified values
float finalDamage = event.getDamage();
float finalKnockback = event.getKnockback();
float finalKnockbackUp = event.getKnockbackUp();
// Apply damage
if (finalDamage > 0) {
@@ -193,15 +189,23 @@ public abstract class Ability implements IAbility {
}
// Apply knockback in specified direction
if (finalKnockback > 0 || finalKnockbackUp > 0) {
hitEntity.motionX = knockbackDirX * finalKnockback;
hitEntity.motionY = finalKnockbackUp;
hitEntity.motionZ = knockbackDirZ * finalKnockback;
hitEntity.velocityChanged = true;
if (finalKnockback > 0) {
applyNpcKnockback(hitEntity, knockbackDirX, knockbackDirZ, finalKnockback);
}
return true;
}
private void applyNpcKnockback(EntityLivingBase hitEntity, double dirX, double dirZ, float knockback) {
double len = Math.sqrt(dirX * dirX + dirZ * dirZ);
if (len <= 0) {
return;
}
double x = (dirX / len) * knockback * 0.5;
double z = (dirZ / len) * knockback * 0.5;
hitEntity.addVelocity(x, 0.1D, z);
hitEntity.velocityChanged = true;
}
public float getTelegraphRadius() { return 5.0f; }
public float getTelegraphLength() { return 5.0f; }
public float getTelegraphWidth() { return 2.0f; }
@@ -169,7 +169,7 @@ public class AbilityBeam extends Ability {
if (isInBeamPath(livingEntity, startX, startY, startZ, dirX, dirZ)) {
hitThisTick.add(entity.getEntityId());
// Apply damage with scripted event support (no knockback for beam)
applyAbilityDamage(npc, livingEntity, damage, 0, 0);
applyAbilityDamage(npc, livingEntity, damage, 0);
if (!piercing) {
return; // Stop at first hit
@@ -32,9 +32,7 @@ public class AbilityCharge extends Ability {
private float chargeSpeed = 0.8f;
private float damage = 15.0f;
private float knockback = 3.0f;
private float knockbackUp = 0.3f;
private float maxDistance = 20.0f;
private float hitRadius = 1.5f;
private float hitWidth = 1.5f;
// Runtime state (transient)
private transient double startX, startY, startZ;
@@ -56,6 +54,8 @@ public class AbilityCharge extends Ability {
// LINE telegraph showing charge path
this.telegraphType = TelegraphType.LINE;
this.showTelegraph = true;
this.windUpSound = "mob.zombie.wood";
this.activeSound = "mob.zombie.attack";
}
@Override
@@ -154,13 +154,18 @@ public class AbilityCharge extends Ability {
);
// Check if reached max distance
if (distanceTraveled >= maxDistance) {
if (distanceTraveled >= maxRange) {
npc.motionX = 0;
npc.motionZ = 0;
npc.velocityChanged = true;
return;
}
if (isChargeBlocked(npc)) {
stopMomentum(npc);
return;
}
// Move NPC
npc.motionX = chargeDirection.xCoord * chargeSpeed;
npc.motionY = 0;
@@ -169,7 +174,7 @@ public class AbilityCharge extends Ability {
// Server-side collision damage
if (!world.isRemote) {
AxisAlignedBB hitBox = npc.boundingBox.expand(hitRadius, hitRadius * 0.5, hitRadius);
AxisAlignedBB hitBox = npc.boundingBox.expand(hitWidth, hitWidth * 0.5, hitWidth);
@SuppressWarnings("unchecked")
List<Entity> entities = world.getEntitiesWithinAABB(EntityLivingBase.class, hitBox);
@@ -185,7 +190,7 @@ public class AbilityCharge extends Ability {
hitEntities.add(entity.getEntityId());
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamageWithDirection(npc, livingEntity, damage, knockback, knockbackUp,
boolean wasHit = applyAbilityDamageWithDirection(npc, livingEntity, damage, knockback,
chargeDirection.xCoord, chargeDirection.zCoord);
// Play impact sound if hit wasn't cancelled
@@ -214,6 +219,13 @@ public class AbilityCharge extends Ability {
npc.velocityChanged = true;
}
private boolean isChargeBlocked(EntityNPCInterface npc) {
double nextX = chargeDirection.xCoord * chargeSpeed;
double nextZ = chargeDirection.zCoord * chargeSpeed;
AxisAlignedBB nextBox = npc.boundingBox.copy().offset(nextX, 0, nextZ);
return !npc.worldObj.getCollidingBoundingBoxes(npc, nextBox).isEmpty();
}
@Override
public void reset() {
super.reset();
@@ -223,7 +235,7 @@ public class AbilityCharge extends Ability {
@Override
public float getTelegraphLength() {
return maxDistance;
return maxRange;
}
@Override
@@ -275,9 +287,7 @@ public class AbilityCharge extends Ability {
nbt.setFloat("chargeSpeed", chargeSpeed);
nbt.setFloat("damage", damage);
nbt.setFloat("knockback", knockback);
nbt.setFloat("knockbackUp", knockbackUp);
nbt.setFloat("maxDistance", maxDistance);
nbt.setFloat("hitRadius", hitRadius);
nbt.setFloat("hitWidth", hitWidth);
}
@Override
@@ -285,9 +295,13 @@ public class AbilityCharge extends Ability {
this.chargeSpeed = nbt.hasKey("chargeSpeed") ? nbt.getFloat("chargeSpeed") : 0.8f;
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 15.0f;
this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 3.0f;
this.knockbackUp = nbt.hasKey("knockbackUp") ? nbt.getFloat("knockbackUp") : 0.3f;
this.maxDistance = nbt.hasKey("maxDistance") ? nbt.getFloat("maxDistance") : 20.0f;
this.hitRadius = nbt.hasKey("hitRadius") ? nbt.getFloat("hitRadius") : 1.5f;
if (nbt.hasKey("hitWidth")) {
this.hitWidth = nbt.getFloat("hitWidth");
} else if (nbt.hasKey("hitRadius")) {
this.hitWidth = nbt.getFloat("hitRadius");
} else {
this.hitWidth = 1.5f;
}
}
// Getters & Setters
@@ -300,12 +314,6 @@ public class AbilityCharge extends Ability {
public float getKnockback() { return knockback; }
public void setKnockback(float knockback) { this.knockback = knockback; }
public float getKnockbackUp() { return knockbackUp; }
public void setKnockbackUp(float knockbackUp) { this.knockbackUp = knockbackUp; }
public float getMaxDistance() { return maxDistance; }
public void setMaxDistance(float maxDistance) { this.maxDistance = maxDistance; }
public float getHitRadius() { return hitRadius; }
public void setHitRadius(float hitRadius) { this.hitRadius = hitRadius; }
public float getHitWidth() { return hitWidth; }
public void setHitWidth(float hitWidth) { this.hitWidth = hitWidth; }
}
@@ -29,32 +29,26 @@ import java.util.Set;
public class AbilityCutter extends Ability {
public enum SweepMode {
INSTANT,
EXPANDING,
ROTATING
SWIPE,
SPIN
}
private float arcAngle = 90.0f;
private float range = 6.0f;
private float damage = 12.0f;
private float knockback = 1.5f;
private float knockbackUp = 0.2f;
private SweepMode sweepMode = SweepMode.INSTANT;
private int sweepWaves = 1;
private int waveInterval = 5;
private float rotationSpeed = 5.0f;
private float startAngleOffset = 0.0f;
private SweepMode sweepMode = SweepMode.SWIPE;
private float sweepSpeed = 6.0f;
private int stunDuration = 0;
private int bleedDuration = 0;
private int bleedLevel = 0;
private int poisonDurationSeconds = 0;
private int poisonLevel = 0;
private boolean piercing = true;
private float innerRadius = 0.0f;
// Runtime state
private transient Set<Integer> hitEntities = new HashSet<>();
private transient int currentWave = 0;
private transient float currentRotation = 0.0f;
public AbilityCutter() {
@@ -68,6 +62,8 @@ public class AbilityCutter extends Ability {
this.activeTicks = 15;
this.recoveryTicks = 15;
this.telegraphType = TelegraphType.CONE;
this.windUpSound = "random.bow";
this.activeSound = "random.break";
}
@Override
@@ -99,12 +95,7 @@ public class AbilityCutter extends Ability {
@Override
public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) {
hitEntities.clear();
currentWave = 0;
currentRotation = startAngleOffset;
if (sweepMode == SweepMode.INSTANT && !world.isRemote) {
performSweepDamage(npc, world, 0.0f, range);
}
currentRotation = -arcAngle / 2.0f;
}
@Override
@@ -112,29 +103,24 @@ public class AbilityCutter extends Ability {
if (world.isRemote) return;
switch (sweepMode) {
case EXPANDING:
if (tick % waveInterval == 0 && currentWave < sweepWaves) {
float waveProgress = (float)(currentWave + 1) / sweepWaves;
float waveInner = innerRadius + (range - innerRadius) * ((float)currentWave / sweepWaves);
float waveOuter = innerRadius + (range - innerRadius) * waveProgress;
performSweepDamage(npc, world, waveInner, waveOuter);
currentWave++;
case SWIPE:
if (currentRotation > arcAngle / 2.0f) {
return;
}
performSweepDamage(npc, world, innerRadius, range, currentRotation);
currentRotation += sweepSpeed;
break;
case ROTATING:
currentRotation += rotationSpeed;
case SPIN:
currentRotation = (currentRotation + sweepSpeed) % 360.0f;
hitEntities.clear();
performSweepDamage(npc, world, innerRadius, range);
break;
case INSTANT:
performSweepDamage(npc, world, innerRadius, range, currentRotation);
break;
}
}
private void performSweepDamage(EntityNPCInterface npc, World world, float minDist, float maxDist) {
float casterYaw = npc.rotationYaw + currentRotation;
private void performSweepDamage(EntityNPCInterface npc, World world, float minDist, float maxDist, float angleOffset) {
float casterYaw = npc.rotationYaw + angleOffset;
AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox(
npc.posX - maxDist, npc.posY - 1, npc.posZ - maxDist,
@@ -163,7 +149,7 @@ public class AbilityCutter extends Ability {
float actualDamage = damage * distFactor;
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, entity, actualDamage, knockback, knockbackUp);
boolean wasHit = applyAbilityDamage(npc, entity, actualDamage, knockback);
// Only apply effects if hit wasn't cancelled
if (wasHit) {
@@ -171,8 +157,8 @@ public class AbilityCutter extends Ability {
entity.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunDuration, 10));
entity.addPotionEffect(new PotionEffect(Potion.weakness.id, stunDuration, 2));
}
if (bleedDuration > 0) {
entity.addPotionEffect(new PotionEffect(Potion.wither.id, bleedDuration, bleedLevel));
if (poisonDurationSeconds > 0) {
entity.addPotionEffect(new PotionEffect(Potion.poison.id, poisonDurationSeconds * 20, poisonLevel));
}
}
}
@@ -193,15 +179,13 @@ public class AbilityCutter extends Ability {
@Override
public void onComplete(EntityNPCInterface npc, EntityLivingBase target) {
hitEntities.clear();
currentWave = 0;
currentRotation = startAngleOffset;
currentRotation = 0.0f;
}
@Override
public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) {
hitEntities.clear();
currentWave = 0;
currentRotation = startAngleOffset;
currentRotation = 0.0f;
}
@Override
@@ -210,15 +194,11 @@ public class AbilityCutter extends Ability {
nbt.setFloat("range", range);
nbt.setFloat("damage", damage);
nbt.setFloat("knockback", knockback);
nbt.setFloat("knockbackUp", knockbackUp);
nbt.setString("sweepMode", sweepMode.name());
nbt.setInteger("sweepWaves", sweepWaves);
nbt.setInteger("waveInterval", waveInterval);
nbt.setFloat("rotationSpeed", rotationSpeed);
nbt.setFloat("startAngleOffset", startAngleOffset);
nbt.setFloat("sweepSpeed", sweepSpeed);
nbt.setInteger("stunDuration", stunDuration);
nbt.setInteger("bleedDuration", bleedDuration);
nbt.setInteger("bleedLevel", bleedLevel);
nbt.setInteger("poisonDurationSeconds", poisonDurationSeconds);
nbt.setInteger("poisonLevel", poisonLevel);
nbt.setBoolean("piercing", piercing);
nbt.setFloat("innerRadius", innerRadius);
}
@@ -229,19 +209,15 @@ public class AbilityCutter extends Ability {
this.range = nbt.hasKey("range") ? nbt.getFloat("range") : 6.0f;
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 12.0f;
this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 1.5f;
this.knockbackUp = nbt.hasKey("knockbackUp") ? nbt.getFloat("knockbackUp") : 0.2f;
try {
this.sweepMode = SweepMode.valueOf(nbt.getString("sweepMode"));
} catch (Exception e) {
this.sweepMode = SweepMode.INSTANT;
this.sweepMode = SweepMode.SWIPE;
}
this.sweepWaves = nbt.hasKey("sweepWaves") ? nbt.getInteger("sweepWaves") : 1;
this.waveInterval = nbt.hasKey("waveInterval") ? nbt.getInteger("waveInterval") : 5;
this.rotationSpeed = nbt.hasKey("rotationSpeed") ? nbt.getFloat("rotationSpeed") : 5.0f;
this.startAngleOffset = nbt.hasKey("startAngleOffset") ? nbt.getFloat("startAngleOffset") : 0.0f;
this.sweepSpeed = nbt.hasKey("sweepSpeed") ? nbt.getFloat("sweepSpeed") : 6.0f;
this.stunDuration = nbt.hasKey("stunDuration") ? nbt.getInteger("stunDuration") : 0;
this.bleedDuration = nbt.hasKey("bleedDuration") ? nbt.getInteger("bleedDuration") : 0;
this.bleedLevel = nbt.hasKey("bleedLevel") ? nbt.getInteger("bleedLevel") : 0;
this.poisonDurationSeconds = nbt.hasKey("poisonDurationSeconds") ? nbt.getInteger("poisonDurationSeconds") : 0;
this.poisonLevel = nbt.hasKey("poisonLevel") ? nbt.getInteger("poisonLevel") : 0;
this.piercing = !nbt.hasKey("piercing") || nbt.getBoolean("piercing");
this.innerRadius = nbt.hasKey("innerRadius") ? nbt.getFloat("innerRadius") : 0.0f;
}
@@ -259,32 +235,20 @@ public class AbilityCutter extends Ability {
public float getKnockback() { return knockback; }
public void setKnockback(float knockback) { this.knockback = knockback; }
public float getKnockbackUp() { return knockbackUp; }
public void setKnockbackUp(float knockbackUp) { this.knockbackUp = knockbackUp; }
public SweepMode getSweepMode() { return sweepMode; }
public void setSweepMode(SweepMode sweepMode) { this.sweepMode = sweepMode; }
public int getSweepWaves() { return sweepWaves; }
public void setSweepWaves(int sweepWaves) { this.sweepWaves = sweepWaves; }
public int getWaveInterval() { return waveInterval; }
public void setWaveInterval(int waveInterval) { this.waveInterval = waveInterval; }
public float getRotationSpeed() { return rotationSpeed; }
public void setRotationSpeed(float rotationSpeed) { this.rotationSpeed = rotationSpeed; }
public float getStartAngleOffset() { return startAngleOffset; }
public void setStartAngleOffset(float startAngleOffset) { this.startAngleOffset = startAngleOffset; }
public float getSweepSpeed() { return sweepSpeed; }
public void setSweepSpeed(float sweepSpeed) { this.sweepSpeed = sweepSpeed; }
public int getStunDuration() { return stunDuration; }
public void setStunDuration(int stunDuration) { this.stunDuration = stunDuration; }
public int getBleedDuration() { return bleedDuration; }
public void setBleedDuration(int bleedDuration) { this.bleedDuration = bleedDuration; }
public int getPoisonDurationSeconds() { return poisonDurationSeconds; }
public void setPoisonDurationSeconds(int poisonDurationSeconds) { this.poisonDurationSeconds = poisonDurationSeconds; }
public int getBleedLevel() { return bleedLevel; }
public void setBleedLevel(int bleedLevel) { this.bleedLevel = bleedLevel; }
public int getPoisonLevel() { return poisonLevel; }
public void setPoisonLevel(int poisonLevel) { this.poisonLevel = poisonLevel; }
public boolean isPiercing() { return piercing; }
public void setPiercing(boolean piercing) { this.piercing = piercing; }
@@ -95,6 +95,8 @@ public class AbilityDash extends Ability {
// No telegraph for dash - it's a quick evasive move
this.telegraphType = TelegraphType.NONE;
this.showTelegraph = false;
this.windUpSound = "mob.bat.takeoff";
this.activeSound = "mob.endermen.portal";
}
@Override
@@ -152,8 +154,6 @@ public class AbilityDash extends Ability {
Math.cos(yawRad)
);
// Play dash sound
world.playSoundAtEntity(npc, "mob.endermen.portal", 0.5f, 1.5f);
}
@Override
@@ -174,6 +174,13 @@ public class AbilityDash extends Ability {
return;
}
if (isDashBlocked(npc)) {
npc.motionX = 0;
npc.motionZ = 0;
npc.velocityChanged = true;
return;
}
// Move NPC
npc.motionX = dashDirection.xCoord * dashSpeed;
npc.motionY = 0;
@@ -202,6 +209,12 @@ public class AbilityDash extends Ability {
chosenDirection = null;
}
private boolean isDashBlocked(EntityNPCInterface npc) {
double nextX = dashDirection.xCoord * dashSpeed;
double nextZ = dashDirection.zCoord * dashSpeed;
return !npc.worldObj.getCollidingBoundingBoxes(npc, npc.boundingBox.copy().offset(nextX, 0, nextZ)).isEmpty();
}
@Override
public void reset() {
super.reset();
@@ -28,12 +28,21 @@ public class AbilityGuard extends Ability {
// Type-specific parameters
private float damageReduction = 0.5f;
private boolean canCounter = false;
private float counterDamage = 10.0f;
private CounterType counterType = CounterType.FLAT;
private float counterValue = 10.0f;
private float counterChance = 0.3f;
private String counterSound = "random.wood_click";
private int counterAnimationId = -1;
// Runtime state
private transient EntityLivingBase lastAttacker;
private transient boolean counterTriggered;
private transient float lastDamageTaken;
public enum CounterType {
FLAT,
PERCENT
}
public AbilityGuard() {
this.typeId = "ability.cnpc.guard";
@@ -48,6 +57,8 @@ public class AbilityGuard extends Ability {
// No telegraph for guard - it's a defensive stance
this.telegraphType = TelegraphType.NONE;
this.showTelegraph = false;
this.windUpSound = "random.anvil_use";
this.activeSound = "random.anvil_land";
}
@Override
@@ -72,22 +83,14 @@ public class AbilityGuard extends Ability {
public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) {
lastAttacker = null;
counterTriggered = false;
lastDamageTaken = 0.0f;
}
@Override
public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) {
// Counter attack logic if triggered
if (canCounter && counterTriggered && lastAttacker != null && !world.isRemote) {
// Apply counter damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, lastAttacker, counterDamage, 0.5f, 0);
// Play counter sound if hit wasn't cancelled
if (wasHit) {
world.playSoundAtEntity(npc, "random.wood_click", 1.0f, 1.2f);
}
counterTriggered = false;
lastAttacker = null;
performCounter(npc, world);
}
}
@@ -98,13 +101,53 @@ public class AbilityGuard extends Ability {
* @param attacker The entity that attacked
* @param damage The damage amount (after reduction)
*/
public void onDamageTaken(EntityLivingBase attacker, float damage) {
if (attacker != null && canCounter && RANDOM.nextFloat() < counterChance) {
lastAttacker = attacker;
counterTriggered = true;
public void onDamageTaken(EntityNPCInterface npc, EntityLivingBase attacker, DamageSource source, float damage) {
if (!canCounter || attacker == null) return;
if (!isDirectHit(source)) return;
if (RANDOM.nextFloat() >= counterChance) return;
lastAttacker = attacker;
lastDamageTaken = damage;
counterTriggered = true;
if (interruptible) {
performCounter(npc, npc.worldObj);
npc.abilities.interruptCurrentAbility(source, damage);
}
}
private void performCounter(EntityNPCInterface npc, World world) {
float counterDamage = counterType == CounterType.PERCENT
? lastDamageTaken * (counterValue / 100.0f)
: counterValue;
boolean wasHit = applyAbilityDamage(npc, lastAttacker, counterDamage, 0.5f);
if (wasHit && counterSound != null && !counterSound.isEmpty()) {
world.playSoundAtEntity(npc, counterSound, 1.0f, 1.2f);
}
if (counterAnimationId >= 0) {
if (noppes.npcs.controllers.AnimationController.Instance != null) {
noppes.npcs.controllers.data.Animation animation =
noppes.npcs.controllers.AnimationController.Instance.animations.get(counterAnimationId);
if (animation != null) {
npc.display.animationData.setEnabled(true);
npc.display.animationData.setAnimation(animation);
npc.display.animationData.updateClient();
}
}
}
counterTriggered = false;
lastAttacker = null;
lastDamageTaken = 0.0f;
}
private boolean isDirectHit(DamageSource source) {
if (source == null) return false;
if (source.isMagicDamage() || source.isFireDamage() || source.isExplosion()) return false;
return source.getEntity() instanceof EntityLivingBase;
}
/**
* Get the damage reduction factor while guarding.
* Returns 0.5 for 50% reduction.
@@ -128,6 +171,7 @@ public class AbilityGuard extends Ability {
super.reset();
lastAttacker = null;
counterTriggered = false;
lastDamageTaken = 0.0f;
}
@Override
@@ -139,16 +183,32 @@ public class AbilityGuard extends Ability {
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setFloat("damageReduction", damageReduction);
nbt.setBoolean("canCounter", canCounter);
nbt.setFloat("counterDamage", counterDamage);
nbt.setString("counterType", counterType.name());
nbt.setFloat("counterValue", counterValue);
nbt.setFloat("counterChance", counterChance);
nbt.setString("counterSound", counterSound);
nbt.setInteger("counterAnimationId", counterAnimationId);
}
@Override
public void readTypeNBT(NBTTagCompound nbt) {
this.damageReduction = nbt.hasKey("damageReduction") ? nbt.getFloat("damageReduction") : 0.5f;
this.canCounter = nbt.hasKey("canCounter") && nbt.getBoolean("canCounter");
this.counterDamage = nbt.hasKey("counterDamage") ? nbt.getFloat("counterDamage") : 10.0f;
try {
this.counterType = CounterType.valueOf(nbt.getString("counterType"));
} catch (Exception e) {
this.counterType = CounterType.FLAT;
}
if (nbt.hasKey("counterValue")) {
this.counterValue = nbt.getFloat("counterValue");
} else if (nbt.hasKey("counterDamage")) {
this.counterValue = nbt.getFloat("counterDamage");
} else {
this.counterValue = 10.0f;
}
this.counterChance = nbt.hasKey("counterChance") ? nbt.getFloat("counterChance") : 0.3f;
this.counterSound = nbt.hasKey("counterSound") ? nbt.getString("counterSound") : "random.wood_click";
this.counterAnimationId = nbt.hasKey("counterAnimationId") ? nbt.getInteger("counterAnimationId") : -1;
}
// Getters & Setters
@@ -158,9 +218,18 @@ public class AbilityGuard extends Ability {
public boolean isCanCounter() { return canCounter; }
public void setCanCounter(boolean canCounter) { this.canCounter = canCounter; }
public float getCounterDamage() { return counterDamage; }
public void setCounterDamage(float counterDamage) { this.counterDamage = counterDamage; }
public CounterType getCounterType() { return counterType; }
public void setCounterType(CounterType counterType) { this.counterType = counterType; }
public float getCounterValue() { return counterValue; }
public void setCounterValue(float counterValue) { this.counterValue = counterValue; }
public float getCounterChance() { return counterChance; }
public void setCounterChance(float counterChance) { this.counterChance = counterChance; }
public String getCounterSound() { return counterSound; }
public void setCounterSound(String counterSound) { this.counterSound = counterSound; }
public int getCounterAnimationId() { return counterAnimationId; }
public void setCounterAnimationId(int counterAnimationId) { this.counterAnimationId = counterAnimationId; }
}
@@ -290,7 +290,7 @@ public class AbilityHazard extends Ability {
entity.hurtResistantTime = 0;
}
// Apply damage with scripted event support (no knockback for hazard ticks)
boolean wasHit = applyAbilityDamage(npc, entity, damagePerTick, 0, 0);
boolean wasHit = applyAbilityDamage(npc, entity, damagePerTick, 0);
if (!wasHit) continue; // Skip debuffs if hit was cancelled
}
@@ -24,8 +24,9 @@ public class AbilityHeavyHit extends Ability {
private float damage = 15.0f;
private float knockback = 2.0f;
private float knockbackUp = 0.3f;
private int stunTicks = 40;
private int slownessLevel = 1;
private int weaknessLevel = 0;
private int potionDurationSeconds = 2;
public AbilityHeavyHit() {
this.typeId = "ability.cnpc.heavy_hit";
@@ -40,6 +41,8 @@ public class AbilityHeavyHit extends Ability {
this.recoveryTicks = 20;
this.telegraphType = TelegraphType.POINT;
this.showTelegraph = false;
this.windUpSound = "random.anvil_use";
this.activeSound = "random.anvil_land";
}
@Override
@@ -65,12 +68,16 @@ public class AbilityHeavyHit extends Ability {
if (world.isRemote || target == null) return;
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, target, damage, knockback, knockbackUp);
boolean wasHit = applyAbilityDamage(npc, target, damage, knockback);
// Apply stun (slowness + weakness) if the hit wasn't cancelled
if (wasHit && stunTicks > 0) {
target.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, stunTicks, 10));
target.addPotionEffect(new PotionEffect(Potion.weakness.id, stunTicks, 2));
if (wasHit && potionDurationSeconds > 0) {
int durationTicks = potionDurationSeconds * 20;
if (slownessLevel >= 0) {
target.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, durationTicks, slownessLevel));
}
if (weaknessLevel >= 0) {
target.addPotionEffect(new PotionEffect(Potion.weakness.id, durationTicks, weaknessLevel));
}
}
}
@@ -83,16 +90,18 @@ public class AbilityHeavyHit extends Ability {
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setFloat("damage", damage);
nbt.setFloat("knockback", knockback);
nbt.setFloat("knockbackUp", knockbackUp);
nbt.setInteger("stunTicks", stunTicks);
nbt.setInteger("slownessLevel", slownessLevel);
nbt.setInteger("weaknessLevel", weaknessLevel);
nbt.setInteger("potionDurationSeconds", potionDurationSeconds);
}
@Override
public void readTypeNBT(NBTTagCompound nbt) {
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 15.0f;
this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 2.0f;
this.knockbackUp = nbt.hasKey("knockbackUp") ? nbt.getFloat("knockbackUp") : 0.3f;
this.stunTicks = nbt.hasKey("stunTicks") ? nbt.getInteger("stunTicks") : 40;
this.slownessLevel = nbt.hasKey("slownessLevel") ? nbt.getInteger("slownessLevel") : 1;
this.weaknessLevel = nbt.hasKey("weaknessLevel") ? nbt.getInteger("weaknessLevel") : 0;
this.potionDurationSeconds = nbt.hasKey("potionDurationSeconds") ? nbt.getInteger("potionDurationSeconds") : 2;
}
// Getters & Setters
@@ -102,9 +111,12 @@ public class AbilityHeavyHit extends Ability {
public float getKnockback() { return knockback; }
public void setKnockback(float knockback) { this.knockback = knockback; }
public float getKnockbackUp() { return knockbackUp; }
public void setKnockbackUp(float knockbackUp) { this.knockbackUp = knockbackUp; }
public int getSlownessLevel() { return slownessLevel; }
public void setSlownessLevel(int slownessLevel) { this.slownessLevel = slownessLevel; }
public int getStunTicks() { return stunTicks; }
public void setStunTicks(int stunTicks) { this.stunTicks = stunTicks; }
public int getWeaknessLevel() { return weaknessLevel; }
public void setWeaknessLevel(int weaknessLevel) { this.weaknessLevel = weaknessLevel; }
public int getPotionDurationSeconds() { return potionDurationSeconds; }
public void setPotionDurationSeconds(int potionDurationSeconds) { this.potionDurationSeconds = potionDurationSeconds; }
}
@@ -194,7 +194,7 @@ public class AbilityOrb extends Ability {
doExplosion(npc, world);
} else {
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback, 0.2f);
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback);
if (wasHit) {
applyEffects(entity);
}
@@ -231,7 +231,7 @@ public class AbilityOrb extends Ability {
if (dist <= explosionRadius) {
float falloff = 1.0f - (float)(dist / explosionRadius) * explosionDamageFalloff;
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, blastTarget, damage * falloff, knockback * falloff, 0.3f);
boolean wasHit = applyAbilityDamage(npc, blastTarget, damage * falloff, knockback * falloff);
if (wasHit) {
applyEffects(blastTarget);
}
@@ -83,7 +83,7 @@ public class AbilityProjectile extends Ability {
// Deal instant damage with scripted event support
// TODO: Use custom EntityAbilityProjectile for actual tracking
applyAbilityDamageWithDirection(npc, target, damage, knockback, 0.1f, dx, dz);
applyAbilityDamageWithDirection(npc, target, damage, knockback, dx, dz);
// Play sound
world.playSoundAtEntity(npc, "random.bow", 1.0f, 0.8f);
@@ -101,7 +101,7 @@ public class AbilityProjectile extends Ability {
if (dist < explosionRadius) {
float falloff = 1.0f - (dist / explosionRadius);
// Apply splash damage with scripted event support (no knockback)
applyAbilityDamage(npc, living, damage * falloff * 0.5f, 0, 0);
applyAbilityDamage(npc, living, damage * falloff * 0.5f, 0);
}
}
}
@@ -27,11 +27,9 @@ public class AbilityShockwave extends Ability {
private float pushRadius = 8.0f;
private float pushStrength = 1.5f;
private float pushUp = 0.5f;
private float damage = 10.0f;
private int stunDuration = 0;
private int maxTargets = 10;
private boolean aoe = true;
// Runtime state
private transient boolean executed = false;
@@ -47,6 +45,8 @@ public class AbilityShockwave extends Ability {
this.activeTicks = 5;
this.recoveryTicks = 20;
this.telegraphType = TelegraphType.CIRCLE;
this.windUpSound = "random.explode";
this.activeSound = "random.explode";
}
@Override
@@ -79,9 +79,6 @@ public class AbilityShockwave extends Ability {
if (executed) return;
executed = true;
// Play shockwave sound
world.playSoundAtEntity(npc, "random.explode", 0.5f, 1.5f);
// Get all entities in radius
AxisAlignedBB box = npc.boundingBox.expand(pushRadius, pushRadius / 2, pushRadius);
@SuppressWarnings("unchecked")
@@ -116,10 +113,8 @@ public class AbilityShockwave extends Ability {
// Scale knockback by distance (closer = stronger)
float distFactor = 1.0f - (float)(dist / pushRadius) * 0.5f;
float finalPush = pushStrength * distFactor;
float finalPushUp = pushUp * distFactor;
// Apply damage with custom knockback direction
boolean wasHit = applyAbilityDamageWithDirection(npc, entity, damage * distFactor, finalPush, finalPushUp, dx, dz);
boolean wasHit = applyAbilityDamageWithDirection(npc, entity, damage * distFactor, finalPush, dx, dz);
// Apply stun if hit connected
if (wasHit && stunDuration > 0) {
@@ -143,22 +138,18 @@ public class AbilityShockwave extends Ability {
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setFloat("pushRadius", pushRadius);
nbt.setFloat("pushStrength", pushStrength);
nbt.setFloat("pushUp", pushUp);
nbt.setFloat("damage", damage);
nbt.setInteger("stunDuration", stunDuration);
nbt.setInteger("maxTargets", maxTargets);
nbt.setBoolean("aoe", aoe);
}
@Override
public void readTypeNBT(NBTTagCompound nbt) {
this.pushRadius = nbt.hasKey("pushRadius") ? nbt.getFloat("pushRadius") : 8.0f;
this.pushStrength = nbt.hasKey("pushStrength") ? nbt.getFloat("pushStrength") : 1.5f;
this.pushUp = nbt.hasKey("pushUp") ? nbt.getFloat("pushUp") : 0.5f;
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 10.0f;
this.stunDuration = nbt.hasKey("stunDuration") ? nbt.getInteger("stunDuration") : 0;
this.maxTargets = nbt.hasKey("maxTargets") ? nbt.getInteger("maxTargets") : 10;
this.aoe = !nbt.hasKey("aoe") || nbt.getBoolean("aoe");
}
// Getters & Setters
@@ -168,9 +159,6 @@ public class AbilityShockwave extends Ability {
public float getPushStrength() { return pushStrength; }
public void setPushStrength(float pushStrength) { this.pushStrength = pushStrength; }
public float getPushUp() { return pushUp; }
public void setPushUp(float pushUp) { this.pushUp = pushUp; }
public float getDamage() { return damage; }
public void setDamage(float damage) { this.damage = damage; }
@@ -180,6 +168,4 @@ public class AbilityShockwave extends Ability {
public int getMaxTargets() { return maxTargets; }
public void setMaxTargets(int maxTargets) { this.maxTargets = maxTargets; }
public boolean isAoe() { return aoe; }
public void setAoe(boolean aoe) { this.aoe = aoe; }
}
@@ -36,8 +36,7 @@ public class AbilitySlam extends Ability {
private float radius = 5.0f;
private float knockbackStrength = 1.5f;
private float leapSpeed = 1.0f;
private float minLeapDistance = 2.0f;
private float maxLeapDistance = 15.0f;
private float leapHeight = 4.0f;
// Runtime state
private transient double targetX, targetY, targetZ;
@@ -58,6 +57,8 @@ public class AbilitySlam extends Ability {
this.minRange = 2.0f;
this.maxRange = 15.0f;
this.telegraphType = TelegraphType.CIRCLE;
this.windUpSound = "mob.irongolem.throw";
this.activeSound = "random.explode";
}
@Override
@@ -157,11 +158,11 @@ public class AbilitySlam extends Ability {
}
// Cap the distance if too far
if (horizontalDist > maxLeapDistance) {
double scale = maxLeapDistance / horizontalDist;
if (horizontalDist > maxRange) {
double scale = maxRange / horizontalDist;
dx *= scale;
dz *= scale;
horizontalDist = maxLeapDistance;
horizontalDist = maxRange;
targetX = npc.posX + dx;
targetZ = npc.posZ + dz;
}
@@ -188,7 +189,7 @@ public class AbilitySlam extends Ability {
// Calculate required upward velocity to create a nice arc and land at target height
// Peak height should be proportional to horizontal distance for visual appeal
double arcHeight = Math.max(3.0, horizontalDist * 0.3) * leapSpeed;
double arcHeight = Math.max(1.0, leapHeight) * leapSpeed;
// Approximate the required initial vertical velocity
// Account for gravity and drag - use a simplified model
@@ -222,8 +223,6 @@ public class AbilitySlam extends Ability {
npc.rotationYaw = targetYaw;
npc.rotationYawHead = targetYaw;
// Play launch sound
npc.worldObj.playSoundAtEntity(npc, "mob.irongolem.throw", 0.8f, 0.8f);
}
@Override
@@ -287,15 +286,12 @@ public class AbilitySlam extends Ability {
double dx = livingTarget.posX - npc.posX;
double dz = livingTarget.posZ - npc.posZ;
if (dx * dx + dz * dz <= radius * radius) {
// Apply damage with scripted event support (0.3f is the upward knockback boost)
applyAbilityDamage(npc, livingTarget, damage, knockbackStrength, 0.3f);
// Apply damage with scripted event support
applyAbilityDamage(npc, livingTarget, damage, knockbackStrength);
}
}
}
// Play impact sound
world.playSoundAtEntity(npc, "random.explode", 0.5f, 1.2f);
// Spawn particles
spawnSlamParticles(world, npc.posX, npc.posY, npc.posZ);
}
@@ -418,8 +414,7 @@ public class AbilitySlam extends Ability {
nbt.setFloat("radius", radius);
nbt.setFloat("knockback", knockbackStrength);
nbt.setFloat("leapSpeed", leapSpeed);
nbt.setFloat("minLeapDistance", minLeapDistance);
nbt.setFloat("maxLeapDistance", maxLeapDistance);
nbt.setFloat("leapHeight", leapHeight);
}
@Override
@@ -428,8 +423,7 @@ public class AbilitySlam extends Ability {
radius = nbt.hasKey("radius") ? nbt.getFloat("radius") : 5.0f;
knockbackStrength = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 1.5f;
leapSpeed = nbt.hasKey("leapSpeed") ? nbt.getFloat("leapSpeed") : 1.0f;
minLeapDistance = nbt.hasKey("minLeapDistance") ? nbt.getFloat("minLeapDistance") : 2.0f;
maxLeapDistance = nbt.hasKey("maxLeapDistance") ? nbt.getFloat("maxLeapDistance") : 15.0f;
leapHeight = nbt.hasKey("leapHeight") ? nbt.getFloat("leapHeight") : 4.0f;
}
// Getters & Setters
@@ -445,9 +439,6 @@ public class AbilitySlam extends Ability {
public float getLeapSpeed() { return leapSpeed; }
public void setLeapSpeed(float leapSpeed) { this.leapSpeed = leapSpeed; }
public float getMinLeapDistance() { return minLeapDistance; }
public void setMinLeapDistance(float minLeapDistance) { this.minLeapDistance = minLeapDistance; }
public float getMaxLeapDistance() { return maxLeapDistance; }
public void setMaxLeapDistance(float maxLeapDistance) { this.maxLeapDistance = maxLeapDistance; }
public float getLeapHeight() { return leapHeight; }
public void setLeapHeight(float leapHeight) { this.leapHeight = leapHeight; }
}
@@ -29,26 +29,22 @@ import java.util.Random;
public class AbilityTeleport extends Ability {
/**
* Pattern for teleport destination.
* Teleport behavior mode.
*/
public enum TeleportPattern {
RANDOM,
TOWARD_TARGET,
AWAY_FROM_TARGET,
BEHIND_TARGET,
IN_FRONT_OF_TARGET,
AROUND_TARGET,
TO_TARGET
public enum TeleportMode {
BLINK,
BEHIND,
SINGLE
}
private static final Random RANDOM = new Random();
// Type-specific parameters
private int blinkCount = 1;
private TeleportMode mode = TeleportMode.BLINK;
private int blinkCount = 3;
private int blinkDelayTicks = 10;
private float blinkRadius = 8.0f;
private float minBlinkRadius = 3.0f;
private TeleportPattern pattern = TeleportPattern.RANDOM;
private float behindDistance = 2.0f;
private boolean requireLineOfSight = true;
private boolean damageAtStart = false;
private boolean damageAtEnd = false;
@@ -72,6 +68,8 @@ public class AbilityTeleport extends Ability {
// No telegraph for teleport - it's instant repositioning
this.telegraphType = TelegraphType.NONE;
this.showTelegraph = false;
this.windUpSound = "mob.endermen.portal";
this.activeSound = "mob.endermen.portal";
}
@Override
@@ -100,7 +98,8 @@ public class AbilityTeleport extends Ability {
@Override
public void onActiveTick(EntityNPCInterface npc, EntityLivingBase target, World world, int tick) {
if (currentBlink >= blinkCount) return;
int blinkLimit = mode == TeleportMode.BLINK ? blinkCount : 1;
if (currentBlink >= blinkLimit) return;
ticksSinceLastBlink++;
@@ -121,27 +120,17 @@ public class AbilityTeleport extends Ability {
Vec3 destination = calculateDestination(npc, target, world);
if (destination == null) return;
// Verify line of sight if required
if (requireLineOfSight && !hasLineOfSight(world, oldX, oldY + npc.getEyeHeight(), oldZ,
destination.xCoord, destination.yCoord + npc.getEyeHeight(), destination.zCoord)) {
boolean mustHaveLOS = mode == TeleportMode.BEHIND || requireLineOfSight;
if (mustHaveLOS && !hasLineOfSight(world, oldX, oldY + npc.getEyeHeight(), oldZ,
destination.xCoord, destination.yCoord + npc.getEyeHeight(), destination.zCoord)) {
destination = findValidPositionAlongLine(world, npc, oldX, oldY, oldZ,
destination.xCoord, destination.yCoord, destination.zCoord);
destination.xCoord, destination.yCoord, destination.zCoord);
if (destination == null) return;
}
// Verify destination is safe
if (!isSafeLocation(world, (int)Math.floor(destination.xCoord),
(int)Math.floor(destination.yCoord),
(int)Math.floor(destination.zCoord))) {
double safeY = findSafeY(world, destination.xCoord, destination.yCoord, destination.zCoord);
destination = Vec3.createVectorHelper(destination.xCoord, safeY, destination.zCoord);
if (!isSafeLocation(world, (int)Math.floor(destination.xCoord),
(int)Math.floor(destination.yCoord),
(int)Math.floor(destination.zCoord))) {
return;
}
}
destination = findSafeDestination(world, oldX, oldY, oldZ,
destination.xCoord, destination.yCoord, destination.zCoord);
if (destination == null) return;
// Damage at origin
if (damageAtStart) {
@@ -158,9 +147,6 @@ public class AbilityTeleport extends Ability {
// Spawn particles at destination
spawnTeleportParticles(world, destination.xCoord, destination.yCoord, destination.zCoord);
// Play teleport sound
world.playSoundAtEntity(npc, "mob.endermen.portal", 1.0f, 1.0f);
// Damage at destination
if (damageAtEnd) {
dealDamageAt(npc, world, destination.xCoord, destination.yCoord, destination.zCoord);
@@ -189,96 +175,67 @@ public class AbilityTeleport extends Ability {
}
private Vec3 calculateDestination(EntityNPCInterface npc, EntityLivingBase target, World world) {
double newX, newY, newZ;
if (target == null) return null;
switch (pattern) {
case TOWARD_TARGET:
if (target != null) {
double dx = target.posX - npc.posX;
double dz = target.posZ - npc.posZ;
double dist = Math.sqrt(dx * dx + dz * dz);
if (dist > 0) {
double blinkDist = Math.min(blinkRadius, dist - 2.0);
blinkDist = Math.max(minBlinkRadius, blinkDist);
newX = npc.posX + (dx / dist) * blinkDist;
newZ = npc.posZ + (dz / dist) * blinkDist;
newY = findSafeY(world, newX, npc.posY, newZ);
return Vec3.createVectorHelper(newX, newY, newZ);
}
}
return null;
double newX;
double newY;
double newZ;
case AWAY_FROM_TARGET:
if (target != null) {
double dx = npc.posX - target.posX;
double dz = npc.posZ - target.posZ;
double dist = Math.sqrt(dx * dx + dz * dz);
if (dist > 0) {
dx /= dist;
dz /= dist;
} else {
dx = RANDOM.nextDouble() - 0.5;
dz = RANDOM.nextDouble() - 0.5;
double len = Math.sqrt(dx * dx + dz * dz);
dx /= len;
dz /= len;
}
double blinkDist = minBlinkRadius + RANDOM.nextDouble() * (blinkRadius - minBlinkRadius);
newX = npc.posX + dx * blinkDist;
newZ = npc.posZ + dz * blinkDist;
newY = findSafeY(world, newX, npc.posY, newZ);
return Vec3.createVectorHelper(newX, newY, newZ);
}
return null;
case BEHIND_TARGET:
if (target != null) {
float targetYaw = (float) Math.toRadians(target.rotationYaw);
double behindX = target.posX + Math.sin(targetYaw) * 3.0;
double behindZ = target.posZ - Math.cos(targetYaw) * 3.0;
newY = findSafeY(world, behindX, target.posY, behindZ);
return Vec3.createVectorHelper(behindX, newY, behindZ);
}
return null;
case IN_FRONT_OF_TARGET:
if (target != null) {
float targetYaw = (float) Math.toRadians(target.rotationYaw);
double frontX = target.posX - Math.sin(targetYaw) * 3.0;
double frontZ = target.posZ + Math.cos(targetYaw) * 3.0;
newY = findSafeY(world, frontX, target.posY, frontZ);
return Vec3.createVectorHelper(frontX, newY, frontZ);
}
return null;
case AROUND_TARGET:
if (target != null) {
double angle = RANDOM.nextDouble() * Math.PI * 2;
double dist = minBlinkRadius + RANDOM.nextDouble() * (blinkRadius - minBlinkRadius);
newX = target.posX + Math.cos(angle) * dist;
newZ = target.posZ + Math.sin(angle) * dist;
newY = findSafeY(world, newX, target.posY, newZ);
return Vec3.createVectorHelper(newX, newY, newZ);
}
return null;
case TO_TARGET:
if (target != null) {
return Vec3.createVectorHelper(target.posX, target.posY, target.posZ);
}
return null;
case RANDOM:
switch (mode) {
case BEHIND:
double yaw = Math.toRadians(target.rotationYaw);
newX = target.posX + Math.sin(yaw) * behindDistance;
newZ = target.posZ - Math.cos(yaw) * behindDistance;
newY = target.posY;
return Vec3.createVectorHelper(newX, newY, newZ);
case SINGLE:
case BLINK:
default:
double angle = RANDOM.nextDouble() * Math.PI * 2;
double blinkDist = minBlinkRadius + RANDOM.nextDouble() * (blinkRadius - minBlinkRadius);
newX = npc.posX + Math.cos(angle) * blinkDist;
newZ = npc.posZ + Math.sin(angle) * blinkDist;
newY = findSafeY(world, newX, npc.posY, newZ);
double dist = Math.min(blinkRadius, maxRange);
double offset = RANDOM.nextDouble() * dist;
newX = target.posX + Math.cos(angle) * offset;
newZ = target.posZ + Math.sin(angle) * offset;
newY = target.posY;
return Vec3.createVectorHelper(newX, newY, newZ);
}
}
private Vec3 findSafeDestination(World world, double oldX, double oldY, double oldZ,
double destX, double destY, double destZ) {
int oldBlockX = (int) Math.floor(oldX);
int oldBlockY = (int) Math.floor(oldY);
int oldBlockZ = (int) Math.floor(oldZ);
int destBlockX = (int) Math.floor(destX);
int destBlockY = (int) Math.floor(destY);
int destBlockZ = (int) Math.floor(destZ);
if (oldBlockX == destBlockX && oldBlockY == destBlockY && oldBlockZ == destBlockZ) {
return null;
}
double safeY = findSafeYNear(world, destX, destY, destZ);
Vec3 safe = Vec3.createVectorHelper(destX, safeY, destZ);
if (!isSafeLocation(world, (int) Math.floor(safe.xCoord),
(int) Math.floor(safe.yCoord), (int) Math.floor(safe.zCoord))) {
return null;
}
return safe;
}
private double findSafeYNear(World world, double x, double baseY, double z) {
int[] offsets = new int[]{0, 1, -1, 2, -2};
for (int offset : offsets) {
double y = baseY + offset;
if (isSafeLocation(world, (int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z))) {
return y;
}
}
return findSafeY(world, x, baseY, z);
}
private boolean hasLineOfSight(World world, double x1, double y1, double z1,
double x2, double y2, double z2) {
double dx = x2 - x1;
@@ -319,7 +276,7 @@ public class AbilityTeleport extends Ability {
double dz = z2 - z1;
double distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
if (distance < minBlinkRadius) return null;
if (distance < 1.0) return null;
dx /= distance;
dy /= distance;
@@ -328,7 +285,7 @@ public class AbilityTeleport extends Ability {
Vec3 lastValid = null;
double step = 0.5;
for (double d = minBlinkRadius; d < distance; d += step) {
for (double d = 1.0; d < distance; d += step) {
double checkX = x1 + dx * d;
double checkY = y1 + dy * d;
double checkZ = z1 + dz * d;
@@ -394,7 +351,7 @@ public class AbilityTeleport extends Ability {
double dist = Math.sqrt(Math.pow(living.posX - x, 2) + Math.pow(living.posZ - z, 2));
if (dist <= damageRadius) {
// Apply damage with scripted event support (no knockback for teleport damage)
applyAbilityDamage(npc, living, damage, 0, 0);
applyAbilityDamage(npc, living, damage, 0);
}
}
}
@@ -413,11 +370,11 @@ public class AbilityTeleport extends Ability {
@Override
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setString("mode", mode.name());
nbt.setInteger("blinkCount", blinkCount);
nbt.setInteger("blinkDelayTicks", blinkDelayTicks);
nbt.setFloat("blinkRadius", blinkRadius);
nbt.setFloat("minBlinkRadius", minBlinkRadius);
nbt.setString("pattern", pattern.name());
nbt.setFloat("behindDistance", behindDistance);
nbt.setBoolean("requireLineOfSight", requireLineOfSight);
nbt.setBoolean("damageAtStart", damageAtStart);
nbt.setBoolean("damageAtEnd", damageAtEnd);
@@ -427,15 +384,28 @@ public class AbilityTeleport extends Ability {
@Override
public void readTypeNBT(NBTTagCompound nbt) {
this.blinkCount = nbt.hasKey("blinkCount") ? nbt.getInteger("blinkCount") : 1;
if (nbt.hasKey("mode")) {
try {
this.mode = TeleportMode.valueOf(nbt.getString("mode"));
} catch (Exception e) {
this.mode = TeleportMode.BLINK;
}
} else if (nbt.hasKey("pattern")) {
String legacy = nbt.getString("pattern");
if ("BEHIND_TARGET".equals(legacy)) {
this.mode = TeleportMode.BEHIND;
} else if ("RANDOM".equals(legacy)) {
this.mode = TeleportMode.BLINK;
} else {
this.mode = TeleportMode.SINGLE;
}
} else {
this.mode = TeleportMode.BLINK;
}
this.blinkCount = nbt.hasKey("blinkCount") ? nbt.getInteger("blinkCount") : 3;
this.blinkDelayTicks = nbt.hasKey("blinkDelayTicks") ? nbt.getInteger("blinkDelayTicks") : 10;
this.blinkRadius = nbt.hasKey("blinkRadius") ? nbt.getFloat("blinkRadius") : 8.0f;
this.minBlinkRadius = nbt.hasKey("minBlinkRadius") ? nbt.getFloat("minBlinkRadius") : 3.0f;
try {
this.pattern = TeleportPattern.valueOf(nbt.getString("pattern"));
} catch (Exception e) {
this.pattern = TeleportPattern.RANDOM;
}
this.behindDistance = nbt.hasKey("behindDistance") ? nbt.getFloat("behindDistance") : 2.0f;
this.requireLineOfSight = !nbt.hasKey("requireLineOfSight") || nbt.getBoolean("requireLineOfSight");
this.damageAtStart = nbt.hasKey("damageAtStart") && nbt.getBoolean("damageAtStart");
this.damageAtEnd = nbt.hasKey("damageAtEnd") && nbt.getBoolean("damageAtEnd");
@@ -444,6 +414,9 @@ public class AbilityTeleport extends Ability {
}
// Getters & Setters
public TeleportMode getMode() { return mode; }
public void setMode(TeleportMode mode) { this.mode = mode; }
public int getBlinkCount() { return blinkCount; }
public void setBlinkCount(int blinkCount) { this.blinkCount = blinkCount; }
@@ -453,11 +426,8 @@ public class AbilityTeleport extends Ability {
public float getBlinkRadius() { return blinkRadius; }
public void setBlinkRadius(float blinkRadius) { this.blinkRadius = blinkRadius; }
public float getMinBlinkRadius() { return minBlinkRadius; }
public void setMinBlinkRadius(float minBlinkRadius) { this.minBlinkRadius = minBlinkRadius; }
public TeleportPattern getPattern() { return pattern; }
public void setPattern(TeleportPattern pattern) { this.pattern = pattern; }
public float getBehindDistance() { return behindDistance; }
public void setBehindDistance(float behindDistance) { this.behindDistance = behindDistance; }
public boolean isRequireLineOfSight() { return requireLineOfSight; }
public void setRequireLineOfSight(boolean requireLineOfSight) { this.requireLineOfSight = requireLineOfSight; }
@@ -45,7 +45,6 @@ public class AbilityTrap extends Ability {
private float damage = 10.0f;
private float damageRadius = 0.0f;
private float knockback = 0.5f;
private float knockbackUp = 0.3f;
private int stunDuration = 0;
private int rootDuration = 40;
private int slowDuration = 0;
@@ -274,7 +273,7 @@ public class AbilityTrap extends Ability {
for (EntityLivingBase entity : affected) {
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback, knockbackUp);
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback);
// Only apply effects if the hit wasn't cancelled
if (wasHit) {
@@ -323,7 +322,6 @@ public class AbilityTrap extends Ability {
nbt.setFloat("damage", damage);
nbt.setFloat("damageRadius", damageRadius);
nbt.setFloat("knockback", knockback);
nbt.setFloat("knockbackUp", knockbackUp);
nbt.setInteger("stunDuration", stunDuration);
nbt.setInteger("rootDuration", rootDuration);
nbt.setInteger("slowDuration", slowDuration);
@@ -351,7 +349,6 @@ public class AbilityTrap extends Ability {
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 10.0f;
this.damageRadius = nbt.hasKey("damageRadius") ? nbt.getFloat("damageRadius") : 0.0f;
this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 0.5f;
this.knockbackUp = nbt.hasKey("knockbackUp") ? nbt.getFloat("knockbackUp") : 0.3f;
this.stunDuration = nbt.hasKey("stunDuration") ? nbt.getInteger("stunDuration") : 0;
this.rootDuration = nbt.hasKey("rootDuration") ? nbt.getInteger("rootDuration") : 40;
this.slowDuration = nbt.hasKey("slowDuration") ? nbt.getInteger("slowDuration") : 0;
@@ -392,9 +389,6 @@ public class AbilityTrap extends Ability {
public float getKnockback() { return knockback; }
public void setKnockback(float knockback) { this.knockback = knockback; }
public float getKnockbackUp() { return knockbackUp; }
public void setKnockbackUp(float knockbackUp) { this.knockbackUp = knockbackUp; }
public int getStunDuration() { return stunDuration; }
public void setStunDuration(int stunDuration) { this.stunDuration = stunDuration; }
@@ -31,8 +31,6 @@ public class AbilityVortex extends Ability {
private float pullRadius = 8.0f;
private float pullStrength = 0.8f;
private float minPullDistance = 1.5f;
private float pullToDistance = 0.0f;
private float damage = 0.0f;
private float knockback = 0.0f;
private int stunDuration = 0;
@@ -45,6 +43,7 @@ public class AbilityVortex extends Ability {
// Runtime state
private transient Set<UUID> pulledEntities = new HashSet<>();
private transient boolean pullComplete = false;
private transient int ticksSincePullDamage = 0;
public AbilityVortex() {
this.typeId = "ability.cnpc.vortex";
@@ -57,6 +56,8 @@ public class AbilityVortex extends Ability {
this.activeTicks = 40;
this.recoveryTicks = 20;
this.telegraphType = TelegraphType.CIRCLE;
this.windUpSound = "mob.ghast.charge";
this.activeSound = "mob.ghast.fireball";
}
@Override
@@ -84,6 +85,7 @@ public class AbilityVortex extends Ability {
public void onExecute(EntityNPCInterface npc, EntityLivingBase target, World world) {
pulledEntities.clear();
pullComplete = false;
ticksSincePullDamage = 0;
if (aoe) {
AxisAlignedBB box = npc.boundingBox.expand(pullRadius, pullRadius / 2, pullRadius);
@@ -96,7 +98,7 @@ public class AbilityVortex extends Ability {
if (entity.isDead) continue;
double dist = npc.getDistanceToEntity(entity);
if (dist <= pullRadius && dist > minPullDistance) {
if (dist <= pullRadius) {
pulledEntities.add(entity.getUniqueID());
count++;
if (count >= maxTargets) break;
@@ -106,7 +108,7 @@ public class AbilityVortex extends Ability {
// Single target mode - still check pullRadius
if (target != null && !target.isDead) {
double dist = npc.getDistanceToEntity(target);
if (dist <= pullRadius && dist > minPullDistance) {
if (dist <= pullRadius) {
pulledEntities.add(target.getUniqueID());
}
}
@@ -123,13 +125,8 @@ public class AbilityVortex extends Ability {
double destY = npc.posY;
double destZ = npc.posZ;
if (pullToDistance > 0) {
double yaw = Math.toRadians(npc.rotationYaw);
destX -= Math.sin(yaw) * pullToDistance;
destZ += Math.cos(yaw) * pullToDistance;
}
boolean anyStillPulling = false;
ticksSincePullDamage++;
for (UUID uuid : new HashSet<>(pulledEntities)) {
EntityLivingBase entity = findEntity(world, uuid);
@@ -143,7 +140,7 @@ public class AbilityVortex extends Ability {
double dz = destZ - entity.posZ;
double dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
if (dist <= minPullDistance) {
if (dist <= 1.0f) {
pulledEntities.remove(uuid);
onTargetArrived(npc, entity, world);
continue;
@@ -152,14 +149,25 @@ public class AbilityVortex extends Ability {
anyStillPulling = true;
double factor = pullStrength / dist;
entity.motionX = dx * factor;
entity.motionY = dy * factor * 0.5;
entity.motionZ = dz * factor;
double nextX = dx * factor;
double nextY = dy * factor * 0.5;
double nextZ = dz * factor;
AxisAlignedBB nextBox = entity.boundingBox.copy().offset(nextX, nextY, nextZ);
if (!world.getCollidingBoundingBoxes(entity, nextBox).isEmpty()) {
pulledEntities.remove(uuid);
continue;
}
entity.motionX = nextX;
entity.motionY = nextY;
entity.motionZ = nextZ;
entity.velocityChanged = true;
if (damageOnPull && pullDamage > 0) {
// Apply damage with scripted event support (no knockback during pull)
applyAbilityDamage(npc, entity, pullDamage, 0, 0);
if (damageOnPull && pullDamage > 0 && ticksSincePullDamage >= 10) {
ticksSincePullDamage = 0;
entity.hurtResistantTime = 0;
applyAbilityDamage(npc, entity, pullDamage * 0.5f, 0);
}
}
@@ -170,7 +178,7 @@ public class AbilityVortex extends Ability {
private void onTargetArrived(EntityNPCInterface npc, EntityLivingBase entity, World world) {
// Apply damage with scripted event support
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback * 0.5f, 0);
boolean wasHit = applyAbilityDamage(npc, entity, damage, knockback * 0.5f);
// Only apply effects if hit wasn't cancelled
if (wasHit) {
@@ -202,20 +210,20 @@ public class AbilityVortex extends Ability {
public void onComplete(EntityNPCInterface npc, EntityLivingBase target) {
pulledEntities.clear();
pullComplete = false;
ticksSincePullDamage = 0;
}
@Override
public void onInterrupt(EntityNPCInterface npc, DamageSource source, float damage) {
pulledEntities.clear();
pullComplete = false;
ticksSincePullDamage = 0;
}
@Override
public void writeTypeNBT(NBTTagCompound nbt) {
nbt.setFloat("pullRadius", pullRadius);
nbt.setFloat("pullStrength", pullStrength);
nbt.setFloat("minPullDistance", minPullDistance);
nbt.setFloat("pullToDistance", pullToDistance);
nbt.setFloat("damage", damage);
nbt.setFloat("knockback", knockback);
nbt.setInteger("stunDuration", stunDuration);
@@ -230,8 +238,6 @@ public class AbilityVortex extends Ability {
public void readTypeNBT(NBTTagCompound nbt) {
this.pullRadius = nbt.hasKey("pullRadius") ? nbt.getFloat("pullRadius") : 8.0f;
this.pullStrength = nbt.hasKey("pullStrength") ? nbt.getFloat("pullStrength") : 0.8f;
this.minPullDistance = nbt.hasKey("minPullDistance") ? nbt.getFloat("minPullDistance") : 1.5f;
this.pullToDistance = nbt.hasKey("pullToDistance") ? nbt.getFloat("pullToDistance") : 0.0f;
this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 0.0f;
this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 0.0f;
this.stunDuration = nbt.hasKey("stunDuration") ? nbt.getInteger("stunDuration") : 0;
@@ -249,12 +255,6 @@ public class AbilityVortex extends Ability {
public float getPullStrength() { return pullStrength; }
public void setPullStrength(float pullStrength) { this.pullStrength = pullStrength; }
public float getMinPullDistance() { return minPullDistance; }
public void setMinPullDistance(float minPullDistance) { this.minPullDistance = minPullDistance; }
public float getPullToDistance() { return pullToDistance; }
public void setPullToDistance(float pullToDistance) { this.pullToDistance = pullToDistance; }
public float getDamage() { return damage; }
public void setDamage(float damage) { this.damage = damage; }
+1 -1
View File
@@ -537,7 +537,7 @@ public class DataAbilities {
* @param hitEntity The entity being hit
* @param damage The damage amount
* @param knockback The horizontal knockback
* @param knockbackUp The vertical knockback
* @param knockbackUp The vertical knockback (deprecated, ignored)
* @return The event (with possibly modified values), or null if cancelled
*/
public AbilityEvent.HitEvent fireHitEvent(Ability ability, EntityLivingBase target,
@@ -79,6 +79,15 @@ public class CombatHandler {
aggressors.put(el, f + damageAmount);
}
// Handle guard counter before interruption
if (npc.abilities.getCurrentAbility() instanceof kamkeel.npcs.controllers.data.ability.type.AbilityGuard) {
kamkeel.npcs.controllers.data.ability.type.AbilityGuard guard =
(kamkeel.npcs.controllers.data.ability.type.AbilityGuard) npc.abilities.getCurrentAbility();
if (guard.isGuarding() && e instanceof EntityLivingBase) {
guard.onDamageTaken(npc, (EntityLivingBase) e, source, damageAmount);
}
}
// Check for ability interruption
npc.abilities.onDamage(source, damageAmount);
}
@@ -35,21 +35,16 @@ public class SubGuiAbilityCharge extends SubGuiAbilityConfig {
y += 24;
// Row 2: Knockback + Knockback Up
// Row 2: Knockback
addLabel(new GuiNpcLabel(102, "ability.knockback", labelX, y + 5));
addTextField(createFloatField(102, fieldX, y, 50, charge.getKnockback()));
addLabel(new GuiNpcLabel(103, "ability.knockbackUp", col2LabelX, y + 5));
addTextField(createFloatField(103, col2FieldX, y, 50, charge.getKnockbackUp()));
y += 24;
// Row 3: Max Distance + Hit Radius
addLabel(new GuiNpcLabel(104, "ability.maxDist", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, charge.getMaxDistance()));
// Row 3: Hit Width
addLabel(new GuiNpcLabel(104, "ability.hitWidth", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, charge.getHitWidth()));
addLabel(new GuiNpcLabel(105, "ability.hitRadius", col2LabelX, y + 5));
addTextField(createFloatField(105, col2FieldX, y, 50, charge.getHitRadius()));
}
@Override
@@ -58,9 +53,7 @@ public class SubGuiAbilityCharge extends SubGuiAbilityConfig {
case 100: charge.setDamage(parseFloat(field, charge.getDamage())); break;
case 101: charge.setChargeSpeed(parseFloat(field, charge.getChargeSpeed())); break;
case 102: charge.setKnockback(parseFloat(field, charge.getKnockback())); break;
case 103: charge.setKnockbackUp(parseFloat(field, charge.getKnockbackUp())); break;
case 104: charge.setMaxDistance(parseFloat(field, charge.getMaxDistance())); break;
case 105: charge.setHitRadius(parseFloat(field, charge.getHitRadius())); break;
case 104: charge.setHitWidth(parseFloat(field, charge.getHitWidth())); break;
}
}
}
@@ -45,18 +45,18 @@ public class SubGuiAbilityCutter extends SubGuiAbilityConfig {
y += 24;
// Row 3: Knockback + Knockback Up
// Row 3: Knockback + Sweep Speed
addLabel(new GuiNpcLabel(104, "ability.knockback", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, cutter.getKnockback()));
addLabel(new GuiNpcLabel(105, "ability.knockbackUp", col2LabelX, y + 5));
addTextField(createFloatField(105, col2FieldX, y, 50, cutter.getKnockbackUp()));
addLabel(new GuiNpcLabel(105, "ability.sweepSpeed", col2LabelX, y + 5));
addTextField(createFloatField(105, col2FieldX, y, 50, cutter.getSweepSpeed()));
y += 24;
// Row 4: Sweep Mode + Piercing
addLabel(new GuiNpcLabel(106, "ability.sweepMode", labelX, y + 5));
String[] sweepModes = {"Instant", "Expanding", "Rotating"};
String[] sweepModes = {"Swipe", "Spin"};
addButton(new GuiNpcButton(106, fieldX, y, 70, 20, sweepModes, cutter.getSweepMode().ordinal()));
addLabel(new GuiNpcLabel(107, "ability.piercing", col2LabelX, y + 5));
@@ -64,12 +64,18 @@ public class SubGuiAbilityCutter extends SubGuiAbilityConfig {
y += 24;
// Row 5: Stun Duration + Bleed Duration
// Row 5: Stun Duration + Poison Time
addLabel(new GuiNpcLabel(108, "ability.stunDuration", labelX, y + 5));
addTextField(createIntField(108, fieldX, y, 50, cutter.getStunDuration()));
addLabel(new GuiNpcLabel(109, "ability.bleedDuration", col2LabelX, y + 5));
addTextField(createIntField(109, col2FieldX, y, 50, cutter.getBleedDuration()));
addLabel(new GuiNpcLabel(109, "ability.poisonTime", col2LabelX, y + 5));
addTextField(createIntField(109, col2FieldX, y, 50, cutter.getPoisonDurationSeconds()));
y += 24;
// Row 6: Poison Level
addLabel(new GuiNpcLabel(110, "ability.poisonLvl", labelX, y + 5));
addTextField(createIntField(110, fieldX, y, 50, cutter.getPoisonLevel()));
}
@Override
@@ -89,9 +95,10 @@ public class SubGuiAbilityCutter extends SubGuiAbilityConfig {
case 102: cutter.setArcAngle(parseFloat(field, cutter.getArcAngle())); break;
case 103: cutter.setInnerRadius(parseFloat(field, cutter.getInnerRadius())); break;
case 104: cutter.setKnockback(parseFloat(field, cutter.getKnockback())); break;
case 105: cutter.setKnockbackUp(parseFloat(field, cutter.getKnockbackUp())); break;
case 105: cutter.setSweepSpeed(parseFloat(field, cutter.getSweepSpeed())); break;
case 108: cutter.setStunDuration(field.getInteger()); break;
case 109: cutter.setBleedDuration(field.getInteger()); break;
case 109: cutter.setPoisonDurationSeconds(field.getInteger()); break;
case 110: cutter.setPoisonLevel(field.getInteger()); break;
}
}
}
@@ -28,34 +28,58 @@ public class SubGuiAbilityGuard extends SubGuiAbilityConfig {
int col2FieldX = guiLeft + 225;
// Row 1: Damage Reduction
addLabel(new GuiNpcLabel(100, "ability.dmgReduction", labelX, y + 5));
addLabel(new GuiNpcLabel(100, "ability.dmgReduce", labelX, y + 5));
addTextField(createFloatField(100, fieldX, y, 50, guard.getDamageReduction()));
y += 24;
// Row 2: Can Counter + Counter Damage
// Row 2: Can Counter + Counter Type
addLabel(new GuiNpcLabel(101, "ability.canCounter", labelX, y + 5));
addButton(new GuiNpcButton(101, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, guard.isCanCounter() ? 1 : 0));
addLabel(new GuiNpcLabel(102, "ability.counterDmg", col2LabelX, y + 5));
GuiNpcTextField counterDmgField = createFloatField(102, col2FieldX, y, 40, guard.getCounterDamage());
counterDmgField.setEnabled(guard.isCanCounter());
addTextField(counterDmgField);
addLabel(new GuiNpcLabel(102, "ability.counterType", col2LabelX, y + 5));
String[] types = {"Flat", "Percent"};
GuiNpcButton counterTypeButton = new GuiNpcButton(102, col2FieldX, y, 60, 20, types, guard.getCounterType().ordinal());
counterTypeButton.setEnabled(guard.isCanCounter());
addButton(counterTypeButton);
y += 24;
// Row 3: Counter Chance
addLabel(new GuiNpcLabel(103, "ability.counterChance", labelX, y + 5));
GuiNpcTextField counterChanceField = createFloatField(103, fieldX, y, 50, guard.getCounterChance());
// Row 3: Counter Value + Counter Chance
addLabel(new GuiNpcLabel(103, "ability.counterValue", labelX, y + 5));
GuiNpcTextField counterValueField = createFloatField(103, fieldX, y, 50, guard.getCounterValue());
counterValueField.setEnabled(guard.isCanCounter());
addTextField(counterValueField);
addLabel(new GuiNpcLabel(104, "ability.counterChance", col2LabelX, y + 5));
GuiNpcTextField counterChanceField = createFloatField(104, col2FieldX, y, 50, guard.getCounterChance());
counterChanceField.setEnabled(guard.isCanCounter());
addTextField(counterChanceField);
y += 24;
// Row 4: Counter Sound + Counter Animation
addLabel(new GuiNpcLabel(105, "ability.counterSound", labelX, y + 5));
GuiNpcTextField counterSoundField = new GuiNpcTextField(105, this, fontRendererObj, fieldX, y, 100, 20, guard.getCounterSound());
counterSoundField.setEnabled(guard.isCanCounter());
addTextField(counterSoundField);
addLabel(new GuiNpcLabel(106, "ability.counterAnim", col2LabelX, y + 5));
GuiNpcTextField counterAnimField = createIntField(106, col2FieldX, y, 50, guard.getCounterAnimationId());
counterAnimField.setEnabled(guard.isCanCounter());
addTextField(counterAnimField);
}
@Override
protected void handleTypeButton(int id, GuiNpcButton button) {
if (id == 101) {
guard.setCanCounter(button.getValue() == 1);
initGui();
switch (id) {
case 101:
guard.setCanCounter(button.getValue() == 1);
initGui();
break;
case 102:
guard.setCounterType(AbilityGuard.CounterType.values()[button.getValue()]);
break;
}
}
@@ -63,8 +87,10 @@ public class SubGuiAbilityGuard extends SubGuiAbilityConfig {
protected void handleTypeTextField(int id, GuiNpcTextField field) {
switch (id) {
case 100: guard.setDamageReduction(parseFloat(field, guard.getDamageReduction())); break;
case 102: guard.setCounterDamage(parseFloat(field, guard.getCounterDamage())); break;
case 103: guard.setCounterChance(parseFloat(field, guard.getCounterChance())); break;
case 103: guard.setCounterValue(parseFloat(field, guard.getCounterValue())); break;
case 104: guard.setCounterChance(parseFloat(field, guard.getCounterChance())); break;
case 105: guard.setCounterSound(field.getText()); break;
case 106: guard.setCounterAnimationId(field.getInteger()); break;
}
}
}
@@ -26,30 +26,37 @@ public class SubGuiAbilityHeavyHit extends SubGuiAbilityConfig {
int col2LabelX = guiLeft + 145;
int col2FieldX = guiLeft + 205;
// Row 1: Damage + Stun Ticks
// Row 1: Damage + Potion Time
addLabel(new GuiNpcLabel(100, "ability.damage", labelX, y + 5));
addTextField(createFloatField(100, fieldX, y, 50, heavyHit.getDamage()));
addLabel(new GuiNpcLabel(101, "ability.stunTicks", col2LabelX, y + 5));
addTextField(createIntField(101, col2FieldX, y, 50, heavyHit.getStunTicks()));
addLabel(new GuiNpcLabel(101, "ability.potionTime", col2LabelX, y + 5));
addTextField(createIntField(101, col2FieldX, y, 50, heavyHit.getPotionDurationSeconds()));
y += 24;
// Row 2: Knockback + Knockback Up
// Row 2: Knockback + Slowness Level
addLabel(new GuiNpcLabel(102, "ability.knockback", labelX, y + 5));
addTextField(createFloatField(102, fieldX, y, 50, heavyHit.getKnockback()));
addLabel(new GuiNpcLabel(103, "ability.knockbackUp", col2LabelX, y + 5));
addTextField(createFloatField(103, col2FieldX, y, 50, heavyHit.getKnockbackUp()));
addLabel(new GuiNpcLabel(103, "ability.slownessLvl", col2LabelX, y + 5));
addTextField(createIntField(103, col2FieldX, y, 50, heavyHit.getSlownessLevel()));
y += 24;
// Row 3: Weakness Level
addLabel(new GuiNpcLabel(104, "ability.weaknessLvl", labelX, y + 5));
addTextField(createIntField(104, fieldX, y, 50, heavyHit.getWeaknessLevel()));
}
@Override
protected void handleTypeTextField(int id, GuiNpcTextField field) {
switch (id) {
case 100: heavyHit.setDamage(parseFloat(field, heavyHit.getDamage())); break;
case 101: heavyHit.setStunTicks(field.getInteger()); break;
case 101: heavyHit.setPotionDurationSeconds(field.getInteger()); break;
case 102: heavyHit.setKnockback(parseFloat(field, heavyHit.getKnockback())); break;
case 103: heavyHit.setKnockbackUp(parseFloat(field, heavyHit.getKnockbackUp())); break;
case 103: heavyHit.setSlownessLevel(field.getInteger()); break;
case 104: heavyHit.setWeaknessLevel(field.getInteger()); break;
}
}
}
@@ -3,7 +3,6 @@ package noppes.npcs.client.gui.advanced.ability;
import kamkeel.npcs.controllers.data.ability.type.AbilityShockwave;
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.gui.util.GuiNpcLabel;
import noppes.npcs.client.gui.util.GuiNpcTextField;
@@ -36,21 +35,21 @@ public class SubGuiAbilityShockwave extends SubGuiAbilityConfig {
y += 24;
// Row 2: Push Strength + Push Up
// Row 2: Push Strength
addLabel(new GuiNpcLabel(102, "ability.pushStrength", labelX, y + 5));
addTextField(createFloatField(102, fieldX, y, 50, shockwave.getPushStrength()));
addLabel(new GuiNpcLabel(103, "ability.pushUp", col2LabelX, y + 5));
addTextField(createFloatField(103, col2FieldX, y, 50, shockwave.getPushUp()));
y += 24;
// Row 3: Stun Duration + Max Targets
addLabel(new GuiNpcLabel(104, "ability.stunDuration", labelX, y + 5));
addTextField(createIntField(104, fieldX, y, 50, shockwave.getStunDuration()));
addLabel(new GuiNpcLabel(103, "ability.stunDuration", labelX, y + 5));
addTextField(createIntField(103, fieldX, y, 50, shockwave.getStunDuration()));
addLabel(new GuiNpcLabel(105, "ability.maxTargets", col2LabelX, y + 5));
addTextField(createIntField(105, col2FieldX, y, 50, shockwave.getMaxTargets()));
addLabel(new GuiNpcLabel(104, "ability.maxTargets", col2LabelX, y + 5));
addTextField(createIntField(104, col2FieldX, y, 50, shockwave.getMaxTargets()));
y += 24;
addLabel(new GuiNpcLabel(105, "ability.shockwaveFalloff", labelX, y + 5));
}
@Override
@@ -59,9 +58,8 @@ public class SubGuiAbilityShockwave extends SubGuiAbilityConfig {
case 100: shockwave.setDamage(parseFloat(field, shockwave.getDamage())); break;
case 101: shockwave.setPushRadius(parseFloat(field, shockwave.getPushRadius())); break;
case 102: shockwave.setPushStrength(parseFloat(field, shockwave.getPushStrength())); break;
case 103: shockwave.setPushUp(parseFloat(field, shockwave.getPushUp())); break;
case 104: shockwave.setStunDuration(field.getInteger()); break;
case 105: shockwave.setMaxTargets(field.getInteger()); break;
case 103: shockwave.setStunDuration(field.getInteger()); break;
case 104: shockwave.setMaxTargets(field.getInteger()); break;
}
}
}
@@ -3,7 +3,6 @@ package noppes.npcs.client.gui.advanced.ability;
import kamkeel.npcs.controllers.data.ability.type.AbilitySlam;
import noppes.npcs.client.gui.util.IAbilityConfigCallback;
import noppes.npcs.client.gui.advanced.SubGuiAbilityConfig;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.gui.util.GuiNpcLabel;
import noppes.npcs.client.gui.util.GuiNpcTextField;
@@ -45,12 +44,9 @@ public class SubGuiAbilitySlam extends SubGuiAbilityConfig {
y += 24;
// Row 3: Min/Max Leap Distance
addLabel(new GuiNpcLabel(104, "ability.minDist", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, slam.getMinLeapDistance()));
addLabel(new GuiNpcLabel(105, "ability.maxDist", col2LabelX, y + 5));
addTextField(createFloatField(105, col2FieldX, y, 50, slam.getMaxLeapDistance()));
// Row 3: Leap Height
addLabel(new GuiNpcLabel(104, "ability.leapHeight", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, slam.getLeapHeight()));
}
@Override
@@ -60,8 +56,7 @@ public class SubGuiAbilitySlam extends SubGuiAbilityConfig {
case 101: slam.setRadius(parseFloat(field, slam.getRadius())); break;
case 102: slam.setKnockbackStrength(parseFloat(field, slam.getKnockbackStrength())); break;
case 103: slam.setLeapSpeed(parseFloat(field, slam.getLeapSpeed())); break;
case 104: slam.setMinLeapDistance(parseFloat(field, slam.getMinLeapDistance())); break;
case 105: slam.setMaxLeapDistance(parseFloat(field, slam.getMaxLeapDistance())); break;
case 104: slam.setLeapHeight(parseFloat(field, slam.getLeapHeight())); break;
}
}
}
@@ -27,55 +27,77 @@ public class SubGuiAbilityTeleport extends SubGuiAbilityConfig {
int col2LabelX = guiLeft + 145;
int col2FieldX = guiLeft + 205;
// Row 1: Pattern
addLabel(new GuiNpcLabel(100, "ability.pattern", labelX, y + 5));
String[] patterns = {"Random", "Toward", "Away", "Behind", "InFront", "Around", "ToTarget"};
addButton(new GuiNpcButton(100, fieldX, y, 80, 20, patterns, teleport.getPattern().ordinal()));
// Row 1: Mode
addLabel(new GuiNpcLabel(100, "ability.mode", labelX, y + 5));
String[] modes = {"Blink", "Behind", "Single"};
addButton(new GuiNpcButton(100, fieldX, y, 80, 20, modes, teleport.getMode().ordinal()));
y += 24;
// Row 2: Blink Radius + Min Blink Radius
addLabel(new GuiNpcLabel(101, "ability.blinkRadius", labelX, y + 5));
addTextField(createFloatField(101, fieldX, y, 50, teleport.getBlinkRadius()));
switch (teleport.getMode()) {
case BLINK:
// Row 2: Blink Radius + Blink Count
addLabel(new GuiNpcLabel(101, "ability.blinkRadius", labelX, y + 5));
addTextField(createFloatField(101, fieldX, y, 50, teleport.getBlinkRadius()));
addLabel(new GuiNpcLabel(102, "ability.minBlinkRad", col2LabelX, y + 5));
addTextField(createFloatField(102, col2FieldX, y, 50, teleport.getMinBlinkRadius()));
addLabel(new GuiNpcLabel(102, "ability.blinkCount", col2LabelX, y + 5));
addTextField(createIntField(102, col2FieldX, y, 50, teleport.getBlinkCount()));
y += 24;
// Row 3: Blink Delay + Line of Sight
addLabel(new GuiNpcLabel(103, "ability.blinkDelay", labelX, y + 5));
addTextField(createIntField(103, fieldX, y, 50, teleport.getBlinkDelayTicks()));
addLabel(new GuiNpcLabel(105, "ability.lineOfSight", col2LabelX, y + 5));
addButton(new GuiNpcButton(105, col2FieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isRequireLineOfSight() ? 1 : 0));
y += 24;
break;
case SINGLE:
// Row 2: Blink Radius + Line of Sight
addLabel(new GuiNpcLabel(101, "ability.blinkRadius", labelX, y + 5));
addTextField(createFloatField(101, fieldX, y, 50, teleport.getBlinkRadius()));
addLabel(new GuiNpcLabel(105, "ability.lineOfSight", col2LabelX, y + 5));
addButton(new GuiNpcButton(105, col2FieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isRequireLineOfSight() ? 1 : 0));
y += 24;
break;
case BEHIND:
// Row 2: Behind Distance
addLabel(new GuiNpcLabel(104, "ability.behindDistance", labelX, y + 5));
addTextField(createFloatField(104, fieldX, y, 50, teleport.getBehindDistance()));
y += 24;
break;
}
// Damage + Damage Radius
addLabel(new GuiNpcLabel(106, "ability.damage", labelX, y + 5));
addTextField(createFloatField(106, fieldX, y, 50, teleport.getDamage()));
addLabel(new GuiNpcLabel(107, "ability.dmgRadius", col2LabelX, y + 5));
addTextField(createFloatField(107, col2FieldX, y, 50, teleport.getDamageRadius()));
y += 24;
// Row 3: Blink Count + Blink Delay
addLabel(new GuiNpcLabel(103, "ability.blinkCount", labelX, y + 5));
addTextField(createIntField(103, fieldX, y, 50, teleport.getBlinkCount()));
// Damage at Start/End
addLabel(new GuiNpcLabel(108, "ability.dmgAtStart", labelX, y + 5));
addButton(new GuiNpcButton(108, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isDamageAtStart() ? 1 : 0));
addLabel(new GuiNpcLabel(104, "ability.blinkDelay", col2LabelX, y + 5));
addTextField(createIntField(104, col2FieldX, y, 50, teleport.getBlinkDelayTicks()));
y += 24;
// Row 4: Damage + Damage Radius
addLabel(new GuiNpcLabel(105, "ability.damage", labelX, y + 5));
addTextField(createFloatField(105, fieldX, y, 50, teleport.getDamage()));
addLabel(new GuiNpcLabel(106, "ability.dmgRadius", col2LabelX, y + 5));
addTextField(createFloatField(106, col2FieldX, y, 50, teleport.getDamageRadius()));
y += 24;
// Row 5: Damage at Start/End + Require LOS
addLabel(new GuiNpcLabel(107, "ability.dmgAtStart", labelX, y + 5));
addButton(new GuiNpcButton(107, fieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isDamageAtStart() ? 1 : 0));
addLabel(new GuiNpcLabel(108, "ability.dmgAtEnd", col2LabelX, y + 5));
addButton(new GuiNpcButton(108, col2FieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isDamageAtEnd() ? 1 : 0));
addLabel(new GuiNpcLabel(109, "ability.dmgAtEnd", col2LabelX, y + 5));
addButton(new GuiNpcButton(109, col2FieldX, y, 50, 20, new String[]{"gui.no", "gui.yes"}, teleport.isDamageAtEnd() ? 1 : 0));
}
@Override
protected void handleTypeButton(int id, GuiNpcButton button) {
int value = button.getValue();
switch (id) {
case 100: teleport.setPattern(AbilityTeleport.TeleportPattern.values()[value]); break;
case 107: teleport.setDamageAtStart(value == 1); break;
case 108: teleport.setDamageAtEnd(value == 1); break;
case 100:
teleport.setMode(AbilityTeleport.TeleportMode.values()[value]);
initGui();
break;
case 105: teleport.setRequireLineOfSight(value == 1); break;
case 108: teleport.setDamageAtStart(value == 1); break;
case 109: teleport.setDamageAtEnd(value == 1); break;
}
}
@@ -83,11 +105,11 @@ public class SubGuiAbilityTeleport extends SubGuiAbilityConfig {
protected void handleTypeTextField(int id, GuiNpcTextField field) {
switch (id) {
case 101: teleport.setBlinkRadius(parseFloat(field, teleport.getBlinkRadius())); break;
case 102: teleport.setMinBlinkRadius(parseFloat(field, teleport.getMinBlinkRadius())); break;
case 103: teleport.setBlinkCount(field.getInteger()); break;
case 104: teleport.setBlinkDelayTicks(field.getInteger()); break;
case 105: teleport.setDamage(parseFloat(field, teleport.getDamage())); break;
case 106: teleport.setDamageRadius(parseFloat(field, teleport.getDamageRadius())); break;
case 102: teleport.setBlinkCount(field.getInteger()); break;
case 103: teleport.setBlinkDelayTicks(field.getInteger()); break;
case 104: teleport.setBehindDistance(parseFloat(field, teleport.getBehindDistance())); break;
case 106: teleport.setDamage(parseFloat(field, teleport.getDamage())); break;
case 107: teleport.setDamageRadius(parseFloat(field, teleport.getDamageRadius())); break;
}
}
}
@@ -64,12 +64,9 @@ public class SubGuiAbilityTrap extends SubGuiAbilityConfig {
y += 24;
// Row 5: Knockback + Knockback Up
// Row 5: Knockback
addLabel(new GuiNpcLabel(108, "ability.knockback", labelX, y + 5));
addTextField(createFloatField(108, fieldX, y, 50, trap.getKnockback()));
addLabel(new GuiNpcLabel(109, "ability.knockbackUp", col2LabelX, y + 5));
addTextField(createFloatField(109, col2FieldX, y, 50, trap.getKnockbackUp()));
}
@Override
@@ -90,7 +87,6 @@ public class SubGuiAbilityTrap extends SubGuiAbilityConfig {
case 106: trap.setRootDuration(field.getInteger()); break;
case 107: trap.setStunDuration(field.getInteger()); break;
case 108: trap.setKnockback(parseFloat(field, trap.getKnockback())); break;
case 109: trap.setKnockbackUp(parseFloat(field, trap.getKnockbackUp())); break;
}
}
}