mirror of
https://github.com/araxiaonline/ets-module-collection.git
synced 2026-06-13 02:52:20 -04:00
155 lines
5.5 KiB
TypeScript
155 lines
5.5 KiB
TypeScript
|
|
import { BotStat } from "../constants/idmaps";
|
|
|
|
export enum ItemRole {
|
|
TANK = "Tank",
|
|
HEALER = "Healer",
|
|
PHYSICAL_DPS = "PhysicalDPS",
|
|
CASTER_DPS = "CasterDPS",
|
|
UNKNOWN = "Unknown"
|
|
}
|
|
|
|
export class ItemAnalyzer {
|
|
private item: Item;
|
|
private stats: Map<number, number> = new Map();
|
|
|
|
constructor(item: Item) {
|
|
this.item = item;
|
|
this.parseStats();
|
|
}
|
|
|
|
private parseStats() {
|
|
const entry = this.item.GetEntry();
|
|
// Query item_template for stats
|
|
// Note: item_template has 10 stat slots usually, but let's check 8 as per example
|
|
const sql = `SELECT
|
|
stat_type1, stat_value1,
|
|
stat_type2, stat_value2,
|
|
stat_type3, stat_value3,
|
|
stat_type4, stat_value4,
|
|
stat_type5, stat_value5,
|
|
stat_type6, stat_value6,
|
|
stat_type7, stat_value7,
|
|
stat_type8, stat_value8,
|
|
stat_type9, stat_value9,
|
|
stat_type10, stat_value10
|
|
FROM item_template WHERE entry = ${entry}`;
|
|
|
|
const result = WorldDBQuery(sql);
|
|
if (result) {
|
|
for (let i = 1; i <= 10; i++) {
|
|
const type = result.GetUInt32( (i-1)*2 ); // 0, 2, 4...
|
|
const value = result.GetInt32( (i-1)*2 + 1 ); // 1, 3, 5...
|
|
if (type > 0 && value !== 0) {
|
|
this.stats.set(type, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public GetRole(): ItemRole {
|
|
const subClass = this.item.GetSubClass();
|
|
const itemClass = this.item.GetClass();
|
|
|
|
// 2 = Weapon, 4 = Armor
|
|
if (itemClass === 4) { // Armor
|
|
// Check for Tank Stats
|
|
if (this.hasAnyStat([
|
|
BotStat.DEFENSE_SKILL_RATING,
|
|
BotStat.DODGE_RATING,
|
|
BotStat.PARRY_RATING,
|
|
BotStat.BLOCK_RATING,
|
|
BotStat.BLOCK_VALUE
|
|
])) {
|
|
return ItemRole.TANK;
|
|
}
|
|
|
|
// Check for Healer Stats (Spirit, Mp5)
|
|
// Note: Some caster gear has Spirit, but Mp5 is very healer specific usually.
|
|
if (this.hasAnyStat([BotStat.MANA_REGENERATION])) {
|
|
return ItemRole.HEALER;
|
|
}
|
|
|
|
// Intellect/Spell Power -> Caster or Healer
|
|
if (this.hasAnyStat([BotStat.INTELLECT, BotStat.SPELL_POWER])) {
|
|
// If Plate + Int -> Holy Paladin -> Healer
|
|
// (Ret uses Str, Prot uses Stam/Str/Def)
|
|
if (subClass === 4) { // Plate
|
|
return ItemRole.HEALER;
|
|
}
|
|
|
|
// If Mail + Int -> Shaman (Ele/Resto) or Paladin (Low level) -> 80 is Shaman
|
|
// Ele = Caster, Resto = Healer.
|
|
// Hard to distinguish without Hit Rating (Caster) vs Spirit/Mp5 (Healer)
|
|
if (this.hasAnyStat([BotStat.HIT_RATING, BotStat.HIT_SPELL_RATING])) {
|
|
return ItemRole.CASTER_DPS;
|
|
}
|
|
// If no Hit, and has Int, lean towards Healer if it has Spirit?
|
|
// Warlocks/Mages use Spirit too.
|
|
// Let's default to Caster DPS unless it has Mp5 or is Plate.
|
|
// Actually, let's check for Spirit.
|
|
if (this.hasAnyStat([BotStat.SPIRIT])) {
|
|
// Cloth + Spirit + Hit = Warlock/Mage/Priest DPS
|
|
// Cloth + Spirit + No Hit = Priest Healer?
|
|
if (this.hasAnyStat([BotStat.HIT_RATING])) {
|
|
return ItemRole.CASTER_DPS;
|
|
}
|
|
// Ambiguous. Let's default to Healer for Spirit items without Hit?
|
|
return ItemRole.HEALER;
|
|
}
|
|
|
|
return ItemRole.CASTER_DPS;
|
|
}
|
|
|
|
// Agility/Strength/AP -> Physical DPS or Tank (if no def stats)
|
|
if (this.hasAnyStat([
|
|
BotStat.AGILITY,
|
|
BotStat.STRENGTH,
|
|
BotStat.ATTACK_POWER,
|
|
BotStat.ARMOR_PENETRATION_RATING,
|
|
BotStat.EXPERTISE_RATING
|
|
])) {
|
|
// If Plate + Strength + No Tank Stats -> Ret/DK/War DPS
|
|
return ItemRole.PHYSICAL_DPS;
|
|
}
|
|
}
|
|
|
|
if (itemClass === 2) { // Weapon
|
|
// Similar logic
|
|
if (this.hasAnyStat([BotStat.SPELL_POWER, BotStat.INTELLECT])) {
|
|
if (this.hasAnyStat([BotStat.MANA_REGENERATION])) return ItemRole.HEALER;
|
|
if (this.hasAnyStat([BotStat.HIT_RATING])) return ItemRole.CASTER_DPS;
|
|
return ItemRole.CASTER_DPS; // Default
|
|
}
|
|
if (this.hasAnyStat([BotStat.DEFENSE_SKILL_RATING, BotStat.DODGE_RATING, BotStat.PARRY_RATING])) {
|
|
return ItemRole.TANK;
|
|
}
|
|
return ItemRole.PHYSICAL_DPS;
|
|
}
|
|
|
|
return ItemRole.UNKNOWN;
|
|
}
|
|
|
|
private hasAnyStat(stats: number[]): boolean {
|
|
for (const s of stats) {
|
|
if (this.stats.has(s)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public GetBestStatForRole(role: ItemRole): string {
|
|
switch (role) {
|
|
case ItemRole.TANK:
|
|
return "Stamina"; // Safe bet
|
|
case ItemRole.HEALER:
|
|
return "Spell Power";
|
|
case ItemRole.CASTER_DPS:
|
|
return "Spell Power"; // or Haste/Crit
|
|
case ItemRole.PHYSICAL_DPS:
|
|
return "Attack Power"; // or Agi/Str
|
|
default:
|
|
return "Stamina";
|
|
}
|
|
}
|
|
}
|