2026-07-26 19:08:44 -04:00
|
|
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
|
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
|
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
|
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
|
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
|
|
|
// Magicbane Emulator Project © 2013 - 2026
|
|
|
|
|
// https://www.magicbane.com
|
2022-04-30 09:41:17 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
package engine.objects;
|
|
|
|
|
|
|
|
|
|
import engine.gameManager.DbManager;
|
2024-05-12 13:36:47 -04:00
|
|
|
import engine.mbEnums;
|
2022-04-30 09:41:17 -04:00
|
|
|
import engine.net.ByteBufferWriter;
|
2026-10-21 08:25:20 -04:00
|
|
|
import engine.parsers.objects.RuneTemplate;
|
2022-04-30 09:41:17 -04:00
|
|
|
import engine.server.MBServerStatics;
|
2026-10-21 10:00:46 -04:00
|
|
|
import engine.util.Hasher;
|
2026-10-21 08:30:43 -04:00
|
|
|
import org.pmw.tinylog.Logger;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
|
|
|
|
import java.sql.ResultSet;
|
|
|
|
|
import java.sql.SQLException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class RuneBase extends AbstractGameObject {
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public static HashMap<Integer, ArrayList<Integer>> AllowedBaseClassRunesMap = new HashMap<>();
|
|
|
|
|
public static HashMap<Integer, ArrayList<Integer>> AllowedRaceRunesMap = new HashMap<>();
|
|
|
|
|
private final String name;
|
|
|
|
|
private final String description;
|
|
|
|
|
private final int type;
|
|
|
|
|
private final byte subtype;
|
|
|
|
|
private final ConcurrentHashMap<Integer, Boolean> race = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
|
|
|
|
|
private final ConcurrentHashMap<Integer, Boolean> baseClass = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
|
|
|
|
|
private final ConcurrentHashMap<Integer, Boolean> promotionClass = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
|
|
|
|
|
private final ConcurrentHashMap<Integer, Boolean> discipline = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
|
|
|
|
|
private final ArrayList<Integer> overwrite = new ArrayList<>();
|
|
|
|
|
private int levelRequired = 1;
|
|
|
|
|
private ArrayList<MobBaseEffects> effectsList = new ArrayList<>();
|
2026-10-21 10:00:46 -04:00
|
|
|
private mbEnums.RuneType runeType;
|
|
|
|
|
private int subTypeToken;
|
|
|
|
|
private int rank;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* No Table ID Constructor
|
|
|
|
|
*/
|
|
|
|
|
public RuneBase(String name, String description, int type, byte subtype, ArrayList<RuneBaseAttribute> attrs) {
|
|
|
|
|
super();
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
this.name = name;
|
|
|
|
|
this.description = description;
|
|
|
|
|
this.type = type;
|
|
|
|
|
this.subtype = subtype;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* Normal Constructor
|
|
|
|
|
*/
|
|
|
|
|
public RuneBase(String name, String description, int type, byte subtype, ArrayList<RuneBaseAttribute> attrs, int newUUID) {
|
|
|
|
|
super(newUUID);
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
this.name = name;
|
|
|
|
|
this.description = description;
|
|
|
|
|
this.type = type;
|
|
|
|
|
this.subtype = subtype;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* ResultSet Constructor
|
|
|
|
|
*/
|
|
|
|
|
public RuneBase(ResultSet rs) throws SQLException {
|
|
|
|
|
super(rs);
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
this.name = rs.getString("name");
|
|
|
|
|
this.description = rs.getString("description");
|
|
|
|
|
this.type = rs.getInt("type");
|
|
|
|
|
this.subtype = rs.getByte("subtype");
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
DbManager.RuneBaseQueries.GET_RUNE_REQS(this);
|
|
|
|
|
this.effectsList = DbManager.MobBaseQueries.GET_RUNEBASE_EFFECTS(this.getObjectUUID());
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2026-10-21 08:25:20 -04:00
|
|
|
/**
|
|
|
|
|
* Rune Template Constructor
|
|
|
|
|
* type and subtype are server enums that don't map cleanly from rune_type/rune_sub_type, so they
|
|
|
|
|
* come from the static_rune_runebase row, as do the requirement maps and effects until 2.5b/2.10.
|
2026-10-21 10:00:46 -04:00
|
|
|
* Talents with the same sub type token replace each other by rank (client 0x4695D0), so no overwrite list.
|
2026-10-21 08:25:20 -04:00
|
|
|
*/
|
|
|
|
|
public RuneBase(RuneTemplate rune, RuneBase dbRuneBase) {
|
|
|
|
|
super(rune.template_id);
|
|
|
|
|
|
|
|
|
|
this.name = rune.item_base_name;
|
|
|
|
|
this.description = rune.rune_dsc;
|
|
|
|
|
this.type = dbRuneBase.type;
|
|
|
|
|
this.subtype = dbRuneBase.subtype;
|
|
|
|
|
this.race.putAll(dbRuneBase.race);
|
|
|
|
|
this.baseClass.putAll(dbRuneBase.baseClass);
|
|
|
|
|
this.promotionClass.putAll(dbRuneBase.promotionClass);
|
|
|
|
|
this.discipline.putAll(dbRuneBase.discipline);
|
|
|
|
|
this.levelRequired = dbRuneBase.levelRequired;
|
|
|
|
|
this.effectsList = dbRuneBase.effectsList;
|
2026-10-21 10:00:46 -04:00
|
|
|
this.runeType = rune.rune_type;
|
|
|
|
|
this.rank = rune.rune_rank;
|
|
|
|
|
|
|
|
|
|
// Same token as CObjectIndex: unresolved sub types are stored as their hash
|
|
|
|
|
if (!rune.rune_sub_type.isEmpty())
|
|
|
|
|
this.subTypeToken = Hasher.SBStringHash(rune.rune_sub_type);
|
|
|
|
|
else
|
|
|
|
|
this.subTypeToken = rune.rune_sub_type_hash;
|
2026-10-21 08:25:20 -04:00
|
|
|
}
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public static RuneBase getRuneBase(int tableId) {
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
if (tableId == 0)
|
|
|
|
|
return null;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2024-04-05 07:59:44 -04:00
|
|
|
RuneBase rb = (RuneBase) DbManager.getFromCache(mbEnums.GameObjectType.RuneBase, tableId);
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
if (rb != null)
|
|
|
|
|
return rb;
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
return DbManager.RuneBaseQueries.GET_RUNEBASE(tableId);
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public static void serializeForClientMsg(RuneBase runeBase, ByteBufferWriter writer) {
|
|
|
|
|
writer.putInt(runeBase.type);
|
|
|
|
|
writer.putInt(0); // Pad
|
|
|
|
|
writer.putInt(runeBase.getObjectUUID());
|
|
|
|
|
writer.putInt(runeBase.getObjectType().ordinal());
|
|
|
|
|
writer.putInt(runeBase.getObjectUUID());
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2026-10-21 08:30:43 -04:00
|
|
|
// Iterates the static_rune_runebase rows: no rune field separates the player runes from the mob
|
|
|
|
|
// talents, and each row still holds the server type/subtype and requirement maps.
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public static void LoadAllRuneBases() {
|
|
|
|
|
|
2026-10-21 08:30:43 -04:00
|
|
|
ArrayList<RuneBase> dbRuneBases;
|
|
|
|
|
ArrayList<RuneBaseAttribute> attributes;
|
|
|
|
|
RuneTemplate rune;
|
|
|
|
|
int loadedCount = 0;
|
|
|
|
|
|
|
|
|
|
dbRuneBases = DbManager.RuneBaseQueries.LOAD_ALL_RUNEBASES();
|
|
|
|
|
RuneBaseAttribute.runeBaseAttributeMap.clear();
|
|
|
|
|
|
|
|
|
|
for (RuneBase dbRuneBase : dbRuneBases) {
|
|
|
|
|
rune = RuneTemplate._runes.get(dbRuneBase.getObjectUUID());
|
|
|
|
|
|
|
|
|
|
if (rune == null) {
|
|
|
|
|
Logger.warn("RuneBase " + dbRuneBase.getObjectUUID() + " has no rune; loaded from static_rune_runebase without attributes");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DbManager.addToCache(new RuneBase(rune, dbRuneBase));
|
|
|
|
|
attributes = RuneBaseAttribute.getAttributesForRune(rune);
|
|
|
|
|
|
|
|
|
|
// getAttrs() returns null for a rune without attributes, as the DB map did
|
|
|
|
|
if (!attributes.isEmpty())
|
|
|
|
|
RuneBaseAttribute.runeBaseAttributeMap.put(rune.template_id, attributes);
|
|
|
|
|
|
|
|
|
|
loadedCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger.info("Loaded " + loadedCount + " rune bases from runes");
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
RuneBase.AllowedBaseClassRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_BASECLASS();
|
|
|
|
|
RuneBase.AllowedRaceRunesMap = DbManager.RuneBaseQueries.LOAD_ALLOWED_STARTING_RUNES_FOR_RACE();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean equals(Object obj) {
|
|
|
|
|
|
|
|
|
|
if (!super.equals(obj)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj instanceof RuneBase) {
|
|
|
|
|
RuneBase rbObj = (RuneBase) obj;
|
|
|
|
|
if (!this.name.equals(rbObj.name)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.description.equals(rbObj.description)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.type != rbObj.type) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.subtype != rbObj.subtype) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/*
|
|
|
|
|
* Getters
|
|
|
|
|
*/
|
|
|
|
|
public String getName() {
|
|
|
|
|
return name;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public String getDescription() {
|
|
|
|
|
return description;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public int getType() {
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* @return the subtype
|
|
|
|
|
*/
|
|
|
|
|
public byte getSubtype() {
|
|
|
|
|
return subtype;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* @return the attrs
|
|
|
|
|
*/
|
|
|
|
|
public ArrayList<RuneBaseAttribute> getAttrs() {
|
|
|
|
|
return RuneBaseAttribute.runeBaseAttributeMap.get(this.getObjectUUID());
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public ConcurrentHashMap<Integer, Boolean> getRace() {
|
|
|
|
|
return this.race;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public ConcurrentHashMap<Integer, Boolean> getBaseClass() {
|
|
|
|
|
return this.baseClass;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public ConcurrentHashMap<Integer, Boolean> getPromotionClass() {
|
|
|
|
|
return this.promotionClass;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public ConcurrentHashMap<Integer, Boolean> getDiscipline() {
|
|
|
|
|
return this.discipline;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public ArrayList<Integer> getOverwrite() {
|
|
|
|
|
return this.overwrite;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2026-10-21 10:00:46 -04:00
|
|
|
public mbEnums.RuneType getRuneType() {
|
|
|
|
|
return this.runeType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 0 when the rune has no sub type; talents sharing a non-zero token replace each other
|
|
|
|
|
public int getSubTypeToken() {
|
|
|
|
|
return this.subTypeToken;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getRank() {
|
|
|
|
|
return this.rank;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/*
|
|
|
|
|
* Serializing
|
|
|
|
|
*/
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public int getLevelRequired() {
|
|
|
|
|
return this.levelRequired;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
public void setLevelRequired(int levelRequired) {
|
|
|
|
|
this.levelRequired = levelRequired;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
@Override
|
|
|
|
|
public void updateDatabase() {
|
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
2023-07-15 09:23:48 -04:00
|
|
|
/**
|
|
|
|
|
* @return the effectsList
|
|
|
|
|
*/
|
|
|
|
|
public ArrayList<MobBaseEffects> getEffectsList() {
|
|
|
|
|
return effectsList;
|
|
|
|
|
}
|
2022-04-30 09:41:17 -04:00
|
|
|
|
|
|
|
|
}
|