Files
ets-module-collection/modules/classes/item-analyzer.ts

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";
}
}
}