From ffdf374cd62e48dfa032da37b9fea22358eadc56 Mon Sep 17 00:00:00 2001
From: MagicBot <MagicBot@magicbane.com>
Date: Fri, 8 Mar 2024 10:08:25 -0500
Subject: [PATCH] Item requirements and restrictions refactored.

---
 src/engine/devcmd/cmds/ItemInfoCmd.java      |  26 ++--
 src/engine/objects/CharacterItemManager.java |   2 +-
 src/engine/objects/ItemBase.java             | 127 ++++---------------
 src/engine/objects/ItemTemplate.java         |  91 +++++++++++++
 4 files changed, 124 insertions(+), 122 deletions(-)

diff --git a/src/engine/devcmd/cmds/ItemInfoCmd.java b/src/engine/devcmd/cmds/ItemInfoCmd.java
index 5c18572f..2332e9c3 100644
--- a/src/engine/devcmd/cmds/ItemInfoCmd.java
+++ b/src/engine/devcmd/cmds/ItemInfoCmd.java
@@ -10,19 +10,11 @@
 package engine.devcmd.cmds;
 
 import engine.Enum;
-import engine.Enum.BuildingGroup;
 import engine.Enum.GameObjectType;
-import engine.Enum.TargetColor;
 import engine.devcmd.AbstractDevCmd;
