From 2d89b8d450da0d66b8f92769a25f821cfad12e6d Mon Sep 17 00:00:00 2001 From: Kam Date: Fri, 28 Feb 2025 18:17:39 -0500 Subject: [PATCH] Requirement System for Items --- .../java/kamkeel/npcs/CustomAttributes.java | 6 ++ .../npcs/command/AttributeCommand.java | 58 ++++++++++++++---- .../kamkeel/npcs/command/CommandKamkeel.java | 4 ++ .../requirement/IRequirementChecker.java | 5 ++ .../QuestCompletedRequirement.java | 24 ++++++++ .../RequirementCheckerRegistry.java | 15 ++++- .../tracker/PlayerAttributeTracker.java | 12 ++++ .../kamkeel/npcs/util/AttributeItemUtil.java | 61 +++++++++++++++++++ 8 files changed, 170 insertions(+), 15 deletions(-) diff --git a/src/main/java/kamkeel/npcs/CustomAttributes.java b/src/main/java/kamkeel/npcs/CustomAttributes.java index 5cbe0b04d..3c207e758 100644 --- a/src/main/java/kamkeel/npcs/CustomAttributes.java +++ b/src/main/java/kamkeel/npcs/CustomAttributes.java @@ -3,6 +3,8 @@ package kamkeel.npcs; import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.controllers.data.attribute.AttributeDefinition; import kamkeel.npcs.controllers.data.attribute.AttributeValueType; +import kamkeel.npcs.controllers.data.attribute.requirement.QuestCompletedRequirement; +import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; /** * ModAttributes registers the core attributes (both non–magic and magic–based). @@ -52,5 +54,9 @@ public class CustomAttributes { MAGIC_DEFENSE = AttributeController.registerAttribute(MAGIC_DEFENSE_KEY, "Magic Defense", 'b', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.BASE); MAGIC_RESISTANCE = AttributeController.registerAttribute(MAGIC_RESISTANCE_KEY, "Magic Resistance", 'b', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.MODIFIER); + + + // Requirement + RequirementCheckerRegistry.registerChecker(new QuestCompletedRequirement()); } } diff --git a/src/main/java/kamkeel/npcs/command/AttributeCommand.java b/src/main/java/kamkeel/npcs/command/AttributeCommand.java index 59952a1cb..5a964db85 100644 --- a/src/main/java/kamkeel/npcs/command/AttributeCommand.java +++ b/src/main/java/kamkeel/npcs/command/AttributeCommand.java @@ -5,7 +5,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; import net.minecraft.item.ItemStack; @@ -195,17 +194,52 @@ public class AttributeCommand extends CommandKamkeelBase { } } - @Override - public List addTabCompletionOptions(ICommandSender sender, String[] args) { - // For the first parameter of the subcommand (apply or remove), list available attribute keys. - if(args.length == 1) { - List keys = new ArrayList<>(); - for (AttributeDefinition def : AttributeController.getAllAttributes()) { - keys.add(def.getKey()); - } - return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()])); + @SubCommand( + name = "requirement", + usage = " [value]", + desc = "Apply or remove a requirement from your held item." + ) + public void requirement(ICommandSender sender, String[] args) throws CommandException { + if (!(sender instanceof EntityPlayer)) { + sendError(sender, "Only players can use this command."); + return; + } + EntityPlayer player = (EntityPlayer) sender; + ItemStack held = player.getHeldItem(); + if (held == null) { + sendError(sender, "You are not holding an item."); + return; + } + if (args.length < 2) { + sendError(sender, "Usage: requirement [value]"); + return; + } + String action = args[0]; + String reqKey = args[1]; + if (action.equalsIgnoreCase("apply")) { + if (args.length < 3) { + sendError(sender, "Usage: requirement apply "); + return; + } + String valueStr = args[2]; + Object value; + try { + value = Integer.parseInt(valueStr); + } catch (NumberFormatException e1) { + try { + value = Float.parseFloat(valueStr); + } catch (NumberFormatException e2) { + value = valueStr; + } + } + + AttributeItemUtil.applyRequirement(held, reqKey, value); + sendResult(sender, "Applied requirement " + reqKey + " with value " + value + " to held item."); + } else if (action.equalsIgnoreCase("remove")) { + AttributeItemUtil.removeRequirement(held, reqKey); + sendResult(sender, "Removed requirement " + reqKey + " from held item."); + } else { + sendError(sender, "Invalid action. Use apply or remove."); } - // If the attribute is magic and we are completing the magicID parameter, you could return dummy numbers. - return super.addTabCompletionOptions(sender, args); } } diff --git a/src/main/java/kamkeel/npcs/command/CommandKamkeel.java b/src/main/java/kamkeel/npcs/command/CommandKamkeel.java index e91c536bc..25e099e41 100644 --- a/src/main/java/kamkeel/npcs/command/CommandKamkeel.java +++ b/src/main/java/kamkeel/npcs/command/CommandKamkeel.java @@ -1,5 +1,6 @@ package kamkeel.npcs.command; +import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; @@ -119,6 +120,9 @@ public class CommandKamkeel extends CommandBase{ keys.add(def.getKey()); } return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()])); + } else if (usage.equals("")) { + List keys = new ArrayList<>(RequirementCheckerRegistry.getAllKeys()); + return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()])); } } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java index 004efee9b..d7afb5e59 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/IRequirementChecker.java @@ -7,6 +7,11 @@ public interface IRequirementChecker { public String getKey(); + public String getTranslation(); + + String getTooltipValue(NBTTagCompound nbt); + + void apply(NBTTagCompound nbt, Object value); /** * Checks the requirement in the provided NBT. diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/QuestCompletedRequirement.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/QuestCompletedRequirement.java index 6f58017ba..c196cb8d9 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/QuestCompletedRequirement.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/QuestCompletedRequirement.java @@ -2,6 +2,7 @@ package kamkeel.npcs.controllers.data.attribute.requirement; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.controllers.QuestController; import noppes.npcs.controllers.data.PlayerData; public class QuestCompletedRequirement implements IRequirementChecker { @@ -11,6 +12,29 @@ public class QuestCompletedRequirement implements IRequirementChecker { return "cnpc_quest_completed"; } + @Override + public String getTranslation() { + return "quest.quest"; + } + + @Override + public String getTooltipValue(NBTTagCompound nbt) { + if(nbt.hasKey(getKey())) { + int questID = nbt.getInteger(getKey()); + if(QuestController.Instance.get(questID) != null) { + return QuestController.Instance.get(questID).getName(); + } + } + return "null"; + } + + @Override + public void apply(NBTTagCompound nbt, Object value) { + if(value instanceof Integer) { + nbt.setInteger(getKey(), (Integer) value); + } + } + @Override public boolean check(EntityPlayer player, NBTTagCompound nbt) { if(nbt.hasKey(getKey())) { diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/RequirementCheckerRegistry.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/RequirementCheckerRegistry.java index cd9d37648..85a047f69 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/RequirementCheckerRegistry.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/requirement/RequirementCheckerRegistry.java @@ -4,13 +4,14 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import java.util.HashMap; import java.util.Map; +import java.util.Set; public class RequirementCheckerRegistry { private static final Map checkers = new HashMap<>(); - public static void registerChecker(String key, IRequirementChecker checker) { - if (!checkers.containsKey(key)) { - checkers.put(key, checker); + public static void registerChecker(IRequirementChecker checker) { + if (!checkers.containsKey(checker.getKey())) { + checkers.put(checker.getKey(), checker); } } @@ -29,4 +30,12 @@ public class RequirementCheckerRegistry { } return true; } + + public static Set getAllKeys() { + return checkers.keySet(); + } + + public static IRequirementChecker getChecker(String key) { + return checkers.get(key); + } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java b/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java index 2e6ce0691..331b9987d 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java +++ b/src/main/java/kamkeel/npcs/controllers/data/attribute/tracker/PlayerAttributeTracker.java @@ -10,6 +10,7 @@ import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.controllers.data.attribute.AttributeDefinition; import kamkeel.npcs.controllers.data.attribute.ICustomAttribute; import kamkeel.npcs.controllers.data.attribute.PlayerAttributeMap; +import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; import kamkeel.npcs.util.AttributeAttackUtil; import kamkeel.npcs.util.AttributeItemUtil; import net.minecraft.entity.SharedMonsterAttributes; @@ -17,6 +18,7 @@ import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; public class PlayerAttributeTracker { @@ -60,6 +62,16 @@ public class PlayerAttributeTracker { ItemStack[] equipment = new ItemStack[] { currentEquip.heldItem, currentEquip.boots, currentEquip.leggings, currentEquip.chestplate, currentEquip.helmet }; for (ItemStack piece : equipment) { if (piece != null) { + if (piece.stackTagCompound != null && piece.stackTagCompound.hasKey(AttributeItemUtil.TAG_RPGCORE)) { + NBTTagCompound rpgCore = piece.stackTagCompound.getCompoundTag(AttributeItemUtil.TAG_RPGCORE); + if (rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) { + NBTTagCompound reqTag = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS); + if (!RequirementCheckerRegistry.checkRequirements(player, reqTag)) { + continue; + } + } + } + for (Entry entry : AttributeItemUtil.readAttributes(piece).entrySet()) { String key = entry.getKey(); float value = entry.getValue(); diff --git a/src/main/java/kamkeel/npcs/util/AttributeItemUtil.java b/src/main/java/kamkeel/npcs/util/AttributeItemUtil.java index 558f775a5..b850e3b46 100644 --- a/src/main/java/kamkeel/npcs/util/AttributeItemUtil.java +++ b/src/main/java/kamkeel/npcs/util/AttributeItemUtil.java @@ -3,6 +3,10 @@ package kamkeel.npcs.util; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.AttributeController; +import kamkeel.npcs.controllers.data.attribute.requirement.IRequirementChecker; +import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; @@ -178,6 +182,43 @@ public class AttributeItemUtil { } } + + public static void applyRequirement(ItemStack item, String reqKey, Object value) { + if (item == null) return; + if (item.stackTagCompound == null) + item.stackTagCompound = new NBTTagCompound(); + NBTTagCompound root = item.stackTagCompound; + // Get (or create) the RPGCore compound. + NBTTagCompound rpgCore = root.hasKey(TAG_RPGCORE) ? root.getCompoundTag(TAG_RPGCORE) : new NBTTagCompound(); + // Get (or create) the Requirements compound. + NBTTagCompound reqTag = rpgCore.hasKey(TAG_REQUIREMENTS) ? rpgCore.getCompoundTag(TAG_REQUIREMENTS) : new NBTTagCompound(); + // Retrieve the checker from the registry. + IRequirementChecker checker = RequirementCheckerRegistry.getChecker(reqKey); + if (checker != null) { + checker.apply(reqTag, value); + } + rpgCore.setTag(TAG_REQUIREMENTS, reqTag); + root.setTag(TAG_RPGCORE, rpgCore); + } + + public static void removeRequirement(ItemStack item, String reqKey) { + if (item == null || item.stackTagCompound == null) return; + NBTTagCompound root = item.stackTagCompound; + if (root.hasKey(TAG_RPGCORE)) { + NBTTagCompound rpgCore = root.getCompoundTag(TAG_RPGCORE); + if (rpgCore.hasKey(TAG_REQUIREMENTS)) { + NBTTagCompound reqTag = rpgCore.getCompoundTag(TAG_REQUIREMENTS); + reqTag.removeTag(reqKey); + if (reqTag.func_150296_c().isEmpty()) { + rpgCore.removeTag(TAG_REQUIREMENTS); + } else { + rpgCore.setTag(TAG_REQUIREMENTS, reqTag); + } + root.setTag(TAG_RPGCORE, rpgCore); + } + } + } + // ----------------- Tooltip Generation with Custom Sorting ------------------- /** @@ -252,6 +293,26 @@ public class AttributeItemUtil { newTooltips.addAll(buildSection(infoList)); // alphabetical newTooltips.addAll(buildSection(extraList)); // alphabetical + if (rpgCore.hasKey(TAG_REQUIREMENTS)) { + NBTTagCompound reqTag = rpgCore.getCompoundTag(TAG_REQUIREMENTS); + List reqEntries = new ArrayList<>(); + + Minecraft mc = Minecraft.getMinecraft(); + EntityPlayer clientPlayer = mc.thePlayer; + Set requirements = reqTag.func_150296_c(); + for (String reqKey : requirements) { + IRequirementChecker checker = RequirementCheckerRegistry.getChecker(reqKey); + if (checker != null) { + boolean met = clientPlayer != null && checker.check(clientPlayer, reqTag); + String tooltipValue = checker.getTooltipValue(reqTag); + String color = met ? EnumChatFormatting.GRAY.toString() : EnumChatFormatting.RED.toString(); + String line = EnumChatFormatting.GRAY + StatCollector.translateToLocal(checker.getTranslation()) + ": " + color + tooltipValue; + reqEntries.add(new TooltipEntry(stripFormatting(StatCollector.translateToLocal(checker.getTranslation())), line)); + } + } + newTooltips.addAll(buildSection(reqEntries)); + } + tooltip = newTooltips; } else { String keyName = Keyboard.getKeyName(ClientProxy.NPCButton.getKeyCode());