mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 15:27:29 +00:00
Revise ability logic and configs
This commit is contained in:
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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user