From 2b6a9d9f79be55307549986e0945d125bf235095 Mon Sep 17 00:00:00 2001 From: Ben Carter Date: Sun, 11 Feb 2024 18:39:16 -0500 Subject: [PATCH] updates to equipment manager --- modules/UI/botmgr/bot.ts | 22 +++- modules/UI/botmgr/botUnit.ts | 86 ++++++++----- modules/UI/botmgr/botmgr.client.ts | 190 ++++++++++++++++------------- modules/UI/botmgr/botmgr.server.ts | 64 +++++++--- modules/constants/idmaps.ts | 8 +- 5 files changed, 232 insertions(+), 138 deletions(-) diff --git a/modules/UI/botmgr/bot.ts b/modules/UI/botmgr/bot.ts index e1c9a52..349e39c 100644 --- a/modules/UI/botmgr/bot.ts +++ b/modules/UI/botmgr/bot.ts @@ -18,6 +18,7 @@ export class BotStorage { private active: number = null; private pickedUp: boolean = false; private itemInHand: ItemInHand = { entry: undefined, link: undefined, bot: undefined, slot: undefined }; + private bankItem: { entry: number, link: string, slot: number } = { entry: 0, link: '', slot: 0 }; public GetBotData(entry: number): BotData | undefined { return this.storage.get(entry); @@ -79,11 +80,24 @@ export class BotStorage { return this.itemInHand; } + GetFromBank(): { entry: number, link: string, slot: number } | undefined { + if(!this.bankItem) { + return undefined; + } + + return this.bankItem; + } + + SetFromBank(item: { entry: number, link: string, slot: number }): void { + this.bankItem = item; + } + + ClearFromBank(): void { + this.bankItem = undefined; + } + BotItemCursorClear(): void { - this.itemInHand.entry = undefined; - this.itemInHand.link = undefined; - this.itemInHand.bot = undefined; - this.itemInHand.slot = undefined; + this.itemInHand = undefined; this.pickedUp = false; } diff --git a/modules/UI/botmgr/botUnit.ts b/modules/UI/botmgr/botUnit.ts index 9ac049c..2b6c600 100644 --- a/modules/UI/botmgr/botUnit.ts +++ b/modules/UI/botmgr/botUnit.ts @@ -17,13 +17,18 @@ function humanizeTalentName(input: string): string { 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); + try { + 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]}`; + } catch (e) { + print(`failed to humanize talent name: ${input}` + e); + } - return `${parts[1]} ${parts[0]}`; } export class BotUnit { @@ -55,8 +60,13 @@ export class BotUnit { this.equipment = this._lookupEquipment(); this.talentSpecId = creature.GetTalentSpec(); this.parseStats(creature.GetBotDump()); - this.statsLeft = this._lookupStats('left'); - this.statsRight = this._lookupStats('right'); + try { + this.statsLeft = this._lookupStats('left'); + this.statsRight = this._lookupStats('right'); + } catch (e) { + print("failed to get stats for bot:" + e); + } + this.roles = creature.GetBotRoles(); @@ -116,7 +126,7 @@ export class BotUnit { left: [ "Strength", "Agility", - "Dmg Main", + "Damage", "Power", "Hit Rating", "Crit %", @@ -131,7 +141,7 @@ export class BotUnit { "Dodge", "Parry", "Block", - "Physical Resist" + "Physical Res." ] } } @@ -141,7 +151,7 @@ export class BotUnit { left: [ "Strength", "Agility", - "Dmg Range", + "Damage Rng", "Speed", "Power", "Hit Rating", @@ -173,12 +183,12 @@ export class BotUnit { "Spell Pen" ], right: [ - "Haste Rating", - "Spell Resist", + "Haste Rating", "MP5", + "Spell Res.", "Dodge", "Armor", - "Parry", + "Parry", ] } } @@ -266,34 +276,37 @@ export class BotUnit { let statValue = this.allStats[statName]; const statRecord= {}; + // skip offhand stats will be handled with main hand + if(statName === 'Dmg Off') { + continue; + } + // handle some special cases for stats - if(statName === 'Dmg Main' || statName === 'Dmg Range' || statName == 'Dmg Off') { - statValue = statValue.replace(" min: ", "").replace(", max: ", "-"); + if(statName === 'Damage') { 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); + if(this.isDualWield()) { + //statRecord['Dmg Off'] = statValue; + //classStats.push(statRecord); } continue; } - + if(this.isHealer() && statName === 'Bonus Dmg') { statRecord['Bonus Heals'] = statValue; classStats.push(statRecord); - print(`Stat: Bonus Heals = ${statValue}`); + // print(`Stat: Bonus Heals = ${statValue}`); continue; } if(statName && statValue) { statRecord[statName] = statValue; classStats.push(statRecord); - print(`Stat: ${statName} = ${statValue}`); + // print(`Stat: ${statName} = ${statValue}`); } else { - print("failed to get stat: " + statName); + // print("failed to get stat: " + statName); } } @@ -317,22 +330,31 @@ export class BotUnit { } parts[1] = parts[1].replace("(-0.00 pct)", ""); - parts[1] = parts[1].replace("pct", "%"); + parts[1] = parts[1].replace("pct", "%").trim(); parts[1] = parts[1].replace("+", ""); const statName = Common.BotStatLabel[parts[0]]; - if(statName == "Dmg Main" || statName == "Dmg Off" || statName == "Dmg Range") { + if(statName == "Damage" || statName == "Dmg Off" || statName == "Damage Rng") { parts[1] = parts[2].split(",")[0].trim() + "-" + parts[3].trim(); } - if(statName == "Physical Resist" || statName == "Spell Resist") { - parts[1] = 1 - parseInt(parts[1]) + "%"; + if(statName == "Physical Res." || statName == "Spell Res.") { + const value = parseFloat(parts[1]); + if(value === 1) { + parts[1] = "0.00%"; + } + parts[1] = ((1 - value) * 100) + ".00%"; + + } + + if(statName == "Expertise") { + parts[1] = parts[1].trim().split(" ")[0]; } if(statName == "Dodge" || statName == "Parry" || statName == "Block" || - statName == "Crit Chance" ) { - parts[1] = parts[1] + " %"; + statName == "Crit %" ) { + parts[1] = parts[1].trim() + "%"; } if(statName == "Strength" || statName == "Agility" || statName == "Intellect" || @@ -340,8 +362,8 @@ export class BotUnit { parts[1] = "" + Math.round(parseInt(parts[1])); } - this.allStats[statName] = parts[1].trim(); - print("Parsed Stat: " + statName + " = " + parts[1]); + this.allStats[statName] = parts[1].trim().replace(" %", "%"); + // print("Parsed Stat: " + statName + " = " + parts[1]); } } } \ No newline at end of file diff --git a/modules/UI/botmgr/botmgr.client.ts b/modules/UI/botmgr/botmgr.client.ts index abc66cf..0a00fdd 100644 --- a/modules/UI/botmgr/botmgr.client.ts +++ b/modules/UI/botmgr/botmgr.client.ts @@ -4,17 +4,8 @@ let aio: AIO = {}; /** - * @todo Add all equipment slots for the bot onload - done - * @todo Create frames for bot status - * @todo Complete resist information frame. - * @todo Update server message to send class name, bot race - done - * @todo Add hover events to handle equipment change on bot. - * @todo Add compare tooltip for bot equipment - sort of done (shows equipment next to each other) - * * v2: - * @todo Add slot management for bot equipment - * @todo Add bot spec under bot info - * @todo Add talent spec to bot profile + * @todo Add slot management for bot equipment */ @@ -115,7 +106,7 @@ if(!aio.AddAddon()) { 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"]}`); @@ -131,7 +122,7 @@ if(!aio.AddAddon()) { 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"]}`); @@ -147,7 +138,7 @@ if(!aio.AddAddon()) { 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"]}`); @@ -313,43 +304,59 @@ if(!aio.AddAddon()) { equipFrame.SetPoint("CENTER", -10, -147); equipFrame.SetSize(129, 40); UpdateEquipFrame('weapons', equipFrame, botData); - ComponentsPool.set(compId(botData.entry, "WeaponsEquipment"), equipFrame); - + ComponentsPool.set(compId(botData.entry, "WeaponsEquipment"), equipFrame); } } - function AddStats(parent: WoWAPI.Frame, botData: BotData) { + function AddStats(parent: WoWAPI.Frame | undefined, 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"); + let statLabel = ComponentsPool.get(compId(botData.entry, `StatName-${statName}`)); + if(!statLabel) { + statLabel = parent.CreateFontString(id(`StatName-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statLabel.SetPoint("TOPLEFT", parent, "TOPLEFT", 5, -7 - (i * 14)); + statLabel.SetJustifyH("LEFT"); + statLabel.SetText(`${statName}:`); + ComponentsPool.set(compId(botData.entry, `StatName-${statName}`), statLabel); + } + let statValue = ComponentsPool.get(compId(botData.entry, `StatValue-${statName}`)); + // if there is not an existing component create a new one + if(!statValue) { + statValue = parent.CreateFontString(id(`StatValue-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statValue.SetPoint("TOPRIGHT", parent, "TOP", -4, -5 - (i * 14)); + statValue.SetSize(50, 14); + statValue.SetJustifyH("RIGHT"); + ComponentsPool.set(compId(botData.entry, `StatValue-${statName}`), statValue); + } + statValue.SetText(`${colors('white')}${leftStats[i][statName]}`); } 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"); + let statLabel = ComponentsPool.get(compId(botData.entry, `StatName-${statName}`)); + if(!statLabel) { + statLabel = parent.CreateFontString(id(`StatName-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statLabel.SetPoint("TOPLEFT", parent, "TOPLEFT", 118, -7 - (i * 14)); + statLabel.SetText(`${statName}:`); + statLabel.SetJustifyH("LEFT"); + ComponentsPool.set(compId(botData.entry, `StatName-${statName}`), statLabel); + } - const statValue = parent.CreateFontString(id(`StatValue-${statName}`), "ARTWORK", "GameFontNormalSmall"); - statValue.SetPoint("TOPRIGHT", parent, "TOPRIGHT", -4, -5 - (i * 14)); - statValue.SetSize(50, 14); + let statValue = ComponentsPool.get(compId(botData.entry, `StatValue-${statName}`)); + if(!statValue) { + statValue = parent.CreateFontString(id(`StatValue-${statName}`), "ARTWORK", "GameFontNormalSmall"); + statValue.SetPoint("TOPRIGHT", parent, "TOPRIGHT", -4, -5 - (i * 14)); + statValue.SetSize(50, 14); + statValue.SetJustifyH("RIGHT"); + ComponentsPool.set(compId(botData.entry, `StatValue-${statName}`), statValue); + } statValue.SetText(`${colors('white')}${rightStats[i][statName]}`); - statValue.SetJustifyH("RIGHT"); - + } } @@ -358,7 +365,8 @@ if(!aio.AddAddon()) { const statsFrame = CreateFrame("Frame", id("CharacterAttr"), parent, null, 1); statsFrame.SetSize(230,78); statsFrame.SetPoint("TOPLEFT", 67, -251); - statsFrame.SetFrameStrata("HIGH"); + statsFrame.SetFrameLevel(parent.GetFrameLevel() + 1); + // statsFrame.SetFrameStrata("LOW"); statsFrame.SetAlpha(1.0); statsFrame.SetBackdropColor(0,0,0,1.0); @@ -487,16 +495,36 @@ 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(); + // IF we have a bank item since it is not our inventory it will crash the server so store it then send equip + const bankItem = botStorage.GetFromBank(); + if(bankItem) { + for(let i=0; i <= 4; i++) { + if(GetContainerNumFreeSlots(i)) { + if(i === 0) { + PutItemInBackpack(); + } else { + PutItemInBag(i); + } + } + } + } + + // Special case to handle unquipping items via modified click + if(IsModifiedClick("AUTOLOOTTOGGLE")) { + if(theItem && !compItem) { + aio.Handle("BotMgr", "UnequipTheItem", GetUnitName("player", false), frame.GetID(), botId); + return; + } + } + if(theItem && !compItem) { if(button == "LeftButton") { PickupItem(theItem.link); - print('Set Bot Pickup Item', botId, theItem.entry, theItem.link); + // print('Set Bot Pickup Item', botId, theItem.entry, theItem.link); botStorage.BotItemPickedUp(botId, theItem.entry, theItem.link); return; } @@ -530,10 +558,10 @@ if(!aio.AddAddon()) { botStorage.SetBotItem(botId, slot, item); BotTooltip.Hide(); - GameTooltip.Hide(); + GameTooltip.Hide(); } - botMgrHandlers.OnUnEquipSuccess = (slot: BotEquipmentSlotNum, botId: number) => { + botMgrHandlers.OnUnEquipSuccess = (botId: number, slot: BotEquipmentSlotNum) => { 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]; @@ -550,7 +578,7 @@ if(!aio.AddAddon()) { // Hide Tooltips otherwise it will show old item. const BotTooltip = ComponentsPool.get(compId(botId, "tooltip")); BotTooltip.Hide(); - GameTooltip.Hide(); + GameTooltip.Hide(); } botMgrHandlers.OnEquipFail = (botId: number, slot: BotEquipmentSlotNum, itemId: number, itemLink: string) => { @@ -566,11 +594,15 @@ if(!aio.AddAddon()) { ClearCursor(); } + botMgrHandlers.UpdateBotData = (data: BotData) => { + botStorage.SetBotData(data.entry, data); + UpdateBotFrame(data); + } + 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(); @@ -585,54 +617,50 @@ if(!aio.AddAddon()) { */ 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) => { - + _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}`) + (callback) ? callback(frame, ...args) : null; + //print(`No callback for bank:${bankSlot}`) + + if(CursorHasItem()) { + const [compItem, compItemId, compItemLink] = GetCursorInfo(); + botStorage.SetFromBank({ + slot: frame.GetID(), + link: compItemLink, + entry: compItemId + }); + } }); } } 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.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats['Resistance: arcane']}`); resist = ComponentsPool.get(compId(botData.entry, "Resist2")); - // resist.SetText(botData.allStats['Resistance: fire']); + resist.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats['Resistance: fire']}`); resist = ComponentsPool.get(compId(botData.entry, "Resist3")); - // resist.SetText(botData.allStats['Resistance: nature']); + resist.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats['Resistance: nature']}`); resist = ComponentsPool.get(compId(botData.entry, "Resist4")); - // resist.SetText(botData.allStats['Resistance: frost']); + resist.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats['Resistance: frost']}`); resist = ComponentsPool.get(compId(botData.entry, "Resist5")); - // resist.SetText(botData.allStats['Resistance: shadow']); + resist.SetText(`${GREEN_FONT_COLOR_CODE}${botData.allStats['Resistance: shadow']}`); + + // Update the stats frame + AddStats(undefined, botData); } @@ -652,10 +680,8 @@ if(!aio.AddAddon()) { function ShowBotFrame(botData: BotData) { let mainFrame: WoWAPI.Frame = null; - mainFrame = InfoFramePool.get(botData.entry); - // 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); @@ -675,14 +701,6 @@ if(!aio.AddAddon()) { mainFrame.SetScript("OnLeave", (frame) => { frame.SetFrameLevel(5); }); - - mainFrame.RegisterEvent("CURSOR_UPDATE"); - // mainFrame.RegisterEvent("ITEM_LOCK_CHANGED"); - // mainFrame.RegisterEvent("ITEM_UNLOCKED"); - - mainFrame.SetScript("OnEvent", (frame: WoWAPI.Frame, eventName: WoWAPI.Event, ...args) => { - }); - BotItemTooltip = CreateFrame("GameTooltip", id("ItemToolTip"+botData.entry), mainFrame, "GameTooltipTemplate", botData.entry); BotItemTooltip.SetOwner(mainFrame, "ANCHOR_NONE"); @@ -700,10 +718,18 @@ if(!aio.AddAddon()) { InfoFramePool.set(botData.entry, mainFrame); ComponentsPool.set(compId(botData.entry, "tooltip"), BotItemTooltip); mainFrame.Show(); + + // mainFrame.RegisterEvent("CURSOR_UPDATE"); + // mainFrame.RegisterEvent("ITEM_LOCK_CHANGED"); + mainFrame.RegisterEvent("ITEM_UNLOCKED"); + mainFrame.SetScript("OnEvent", (frame: WoWAPI.Frame, eventName: WoWAPI.Event, ...args) => { + if(eventName === "ITEM_UNLOCKED") { + botStorage.ClearFromBank(); + } + }); + } else { - mainFrame.Show(); - print("updating bot data"); - print(botData.talentSpecName); + mainFrame.Show(); UpdateBotFrame(botData); } diff --git a/modules/UI/botmgr/botmgr.server.ts b/modules/UI/botmgr/botmgr.server.ts index b766216..ec981c2 100644 --- a/modules/UI/botmgr/botmgr.server.ts +++ b/modules/UI/botmgr/botmgr.server.ts @@ -93,6 +93,22 @@ function TargetIsEligible(player: Player) { return false; } +/** + * Used to retrieve the bot for the player + * @param player + * @returns Creature + */ +function GetBotForPlayer(player: string, botEntry: number) { + try { + const owner = GetPlayerByName(player); + const creatures = owner.GetCreaturesInRange(300, botEntry) as Creature[]; + const bot = creatures[0]; + return bot; + } catch (e) { + log.error(`Could not get bot for player ${player}: ${e}`); + } +} + /** * @noSelf */ @@ -108,6 +124,25 @@ function GetBotDetails(bot: Creature): BotData { return NpcDetailStorage[bot.GetEntry()]; } +/** + * Sends a client message with update bot details typically fired + * after an equipment event. + * @param player + * @param botEntry + */ +function RefreshBotData(bot: Creature): void { + try { + bot.RegisterEvent((delay:number, repeats:number, bot: Creature) => { + const data = GetBotDetails(bot); + log.info(`Sending bot details to player: ${bot.GetBotOwner().GetName()}`); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'UpdateBotData', data); + }, 650, 1); + + } catch (e) { + log.error(`Could not send bot details: ${e}`); + } +} + /** * Equip an item for the bot and update bot details * @param event @@ -121,9 +156,7 @@ function EquipTheItem(player: string, botEntry: number, slot: BotEquipmentSlotNu } try { - const owner = GetPlayerByName(player); - const creatures = owner.GetCreaturesInRange(300, botEntry) as Creature[]; - const bot = creatures[0]; + const bot = GetBotForPlayer(player, botEntry); let data; const isEligible = bot.BotCanEquipItem(item, slot); @@ -136,10 +169,11 @@ function EquipTheItem(player: string, botEntry: number, slot: BotEquipmentSlotNu 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]); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipSuccess',bot.GetEntry(), slot, data.equipment[slot]); + RefreshBotData(bot); } else { // log.error(`Bot failed to equip item: ${item} in slot: ${slot}`); - aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipFail', botEntry, slot, item, link); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnEquipFail', bot.GetEntry(), slot, item, link); } } catch (error) { log.error(`Error equipping item: ${error}`); @@ -149,23 +183,21 @@ function EquipTheItem(player: string, botEntry: number, slot: BotEquipmentSlotNu 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]; - + const bot = GetBotForPlayer(player, botEntry); + if(bot.BotUnequipBotItem(slot)) { - GetBotDetails(bot); + let data = GetBotDetails(bot); log.log(`Bot successfully unequipped item at slot: ${slot}`); - aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipSuccess',slot, botEntry, ); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipSuccess',bot.GetEntry(), slot); + + RefreshBotData(bot); } else { log.error(`Bot failed to equip item in slot: ${slot}`); - aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipFail', slot, botEntry); + aio.Handle(bot.GetBotOwner(), 'BotMgr', 'OnUnEquipFail', bot.GetEntry(), slot); } } catch (error) { log.error(`Error unequipping item: ${error}`); - } - - + } } @@ -217,7 +249,7 @@ const botMgrHandlers = aio.AddHandlers('BotMgr', { TargetIsEligible, GetBotPanelInfo, "EquipTheItem": EquipTheItem, - "UnequipTheItem": UnequipTheItem, + "UnequipTheItem": UnequipTheItem }); diff --git a/modules/constants/idmaps.ts b/modules/constants/idmaps.ts index 5553cd3..48dc30a 100644 --- a/modules/constants/idmaps.ts +++ b/modules/constants/idmaps.ts @@ -57,14 +57,14 @@ export const BotStatLabel = { "parry": "Parry", "block": "Block", "block value": "Block Value", - "Damage taken melee": "Physical Resist", - "Damage taken spell": "Spell Resist", - "Damage range mainhand": "Dmg Main", + "Damage taken melee": "Physical Res.", + "Damage taken spell": "Spell Res.", + "Damage range mainhand": "Damage", "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 range ranged": "Damage Rng", "Damage mult ranged": "Damage Multiplier (Ranged)", "Attack time ranged": "Speed", "base hp": "Base Health",