diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 856a98b39..a474044e9 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -175,6 +175,7 @@ public class CustomNpcs { // Load Mod Support PixelmonHelper.load(); new AddonManager(); + new AttributeController(); } @EventHandler @@ -219,8 +220,6 @@ public class CustomNpcs { new ProfileController(); ProfileController.registerProfileType(new CNPCData()); - new AttributeController(); - ScriptController.Instance.loadStoredData(); ScriptController.Instance.loadForgeScripts(); ScriptController.Instance.loadGlobalNPCScripts(); diff --git a/src/main/java/noppes/npcs/ScriptPlayerEventHandler.java b/src/main/java/noppes/npcs/ScriptPlayerEventHandler.java index af06b8837..2df81b752 100644 --- a/src/main/java/noppes/npcs/ScriptPlayerEventHandler.java +++ b/src/main/java/noppes/npcs/ScriptPlayerEventHandler.java @@ -61,7 +61,7 @@ public class ScriptPlayerEventHandler { } } - AttributeController.getTracker(player.getUniqueID()).updateIfChanged(player); + AttributeController.getTracker(player).updateIfChanged(player); } if (PlayerDataController.Instance != null) { diff --git a/src/main/java/noppes/npcs/attribute/AttributeController.java b/src/main/java/noppes/npcs/attribute/AttributeController.java index fbec3418b..cdd00e1b4 100644 --- a/src/main/java/noppes/npcs/attribute/AttributeController.java +++ b/src/main/java/noppes/npcs/attribute/AttributeController.java @@ -29,11 +29,11 @@ public class AttributeController { } - public static AttributeDefinition registerAttribute(String key, String displayName, AttributeValueType valueType) { + public static AttributeDefinition registerAttribute(String key, String displayName, AttributeValueType valueType, AttributeDefinition.AttributeSection section) { if (definitions.containsKey(key)) { throw new IllegalArgumentException("Attribute already registered with key: " + key); } - AttributeDefinition def = new AttributeDefinition(key, displayName, valueType); + AttributeDefinition def = new AttributeDefinition(key, displayName, valueType, section); definitions.put(key, def); return def; } @@ -46,8 +46,8 @@ public class AttributeController { return definitions.values(); } - public static PlayerAttributeTracker getTracker(UUID playerId) { - return trackers.computeIfAbsent(playerId, id -> new PlayerAttributeTracker(id)); + public static PlayerAttributeTracker getTracker(EntityPlayer player) { + return trackers.computeIfAbsent(player.getUniqueID(), id -> new PlayerAttributeTracker(id)); } public static void removeTracker(UUID playerId) { @@ -59,7 +59,7 @@ public class AttributeController { */ public static void updateAllTrackers(Iterable players) { for (EntityPlayer player : players) { - PlayerAttributeTracker tracker = getTracker(player.getUniqueID()); + PlayerAttributeTracker tracker = getTracker(player); tracker.updateIfChanged(player); } } diff --git a/src/main/java/noppes/npcs/attribute/AttributeDefinition.java b/src/main/java/noppes/npcs/attribute/AttributeDefinition.java index 61e4e0fba..45a2a54c2 100644 --- a/src/main/java/noppes/npcs/attribute/AttributeDefinition.java +++ b/src/main/java/noppes/npcs/attribute/AttributeDefinition.java @@ -1,19 +1,16 @@ package noppes.npcs.attribute; -/** - * Defines a valid attribute – for example, "cnpc:main_attack_flat" (a flat bonus) - * or "cnpc:main_attack_percent" (a percent bonus). These definitions are registered - * once in the AttributeController. - */ public class AttributeDefinition { private final String key; // e.g., "main_attack_flat" private final String displayName; // Human‑readable name private final AttributeValueType attributeValueType; + private final AttributeSection section; - public AttributeDefinition(String key, String displayName, AttributeValueType attributeValueType) { + public AttributeDefinition(String key, String displayName, AttributeValueType attributeValueType, AttributeSection section) { this.key = key; this.displayName = displayName; this.attributeValueType = attributeValueType; + this.section = section; } public String getKey() { @@ -27,4 +24,15 @@ public class AttributeDefinition { public AttributeValueType getValueType() { return attributeValueType; } + + public AttributeSection getSection() { + return section; + } + + public enum AttributeSection { + BASE, + MODIFIER, + INFO, + EXTRA; + } } diff --git a/src/main/java/noppes/npcs/attribute/AttributeKeys.java b/src/main/java/noppes/npcs/attribute/AttributeKeys.java deleted file mode 100644 index a59e356bb..000000000 --- a/src/main/java/noppes/npcs/attribute/AttributeKeys.java +++ /dev/null @@ -1,19 +0,0 @@ -package noppes.npcs.attribute; - -public final class AttributeKeys { - public static final String HEALTH = "health"; - - public static final String MAIN_ATTACK = "main_attack"; - public static final String MAIN_ATTACK_BOOST = "main_attack_boost"; - - public static final String CRITICAL_DAMAGE_FLAT = "critical_damage"; - public static final String CRITICAL_CHANCE = "critical_chance"; - - - // Magic–based attribute keys: - public static final String MAGIC_DAMAGE = "magic_damage"; - public static final String MAGIC_BOOST = "magic_boost"; - - public static final String MAGIC_DEFENSE = "magic_defense"; - public static final String MAGIC_RESISTANCE = "magic_resistance"; -} diff --git a/src/main/java/noppes/npcs/attribute/DamageCalculator.java b/src/main/java/noppes/npcs/attribute/DamageCalculator.java index ff8795d6a..c1923a01a 100644 --- a/src/main/java/noppes/npcs/attribute/DamageCalculator.java +++ b/src/main/java/noppes/npcs/attribute/DamageCalculator.java @@ -1,15 +1,59 @@ package noppes.npcs.attribute; import noppes.npcs.attribute.player.PlayerAttributeTracker; +import noppes.npcs.controllers.MagicController; +import java.util.Map; import java.util.Random; public class DamageCalculator { private static final Random random = new Random(); + public static double calculateDamage(PlayerAttributeTracker attacker, PlayerAttributeTracker defender, double baseDamage) { - public static double calculateDamage(PlayerAttributeTracker attacker, PlayerAttributeTracker defender, int baseDamage) { - return 0; + // Calculate physical damage + double mainAttack = attacker.getAttributeValue(ModAttributes.MAIN_ATTACK); + double mainBoost = attacker.getAttributeValue(ModAttributes.MAGIC_BOOST) + 1; + double physicalDamage = (baseDamage * mainBoost) + mainAttack; + + // Calculate neutral damage + double neutralDamage = attacker.getAttributeValue(ModAttributes.NEUTRAL_ATTACK); + double neutralBoost = attacker.getAttributeValue(ModAttributes.NEUTRAL_BOOST) + 1; + double neutralTotal = neutralDamage * neutralBoost; + + // Calculate magic damage + double magicTotal = 0.0; + MagicController magicController = MagicController.getInstance(); + for (Map.Entry entry : attacker.magicDamage.entrySet()) { + int magicId = entry.getKey(); + if (magicController.getMagic(magicId) != null) { + double attackMagic = entry.getValue(); + double defenseMagic = defender.magicDefense.getOrDefault(magicId, 0.0); + double effectiveMagic = attackMagic - defenseMagic; + + double boostMagic = attacker.magicBoost.getOrDefault(magicId, 0.0); + double resistanceMagic = defender.magicResistance.getOrDefault(magicId, 0.0); + double effectiveBoost = boostMagic - resistanceMagic; + + double magicDamageForMagic = effectiveMagic * (effectiveBoost + 1); + // Ensure magic damage doesn't drop below 0 for this magic + magicTotal += Math.max(0, magicDamageForMagic); + } + } + + // Sum all damage components + double totalDamage = physicalDamage + neutralTotal + magicTotal; + + // Critical hit: if critical, double damage and add bonus + double criticalChance = attacker.getAttributeValue(ModAttributes.CRITICAL_CHANCE); + double criticalBonus = attacker.getAttributeValue(ModAttributes.CRITICAL_DAMAGE); + if (random.nextDouble() < (criticalChance / 100)) { + totalDamage = (totalDamage * 2) + criticalBonus; + } + + return totalDamage; } + + } diff --git a/src/main/java/noppes/npcs/attribute/ItemAttributeHelper.java b/src/main/java/noppes/npcs/attribute/ItemAttributeHelper.java index 54954ee2f..8c9927bb8 100644 --- a/src/main/java/noppes/npcs/attribute/ItemAttributeHelper.java +++ b/src/main/java/noppes/npcs/attribute/ItemAttributeHelper.java @@ -1,10 +1,19 @@ package noppes.npcs.attribute; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import java.util.Set; -import java.util.HashMap; -import java.util.Map; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import noppes.npcs.client.ClientProxy; +import org.lwjgl.input.Keyboard; + +import java.util.*; + +import static noppes.npcs.attribute.AttributeDefinition.AttributeSection.INFO; +import static noppes.npcs.attribute.AttributeDefinition.AttributeSection.MODIFIER; /** * Provides helper functions to write/read item attributes to/from NBT. @@ -12,7 +21,7 @@ import java.util.Map; * and magic attributes are stored as a compound mapping (by magic ID) under specific keys. */ public class ItemAttributeHelper { - public static final String TAG_ROOT = "RPGCoreAttributes"; + public static final String RPGItemAttributes = "RPGCoreAttributes"; /** * Applies a non–magic attribute to an item. @@ -24,13 +33,13 @@ public class ItemAttributeHelper { } NBTTagCompound root = item.stackTagCompound; NBTTagCompound attrTag; - if (root.hasKey(TAG_ROOT)) { - attrTag = root.getCompoundTag(TAG_ROOT); + if (root.hasKey(RPGItemAttributes)) { + attrTag = root.getCompoundTag(RPGItemAttributes); } else { attrTag = new NBTTagCompound(); } attrTag.setDouble(attributeKey, value); - root.setTag(TAG_ROOT, attrTag); + root.setTag(RPGItemAttributes, attrTag); } /** @@ -39,12 +48,12 @@ public class ItemAttributeHelper { public static void removeAttribute(ItemStack item, String attributeKey) { if (item == null || item.stackTagCompound == null) return; NBTTagCompound root = item.stackTagCompound; - if (root.hasKey(TAG_ROOT)) { - NBTTagCompound attrTag = root.getCompoundTag(TAG_ROOT); + if (root.hasKey(RPGItemAttributes)) { + NBTTagCompound attrTag = root.getCompoundTag(RPGItemAttributes); attrTag.removeTag(attributeKey); // If no attributes remain, remove the root tag. if (attrTag.func_150296_c().isEmpty()) { - root.removeTag(TAG_ROOT); + root.removeTag(RPGItemAttributes); } } } @@ -56,8 +65,8 @@ public class ItemAttributeHelper { Map map = new HashMap<>(); if (item == null || item.stackTagCompound == null) return map; NBTTagCompound root = item.stackTagCompound; - if (root.hasKey(TAG_ROOT)) { - NBTTagCompound attrTag = root.getCompoundTag(TAG_ROOT); + if (root.hasKey(RPGItemAttributes)) { + NBTTagCompound attrTag = root.getCompoundTag(RPGItemAttributes); Set keys = attrTag.func_150296_c(); for (String key : keys) { map.put(key, attrTag.getDouble(key)); @@ -128,4 +137,114 @@ public class ItemAttributeHelper { root.removeTag(attributeTag); } } + + @SideOnly(Side.CLIENT) + public static List getToolTip(List original, NBTTagCompound compound) { + List tooltip = original; + NBTTagCompound attrTag = compound.getCompoundTag(RPGItemAttributes); + if (Keyboard.isKeyDown(ClientProxy.NPCButton.getKeyCode())) { + List newTooltips = new ArrayList<>(); + if (!tooltip.isEmpty()) { + newTooltips.add((String) tooltip.get(0)); + newTooltips.add(""); + } + + // Create lists for each section + List baseList = new ArrayList<>(); + List modifierList = new ArrayList<>(); + List infoList = new ArrayList<>(); + List extraList = new ArrayList<>(); + + Iterator iterator = attrTag.func_150296_c().iterator(); + while (iterator.hasNext()) { + String key = (String) iterator.next(); + double value = attrTag.getDouble(key); + AttributeDefinition def = AttributeController.getAttribute(key); + // Default section is EXTRA if not defined + AttributeDefinition.AttributeSection section = def != null ? def.getSection() : AttributeDefinition.AttributeSection.EXTRA; + String line; + String translation = null; + if (key.contains(":")) { + if (StatCollector.canTranslate(key)) { + translation = StatCollector.translateToLocal(key); + } + } else { + if (StatCollector.canTranslate("rpgcore:attribute." + key)) { + translation = StatCollector.translateToLocal("rpgcore:attribute." + key); + } + } + if (translation == null && def != null) { + translation = def.getDisplayName(); + } else if (translation == null) { + translation = key; + } + translation = EnumChatFormatting.AQUA + translation; + String formattedValue = formatDouble(value); + if (section == MODIFIER || section == INFO) { + String sign = (value >= 0) ? "+" : ""; + String valueColor = (value >= 0) ? EnumChatFormatting.GREEN + "" : EnumChatFormatting.RED + ""; + String valueString = valueColor + sign + formattedValue + EnumChatFormatting.GRAY; + switch (section) { + case MODIFIER: + line = valueString + " " + translation; + modifierList.add(line); + break; + case INFO: + line = valueString + " " + translation; + infoList.add(line); + break; + default: + line = translation + ": " + formattedValue; + break; + } + } else { + formattedValue = EnumChatFormatting.GRAY + formattedValue; + switch (section) { + case BASE: + line = translation + ": " + formattedValue; + baseList.add(line); + break; + case EXTRA: + line = translation + ": " + formattedValue; + extraList.add(line); + break; + default: + line = translation + ": " + formattedValue; + break; + } + } + } + + if (!baseList.isEmpty()) { + newTooltips.add(""); + newTooltips.addAll(baseList); + } + if (!modifierList.isEmpty()) { + newTooltips.add(""); + newTooltips.addAll(modifierList); + } + if (!infoList.isEmpty()) { + newTooltips.add(""); + newTooltips.addAll(infoList); + } + if (!extraList.isEmpty()) { + newTooltips.add(""); + newTooltips.addAll(extraList); + } + tooltip = newTooltips; + } else { + // Inform the user to hold the NPCButton key for attribute details + String keyName = Keyboard.getKeyName(ClientProxy.NPCButton.getKeyCode()); + tooltip.add(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.ITALIC + + StatCollector.translateToLocal("rpgcore:tooltip").replace("%key%", keyName)); + } + return tooltip; + } + + /** + * Helper to format a double by removing trailing zeros. + */ + private static String formatDouble(double value) { + return new java.math.BigDecimal(Double.toString(value)).stripTrailingZeros().toPlainString(); + } } diff --git a/src/main/java/noppes/npcs/attribute/ModAttributes.java b/src/main/java/noppes/npcs/attribute/ModAttributes.java index ec4b761a4..9f62aec15 100644 --- a/src/main/java/noppes/npcs/attribute/ModAttributes.java +++ b/src/main/java/noppes/npcs/attribute/ModAttributes.java @@ -4,27 +4,49 @@ package noppes.npcs.attribute; * ModAttributes registers the core attributes (both non–magic and magic–based). */ public class ModAttributes { - public static AttributeDefinition MAIN_ATTACK_FLAT; - public static AttributeDefinition MAIN_ATTACK_PERCENT; - public static AttributeDefinition HEALTH; - public static AttributeDefinition CRITICAL_CHANCE_PERCENT; - public static AttributeDefinition CRITICAL_DAMAGE_FLAT; + public static final String HEALTH_KEY = "health"; + public static final String MAIN_ATTACK_KEY = "main_attack"; + public static final String MAIN_ATTACK_BOOST_KEY = "main_attack_boost"; + public static final String NEUTRAL_KEY = "neutral"; + public static final String NEUTRAL_BOOST_KEY = "neutral_boost"; + public static final String CRITICAL_DAMAGE_KEY = "critical_damage"; + public static final String CRITICAL_CHANCE_KEY = "critical_chance"; + public static final String MAGIC_DAMAGE_KEY = "magic_damage"; + public static final String MAGIC_BOOST_KEY = "magic_boost"; + public static final String MAGIC_DEFENSE_KEY = "magic_defense"; + public static final String MAGIC_RESISTANCE_KEY = "magic_resistance"; - public static AttributeDefinition MAGIC_DAMAGE_FLAT; - public static AttributeDefinition MAGIC_DAMAGE_PERCENT; - public static AttributeDefinition MAGIC_DEFENSE_FLAT; - public static AttributeDefinition MAGIC_RESISTANCE_PERCENT; + + public static AttributeDefinition MAIN_ATTACK; + public static AttributeDefinition MAIN_BOOST; + public static AttributeDefinition NEUTRAL_ATTACK; + public static AttributeDefinition NEUTRAL_BOOST; + + public static AttributeDefinition HEALTH; + public static AttributeDefinition CRITICAL_CHANCE; + public static AttributeDefinition CRITICAL_DAMAGE; + + public static AttributeDefinition MAGIC_DAMAGE; + public static AttributeDefinition MAGIC_BOOST; + public static AttributeDefinition MAGIC_DEFENSE; + public static AttributeDefinition MAGIC_RESISTANCE; public ModAttributes(){ - MAIN_ATTACK_FLAT = AttributeController.registerAttribute(AttributeKeys.MAIN_ATTACK, "Main Attack Damage", AttributeValueType.FLAT); - MAIN_ATTACK_PERCENT = AttributeController.registerAttribute(AttributeKeys.MAIN_ATTACK_BOOST, "Main Attack Damage (%)", AttributeValueType.PERCENT); - HEALTH = AttributeController.registerAttribute(AttributeKeys.HEALTH, "Health", AttributeValueType.FLAT); - CRITICAL_CHANCE_PERCENT = AttributeController.registerAttribute(AttributeKeys.CRITICAL_CHANCE, "Critical Chance (%)", AttributeValueType.PERCENT); - CRITICAL_DAMAGE_FLAT = AttributeController.registerAttribute(AttributeKeys.CRITICAL_DAMAGE_FLAT, "Critical Damage Bonus", AttributeValueType.FLAT); + HEALTH = AttributeController.registerAttribute(HEALTH_KEY, "Health", AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE); - MAGIC_DAMAGE_FLAT = AttributeController.registerAttribute(AttributeKeys.MAGIC_DAMAGE, "Magic Damage", AttributeValueType.MAGIC); - MAGIC_DAMAGE_PERCENT = AttributeController.registerAttribute(AttributeKeys.MAGIC_BOOST, "Magic Damage (%)", AttributeValueType.MAGIC); - MAGIC_DEFENSE_FLAT = AttributeController.registerAttribute(AttributeKeys.MAGIC_DEFENSE, "Magic Defense", AttributeValueType.MAGIC); - MAGIC_RESISTANCE_PERCENT = AttributeController.registerAttribute(AttributeKeys.MAGIC_RESISTANCE, "Magic Resistance (%)", AttributeValueType.MAGIC); + MAIN_ATTACK = AttributeController.registerAttribute(MAIN_ATTACK_KEY, "Main Attack Damage", AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE); + MAIN_BOOST = AttributeController.registerAttribute(MAIN_ATTACK_BOOST_KEY, "Main Attack Damage (%)", AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.MODIFIER); + + NEUTRAL_ATTACK = AttributeController.registerAttribute(NEUTRAL_KEY, "Neutral Damage", AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE); + NEUTRAL_BOOST = AttributeController.registerAttribute(NEUTRAL_BOOST_KEY, "Neutral Damage (%)", AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.MODIFIER); + + CRITICAL_CHANCE = AttributeController.registerAttribute(CRITICAL_CHANCE_KEY, "Critical Chance (%)", AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.INFO); + CRITICAL_DAMAGE = AttributeController.registerAttribute(CRITICAL_DAMAGE_KEY, "Critical Damage Bonus", AttributeValueType.FLAT, AttributeDefinition.AttributeSection.INFO); + + MAGIC_DAMAGE = AttributeController.registerAttribute(MAGIC_DAMAGE_KEY, "Magic Damage", AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.BASE); + MAGIC_BOOST = AttributeController.registerAttribute(MAGIC_BOOST_KEY, "Magic Damage (%)", AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.MODIFIER); + + MAGIC_DEFENSE = AttributeController.registerAttribute(MAGIC_DEFENSE_KEY, "Magic Defense", AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.BASE); + MAGIC_RESISTANCE = AttributeController.registerAttribute(MAGIC_RESISTANCE_KEY, "Magic Resistance (%)", AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.MODIFIER); } } diff --git a/src/main/java/noppes/npcs/attribute/player/PlayerAttributeTracker.java b/src/main/java/noppes/npcs/attribute/player/PlayerAttributeTracker.java index 819a1d2d5..12a467712 100644 --- a/src/main/java/noppes/npcs/attribute/player/PlayerAttributeTracker.java +++ b/src/main/java/noppes/npcs/attribute/player/PlayerAttributeTracker.java @@ -10,40 +10,28 @@ import noppes.npcs.attribute.*; public class PlayerAttributeTracker { - public static final int BASE_ID = -100; - private final UUID playerId; private PlayerAttributeMap playerAttributes = new PlayerAttributeMap(); - private final Map damageMap = new HashMap<>(); - private final Map defenseMap = new HashMap<>(); - - private final Map magicDamage = new HashMap<>(); - private final Map magicBoost = new HashMap<>(); - private final Map magicDefense = new HashMap<>(); - private final Map magicResistance = new HashMap<>(); + public final int extraHealth = 0; + public final Map magicDamage = new HashMap<>(); + public final Map magicBoost = new HashMap<>(); + public final Map magicDefense = new HashMap<>(); + public final Map magicResistance = new HashMap<>(); private PlayerEquipmentTracker equipmentTracker = new PlayerEquipmentTracker(); public PlayerAttributeTracker(UUID playerId) { this.playerId = playerId; // Initial recalc with base damage 0. - recalcAttributes(null, 0); + recalcAttributes(null); } public PlayerAttributeMap getPlayerAttributes() { return playerAttributes; } - public Map getOffenseMap() { - return damageMap; - } - - public Map getDefenseMap() { - return defenseMap; - } - - public void recalcAttributes(EntityPlayer player, int baseDamage) { + public void recalcAttributes(EntityPlayer player) { // Reset aggregated attributes and magic maps. playerAttributes = new PlayerAttributeMap(); magicDamage.clear(); @@ -55,42 +43,9 @@ public class PlayerAttributeTracker { // Update equipment tracker. PlayerEquipmentTracker currentEquip = new PlayerEquipmentTracker(); currentEquip.updateFrom(player); - - // Process held item (offense). - ItemStack held = currentEquip.heldItem; - if (held != null) { - // Process non-magic attributes. - for (Entry entry : ItemAttributeHelper.readAttributes(held).entrySet()) { - String key = entry.getKey(); - double value = entry.getValue(); - AttributeDefinition def = AttributeController.getAttribute(key); - if (def != null) { - IAttributeInstance inst = playerAttributes.getAttributeInstance(def); - if (inst == null) { - inst = playerAttributes.registerAttribute(def, 0.0); - } - inst.setValue(inst.getValue() + value); - } - } - // Process magic offense. - Map magicFlat = ItemAttributeHelper.readMagicAttributeMap(held, AttributeKeys.MAGIC_DAMAGE); - for (Entry entry : magicFlat.entrySet()) { - int magicId = entry.getKey(); - double value = entry.getValue(); - magicDamage.put(magicId, magicDamage.getOrDefault(magicId, 0.0) + value); - } - Map magicPercent = ItemAttributeHelper.readMagicAttributeMap(held, AttributeKeys.MAGIC_BOOST); - for (Entry entry : magicPercent.entrySet()) { - int magicId = entry.getKey(); - double value = entry.getValue(); - magicBoost.put(magicId, magicBoost.getOrDefault(magicId, 0.0) + value); - } - } - // Process armor (defense). - ItemStack[] armor = new ItemStack[] { currentEquip.boots, currentEquip.leggings, currentEquip.chestplate, currentEquip.helmet }; - for (ItemStack piece : armor) { + ItemStack[] equipment = new ItemStack[] { currentEquip.heldItem, currentEquip.boots, currentEquip.leggings, currentEquip.chestplate, currentEquip.helmet }; + for (ItemStack piece : equipment) { if (piece != null) { - // Process non-magic attributes. for (Entry entry : ItemAttributeHelper.readAttributes(piece).entrySet()) { String key = entry.getKey(); double value = entry.getValue(); @@ -103,14 +58,30 @@ public class PlayerAttributeTracker { inst.setValue(inst.getValue() + value); } } - // Process magic defense. - Map magicDefFlat = ItemAttributeHelper.readMagicAttributeMap(piece, AttributeKeys.MAGIC_DEFENSE); + // Process Magic + + // OFFENSIVE MAGIC + Map magicFlat = ItemAttributeHelper.readMagicAttributeMap(piece, ModAttributes.MAGIC_DAMAGE_KEY); + for (Entry entry : magicFlat.entrySet()) { + int magicId = entry.getKey(); + double value = entry.getValue(); + magicDamage.put(magicId, magicDamage.getOrDefault(magicId, 0.0) + value); + } + Map magicPercent = ItemAttributeHelper.readMagicAttributeMap(piece, ModAttributes.MAGIC_BOOST_KEY); + for (Entry entry : magicPercent.entrySet()) { + int magicId = entry.getKey(); + double value = entry.getValue(); + magicBoost.put(magicId, magicBoost.getOrDefault(magicId, 0.0) + value); + } + + // DEFENSIVE MAGIC + Map magicDefFlat = ItemAttributeHelper.readMagicAttributeMap(piece, ModAttributes.MAGIC_DEFENSE_KEY); for (Entry entry : magicDefFlat.entrySet()) { int magicId = entry.getKey(); double value = entry.getValue(); magicDefense.put(magicId, magicDefense.getOrDefault(magicId, 0.0) + value); } - Map magicResist = ItemAttributeHelper.readMagicAttributeMap(piece, AttributeKeys.MAGIC_RESISTANCE); + Map magicResist = ItemAttributeHelper.readMagicAttributeMap(piece, ModAttributes.MAGIC_RESISTANCE_KEY); for (Entry entry : magicResist.entrySet()) { int magicId = entry.getKey(); double value = entry.getValue(); @@ -120,41 +91,6 @@ public class PlayerAttributeTracker { } equipmentTracker = currentEquip; } - // Recalculate the maps using the provided baseDamage. - recalcOffenseMap(baseDamage); - recalcDefenseMap(); - } - - private void recalcOffenseMap(int baseDamage) { - damageMap.clear(); - // Compute non-magic offense = (baseDamage + MAIN_ATTACK_FLAT) * (1 + MAIN_ATTACK_PERCENT) - double mainFlat = getAttributeValue(ModAttributes.MAIN_ATTACK_FLAT); - double mainPercent = getAttributeValue(ModAttributes.MAIN_ATTACK_PERCENT); - double nonMagicOffense = (baseDamage + mainFlat) * (1 + mainPercent); - damageMap.put(BASE_ID, nonMagicOffense); - - // For each magic type: offense = (magicDamageFlat) * (1 + magicDamagePercent) - for (Entry entry : magicDamage.entrySet()) { - int magicId = entry.getKey(); - double flat = entry.getValue(); - double percent = magicBoost.getOrDefault(magicId, 0.0); - double magicOffense = flat * (1 + percent); - damageMap.put(magicId, magicOffense); - } - } - - private void recalcDefenseMap() { - defenseMap.clear(); - // For each magic type: defense = (magicDefenseFlat) * (1 + magicResistancePercent) - for (Entry entry : magicDefense.entrySet()) { - int magicId = entry.getKey(); - double flat = entry.getValue(); - double percent = magicResistance.getOrDefault(magicId, 0.0); - double magicDef = flat * (1 + percent); - defenseMap.put(magicId, magicDef); - } - // Set non-magic defense to 0. - defenseMap.put(BASE_ID, 0.0); } /** @@ -164,7 +100,7 @@ public class PlayerAttributeTracker { PlayerEquipmentTracker currentEquip = new PlayerEquipmentTracker(); currentEquip.updateFrom(player); if (!equipmentTracker.equals(player)) { - recalcAttributes(player, 0); + recalcAttributes(player); } } diff --git a/src/main/java/noppes/npcs/attribute/player/PlayerEquipmentTracker.java b/src/main/java/noppes/npcs/attribute/player/PlayerEquipmentTracker.java index 661bd0f70..ba216e2a5 100644 --- a/src/main/java/noppes/npcs/attribute/player/PlayerEquipmentTracker.java +++ b/src/main/java/noppes/npcs/attribute/player/PlayerEquipmentTracker.java @@ -57,10 +57,10 @@ public class PlayerEquipmentTracker { if (a.getItem() != b.getItem()) return false; NBTTagCompound tagA = a.stackTagCompound; NBTTagCompound tagB = b.stackTagCompound; - String attrA = (tagA != null && tagA.hasKey(ItemAttributeHelper.TAG_ROOT)) - ? tagA.getCompoundTag(ItemAttributeHelper.TAG_ROOT).toString() : ""; - String attrB = (tagB != null && tagB.hasKey(ItemAttributeHelper.TAG_ROOT)) - ? tagB.getCompoundTag(ItemAttributeHelper.TAG_ROOT).toString() : ""; + String attrA = (tagA != null && tagA.hasKey(ItemAttributeHelper.RPGItemAttributes)) + ? tagA.getCompoundTag(ItemAttributeHelper.RPGItemAttributes).toString() : ""; + String attrB = (tagB != null && tagB.hasKey(ItemAttributeHelper.RPGItemAttributes)) + ? tagB.getCompoundTag(ItemAttributeHelper.RPGItemAttributes).toString() : ""; return attrA.equals(attrB); } } diff --git a/src/main/java/noppes/npcs/mixin/CustomNPCsMixinPlugin.java b/src/main/java/noppes/npcs/mixin/CustomNPCsMixinPlugin.java index e081cee32..1088c2c44 100644 --- a/src/main/java/noppes/npcs/mixin/CustomNPCsMixinPlugin.java +++ b/src/main/java/noppes/npcs/mixin/CustomNPCsMixinPlugin.java @@ -54,6 +54,8 @@ public class CustomNPCsMixinPlugin implements IMixinConfigPlugin { if (ConfigMixin.FirstPersonAnimationMixin) { mixins.add("MixinItemRenderer"); } + + mixins.add("MixinItemStack"); } return mixins; } diff --git a/src/main/java/noppes/npcs/mixin/MixinItemStack.java b/src/main/java/noppes/npcs/mixin/MixinItemStack.java new file mode 100644 index 000000000..13baf133b --- /dev/null +++ b/src/main/java/noppes/npcs/mixin/MixinItemStack.java @@ -0,0 +1,35 @@ +package noppes.npcs.mixin; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.attribute.ItemAttributeHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.List; + +import static noppes.npcs.attribute.ItemAttributeHelper.RPGItemAttributes; + +@Mixin(ItemStack.class) +public abstract class MixinItemStack { + + @Shadow + public abstract boolean hasTagCompound(); + + @Shadow + public abstract NBTTagCompound getTagCompound(); + + @Shadow + public NBTTagCompound stackTagCompound; + + @Inject(method = "getTooltip", at = @At("TAIL"), cancellable = true) + public void getAttributeTooltip(EntityPlayer player, boolean advanced, CallbackInfoReturnable> cir) { + List tooltip = cir.getReturnValue(); + if (hasTagCompound() && getTagCompound().hasKey(RPGItemAttributes)) { + cir.setReturnValue(ItemAttributeHelper.getToolTip(tooltip, getTagCompound())); + } + } +} diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index 2e118025d..89cf51a8a 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1329,3 +1329,7 @@ profile.enableOptions=Enable Options profile.completion=Completion profile.cooldown=Cooldown profile.individual=Individual + +rpgcore:tooltip=Hold %key% to view attributes +rpgcore:attribute.damage=Damage +rpgcore:attribute.neutral=Neutral