Refactor ProtectionAuraHandler: improve energy calculation and armor damage handling
This commit is contained in:
parent
4d35361b28
commit
ed8c4433be
@ -20,127 +20,138 @@ public final class ProtectionAuraHandler {
|
|||||||
private static final float BASE_RECHARGE_RATE = 0.0005f;
|
private static final float BASE_RECHARGE_RATE = 0.0005f;
|
||||||
private static final float BASE_DRAIN_RATE = 0.0008f;
|
private static final float BASE_DRAIN_RATE = 0.0008f;
|
||||||
|
|
||||||
private static final float CASCADE_LOSS = 0.30f; // 30% relative
|
private static final float CASCADE_LOSS = 0.30f;
|
||||||
private static final int CRITICAL_PCT = 10;
|
private static final int CRITICAL_PCT = 10;
|
||||||
|
|
||||||
private ProtectionAuraHandler() {}
|
private ProtectionAuraHandler() {}
|
||||||
|
|
||||||
/* ==========================================================
|
/* ==========================================================
|
||||||
ENTRY POINT — SERVER SIDE
|
ENTRY POINT
|
||||||
========================================================== */
|
========================================================== */
|
||||||
|
|
||||||
public static void tick(PlayerEntity player) {
|
public static void tick(PlayerEntity player) {
|
||||||
if (!hasFullChipperArmor(player)) return;
|
if (!hasFullChipperArmor(player)) return;
|
||||||
|
|
||||||
Float value = player.getDataTracker().get(CHIPI_ENERGY);
|
Float energy = player.getDataTracker().get(CHIPI_ENERGY);
|
||||||
if (value == null) return;
|
if (energy == null) return;
|
||||||
|
|
||||||
float durabilityFactor = getDurabilityFactor(player);
|
float durabilityFactor = getDurabilityFactor(player);
|
||||||
if (durabilityFactor <= 0f) return;
|
if (durabilityFactor <= 0f) return;
|
||||||
|
|
||||||
boolean inChipi = isInChipi(player.getWorld());
|
float nextEnergy = calculateNextEnergy(player, energy, durabilityFactor);
|
||||||
boolean protectedAura = isOnProtectedBlock(player);
|
if (nextEnergy == energy) return;
|
||||||
|
|
||||||
float rechargeRate = BASE_RECHARGE_RATE * durabilityFactor;
|
applyEnergyDelta(player, energy, nextEnergy);
|
||||||
float drainRate = BASE_DRAIN_RATE * (1.0f + (1.0f - durabilityFactor));
|
player.getDataTracker().set(CHIPI_ENERGY, nextEnergy);
|
||||||
|
}
|
||||||
|
|
||||||
float next = (!inChipi || protectedAura)
|
/* ==========================================================
|
||||||
? Math.min(1.0f, value + rechargeRate)
|
ENERGY
|
||||||
: Math.max(0.0f, value - drainRate);
|
========================================================== */
|
||||||
|
|
||||||
if (next == value) return;
|
private static float calculateNextEnergy(PlayerEntity player, float current, float durabilityFactor) {
|
||||||
|
boolean recharge = !isInChipi(player.getWorld()) || isOnProtectedBlock(player);
|
||||||
|
|
||||||
int oldPercent = (int) (value * 100f);
|
float rate = recharge
|
||||||
int newPercent = (int) (next * 100f);
|
? BASE_RECHARGE_RATE * durabilityFactor
|
||||||
int delta = Math.abs(newPercent - oldPercent);
|
: BASE_DRAIN_RATE * (1.0f + (1.0f - durabilityFactor));
|
||||||
|
|
||||||
|
return recharge
|
||||||
|
? Math.min(1.0f, current + rate)
|
||||||
|
: Math.max(0.0f, current - rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyEnergyDelta(PlayerEntity player, float before, float after) {
|
||||||
|
int oldPct = (int) (before * 100f);
|
||||||
|
int newPct = (int) (after * 100f);
|
||||||
|
int delta = Math.abs(newPct - oldPct);
|
||||||
|
|
||||||
if (delta > 0) {
|
if (delta > 0) {
|
||||||
damageArmor(player, delta);
|
applyArmorDamage(player, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getDataTracker().set(CHIPI_ENERGY, next);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================
|
/* ==========================================================
|
||||||
ARMOR CHECK
|
ARMOR DAMAGE
|
||||||
========================================================== */
|
========================================================== */
|
||||||
|
|
||||||
public static boolean hasFullChipperArmor(PlayerEntity player) {
|
private static void applyArmorDamage(PlayerEntity player, int amount) {
|
||||||
PlayerInventory inv = player.getInventory();
|
|
||||||
return inv.getArmorStack(3).isOf(ModItems.CHIPPER_HELMET)
|
|
||||||
&& inv.getArmorStack(2).isOf(ModItems.CHIPPER_CHESTPLATE)
|
|
||||||
&& inv.getArmorStack(1).isOf(ModItems.CHIPPER_LEGGINGS)
|
|
||||||
&& inv.getArmorStack(0).isOf(ModItems.CHIPPER_BOOTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================
|
|
||||||
DURABILITY LOGIC
|
|
||||||
========================================================== */
|
|
||||||
|
|
||||||
private static float getDurabilityFactor(PlayerEntity player) {
|
|
||||||
int max = 0, current = 0;
|
|
||||||
|
|
||||||
for (ItemStack stack : player.getArmorItems()) {
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
max += stack.getMaxDamage();
|
|
||||||
current += stack.getMaxDamage() - stack.getDamage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max <= 0) return 0f;
|
|
||||||
return Math.min(1f, (float) current / max);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void damageArmor(PlayerEntity player, int amount) {
|
|
||||||
int[] before = getArmorPercents(player);
|
int[] before = getArmorPercents(player);
|
||||||
|
boolean broke = damageAllPieces(player, amount);
|
||||||
|
|
||||||
|
if (broke) {
|
||||||
|
handleCascade(player, before);
|
||||||
|
} else {
|
||||||
|
handleWarnings(player, before, getArmorPercents(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean damageAllPieces(PlayerEntity player, int amount) {
|
||||||
boolean broke = false;
|
boolean broke = false;
|
||||||
|
|
||||||
for (ItemStack stack : player.getArmorItems()) {
|
for (ItemStack stack : player.getArmorItems()) {
|
||||||
if (!stack.isEmpty()) {
|
if (stack.isEmpty()) continue;
|
||||||
|
|
||||||
stack.damage(amount, player, p -> {});
|
stack.damage(amount, player, p -> {});
|
||||||
if (stack.getDamage() >= stack.getMaxDamage()) {
|
if (stack.getDamage() >= stack.getMaxDamage()) {
|
||||||
broke = true;
|
broke = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return broke;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (broke) {
|
/* ==========================================================
|
||||||
applyCascadeDamage(player, before);
|
CASCADE
|
||||||
} else {
|
========================================================== */
|
||||||
sendWarningIfNeeded(player, before, getArmorPercents(player));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void applyCascadeDamage(PlayerEntity player, int[] before) {
|
|
||||||
for (ItemStack stack : player.getArmorItems()) {
|
|
||||||
if (stack.isEmpty()) continue;
|
|
||||||
|
|
||||||
int max = stack.getMaxDamage();
|
|
||||||
int current = max - stack.getDamage();
|
|
||||||
if (current <= 0) continue;
|
|
||||||
|
|
||||||
int extra = Math.round(current * CASCADE_LOSS);
|
|
||||||
stack.setDamage(Math.min(max, stack.getDamage() + extra));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private static void handleCascade(PlayerEntity player, int[] before) {
|
||||||
|
applyCascadeLoss(player);
|
||||||
player.getDataTracker().set(CHIPI_ENERGY, 0f);
|
player.getDataTracker().set(CHIPI_ENERGY, 0f);
|
||||||
sendCollapseMessage(player, before, getArmorPercents(player));
|
sendCollapseMessage(player, before, getArmorPercents(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void applyCascadeLoss(PlayerEntity player) {
|
||||||
|
for (ItemStack stack : player.getArmorItems()) {
|
||||||
|
if (stack.isEmpty()) continue;
|
||||||
|
|
||||||
|
int max = stack.getMaxDamage();
|
||||||
|
int remaining = max - stack.getDamage();
|
||||||
|
if (remaining <= 0) continue;
|
||||||
|
|
||||||
|
int extra = Math.round(remaining * CASCADE_LOSS);
|
||||||
|
stack.setDamage(Math.min(max, stack.getDamage() + extra));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================
|
/* ==========================================================
|
||||||
CHAT MESSAGES (PLAYER ONLY)
|
WARNINGS
|
||||||
========================================================== */
|
========================================================== */
|
||||||
|
|
||||||
private static void sendWarningIfNeeded(PlayerEntity player, int[] before, int[] after) {
|
private static void handleWarnings(PlayerEntity player, int[] before, int[] after) {
|
||||||
boolean trigger = false;
|
if (!enteredCritical(before, after)) return;
|
||||||
|
player.sendMessage(Text.literal(buildWarningMessage(after)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean enteredCritical(int[] before, int[] after) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (before[i] > CRITICAL_PCT && after[i] <= CRITICAL_PCT) {
|
if (before[i] > CRITICAL_PCT && after[i] <= CRITICAL_PCT) {
|
||||||
trigger = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!trigger) return;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
player.sendMessage(Text.literal(buildWarningMessage(after)), false);
|
/* ==========================================================
|
||||||
|
CHAT BUILDERS
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
private static String buildWarningMessage(int[] pct) {
|
||||||
|
StringBuilder sb = new StringBuilder("§6[AURA WARNING]\n");
|
||||||
|
appendPiece(sb, "Head", pct[3]);
|
||||||
|
appendPiece(sb, "Body", pct[2]);
|
||||||
|
appendPiece(sb, "Legs", pct[1]);
|
||||||
|
appendPiece(sb, "Feet", pct[0]);
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendCollapseMessage(PlayerEntity player, int[] before, int[] after) {
|
private static void sendCollapseMessage(PlayerEntity player, int[] before, int[] after) {
|
||||||
@ -152,15 +163,6 @@ public final class ProtectionAuraHandler {
|
|||||||
player.sendMessage(Text.literal(sb.toString()), false);
|
player.sendMessage(Text.literal(sb.toString()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildWarningMessage(int[] pct) {
|
|
||||||
StringBuilder sb = new StringBuilder("§6[AURA WARNING]\n");
|
|
||||||
appendPiece(sb, "Head", pct[3]);
|
|
||||||
appendPiece(sb, "Body", pct[2]);
|
|
||||||
appendPiece(sb, "Legs", pct[1]);
|
|
||||||
appendPiece(sb, "Feet", pct[0]);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void appendPiece(StringBuilder sb, String name, int pct) {
|
private static void appendPiece(StringBuilder sb, String name, int pct) {
|
||||||
sb.append("§7").append(name).append(": ").append(pct).append("%");
|
sb.append("§7").append(name).append(": ").append(pct).append("%");
|
||||||
if (pct <= CRITICAL_PCT) sb.append(" §c!!!");
|
if (pct <= CRITICAL_PCT) sb.append(" §c!!!");
|
||||||
@ -172,9 +174,14 @@ public final class ProtectionAuraHandler {
|
|||||||
.append(after).append("% (was ").append(before).append("%)\n");
|
.append(after).append("% (was ").append(before).append("%)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
UTIL
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
private static int[] getArmorPercents(PlayerEntity player) {
|
private static int[] getArmorPercents(PlayerEntity player) {
|
||||||
int[] out = new int[4];
|
int[] out = new int[4];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (ItemStack stack : player.getArmorItems()) {
|
for (ItemStack stack : player.getArmorItems()) {
|
||||||
if (stack.isEmpty()) {
|
if (stack.isEmpty()) {
|
||||||
out[i++] = 0;
|
out[i++] = 0;
|
||||||
@ -187,20 +194,38 @@ public final class ProtectionAuraHandler {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static float getDurabilityFactor(PlayerEntity player) {
|
||||||
|
int max = 0, cur = 0;
|
||||||
|
|
||||||
|
for (ItemStack stack : player.getArmorItems()) {
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
max += stack.getMaxDamage();
|
||||||
|
cur += stack.getMaxDamage() - stack.getDamage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max <= 0 ? 0f : Math.min(1f, (float) cur / max);
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================
|
/* ==========================================================
|
||||||
AURA CONDITIONS
|
CONDITIONS
|
||||||
========================================================== */
|
========================================================== */
|
||||||
|
|
||||||
|
public static boolean hasFullChipperArmor(PlayerEntity player) {
|
||||||
|
PlayerInventory inv = player.getInventory();
|
||||||
|
return inv.getArmorStack(3).isOf(ModItems.CHIPPER_HELMET)
|
||||||
|
&& inv.getArmorStack(2).isOf(ModItems.CHIPPER_CHESTPLATE)
|
||||||
|
&& inv.getArmorStack(1).isOf(ModItems.CHIPPER_LEGGINGS)
|
||||||
|
&& inv.getArmorStack(0).isOf(ModItems.CHIPPER_BOOTS);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isOnProtectedBlock(PlayerEntity player) {
|
private static boolean isOnProtectedBlock(PlayerEntity player) {
|
||||||
BlockPos pos = player.getBlockPos();
|
BlockPos pos = player.getBlockPos();
|
||||||
BlockState state = player.getWorld().getBlockState(pos);
|
BlockState state = player.getWorld().getBlockState(pos);
|
||||||
|
|
||||||
if (!state.contains(Properties.WATERLOGGED) || !state.get(Properties.WATERLOGGED)) {
|
return state.contains(Properties.WATERLOGGED)
|
||||||
return false;
|
&& state.get(Properties.WATERLOGGED)
|
||||||
}
|
&& (state.getBlock() instanceof StairsBlock
|
||||||
|
|| state.getBlock() instanceof SlabBlock);
|
||||||
return state.getBlock() instanceof StairsBlock
|
|
||||||
|| state.getBlock() instanceof SlabBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInChipi(World world) {
|
private static boolean isInChipi(World world) {
|
||||||
@ -209,7 +234,7 @@ public final class ProtectionAuraHandler {
|
|||||||
|
|
||||||
public static boolean hasAura(PlayerEntity player) {
|
public static boolean hasAura(PlayerEntity player) {
|
||||||
if (!hasFullChipperArmor(player)) return false;
|
if (!hasFullChipperArmor(player)) return false;
|
||||||
Float value = player.getDataTracker().get(CHIPI_ENERGY);
|
Float v = player.getDataTracker().get(CHIPI_ENERGY);
|
||||||
return value != null && value > 0f && getDurabilityFactor(player) > 0f;
|
return v != null && v > 0f && getDurabilityFactor(player) > 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user