Files
Server/src/engine/objects/PromotionClass.java
T
MagicBotandClaude Opus 5.5 d576ed1468 Stop reading the replaced race, base class and promotion columns
static_rune_race is read only for the race ids and the server-only heights;
the hair/beard style, racebaseclass, baseclass and promotionrunereq queries
are gone. GET_BASE_CLASS is cache-only, which also drops the obj_account
cache-miss query. CSR/admin promotions 2901+ (no promotionrunereq rows) get an
empty allowed list. No value changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 12:41:06 -04:00

239 lines
7.8 KiB
Java

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// 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<Integer> allowedRunes;
private final ArrayList<SkillReq> skillsGranted;
private final ArrayList<PowerReq> powersGranted;
private int token = 0;
private ArrayList<MobBaseEffects> effectsList = new ArrayList<>();
/**
* No Table ID Constructor
*/
public PromotionClass(String name, String description,
ArrayList<Integer> allowedRunes, ArrayList<SkillReq> skillsGranted, ArrayList<PowerReq> 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;
}
/**
* Normal Constructor
*/
public PromotionClass(String name, String description,
ArrayList<Integer> allowedRunes, ArrayList<SkillReq> skillsGranted, ArrayList<PowerReq> 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;
}
/**
* ResultSet Constructor
* Only the CSR/admin rows 2901+ load from the DB; they have no promotion rune and allow no runes.
*/
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 = new ArrayList<>();
this.skillsGranted = SkillReq.getSkillReqsForRune(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsList = MobBaseEffects.getEffectsForRune(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 = SkillReq.getSkillReqsForRune(this.getObjectUUID());
this.powersGranted = PowerReq.getPowerReqsForRune(this.getObjectUUID());
this.effectsList = MobBaseEffects.getEffectsForRune(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<Integer> getAllowedRuneTokens(RuneTemplate rune) {
ArrayList<Integer> 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<Integer> getRuneList() {
return this.allowedRunes;
}
public ArrayList<SkillReq> getSkillsGranted() {
return this.skillsGranted;
}
public ArrayList<PowerReq> getPowersGranted() {
return this.powersGranted;
}
/*
* Serializing
*/
@Override
public void updateDatabase() {
// TODO Create update logic.
}
public ArrayList<MobBaseEffects> getEffectsList() {
return effectsList;
}
public void setEffectsList(ArrayList<MobBaseEffects> effectsList) {
this.effectsList = effectsList;
}
}