From 207f7027f1a1337f82d5508e3ec51ce80d48c4ce Mon Sep 17 00:00:00 2001 From: Ben Carter Date: Sat, 10 Feb 2024 22:59:53 -0500 Subject: [PATCH] Updated to add stats v1 --- modules/UI/botmgr/bot.ts | 59 +++- modules/UI/botmgr/botUnit.ts | 301 ++++++++++++++++++-- modules/UI/botmgr/botmgr.client.ts | 430 ++++++++++++++++++----------- modules/UI/botmgr/botmgr.server.ts | 167 ++++------- modules/constants/idmaps.ts | 65 ++++- 5 files changed, 730 insertions(+), 292 deletions(-) diff --git a/modules/UI/botmgr/bot.ts b/modules/UI/botmgr/bot.ts index 963f727..e1c9a52 100644 --- a/modules/UI/botmgr/bot.ts +++ b/modules/UI/botmgr/bot.ts @@ -1,6 +1,13 @@ import { BotData } from './botmgr.server'; import { Equipment } from './botmgr.server'; +type ItemInHand = { + entry: number | undefined, + link: string | undefined, + bot: number | undefined, + slot: number | undefined +} + /** * This is the UI bot data manager class to make it easier * to managed bot data in the UI. @@ -9,6 +16,8 @@ export class BotStorage { private storage: Map = new Map(); private active: number = null; + private pickedUp: boolean = false; + private itemInHand: ItemInHand = { entry: undefined, link: undefined, bot: undefined, slot: undefined }; public GetBotData(entry: number): BotData | undefined { return this.storage.get(entry); @@ -22,14 +31,16 @@ export class BotStorage { } SetBotData(entry: number, data: BotData): void { - + this.storage.set(entry, data); } SetBotItem(botId: number, slot: BotEquipmentSlotNum, item: Equipment): void { - const bot = this.GetBotData(botId); - if(bot) { - bot.equipment[slot] = item; + const botData = this.GetBotData(botId); + if(botData) { + botData.equipment[slot] = item; } + + this.SetBotData(botId, botData); } UpdateBotData(entry: number, data: BotData): void { @@ -48,4 +59,44 @@ export class BotStorage { this.active = null; } + IsPickedUp(): boolean { + return this.pickedUp; + } + + BotItemPickedUp(botId: number, entry: number, link: string): void { + const bot = this.GetBotData(botId); + if(bot) { + this.itemInHand.entry = entry; + this.itemInHand.link = link; + this.itemInHand.bot = botId; + this.itemInHand.slot = this.GetSlotByItemId(entry); + } + this.pickedUp = true; + + } + + GetItemInHand(): ItemInHand { + return this.itemInHand; + } + + BotItemCursorClear(): void { + this.itemInHand.entry = undefined; + this.itemInHand.link = undefined; + this.itemInHand.bot = undefined; + this.itemInHand.slot = undefined; + this.pickedUp = false; + } + + GetSlotByItemId(entry: number): number | undefined { + const botData = this.GetBotData(this.GetActive()); + const allItems = Object.entries(botData.equipment) + for(const [slot, item] of allItems) { + if(item.entry === entry) { + return parseInt(slot); + } + } + return; + } + + } \ No newline at end of file diff --git a/modules/UI/botmgr/botUnit.ts b/modules/UI/botmgr/botUnit.ts index 24c6e5c..9ac049c 100644 --- a/modules/UI/botmgr/botUnit.ts +++ b/modules/UI/botmgr/botUnit.ts @@ -1,5 +1,5 @@ import * as Common from '../../constants/idmaps'; -import { Equipment, EquipmentList } from './botmgr.server'; +import { BotData, Equipment, EquipmentList } from './botmgr.server'; type CharInfo = { name: string, @@ -10,19 +10,32 @@ type CharInfo = { raceId: keyof typeof Common.RacesMapping } -type CharStats = Record; -type CharTalentSpec = typeof Common.BotTalentSpecs[keyof typeof Common.BotTalentSpecs]; -type CharRoles = typeof Common.BotRoles[keyof typeof Common.BotRoles]; +type CharStats = Partial>; +function humanizeTalentName(input: string): string { + if (input.length === 0) { + return input; // Return unchanged if the input is an empty string + } + + const parts = input.split("_"); + parts[0] = parts[0].toLowerCase(); + parts[0] = parts[0].charAt(0).toUpperCase() + parts[0].slice(1); + parts[1] = parts[1].toLowerCase(); + parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1); + + return `${parts[1]} ${parts[0]}`; +} export class BotUnit { protected myself: Creature; protected myOwner: Player; protected charinfo: CharInfo; protected equipment: EquipmentList; - protected stats: CharStats; - protected talentSpecId: CharTalentSpec; - protected roles: CharRoles; + protected statsLeft: Record[]; + protected statsRight: Record[]; + protected talentSpecId: number; + protected roles: number; + protected allStats: Record = {}; constructor(creature: Creature) { if(!creature.IsNPCBot()) { @@ -30,7 +43,7 @@ export class BotUnit { } this.myself = creature; - this.myOwner = creature.GetOwner(); + this.myOwner = creature.GetBotOwner(); this.charinfo = { name: creature.GetName(), level: creature.GetLevel(), @@ -40,20 +53,188 @@ export class BotUnit { raceId: creature.GetRace() }; this.equipment = this._lookupEquipment(); + this.talentSpecId = creature.GetTalentSpec(); + this.parseStats(creature.GetBotDump()); + this.statsLeft = this._lookupStats('left'); + this.statsRight = this._lookupStats('right'); this.roles = creature.GetBotRoles(); - + + } - // public isMeleeDps(): boolean { - // const meleeClassMap = [ - // Common.Characte + public toBotData(): BotData { + return { + name: this.charinfo.name, + entry: this.myself.GetEntry(), + owner: this.myOwner.GetName(), + level: this.charinfo.level, + class: this.charinfo.className, + classId: this.charinfo.classId, + race: this.charinfo.raceName, + raceId: this.charinfo.raceId, + talentSpec: this.talentSpecId, + talentSpecName: humanizeTalentName(this.talentSpecName()), + roles: this.roles, + equipment: this.equipment, + leftStats: this.statsLeft, + rightStats: this.statsRight, + allStats: this.allStats + } + } - // ] + public isHealer(): boolean { + if(this.talentSpecId == Common.TalentSpecs.SHAMAN_RESTORATION || + this.talentSpecId == Common.TalentSpecs.PRIEST_DISCIPLINE || + this.talentSpecId == Common.TalentSpecs.PRIEST_HOLY || + this.talentSpecId == Common.TalentSpecs.PALADIN_HOLY || + this.talentSpecId == Common.TalentSpecs.DRUID_RESTORATION) { + return true; + } + return false; + } - // if(this.charinfo.classId) + public isDualWield(): boolean { + if(this.talentSpecId == Common.TalentSpecs.ROGUE_COMBAT || + this.talentSpecId == Common.TalentSpecs.ROGUE_SUBTLETY || + this.talentSpecId == Common.TalentSpecs.ROGUE_ASSASSINATION || + this.talentSpecId == Common.TalentSpecs.SHAMAN_ENHANCEMENT || + this.talentSpecId == Common.TalentSpecs.WARRIOR_FURY) { + if(this.equipment[Common.BotEquipSlot.MAINHAND] && + this.equipment[Common.BotEquipSlot.OFFHAND]) { + return true; + } - // // return this.roles === Common.BotRoles.MeleeDps; - // } + } + } + + + public GetMeleeStats (): Record{ + const botStatValues = Object.values(Common.BotStatLabel); + type BotStatValues = typeof botStatValues[number]; + + return { + left: [ + "Strength", + "Agility", + "Dmg Main", + "Power", + "Hit Rating", + "Crit %", + "Expertise", + "Armor Pen" + ], + right: [ + "Haste Rating", + "Armor", + "Stamina", + "Defense", + "Dodge", + "Parry", + "Block", + "Physical Resist" + ] + } + } + + public GetRangedStats (): Record{ + return { + left: [ + "Strength", + "Agility", + "Dmg Range", + "Speed", + "Power", + "Hit Rating", + "Crit %", + "Armor Pen" + ], + right: [ + "Expertise", + "Haste Rating", + "Armor", + "Stamina", + "Defense", + "Dodge", + "Parry", + "Block", + ] + } + } + + public GetCasterStats (): Record { + return { + left: [ + "Intellect", + "Spirit", + "Stamina", + "Bonus Dmg", + "Crit %", + "Hit Rating", + "Spell Pen" + ], + right: [ + "Haste Rating", + "Spell Resist", + "MP5", + "Dodge", + "Armor", + "Parry", + ] + } + } + + public GetStatMappings() { + + switch(this.talentSpecId) { + case Common.TalentSpecs.WARRIOR_ARMS: + case Common.TalentSpecs.WARRIOR_FURY: + case Common.TalentSpecs.WARRIOR_PROTECTION: + case Common.TalentSpecs.PALADIN_PROTECTION: + case Common.TalentSpecs.PALADIN_RETRIBUTION: + case Common.TalentSpecs.DK_BLOOD: + case Common.TalentSpecs.DK_FROST: + case Common.TalentSpecs.DK_UNHOLY: + case Common.TalentSpecs.ROGUE_ASSASSINATION: + case Common.TalentSpecs.ROGUE_COMBAT: + case Common.TalentSpecs.ROGUE_SUBTLETY: + case Common.TalentSpecs.SHAMAN_ENHANCEMENT: + case Common.TalentSpecs.DRUID_FERAL: + return this.GetMeleeStats(); + + case Common.TalentSpecs.HUNTER_SURVIVAL: + case Common.TalentSpecs.HUNTER_MARKSMANSHIP: + case Common.TalentSpecs.HUNTER_BEASTMASTERY: + return this.GetRangedStats(); + + case Common.TalentSpecs.MAGE_ARCANE: + case Common.TalentSpecs.MAGE_FIRE: + case Common.TalentSpecs.MAGE_FROST: + case Common.TalentSpecs.WARLOCK_AFFLICTION: + case Common.TalentSpecs.WARLOCK_DEMONOLOGY: + case Common.TalentSpecs.WARLOCK_DESTRUCTION: + case Common.TalentSpecs.PRIEST_DISCIPLINE: + case Common.TalentSpecs.PRIEST_HOLY: + case Common.TalentSpecs.PRIEST_SHADOW: + case Common.TalentSpecs.SHAMAN_ELEMENTAL: + case Common.TalentSpecs.SHAMAN_RESTORATION: + case Common.TalentSpecs.DRUID_BALANCE: + case Common.TalentSpecs.DRUID_RESTORATION: + return this.GetCasterStats(); + + default: + print(`Unknown Talent Spec: ${this.talentSpecId}`); + } + } + + public talentSpecName() { + // print(`Talent Spec: ${this.talentSpecId}`); + const keys = Object.keys(Common.TalentSpecs); + for(let i=0; i < keys.length; i++) { + if(Common.TalentSpecs[keys[i]] === this.talentSpecId) { + return keys[i]; + } + } + } private _lookupEquipment(): EquipmentList { const myEquipment = {} as EquipmentList; @@ -75,4 +256,92 @@ export class BotUnit { return myEquipment; } + + private _lookupStats(panel: 'left' | 'right'): Record[] { + const statMappings = this.GetStatMappings(); + const classStats: Record[] = [] + + for(let stat = 0; stat < statMappings[panel].length; stat++) { + const statName = statMappings[panel][stat]; + let statValue = this.allStats[statName]; + const statRecord= {}; + + // handle some special cases for stats + if(statName === 'Dmg Main' || statName === 'Dmg Range' || statName == 'Dmg Off') { + statValue = statValue.replace(" min: ", "").replace(", max: ", "-"); + statRecord[statName] = statValue; + classStats.push(statRecord); + + // Go ahead and add dual wield damage also + if(this.isDualWield()) { + const offhand = this.allStats['Damage Range (Offhand)']; + statRecord['Damage Range (Offhand)'] = offhand.replace(" min: ", "").replace(", max: ", "-"); + classStats.push(statRecord); + } + continue; + } + + if(this.isHealer() && statName === 'Bonus Dmg') { + statRecord['Bonus Heals'] = statValue; + classStats.push(statRecord); + print(`Stat: Bonus Heals = ${statValue}`); + continue; + } + + if(statName && statValue) { + statRecord[statName] = statValue; + classStats.push(statRecord); + print(`Stat: ${statName} = ${statValue}`); + } else { + print("failed to get stat: " + statName); + } + + } + + return classStats; + } + + private parseStats(botdump: string) { + const stats = botdump.split('\n'); + for(let i=0; i `BotMgr${name}` + (entry ? entry : ''); const compId = (botId: number, name: string) => `${botId}:BotMgr${name}`; +// includes of global polyfills in main file for submodules +let incObjectEntries = { 1: 'inlude'}; Object.entries(incObjectEntries); +let incParseInt = parseInt('1'); + function ucase(input: string): string { if (input.length === 0) { return input; // Return unchanged if the input is an empty string @@ -41,29 +45,38 @@ function ucase(input: string): string { return firstLetter + restOfTheString; } +function humanizeName(input: string): string { + if (input.length === 0) { + return input; // Return unchanged if the input is an empty string + } + + const parts = input.split("_"); + parts[0] = parts[0].toLowerCase(); + parts[0] = parts[0].charAt(0).toUpperCase() + parts[0].slice(1); + parts[1] = parts[1].toLowerCase(); + parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1); + + return `${parts[1]} ${parts[0]}`; +} + // If we are a client file. aio.AddAddon() will return false and this file will be serialized and sent to client. if(!aio.AddAddon()) { const botMgrHandlers = aio.AddHandlers('BotMgr', {}); const InfoFramePool: Map = new Map(); const ComponentsPool: Map = new Map(); // key botId + ":" + componentid + const ItemClickFuncs: Map = new Map(); // containerid (1-13):itemslotId (1-36) => click function const botStorage: BotStorage = new BotStorage(); let BotItemTooltip: WoWAPI.GameTooltip; - /** - * All Resists for the bot - * Is a SubFrame as well as children. - * @param parent - * @param resists - */ - function AddResistFrame(parent: WoWAPI.Frame, resists: any = {}) { + function AddResistFrame(parent: WoWAPI.Frame, botData: BotData) { const resistFrame = CreateFrame("Frame", id("ResistsFrame"), parent); resistFrame.SetSize(32, 160); resistFrame.SetPoint("TOPRIGHT", parent, "TOPLEFT", 297, -77); - const magicRes1 = CreateFrame("Frame", id("MagicResFrame1"), resistFrame, "MagicResistanceFrameTemplate", 6); - magicRes1.SetPoint("TOP", resistFrame, "TOP", 0, 0); + const magicRes1 = CreateFrame("Frame", id("MagicResFrame1"), resistFrame, "MagicResistanceFrameTemplate", 1); + magicRes1.SetPoint("TOP", 0, 0); magicRes1.SetSize(32, 32); const magResBack1 = magicRes1.CreateTexture(id("MagicResTexture1"), "BACKGROUND"); @@ -71,15 +84,78 @@ if(!aio.AddAddon()) { magResBack1.SetTexCoord(0, 1, 0.2265, 0.3398); magResBack1.SetAllPoints(magicRes1); - const magResFont1 = magicRes1.CreateFontString(id("MagicResFont1"), "BACKGROUND", "GameFontHighlightSmall"); - magResFont1.SetPoint("BOTTOM", magicRes1, null, 0, 3); - magResFont1.SetText("X"); + const magResFont1 = magicRes1.CreateFontString(id("Resist2"), "BACKGROUND", "GameFontHighlightSmall"); + magResFont1.SetPoint("BOTTOM", magResBack1, null, 0, 3); + magResFont1.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats["Resistance: arcane"]}`); + ComponentsPool.set(compId(botData.entry, "Resist1"), magResFont1); + + // End Arcance Resistance + + const magicRes2 = CreateFrame("Frame", id("MagicResFrame2"), resistFrame, "MagicResistanceFrameTemplate", 2); + magicRes2.SetPoint("TOP", magicRes1, "BOTTOM", 0, 0); + magicRes2.SetSize(32, 32); + + const magResBack2 = magicRes2.CreateTexture(id("MagicResTexture2"), "BACKGROUND"); + magResBack2.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ResistanceIcons"); + magResBack2.SetTexCoord(0, 1, 0, 0.11328125); + magResBack2.SetAllPoints(magicRes2); + + const magResFont2 = magicRes1.CreateFontString(id("Resist2"), "BACKGROUND", "GameFontHighlightSmall"); + magResFont2.SetPoint("BOTTOM", magicRes2, null, 0, 3); + magResFont2.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats["Resistance: fire"]}`); + ComponentsPool.set(compId(botData.entry, "Resist2"), magResFont2); + + // end fire resistance + + const magicRes3 = CreateFrame("Frame", id("MagicResFrame3"), resistFrame, "MagicResistanceFrameTemplate", 3); + magicRes3.SetPoint("TOP", magicRes2, "BOTTOM", 0, 0); + magicRes3.SetSize(32, 32); + + const magResBack3 = magicRes3.CreateTexture(id("MagicResTexture3"), "BACKGROUND"); + magResBack3.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ResistanceIcons"); + magResBack3.SetTexCoord(0, 1, 0.11328125, 0.2265625); + magResBack3.SetAllPoints(magicRes3); + 3 + const magResFont3 = magicRes3.CreateFontString(id("Resist3"), "BACKGROUND", "GameFontHighlightSmall"); + magResFont3.SetPoint("BOTTOM", magicRes3, null, 0, 3); + magResFont3.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats["Resistance: nature"]}`); + ComponentsPool.set(compId(botData.entry, "Resist3"), magResFont3); + + // end nature resistance + + const magicRes4 = CreateFrame("Frame", id("MagicResFrame4"), resistFrame, "MagicResistanceFrameTemplate", 4); + magicRes4.SetPoint("TOP", magicRes3, "BOTTOM", 0, 0); + magicRes4.SetSize(32, 32); + + const magResBack4 = magicRes4.CreateTexture(id("MagicResTexture4"), "BACKGROUND"); + magResBack4.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ResistanceIcons"); + magResBack4.SetTexCoord(0, 1, 0.33984375, 0.453125); + magResBack4.SetAllPoints(magicRes4); + 3 + const magResFont4 = magicRes4.CreateFontString(id("Resist4"), "BACKGROUND", "GameFontHighlightSmall"); + magResFont4.SetPoint("BOTTOM", magicRes4, null, 0, 3); + magResFont4.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats["Resistance: frost"]}`); + ComponentsPool.set(compId(botData.entry, "Resist4"), magResFont4); + + // end frost resistance + + const magicRes5 = CreateFrame("Frame", id("MagicResFrame5"), resistFrame, "MagicResistanceFrameTemplate", 5); + magicRes5.SetPoint("TOP", magicRes4, "BOTTOM", 0, 0); + magicRes5.SetSize(32, 32); + + const magResBack5 = magicRes5.CreateTexture(id("MagicResTexture5"), "BACKGROUND"); + magResBack5.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ResistanceIcons"); + magResBack5.SetTexCoord(0, 1, 0.453125, 0.56640625); + magResBack5.SetAllPoints(magicRes5); + 3 + const magResFont5 = magicRes5.CreateFontString(id("Resist5"), "BACKGROUND", "GameFontHighlightSmall"); + magResFont5.SetPoint("BOTTOM", magicRes5, null, 0, 3); + magResFont5.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats["Resistance: shadow"]}`); + ComponentsPool.set(compId(botData.entry, "Resist5"), magResFont5); + + // end shadow resistance } - /** - * This is for the Characters left picture and class,race, name details. - * Only created once per bot panel. - */ function AddPortrait(parent: WoWAPI.Frame, botData: BotData) { const portrait = parent.CreateTexture(id("Portrait", botData.entry), "ARTWORK"); portrait.SetPoint("TOPLEFT", 10, -7); @@ -114,6 +190,11 @@ if(!aio.AddAddon()) { infoTextFont.SetText(`${YELLOW_FONT_COLOR_CODE} Level ${UnitLevel("target")} ${botData.race} ${botData.class}`); } + const spec = infoTextFrame.CreateFontString(id("SpecFont", botData.entry), "BACKGROUND", "GameFontHighlightSmall"); + spec.SetText(`${botData.talentSpecName}`); + spec.SetPoint("TOP", infoTextFont, "BOTTOM", 0, -2); + ComponentsPool.set(compId(botData.entry, "SpecFont"), spec); + infoTextFont.SetSize(300,12); infoTextFont.SetPoint("CENTER",0,0); @@ -223,35 +304,60 @@ if(!aio.AddAddon()) { equipFrame = CreateFrame("Frame", id("RightEquipment"), parent, null, 2); equipFrame.SetPoint("TOPRIGHT", -40, -73); equipFrame.SetSize(40, 330); - ComponentsPool.set(compId(botData.entry, "RightEquipment"), equipFrame); UpdateEquipFrame('right', equipFrame, botData); - + ComponentsPool.set(compId(botData.entry, "RightEquipment"), equipFrame); } if(!frames.weapons) { equipFrame = CreateFrame("Frame", id("WeaponEquipment"), parent, null, 3); equipFrame.SetPoint("CENTER", -10, -147); equipFrame.SetSize(129, 40); - ComponentsPool.set(compId(botData.entry, "WeaponsEquipment"), equipFrame); UpdateEquipFrame('weapons', equipFrame, botData); - // const placeholder = equipFrame.CreateTexture(id("RightEquipmentPlaceholder"), "OVERLAY"); - // placeholder.SetAllPoints(equipFrame); - // placeholder.SetTexture(0,0,0,0.8); + ComponentsPool.set(compId(botData.entry, "WeaponsEquipment"), equipFrame); + } } - function CreateStats(parent: WoWAPI.Frame, botData: BotData) { - - const reverseObject = (obj: { [key: string]: any }): { [key: string]: string } => - Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k])); - const lookup = reverseObject(BotStat); - + function AddStats(parent: WoWAPI.Frame, botData: BotData) { + const leftStats = botData.leftStats; + const rightStats = botData.rightStats; + for(let i =0; i < leftStats.length; i++) { + const statName = Object.keys(leftStats[i])[0]; + const statLabel = parent.CreateFontString(id(`StatName-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statLabel.SetPoint("TOPLEFT", parent, "TOPLEFT", 5, -7 - (i * 14)); + statLabel.SetText(`${statName}:`); + statLabel.SetJustifyH("LEFT"); + const statValue = parent.CreateFontString(id(`StatValue-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statValue.SetPoint("TOPRIGHT", parent, "TOP", -4, -5 - (i * 14)); + statValue.SetSize(50, 14); + statValue.SetText(`${colors('white')}${leftStats[i][statName]}`); + statValue.SetJustifyH("RIGHT"); + + } + + for(let i =0; i < rightStats.length; i++) { + const statName = Object.keys(rightStats[i])[0]; + const statLabel = parent.CreateFontString(id(`StatName-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statLabel.SetPoint("TOPLEFT", parent, "TOPLEFT", 118, -7 - (i * 14)); + statLabel.SetText(`${statName}:`); + statLabel.SetJustifyH("LEFT"); + + const statValue = parent.CreateFontString(id(`StatValue-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statValue.SetPoint("TOPRIGHT", parent, "TOPRIGHT", -4, -5 - (i * 14)); + statValue.SetSize(50, 14); + statValue.SetText(`${colors('white')}${rightStats[i][statName]}`); + statValue.SetJustifyH("RIGHT"); + + } + } + + function CreateStats(parent: WoWAPI.Frame, botData: BotData) { const statsFrame = CreateFrame("Frame", id("CharacterAttr"), parent, null, 1); statsFrame.SetSize(230,78); - statsFrame.SetPoint("TOPLEFT", 67, -231); + statsFrame.SetPoint("TOPLEFT", 67, -251); statsFrame.SetFrameStrata("HIGH"); statsFrame.SetAlpha(1.0); statsFrame.SetBackdropColor(0,0,0,1.0); @@ -264,7 +370,7 @@ if(!aio.AddAddon()) { const leftmiddle = statsFrame.CreateTexture(id("StatLeftMiddle"), "BACKGROUND"); leftmiddle.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-StatBackground"); - leftmiddle.SetSize(115,113); + leftmiddle.SetSize(115,95); leftmiddle.SetPoint("TOPLEFT", leftTop, "BOTTOMLEFT", 0, 0); leftmiddle.SetTexCoord(0, 0.8984375, 0.125, 0.1953125); @@ -282,7 +388,7 @@ if(!aio.AddAddon()) { const rightMiddle = statsFrame.CreateTexture(id("StatRightMiddle"), "BACKGROUND"); rightMiddle.SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-StatBackground"); - rightMiddle.SetSize(115,113); + rightMiddle.SetSize(115,95); rightMiddle.SetPoint("TOPLEFT", leftmiddle, "TOPRIGHT", 0, 0); rightMiddle.SetTexCoord(0, 0.8984375, 0.125, 0.1953125); @@ -292,14 +398,7 @@ if(!aio.AddAddon()) { rightBottom.SetPoint("TOPLEFT", leftBottom, "TOPRIGHT", 0, 0); rightBottom.SetTexCoord(0, 0.8984375, 0.484375, 0.609375); - let counter = 0; - // for(const stats in botData.stats.left) { - // const stat = statsFrame.CreateFontString(id(`Stat-${stats}`), "ARTWORK", "GameFontNormalSmall"); - // stat.SetPoint("TOPLEFT", statsFrame, "TOPLEFT", 10, -10 - (counter * 14)); - // stat.SetText(lookup[stats] + " " + botData.stats[stats]); - // counter++; - // } - + AddStats(statsFrame, botData); } function SetBackground(parent: WoWAPI.Frame) { @@ -388,31 +487,65 @@ if(!aio.AddAddon()) { function ItemSlotOnClick(frame: WoWAPI.Button, button: string) { const botId = botStorage.GetActive(); + + print(botId); const theItem = botStorage.GetBotItem(botId, frame.GetID()); - const [compItem, compItemId, compItemLink] = GetCursorInfo(); - print(`CursorHasItem: ${compItemLink}`); + const [compItem, compItemId, compItemLink] = GetCursorInfo(); if(theItem && !compItem) { if(button == "LeftButton") { PickupItem(theItem.link); + print('Set Bot Pickup Item', botId, theItem.entry, theItem.link); + botStorage.BotItemPickedUp(botId, theItem.entry, theItem.link); return; } } if(compItem) { const slot = frame.GetID(); - - aio.Handle("BotMgr", "EquipTheItem", GetUnitName("player", false), botId, slot, compItemId, compItemLink); + + // if we have a bot virtual item in hand + if(botStorage.IsPickedUp()) { + const botItemInHand = botStorage.GetItemInHand(); + // first unequip item on target bot + aio.Handle("BotMgr", "UnequipTheItem", GetUnitName("player", false), slot, botItemInHand.bot); + aio.Handle("BotMgr", "EquipTheItem", GetUnitName("player", false), botId, slot, compItemId, compItemLink); + } else { + aio.Handle("BotMgr", "EquipTheItem", GetUnitName("player", false), botId, slot, compItemId, compItemLink); + } + // Attempt to equip the item. PlaySound("INTERFACESOUND_CURSORDROPOBJECT"); ClearCursor(); } } - botMgrHandlers.OnEquipSuccess = (botId: number, slot: BotEquipmentSlotNum, itemId: number, itemLink: string) => { + botMgrHandlers.OnEquipSuccess = (botId: number, slot: BotEquipmentSlotNum, item: Equipment) => { const itemTexture = ComponentsPool.get(compId(botId, `ItemSlotTexture-${slot}`)); - itemTexture.SetTexture(GetItemIcon(itemId)); + itemTexture.SetTexture(GetItemIcon(item.entry)); + + // Hide Tooltips otherwise it will show old item. + const BotTooltip = ComponentsPool.get(compId(botId, "tooltip")); + botStorage.SetBotItem(botId, slot, item); + + BotTooltip.Hide(); + GameTooltip.Hide(); + } + + botMgrHandlers.OnUnEquipSuccess = (slot: BotEquipmentSlotNum, botId: number) => { + const itemTexture = ComponentsPool.get(compId(botId, `ItemSlotTexture-${slot}`)); + /** TO DO move to generic function for getting textures right now is copy/paste */ + let slotName: string = BotSlotName[slot]; + + if(slot === BotEquipSlot.FINGER1) slotName = "FINGER0"; + if(slot === BotEquipSlot.FINGER2) slotName = "FINGER1"; + if(slot === BotEquipSlot.TRINKET1) slotName = "TRINKET0"; + if(slot === BotEquipSlot.TRINKET2) slotName = "TRINKET1"; + if(slot === BotEquipSlot.OFFHAND) slotName = "SECONDARYHAND"; + + const [, itemIcon] = GetInventorySlotInfo(UIInvSlot[`${slotName}SLOT`]); + itemTexture.SetTexture(itemIcon); // Hide Tooltips otherwise it will show old item. const BotTooltip = ComponentsPool.get(compId(botId, "tooltip")); @@ -422,10 +555,87 @@ if(!aio.AddAddon()) { botMgrHandlers.OnEquipFail = (botId: number, slot: BotEquipmentSlotNum, itemId: number, itemLink: string) => { PlaySound("ITEMGENERICSOUND"); + botStorage.BotItemCursorClear(); ClearCursor(); } + botMgrHandlers.OnUnEquipFail = (botId: number, slot: BotEquipmentSlotNum) => { + PlaySound("ITEMGENERICSOUND"); + botStorage.BotItemCursorClear(); + ClearCursor(); + } + + function HandleUnequipItem(itemButton: WoWAPI.Button, isBankSlot: boolean = false): void { + + const slotNum = itemButton.GetID(); + const bagId = itemButton.GetParent().GetID(); + print(`Is Item Picked Up: ${botStorage.IsPickedUp()}`); + if(!GetContainerItemLink((isBankSlot) ? -1 : bagId, slotNum)) { + if(botStorage.IsPickedUp()) { + const item = botStorage.GetItemInHand(); + aio.Handle("BotMgr", "UnequipTheItem", GetUnitName("player", false), item.slot, item.bot); + } + } + } + + /** + * This handles listening on Bot Items being dragged to the bag. Attaches + * to the default handler before run and handles bot items specifically. + */ + function StoreItemSlotHandlers(): void { + + // Intercept Bags Item Slots Click Event + for(let container = 1; container <= 13; container++) { + for(let slot = 1; slot <= 36; slot++) { + ItemClickFuncs.set(`${container}:${slot}`, _G[`ContainerFrame${container}Item${slot}`].GetScript("OnClick")); + + _G[`ContainerFrame${container}Item${slot}`].SetScript("OnClick", (frame: WoWAPI.Button, ...args) => { + + const bagId = frame.GetParent().GetID(); + const slotNum = frame.GetID(); + HandleUnequipItem(frame); + print(`Unequipped - BagId: ${bagId} Slot: ${slotNum}`); + const callback = ItemClickFuncs.get(`${bagId}:${slotNum}`); + (callback) ? callback(frame, ...args) : print(`No callback for ${bagId}:${slotNum}`); + + }); + } + } + + // Intercept Bank Item Slots Click Event + for(let bankSlot = 1; bankSlot <= _G[`NUM_BANKGENERIC_SLOTS`]; bankSlot++) { + ItemClickFuncs.set(`bank:${bankSlot}`, _G[`BankFrameItem${bankSlot}`].GetScript("OnClick")); + + _G[`BankFrameItem${bankSlot}`].SetScript("OnClick", (frame: WoWAPI.Button, ...args) => { + + HandleUnequipItem(frame, true); + const callback = ItemClickFuncs.get(`bank:${frame.GetID()}`); + (callback) ? callback(frame, ...args) : print(`No callback for bank:${bankSlot}`) + }); + } + + } + + function UpdateBotFrame(botData: BotData) { + // Set the new Talent Spec + const talentSpec = ComponentsPool.get(compId(botData.entry, "SpecFont")); + talentSpec.SetText(botData.talentSpecName); + + // Update Resist Frames + let resist = ComponentsPool.get(compId(botData.entry, "Resist1")); + // resist.SetText(botData.allStats['Resistance: arcane']); + resist = ComponentsPool.get(compId(botData.entry, "Resist2")); + // resist.SetText(botData.allStats['Resistance: fire']); + resist = ComponentsPool.get(compId(botData.entry, "Resist3")); + // resist.SetText(botData.allStats['Resistance: nature']); + resist = ComponentsPool.get(compId(botData.entry, "Resist4")); + // resist.SetText(botData.allStats['Resistance: frost']); + resist = ComponentsPool.get(compId(botData.entry, "Resist5")); + // resist.SetText(botData.allStats['Resistance: shadow']); + } + + /** * Shows or Creates a new Bot Equipment Management Frame * Every NPC Bot that is requested to be managed will get their own unique frame. This @@ -445,7 +655,7 @@ if(!aio.AddAddon()) { mainFrame = InfoFramePool.get(botData.entry); - if(mainFrame) { print('main frame already created'); } + // if(mainFrame) { print('main frame already created'); } // Build the complete frame if we do not already have one in the pool. if(!mainFrame) { mainFrame = CreateFrame("Frame", id("MainFrame"+botData.entry), UIParent, null, botData.entry); @@ -467,22 +677,12 @@ if(!aio.AddAddon()) { }); mainFrame.RegisterEvent("CURSOR_UPDATE"); - mainFrame.RegisterEvent("ITEM_LOCK_CHANGED"); - mainFrame.RegisterEvent("ITEM_UNLOCKED"); + // mainFrame.RegisterEvent("ITEM_LOCK_CHANGED"); + // mainFrame.RegisterEvent("ITEM_UNLOCKED"); - mainFrame.SetScript("OnEvent", (frame: WoWAPI.Frame, eventName: WoWAPI.Event, ...args) => { - if(eventName == "ITEM_LOCKED") { - GetCursorInfo() - print(args); - for(const arg of args) { - print(arg); - } - } + mainFrame.SetScript("OnEvent", (frame: WoWAPI.Frame, eventName: WoWAPI.Event, ...args) => { }); - - - // mainFrame.Hide(); BotItemTooltip = CreateFrame("GameTooltip", id("ItemToolTip"+botData.entry), mainFrame, "GameTooltipTemplate", botData.entry); BotItemTooltip.SetOwner(mainFrame, "ANCHOR_NONE"); @@ -492,109 +692,31 @@ if(!aio.AddAddon()) { SetBackground(mainFrame); AddPortrait(mainFrame, botData); AddCharacterModel(mainFrame, botData); - AddResistFrame(mainFrame); + AddResistFrame(mainFrame, botData); AddEquipmentFrames(mainFrame, botData); CreateStats(mainFrame, botData); AddSoundEffects(mainFrame); - InfoFramePool.set(botData.entry, mainFrame); ComponentsPool.set(compId(botData.entry, "tooltip"), BotItemTooltip); + mainFrame.Show(); + } else { + mainFrame.Show(); + print("updating bot data"); + print(botData.talentSpecName); + UpdateBotFrame(botData); + } - // const button2 = CreateFrame("Button", id("CharacterNeckSlot"), mainFrame, "ItemButtonTemplate"); - // button2.SetPoint("TOP", button, "BOTTOM", 0, -3); - // button2.SetSize(40,40); - - // const [itemId, texture] = GetInventorySlotInfo(UIInvSlot.NECKSLOT); - - // const itemTexture2 = button2.CreateTexture(id("ItemTextureNeck"), "OVERLAY"); - // itemTexture2.SetTexture(texture); - // itemTexture2.SetPoint("CENTER", 0, 0); - // itemTexture2.SetSize(38,38); - - - - // const leftEquipment = CreateFrame("Frame", id("LeftEquipment"), mainFrame); - // leftEquipment.SetPoint("TOPLEFT", 20, -73); - // leftEquipment.SetSize(40, 330); - - // const background = leftEquipment.CreateTexture(id("Background"), "OVERLAY"); - // background.SetTexture(0,0,0,0.7); - // background.SetAllPoints(leftEquipment); - - // const button = CreateFrame("Button", id("CharacterHeadSlot"), leftEquipment, "ItemButtonTemplate"); - // button.SetPoint("TOPLEFT", 0, 0); - // button.SetSize(40,40); - - // const itemTexture = button.CreateTexture(id("ItemTextureHead"), "OVERLAY"); - // itemTexture.SetTexture(GetItemIcon(botData.equipment[BotEquipSlot.HEAD])); - // itemTexture.SetPoint("CENTER", 0, 0); - // itemTexture.SetSize(36,36); - - } - - mainFrame.Show(); - - - // aio.Handle("BotMgr", "ParseBotEntry", UnitGUID("target")); - // aio.Handle("BotMgr", "ShowComplexArray", { "one": 1, "two": 2, "three": 3 }); - - - // const headTex = GetItemIcon(botdetails.equipment[BotEquipSlot.HEAD]); - // print(headTex); - - - - - // const testTexture = itemFrame.CreateTexture(id("TestTexture"), "OVERLAY"); - // testTexture.SetTexture(GetItemIcon(2194)); - // // testTexture.SetSize(64,64); - // testTexture.SetAllPoints(button); - // testTexture.SetPoint("TOPLEFT", 0, 0); - - - // SetItemButtonTexture(button, texture); - - // button.SetScript("OnLoad", (frame) => { - // const head = frame.CreateTexture("CharacterHeadSlotTexture", "ARTWORK"); - // head.SetAllPoints(button); - // head.SetTexture(1,0,0,1); - // }); - - - - - //button.SetName("CharacterHeadSlot"); - - - - - - - - // const frameCore = CreateFrame("Frame", "BotMgrCoreFrame", mainFrame); - // frameCore.SetSize(600, 440); - // frameCore.SetPoint("TOPLEFT", 0, 0); - - // const mainTexture = frameCore.CreateTexture("BotMgrMainFrameTexture", "BACKGROUND"); - // mainTexture.SetAllPoints(frameCore); - - // const titleText = frameCore.CreateFontString("BotMgrTitle", "ARTWORK"); - // titleText.SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE"); - // titleText.SetPoint("TOP", 0, -5); - // titleText.SetText(GetUnitName("target", false)); - - // const unitTexture = frameChar.CreateTexture("BotMgrCharTexture", "BACKGROUND"); - // unitTexture.SetTexture(0, 0, 0); - // unitTexture.SetAllPoints(frameChar); - + } - - botMgrHandlers.ShowFrame = (botData: BotData) =>{ + botMgrHandlers.ShowFrame = (botData: BotData) => { botStorage.UpdateBotData(botData.entry, botData); - ShowBotFrame(botData); - } + ShowBotFrame(botData); + } + // Global calls to set things up + StoreItemSlotHandlers(); + } diff --git a/modules/UI/botmgr/botmgr.server.ts b/modules/UI/botmgr/botmgr.server.ts index 22de277..b766216 100644 --- a/modules/UI/botmgr/botmgr.server.ts +++ b/modules/UI/botmgr/botmgr.server.ts @@ -3,19 +3,16 @@ let aio: AIO = {}; const SCRIPT_NAME = 'BotMgr'; import { Logger } from "../../classes/logger"; +import { BotUnit } from "./botUnit"; const log = new Logger(SCRIPT_NAME); import { - BotStat, - BotEquipSlot, - BotSlotName, - BotEquipLast, - BotStatLast, + BotStat, + BotEquipLast, ClassesMapping, CharacterClass, RacesMapping, - CharacterRace, - ItemQuality, + CharacterRace, QualityType } from "../../constants/idmaps"; @@ -35,13 +32,19 @@ export type EquipmentList = Record; export type BotData = { owner: string, name: string, + level: number, + talentSpec: number, + talentSpecName: string, + roles: number, entry: number, class: CharacterClass, classId: number, race: CharacterRace, raceId: number, equipment?: EquipmentList, // SlotName - ItemId See BotEquipSlot - stats?: Record, // StatId - Value + leftStats?: Record[], + rightStats?: Record[], + allStats?: Record // StatId - Value }; /** @@ -90,89 +93,17 @@ function TargetIsEligible(player: Player) { return false; } -function GetMeleeStats () { - return { - left: [ - BotStat.STRENGTH, - BotStat.AGILITY, - BotStat.DAMAGE_MIN, - BotStat.DAMAGE_MAX, - BotStat.ATTACK_POWER, - BotStat.HIT_RATING, - BotStat.CRIT_RATING, - BotStat.EXPERTISE, - BotStat.ARMOR_PENETRATION_RATING, - ], - right: [ - BotStat.HASTE_RATING, - BotStat.ARMOR, - BotStat.STAMINA, - BotStat.DEFENSE_SKILL_RATING, - BotStat.DODGE_RATING, - BotStat.PARRY_RATING, - BotStat.BLOCK_RATING, - BotStat.BLOCK_VALUE - ] - } -} - -function GetCasterStats() { - -} - /** * @noSelf */ function GetBotDetails(bot: Creature): BotData { - const owner = bot.GetBotOwner(); - - // We can use bot entrys since they are 1:1 with GUIDs for shorter storage keys - NpcDetailStorage[bot.GetEntry()] = { - owner: owner.GetName(), - name: bot.GetName(), - entry: bot.GetEntry(), - class: ClassesMapping[bot.GetBotClass()], - classId: bot.GetBotClass(), - race: RacesMapping[bot.GetRace()], - raceId: bot.GetRace(), - equipment: {} as EquipmentList, - stats: {}, - }; - - print(bot.GetBotRoles()); - - - // Get all the equipment - for(let slot=0; slot <= BotEquipLast; slot++) { - const equipment = bot.GetBotEquipment(slot); - - if(equipment) { - NpcDetailStorage[bot.GetEntry()].equipment[slot] = { - entry: equipment.GetEntry(), - link: equipment.GetItemLink(), - quality: equipment.GetQuality(), - itemLevel: equipment.GetItemLevel(), - enchantmentId: equipment.GetEnchantmentId(0), - } - } else { - NpcDetailStorage[bot.GetEntry()].equipment[slot] = undefined; - } + try { + const botUnit = new BotUnit(bot); + NpcDetailStorage[bot.GetEntry()] = botUnit.toBotData(); + } catch (e) { + log.error(`Could not get bot details: ${e}`); } - - // get the stats we care about by Class - // This will determine what stats to lookup for the bot. - const lookups = GetMeleeStats(); - - - lookups.left.forEach(stat => { - const result = bot.GetBotStat(stat); - NpcDetailStorage[bot.GetEntry()].stats[stat] = result; - }); - lookups.right.forEach(stat => { - const result = bot.GetBotStat(stat); - NpcDetailStorage[bot.GetEntry()].stats[stat] = result; - }); return NpcDetailStorage[bot.GetEntry()]; } @@ -189,26 +120,52 @@ function EquipTheItem(player: string, botEntry: number, slot: BotEquipmentSlotNu return; } - const owner = GetPlayerByName(player); - const creatures = owner.GetCreaturesInRange(60, botEntry) as Creature[]; - const bot = creatures[0]; + try { + const owner = GetPlayerByName(player); + const creatures = owner.GetCreaturesInRange(300, botEntry) as Creature[]; + const bot = creatures[0]; + let data; + + const isEligible = bot.BotCanEquipItem(item, slot); + if(!isEligible) { + log.error(`Bot cannot equip item: ${item} in slot: ${slot}`); + return; + } + // already equipped + + if(bot.BotEquipItem(item, slot)) { + data = GetBotDetails(bot); + // log.log(`Bot successfully equipped item: ${item} in slot: ${slot}`); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipSuccess',botEntry, slot, data.equipment[slot]); + } else { + // log.error(`Bot failed to equip item: ${item} in slot: ${slot}`); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipFail', botEntry, slot, item, link); + } + } catch (error) { + log.error(`Error equipping item: ${error}`); + } + +} - - const isEligible = bot.BotCanEquipItem(item, slot); - if(!isEligible) { - log.error(`Bot cannot equip item: ${item} in slot: ${slot}`); - return; - } - - if(bot.BotEquipItem(item, slot)) { +function UnequipTheItem(player: string, slot: number, botEntry: number): void { + try { + const owner = GetPlayerByName(player); + const creatures = owner.GetCreaturesInRange(60, botEntry) as Creature[]; + const bot = creatures[0]; + + if(bot.BotUnequipBotItem(slot)) { GetBotDetails(bot); - log.log(`Bot successfully equipped item: ${item} in slot: ${slot}`); - aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipSuccess',botEntry, slot, item, link); + log.log(`Bot successfully unequipped item at slot: ${slot}`); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipSuccess',slot, botEntry, ); } else { - log.error(`Bot failed to equip item: ${item} in slot: ${slot}`); - aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipFail', botEntry, slot, item, link); + log.error(`Bot failed to equip item in slot: ${slot}`); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipFail', slot, botEntry); } - + } catch (error) { + log.error(`Error unequipping item: ${error}`); + } + + } @@ -217,11 +174,6 @@ const ShowBotMgr: player_event_on_command = (event: number,player: Player, comma if(TargetIsEligible(player)) { const botdetails = GetBotDetails(GetBotNpc(player)); - - // loop through bot details and print the key value pair - for (const [key, value] of Object.entries(botdetails.equipment)) { - print(`${key}: ${value}`); - } aio.Handle(player, 'BotMgr', 'ShowFrame', botdetails); return false; @@ -264,7 +216,8 @@ function GetBotPanelInfo(player: Player): void { const botMgrHandlers = aio.AddHandlers('BotMgr', { TargetIsEligible, GetBotPanelInfo, - "EquipTheItem": EquipTheItem + "EquipTheItem": EquipTheItem, + "UnequipTheItem": UnequipTheItem, }); diff --git a/modules/constants/idmaps.ts b/modules/constants/idmaps.ts index 04d9611..5553cd3 100644 --- a/modules/constants/idmaps.ts +++ b/modules/constants/idmaps.ts @@ -41,7 +41,54 @@ export const BotSlotName = { } as const; export const BotEquipLast = 17; - +export const BotStatLabel = { + "total str": "Strength", + "total agi": "Agility", + "total sta": "Stamina", + "total int": "Intellect", + "total spi": "Spirit", + "Melee AP": "Power", + "Ranged AP": "Power", + "armor": "Armor", + "crit": "Crit %", + "defense": "Defense", + "miss": "Miss", + "dodge": "Dodge", + "parry": "Parry", + "block": "Block", + "block value": "Block Value", + "Damage taken melee": "Physical Resist", + "Damage taken spell": "Spell Resist", + "Damage range mainhand": "Dmg Main", + "Damage range offhand": "Dmg Off", + "Attack time offhand": "Speed Off", + "Damage mult mainhand": "Damage Multiplier (Mainhand)", + "Attack time mainhand": "Speed Main", + "Damage range ranged": "Dmg Range", + "Damage mult ranged": "Damage Multiplier (Ranged)", + "Attack time ranged": "Speed", + "base hp": "Base Health", + "total hp": "Total Health", + "base mana": "Base Mana", + "total mana": "Total Mana", + "spell power": "Bonus Dmg", + "health regen_5 bonus": "Health Regen (5s Bonus)", + "haste": "Haste Rating", + "hit": "Hit Rating", + "expertise": "Expertise", + "mana regen_5 casting": "MP5", + "armor penetration": "Armor Pen", + "spell penetration": "Spell Pen", + "Resistance: holy": "Resist Holy", + "Resistance: fire": "Resist Fire", + "Resistance: nature": "Resist Nature", + "Resistance: frost": "Resist Frost", + "Resistance: shadow": "Resist Shadow", + "Resistance: arcane": "Resist Arcane", +} as const; + +export type BotStatName = Partial; + export const BotStat = { MANA: 0, HEALTH: 1, @@ -100,7 +147,7 @@ export const BotStat = { MAX_BOT_ITEM_MOD: 59, BOT_STAT_MOD_RESISTANCE_START: 51, // Assuming BOT_STAT_MOD_ARMOR is defined somewhere } as const; - + export const BotStatLast = 58; export const UIInvSlot = { @@ -167,7 +214,7 @@ export const RacesMapping: Record = { export type CharacterRace = typeof RacesMapping[keyof typeof RacesMapping]; -export const BotTalentSpecs = { +export const TalentSpecs = { WARRIOR_ARMS : 1, WARRIOR_FURY : 2, WARRIOR_PROTECTION : 3, @@ -203,10 +250,6 @@ export const BotTalentSpecs = { END : 31 } as const; -export function talentSpecName(id: number) { - return Object.keys(BotTalentSpecs).find(key => BotTalentSpecs[key] === id); -} - export const BotRoles = { NONE : 0, TANK : 1, @@ -226,10 +269,10 @@ export const BotRoles = { AUTOLOOT_RARE : 16384, AUTOLOOT_EPIC : 32768, AUTOLOOT_LEGENDARY : 65536, - MASK_MAIN : (1 | 2 | 4 | 8 | 16), - MASK_GATHERING : (64 | 128 | 256 | 512), - MASK_LOOTING : (2048 | 4096 | 8192 | 16384 | 32768 | 65536), - BOT_MAX_ROLE : 131072, +// MASK_MAIN : (1 | 2 | 4 | 8 | 16), +// MASK_GATHERING : (64 | 128 | 256 | 512), +// MASK_LOOTING : (2048 | 4096 | 8192 | 16384 | 32768 | 65536), +// BOT_MAX_ROLE : 131072, } as const;