-import engine.gameManager.BuildingManager;
-import engine.gameManager.SessionManager;
-import engine.math.Vector3fImmutable;
-import engine.objects.*;
-import engine.util.StringUtils;
-
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.concurrent.ConcurrentHashMap;
+import engine.objects.AbstractGameObject;
+import engine.objects.Item;
+import engine.objects.PlayerCharacter;
 
 
 /**
@@ -47,22 +39,22 @@ public class ItemInfoCmd extends AbstractDevCmd {
         String newline = "\r\n ";
         String output = "";
         output += "Required Races:" + newline;
-        for(Enum.MonsterType required : item.getItemBase().requiredRaces)
+        for (Enum.MonsterType required : item.template.item_race_req)
             output += "     " + required.name() + newline;
         output += "Restricted Races:" + newline;
-        for(Enum.MonsterType required : item.getItemBase().restrictedRaces)
+        for (Enum.MonsterType required : item.template.item_race_res)
             output += "     " + required.name() + newline;
         output += "Required Classes:" + newline;
-        for(Enum.ClassType required : item.getItemBase().requiredClasses)
+        for (Enum.ClassType required : item.template.item_class_req)
             output += "     " + required.name() + newline;
         output += "Restricted Classes:" + newline;
-        for(Enum.ClassType required : item.getItemBase().restrictedClasses)
+        for (Enum.ClassType required : item.template.item_class_res)
             output += "     " + required.name() + newline;
         output += "Required Disciplines:" + newline;
-        for(Enum.DisciplineType required : item.getItemBase().requiredDiscs)
+        for (Enum.DisciplineType required : item.template.item_disc_req)
             output += "     " + required.name() + newline;
         output += "Restricted Disciplines:" + newline;
-        for(Enum.DisciplineType required : item.getItemBase().restrictedDiscs)
+        for (Enum.DisciplineType required : item.template.item_disc_res)
             output += "     " + required.name() + newline;
         throwbackInfo(pc, output);
     }
diff --git a/src/engine/objects/CharacterItemManager.java b/src/engine/objects/CharacterItemManager.java
index a8ef06c7..901524d2 100644
--- a/src/engine/objects/CharacterItemManager.java
+++ b/src/engine/objects/CharacterItemManager.java
@@ -1871,7 +1871,7 @@ public class CharacterItemManager {
                 continue;
             }
 
-            if (!item.getItemBase().validForSkills(pc.getSkills())) {
+            if (!ItemTemplate.validForSkills(item, pc.getSkills())) {
                 this.forceToInventory(slot, item, pc, initialized);
                 pc.applyBonuses();
             }
diff --git a/src/engine/objects/ItemBase.java b/src/engine/objects/ItemBase.java
index 928924aa..5aeb53d6 100644
--- a/src/engine/objects/ItemBase.java
+++ b/src/engine/objects/ItemBase.java
@@ -19,17 +19,15 @@ import org.pmw.tinylog.Logger;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.concurrent.ConcurrentHashMap;
 
 public class ItemBase {
 
-    public static final byte GOLD_BASE_TYPE = 4;
     public static ItemBase GOLD_ITEM_BASE = null;
     public static int GOLD_BASE_ID = 7;
-    public static ArrayList<Integer> AnniverseryGifts = new ArrayList<>();
+    public static ArrayList<Integer> AnniversaryGifts = new ArrayList<>();
     public static HashMap<Integer, ItemBase> _itemBaseByUUID = new HashMap<>();
     public static HashMap<engine.Enum.ItemType, HashSet<ItemBase>> ItemBaseTypeMap = new HashMap<>();
     // Internal cache
@@ -37,15 +35,8 @@ public class ItemBase {
     private static final HashMap<String, Integer> _IDsByNames = new HashMap<>();
     private static final ArrayList<ItemBase> _resourceList = new ArrayList<>();
     private final int uuid;
-//     private String name;
+
 //requirements/restrictions
-    public EnumSet<Enum.MonsterType> restrictedRaces;
-    public EnumSet<Enum.MonsterType> requiredRaces;
-    public EnumSet<Enum.ClassType> restrictedClasses;
-    public EnumSet<Enum.ClassType> requiredClasses;
-    public EnumSet<Enum.DisciplineType> requiredDiscs;
-    public EnumSet<Enum.DisciplineType> restrictedDiscs;
-    private final short color;
     private final ItemType type;
     private int vendorType;
     private final int modTable;
@@ -85,7 +76,6 @@ public class ItemBase {
 
         this.uuid = rs.getInt("ID");
 
-        this.color = rs.getShort("color");
         this.type = ItemType.valueOf(rs.getString("Type"));
         this.useID = rs.getInt("useID");
         this.vendorType = rs.getInt("vendorType");
@@ -109,13 +99,6 @@ public class ItemBase {
         this.minDamage = rs.getShort("minDamage");
         this.maxDamage = rs.getShort("maxDamage");
 
-        // Item restrictions and requirements
-
-        this.requiredRaces = DbManager.parseEnumSet(rs.getString("race_required"), Enum.MonsterType.class);
-        this.restrictedRaces = DbManager.parseEnumSet(rs.getString("race_restricted"), Enum.MonsterType.class);
-        this.requiredClasses = DbManager.parseEnumSet(rs.getString("class_required"), Enum.ClassType.class);
-        this.requiredDiscs = DbManager.parseEnumSet(rs.getString("disc_required"), Enum.DisciplineType.class);
-
         this.mastery = rs.getString("mastery");
         damageType = Enum.SourceType.valueOf(rs.getString("damageType").toUpperCase());
 
@@ -214,25 +197,25 @@ public class ItemBase {
     public static void loadAllItemBases() {
         DbManager.ItemBaseQueries.LOAD_ALL_ITEMBASES();
 
-        AnniverseryGifts.add(971000);
-        AnniverseryGifts.add(971001);
-        AnniverseryGifts.add(971002);
-        AnniverseryGifts.add(971003);
-        AnniverseryGifts.add(971004);
-        AnniverseryGifts.add(971005);
-        AnniverseryGifts.add(971006);
-        AnniverseryGifts.add(971007);
-        AnniverseryGifts.add(971008);
-        AnniverseryGifts.add(971009);
-        AnniverseryGifts.add(971010);
-        AnniverseryGifts.add(5101000);
-        AnniverseryGifts.add(5101020);
-        AnniverseryGifts.add(5101100);
-        AnniverseryGifts.add(5101120);
-        AnniverseryGifts.add(5101040);
-        AnniverseryGifts.add(5101140);
-        AnniverseryGifts.add(5101060);
-        AnniverseryGifts.add(5101080);
+        AnniversaryGifts.add(971000);
+        AnniversaryGifts.add(971001);
+        AnniversaryGifts.add(971002);
+        AnniversaryGifts.add(971003);
+        AnniversaryGifts.add(971004);
+        AnniversaryGifts.add(971005);
+        AnniversaryGifts.add(971006);
+        AnniversaryGifts.add(971007);
+        AnniversaryGifts.add(971008);
+        AnniversaryGifts.add(971009);
+        AnniversaryGifts.add(971010);
+        AnniversaryGifts.add(5101000);
+        AnniversaryGifts.add(5101020);
+        AnniversaryGifts.add(5101100);
+        AnniversaryGifts.add(5101120);
+        AnniversaryGifts.add(5101040);
+        AnniversaryGifts.add(5101140);
+        AnniversaryGifts.add(5101060);
+        AnniversaryGifts.add(5101080);
 
 
     }
@@ -402,20 +385,6 @@ public class ItemBase {
         }
     }
 
-    public boolean validForSkills(ConcurrentHashMap<String, CharacterSkill> skills) {
-
-        CharacterSkill characterSkill;
-
-        if (this.skillRequired.isEmpty())
-            return true;
-
-        characterSkill = skills.get(this.skillRequired);
-
-        if (characterSkill == null)
-            return false;
-
-        return !(this.percentRequired > characterSkill.getModifiedAmountBeforeMods());
-    }
 
     public boolean canEquip(int slot, CharacterItemManager itemManager, AbstractCharacter abstractCharacter, Item item) {
 
@@ -427,10 +396,10 @@ public class ItemBase {
             if (!validForSlot(slot, itemManager.getEquipped(), item))
                 return false;
 
-            if (!validForSkills(abstractCharacter.getSkills()))
+            if (!ItemTemplate.validForSkills(item, abstractCharacter.getSkills()))
                 return false;
 
-            if (this.canCharacterEquip(abstractCharacter) == false)
+            if (ItemTemplate.canCharacterEquip(item, abstractCharacter) == false)
                 return false;
 
             return item.template.item_value != 0 || Kit.IsNoobGear(item.getItemBase().uuid);
@@ -873,54 +842,4 @@ public class ItemBase {
         return this.isClothArmor();
     }
 
-    public Boolean canCharacterEquip(AbstractCharacter character) {
-        return ValidRace(character.absRace) && ValidClass(character.absBaseClass, character.absPromotionClass) && ValidDiscipline(character.absDisciplines);
-    }
-
-    public Boolean ValidRace(Enum.MonsterType race) {
-
-        if (this.requiredRaces.isEmpty() && this.restrictedRaces.isEmpty())
-            return true;
-
-        if (this.requiredRaces.isEmpty() == false && race.elementOf(this.requiredRaces) == true)
-            return true;
-
-        return this.restrictedRaces.isEmpty() == false && race.elementOf(this.restrictedRaces) == false;
-    }
-
-    public Boolean ValidClass(Enum.ClassType base, Enum.ClassType profession) {
-
-        boolean requiredEmpty = this.requiredClasses == null || this.requiredClasses.isEmpty();
-        boolean restrictedEmpty = this.restrictedClasses == null || this.restrictedClasses.isEmpty();
-
-        if (requiredEmpty && restrictedEmpty)
-            return true;
-
-        if (this.requiredClasses != null && this.requiredClasses.isEmpty() == false)
-            if (this.requiredClasses.contains(base) || this.requiredClasses.contains(profession))
-                return true;
-
-        if (this.restrictedClasses != null && this.restrictedClasses.isEmpty() == false)
-            return this.restrictedClasses.contains(base) == false && this.restrictedClasses.contains(profession) == false;
-
-        return false;
-    }
-
-    public Boolean ValidDiscipline(EnumSet<Enum.DisciplineType> discs) {
-
-        boolean requiredEmpty = this.requiredDiscs == null || this.requiredDiscs.isEmpty();
-        boolean restrictedEmpty = this.restrictedDiscs == null || this.restrictedDiscs.isEmpty();
-
-        if (requiredEmpty && restrictedEmpty)
-            return true;
-
-        for (Enum.DisciplineType disc : discs) {
-            if (this.requiredDiscs.isEmpty() == false && this.requiredDiscs.contains(disc))
-                return true;
-
-            if (this.restrictedDiscs.isEmpty() == false && this.restrictedDiscs.contains(disc))
-                return false;
-        }
-        return false;
-    }
 }
diff --git a/src/engine/objects/ItemTemplate.java b/src/engine/objects/ItemTemplate.java
index baaf3c81..ffb37699 100644
--- a/src/engine/objects/ItemTemplate.java
+++ b/src/engine/objects/ItemTemplate.java
@@ -17,6 +17,7 @@ import org.pmw.tinylog.Logger;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class ItemTemplate {
 
@@ -376,4 +377,94 @@ public class ItemTemplate {
 
         return template.item_eq_slots_or.contains(EnumSet.of(Enum.ItemEquipSlotType.LHELD, Enum.ItemEquipSlotType.RHELD));
     }
+
+
+    public static Boolean ValidRace(Item item, Enum.MonsterType race) {
+
+        if (item.template.item_race_req.isEmpty() && item.template.item_race_res.isEmpty())
+            return true;
+
+        if (item.template.item_race_req.isEmpty() == false)
+            if (item.template.item_race_req.contains(race))
+                return true;
+
+        if (item.template.item_race_res.isEmpty() == false)
+            if (item.template.item_class_res.contains(race) == false)
+                return true;
+
+        return false;
+    }
+
+    public static Boolean ValidClass(Item item, Enum.ClassType base, Enum.ClassType profession) {
+
+        // Early exit if no entry
+
+        if (item.template.item_class_req.isEmpty() && item.template.item_class_res.isEmpty())
+            return true;
+
+        if (item.template.item_class_req.isEmpty() == false)
+            if (item.template.item_class_req.contains(base) || item.template.item_class_req.contains(profession))
+                return true;
+
+        if (item.template.item_class_res.isEmpty() == false)
+            if (item.template.item_class_res.contains(base) == false && item.template.item_class_res.contains(profession) == false)
+                return true;
+
+        return false;
+    }
+
+    public static Boolean ValidDiscipline(Item item, EnumSet<Enum.DisciplineType> discs) {
+
+        // Early exit if no entry
+
+        if (item.template.item_disc_req.isEmpty() && item.template.item_disc_res.isEmpty())
+            return true;
+
+        EnumSet<Enum.DisciplineType> workSet = EnumSet.copyOf(discs);
+
+        if (item.template.item_disc_req.isEmpty() == false) {
+
+            workSet.retainAll(item.template.item_disc_req);
+
+            if (workSet.isEmpty() == false)
+                return true;
+        }
+
+        if (item.template.item_disc_res.isEmpty() == false) {
+
+            workSet.retainAll(item.template.item_disc_res);
+
+            if (workSet.isEmpty() == false)
+                return true;
+        }
+
+        return false;
+    }
+
+    public static Boolean canCharacterEquip(Item item, AbstractCharacter character) {
+        return ValidRace(item, character.absRace) && ValidClass(item, character.absBaseClass, character.absPromotionClass) && ValidDiscipline(item, character.absDisciplines);
+    }
+
+    public static boolean validForSkills(Item item, ConcurrentHashMap<String, CharacterSkill> skills) {
+
+        CharacterSkill characterSkill;
+
+        if (item.template.item_skill_required.isEmpty())
+            return true;
+
+        for (String skillRequired : item.template.item_skill_required.keySet()) {
+
+            int required_value = item.template.item_skill_required.get(skillRequired);
+            characterSkill = skills.get(skillRequired);
+
+            if (characterSkill == null)
+                return false;
+
+            if (characterSkill.getModifiedAmountBeforeMods() > required_value)
+                return true;
+
+        }
+
+        return false;
+    }
 }