diff --git a/src/engine/objects/RuneBase.java b/src/engine/objects/RuneBase.java index fd702ea8..3f5e04b7 100644 --- a/src/engine/objects/RuneBase.java +++ b/src/engine/objects/RuneBase.java @@ -22,6 +22,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -29,6 +30,9 @@ public class RuneBase extends AbstractGameObject { public static HashMap> AllowedBaseClassRunesMap = new HashMap<>(); public static HashMap> AllowedRaceRunesMap = new HashMap<>(); + // Flagged rune_is_standard_character_creation but missing from CharCreateRuneList.cfg ATTRRUNES: + // admin runes 2910/2911, unused duplicates, and Proficient with Bows (commented out in the cfg). + private static final Set NON_CREATION_TALENTS = Set.of(2910, 2911, 250081, 250116, 250117, 250123, 250124, 250125); private final String name; private final String description; private final int type; @@ -215,8 +219,84 @@ public class RuneBase extends AbstractGameObject { Logger.info("Loaded " + loadedCount + " rune bases from runes"); - RuneBase.AllowedBaseClassRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_BASECLASS(); - RuneBase.AllowedRaceRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_RACE(); + loadCreationTalents(); + } + + // Every creation race and class gets a list, so the 111111 "any" sentinel of the DB tables is no longer used. + + private static void loadCreationTalents() { + + ArrayList creationRaceIDs = new ArrayList<>(); + ArrayList creationClassIDs = new ArrayList<>(); + ArrayList listedRaceIDs; + ArrayList listedClassIDs; + Integer classRuneID; + boolean listed; + boolean allowed; + int talentCount = 0; + + AllowedRaceRunesMap = new HashMap<>(); + AllowedBaseClassRunesMap = new HashMap<>(); + + for (RuneTemplate rune : RuneTemplate._runes.values()) { + + if (!rune.rune_is_standard_character_creation) + continue; + + if (rune.rune_type == mbEnums.RuneType.RACE) { + creationRaceIDs.add(rune.template_id); + AllowedRaceRunesMap.put(rune.template_id, new ArrayList<>()); + } + + if (rune.rune_type == mbEnums.RuneType.CLASS) { + creationClassIDs.add(rune.template_id); + AllowedBaseClassRunesMap.put(rune.template_id, new ArrayList<>()); + } + } + + for (RuneTemplate rune : RuneTemplate._runes.values()) { + + if (!rune.rune_is_standard_character_creation || rune.rune_type != mbEnums.RuneType.TALENT) + continue; + + if (NON_CREATION_TALENTS.contains(rune.template_id)) + continue; + + listedRaceIDs = new ArrayList<>(); + listedClassIDs = new ArrayList<>(); + + for (mbEnums.MonsterType raceType : rune.item_race_req) + listedRaceIDs.addAll(CObjectIndex.getRaceRuneIds(raceType)); + + for (mbEnums.ClassType classType : rune.item_class_req) { + classRuneID = CObjectIndex.getClassRuneId(classType); + + if (classRuneID != null) + listedClassIDs.add(classRuneID); + } + + // restrict true = blacklist, false = whitelist (ArcItemRestrict_Check 0x4BAC60) + for (int raceRuneID : creationRaceIDs) { + listed = listedRaceIDs.contains(raceRuneID); + allowed = rune.item_race_req_restrict ? !listed : listed; + + if (allowed) + AllowedRaceRunesMap.get(raceRuneID).add(rune.template_id); + } + + for (int baseClassID : creationClassIDs) { + listed = listedClassIDs.contains(baseClassID); + allowed = rune.item_class_req_restrict ? !listed : listed; + + if (allowed) + AllowedBaseClassRunesMap.get(baseClassID).add(rune.template_id); + } + + talentCount++; + } + + Logger.info("Loaded " + talentCount + " creation talents for " + creationRaceIDs.size() + " races and " + + creationClassIDs.size() + " classes from runes"); } @Override