// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2026 // https://www.magicbane.com package engine.objects; import engine.gameManager.DbManager; import engine.mbEnums; import engine.mbEnums.GameObjectType; import engine.net.ByteBufferWriter; import engine.parsers.cache.CObjectIndex; import engine.parsers.objects.RuneTemplate; import engine.util.Hasher; import org.pmw.tinylog.Logger; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; public class PromotionClass extends AbstractGameObject { private final String name; private final String description; private final float healthMod; private final float manaMod; private final float staminaMod; private final ArrayList allowedRunes; private final ArrayList skillsGranted; private final ArrayList powersGranted; private final ArrayList effectsGranted; private final ArrayList effectsGrantedFighter; private final ArrayList effectsGrantedHealer; private final ArrayList effectsGrantedRogue; private final ArrayList effectsGrantedMage; private int token = 0; private ArrayList effectsList = new ArrayList<>(); /** * No Table ID Constructor */ public PromotionClass(String name, String description, ArrayList allowedRunes, ArrayList skillsGranted, ArrayList powersGranted) { super(); this.name = name; this.description = description; this.allowedRunes = allowedRunes; this.skillsGranted = skillsGranted; this.powersGranted = powersGranted; this.healthMod = 0f; this.manaMod = 0f; this.staminaMod = 0f; this.effectsGranted = new ArrayList<>(); this.effectsGrantedFighter = new ArrayList<>(); this.effectsGrantedHealer = new ArrayList<>(); this.effectsGrantedRogue = new ArrayList<>(); this.effectsGrantedMage = new ArrayList<>(); } /** * Normal Constructor */ public PromotionClass(String name, String description, ArrayList allowedRunes, ArrayList skillsGranted, ArrayList powersGranted, int newUUID) { super(newUUID); this.name = name; this.description = description; this.allowedRunes = allowedRunes; this.skillsGranted = skillsGranted; this.powersGranted = powersGranted; this.healthMod = 0f; this.manaMod = 0f; this.staminaMod = 0f; this.effectsGranted = new ArrayList<>(); this.effectsGrantedFighter = new ArrayList<>(); this.effectsGrantedHealer = new ArrayList<>(); this.effectsGrantedRogue = new ArrayList<>(); this.effectsGrantedMage = new ArrayList<>(); } /** * ResultSet Constructor */ public PromotionClass(ResultSet rs) throws SQLException { super(rs); this.name = rs.getString("name"); this.description = rs.getString("description"); this.token = rs.getInt("token"); this.healthMod = rs.getFloat("healthMod"); this.manaMod = rs.getFloat("manaMod"); this.staminaMod = rs.getFloat("staminaMod"); this.allowedRunes = DbManager.PromotionQueries.GET_ALLOWED_RUNES(this); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID()); this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID()); this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500); this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501); this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502); this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503); this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID()); } /** * Rune Template Constructor */ public PromotionClass(RuneTemplate rune) { super(rune.template_id); this.name = rune.obj_name; this.description = rune.rune_dsc; this.token = Hasher.SBStringHash(rune.rune_sub_type); this.healthMod = rune.rune_health; this.manaMod = rune.rune_mana; this.staminaMod = rune.rune_stamina; this.allowedRunes = getAllowedRuneTokens(rune); this.skillsGranted = DbManager.SkillReqQueries.GET_REQS_FOR_RUNE(this.getObjectUUID()); this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID()); this.effectsGranted = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE(this.getObjectUUID()); this.effectsGrantedFighter = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2500); this.effectsGrantedHealer = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2501); this.effectsGrantedRogue = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2502); this.effectsGrantedMage = DbManager.RuneBaseEffectQueries.GET_EFFECTS_FOR_RUNEBASE((this.getObjectUUID() * 10) + 2503); this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID()); } // Promotions are the CLASS runes that require a base class; this skips the creation classes and Pet 2522. public static boolean isPromotionRune(RuneTemplate rune) { return rune.rune_type == mbEnums.RuneType.CLASS && !rune.rune_is_standard_character_creation && !rune.item_class_req.isEmpty(); } // Race and base class tokens are SBStringHash(rune_sub_type) of the runes named in the req lists. // Every promotion rune's lists are whitelists (restrict false). private static ArrayList getAllowedRuneTokens(RuneTemplate rune) { ArrayList tokens = new ArrayList<>(); Integer classRuneId; int token; for (mbEnums.MonsterType race : rune.item_race_req) for (int raceRuneId : CObjectIndex.getRaceRuneIds(race)) { token = Hasher.SBStringHash(RuneTemplate._runes.get(raceRuneId).rune_sub_type); if (!tokens.contains(token)) tokens.add(token); } for (mbEnums.ClassType classType : rune.item_class_req) { classRuneId = CObjectIndex.getClassRuneId(classType); if (classRuneId != null) tokens.add(Hasher.SBStringHash(RuneTemplate._runes.get(classRuneId).rune_sub_type)); } return tokens; } public static void LoadAllPromotions() { int loadedCount = 0; for (RuneTemplate rune : RuneTemplate._runes.values()) { if (!isPromotionRune(rune)) continue; DbManager.addToCache(new PromotionClass(rune)); loadedCount++; } Logger.info("Loaded " + loadedCount + " promotion classes from runes"); // The CSR/admin rows 2901+ have no promotion rune; the DB loader skips ids already cached DbManager.PromotionQueries.GET_ALL_PROMOTIONS(); } public static void serializeForClientMsg(PromotionClass promotionClass, ByteBufferWriter writer) { writer.putInt(3); // For BaseClass writer.putInt(0); // Pad writer.putInt(promotionClass.getObjectUUID()); writer.putInt(promotionClass.getObjectType().ordinal()); writer.putInt(promotionClass.getObjectUUID()); } public static PromotionClass GetPromtionClassFromCache(int runeID) { if (runeID == 0) return null; return (PromotionClass) DbManager.getFromCache(GameObjectType.PromotionClass, runeID); } /* * Getters */ public String getName() { return name; } public String getDescription() { return description; } public int getToken() { return this.token; } public float getHealthMod() { return this.healthMod; } public float getManaMod() { return this.manaMod; } public float getStaminaMod() { return this.staminaMod; } public boolean isAllowedRune(int token) { for (int b : this.allowedRunes) { if (token == b) { return true; } } return false; } public ArrayList getRuneList() { return this.allowedRunes; } public ArrayList getSkillsGranted() { return this.skillsGranted; } public ArrayList getPowersGranted() { return this.powersGranted; } /* * Serializing */ public ArrayList getEffectsGranted() { return this.effectsGranted; } public ArrayList getEffectsGranted(int baseClassID) { if (baseClassID == 2500) return this.effectsGrantedFighter; else if (baseClassID == 2501) return this.effectsGrantedHealer; else if (baseClassID == 2502) return this.effectsGrantedRogue; else if (baseClassID == 2503) return this.effectsGrantedMage; else return new ArrayList<>(); } @Override public void updateDatabase() { // TODO Create update logic. } public ArrayList getEffectsList() { return effectsList; } public void setEffectsList(ArrayList effectsList) { this.effectsList = effectsList; } }