Fix Critical and Attribute Handling for CNPC+ and DBC Addon

This commit is contained in:
Kam committed 2026-03-03 04:06:34 -05:00
1 parent 159b740f39
commit c3096b320e
2 files changed
+55 -4

No files matched your search

@@ -20,6 +20,13 @@ import static kamkeel.npcs.controllers.AttributeController.getTracker;
public class AttributeAttackUtil {
private static final Random random = new Random();
/**
* Crit decision from the last LivingAttackEvent for vanilla/modded mob targets.
* Set in LivingAttackEvent, consumed in LivingHurtEvent.
* null = no roll occurred, true = critted, false = did not crit.
*/
public static Boolean lastAttackCritted = null;
// --- Helper Classes & Methods ---
// Container for allocation results.
@@ -168,10 +175,31 @@ public class AttributeAttackUtil {
public static float applyCrit(float damage, PlayerAttributeTracker tracker) {
if (ConfigMain.AttributesEnabled) {
if (rollCrit(tracker))
damage = applyCritDamage(damage, tracker);
}
return damage;
}
/**
* Rolls for a critical hit based on the tracker's CRITICAL_CHANCE attribute.
*/
public static boolean rollCrit(PlayerAttributeTracker tracker) {
if (ConfigMain.AttributesEnabled && tracker != null) {
float critChance = tracker.getAttributeValue(CustomAttributes.CRITICAL_CHANCE);
return random.nextFloat() < (critChance / 100f);
}
return false;
}
/**
* Applies crit damage unconditionally (no chance roll).
* Use when the crit decision was already made via {@link #rollCrit}.
*/
public static float applyCritDamage(float damage, PlayerAttributeTracker tracker) {
if (ConfigMain.AttributesEnabled && tracker != null) {
float critBonus = tracker.getAttributeValue(CustomAttributes.CRITICAL_DAMAGE);
if (random.nextFloat() < (critChance / 100f))
damage = (damage * (1 + (float) ConfigMain.AttributesCriticalBoost / 100f)) + critBonus;
damage = (damage * (1 + (float) ConfigMain.AttributesCriticalBoost / 100f)) + critBonus;
}
return damage;
}
@@ -8,6 +8,7 @@ import cpw.mods.fml.relauncher.Side;
import kamkeel.npcs.addon.DBCAddon;
import kamkeel.npcs.controllers.AbilityController;
import kamkeel.npcs.controllers.AttributeController;
import kamkeel.npcs.controllers.data.attribute.tracker.PlayerAttributeTracker;
import kamkeel.npcs.controllers.SyncController;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.type.AbilityCounter;
@@ -623,8 +624,21 @@ public class ScriptPlayerEventHandler {
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts((EntityPlayer) event.source.getEntity());
float attackAmount = event.ammount;
if (ConfigMain.AttributesEnabled && !DBCAddon.IsAvailable())
attackAmount = AttributeAttackUtil.calculateOutgoing((EntityPlayer) event.source.getEntity(), attackAmount);
AttributeAttackUtil.lastAttackCritted = null;
if (ConfigMain.AttributesEnabled && !DBCAddon.IsAvailable()) {
EntityPlayer attackPlayer = (EntityPlayer) event.source.getEntity();
attackAmount = AttributeAttackUtil.calculateOutgoing(attackPlayer, attackAmount);
// For vanilla/modded mob targets, roll crit once and store for LivingHurtEvent
if (!(event.entityLiving instanceof EntityPlayerMP) && !(event.entityLiving instanceof EntityNPCInterface)) {
PlayerAttributeTracker tracker = AttributeController.getTracker(attackPlayer);
if (AttributeAttackUtil.rollCrit(tracker)) {
AttributeAttackUtil.lastAttackCritted = true;
attackAmount = AttributeAttackUtil.applyCritDamage(attackAmount, tracker);
} else {
AttributeAttackUtil.lastAttackCritted = false;
}
}
}
noppes.npcs.scripted.event.player.PlayerEvent.AttackEvent pevent1 = new noppes.npcs.scripted.event.player.PlayerEvent.AttackEvent((IPlayer) NpcAPI.Instance().getIEntity((EntityPlayer) event.source.getEntity()), event.entityLiving, attackAmount, event.source);
cancel = cancel || EventHooks.onPlayerAttack(handler, pevent1);
@@ -663,6 +677,15 @@ public class ScriptPlayerEventHandler {
event.ammount = AttributeAttackUtil.calculateDamagePlayerToPlayer((EntityPlayer) source, (EntityPlayer) event.entityLiving, event.ammount);
} else if (!(event.entityLiving instanceof EntityNPCInterface) && source instanceof EntityPlayer) {
event.ammount = AttributeAttackUtil.calculateOutgoing((EntityPlayer) source, event.ammount);
if (AttributeAttackUtil.lastAttackCritted != null) {
// Use the crit decision from LivingAttackEvent
if (AttributeAttackUtil.lastAttackCritted)
event.ammount = AttributeAttackUtil.applyCritDamage(event.ammount, AttributeController.getTracker((EntityPlayer) source));
AttributeAttackUtil.lastAttackCritted = null;
} else {
// Fallback: roll independently (no preceding LivingAttackEvent)
event.ammount = AttributeAttackUtil.applyCrit(event.ammount, AttributeController.getTracker((EntityPlayer) source));
}
}
}