diff --git a/modules/UI/mythicplus/advancement_state.ts b/modules/UI/mythicplus/advancement_state.ts deleted file mode 100644 index 28145d7..0000000 --- a/modules/UI/mythicplus/advancement_state.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Logger } from "../../classes/logger"; -const log = new Logger("AdvancementState"); - -export type AdvancementType = "Magic" | "Attack" | "Defense"; -export class AdvancementState { - - private advancement: string | null = null; - private advType: AdvancementType | null = null; - - SetType(type: AdvancementType): void { - this.advType = type; - } - - GetAdvType(): AdvancementType | null { - return this.advType; - } - - SetAdvancement(icon: string): void { - this.advancement = icon; - } - - GetAdvancement(): string | null { - return this.advancement; - } - - ClearAdvancement() { - this.advancement = null; - } - - ClearState() { - this.advancement = null; - this.advType = null; - } - -} \ No newline at end of file diff --git a/modules/UI/mythicplus/mythic_advancement.client.ts b/modules/UI/mythicplus/mythic_advancement.client.ts deleted file mode 100644 index 7c4e286..0000000 --- a/modules/UI/mythicplus/mythic_advancement.client.ts +++ /dev/null @@ -1,591 +0,0 @@ -/** @ts-expect-error */ -let aio: AIO = {}; - -const id = (name: string) => `MythicAdvUI_${name}`; - -function GetComponent(name: string, type: string = "Frame"): T | null { - const component = _G[id(name)]; - return component ? component as T : null; -} - -import { colors } from "../../classes/ui-utils"; -import { AdvancementState } from "./advancement_state"; - -/** - * Advancement Name and Spell Reference - * - * ('80000001','spell_mp_titans_strength_aura'), - * ('80000002','spell_mp_steel_forged_aura'), - * ('80000003','spell_mp_celestial_grace_aura'), - * ('80000004','spell_mp_forbidden_knowledge_aura'), - * ('80000005','spell_mp_spectral_reflexes_aura'), - * ('80000006','spell_mp_eldritch_barrier_aura'), - * ('80000007','spell_mp_hellfire_shielding_aura'), - * ('80000008','spell_mp_primal_endurance_aura'), - * ('80000009','spell_mp_lichbane_aura'), - * ('80000010','spell_mp_glacial_fortress_aura'); - */ - -if (!aio.AddAddon()) { - const upgradeUIHandlers = aio.AddHandlers("MythicAdvUI", {}); - const UpgradeUIFrames: Map = new Map(); - - // const itemSlots: Map = new Map(); - // let selectedDice: WoWAPI.Button | null = null; - // let rolling: boolean = false; - - const mainWidth = 768; - const mainHeight = 512; - const centerOffset = mainWidth / 2; - - // Load the advancement state based on the requested type for now just do magic type - const advancementState = new AdvancementState(); - advancementState.SetType("Magic"); - - const customTextures = { - // frame background elements - "bgFrame": "Interface\\AddOns\\MythicPlusData\\Textures\\mythic-adv-frame", - "bgFrameHq": "Interface\\AddOns\\MythicPlusData\\Textures\\mythic-adv-frame-hq", - "darkBg": "Interface\\AddOns\\MythicPlusData\\Textures\\DialogBox-Background-Dark", - "diceFrame": "Interface\\AddOns\\MythicPlusData\\Textures\\advancement_frame", - - // advancement icons buttons - "str": "Interface\\AddOns\\MythicPlusData\\Textures\\str_adv.tga", - "agi": "Interface\\AddOns\\MythicPlusData\\Textures\\agi_adv.tga", - "int": "Interface\\AddOns\\MythicPlusData\\Textures\\int_adv.tga", - "spr": "Interface\\AddOns\\MythicPlusData\\Textures\\spr_adv.tga", - "sta": "Interface\\AddOns\\MythicPlusData\\Textures\\sta_adv.tga", - "icon_overlay": "Interface\\AddOns\\MythicPlusData\\Textures\\icon_overlay.tga", - "int_selected": "Interface\\AddOns\\MythicPlusData\\Textures\\int_adv_selected.tga", - "spr_selected": "Interface\\AddOns\\MythicPlusData\\Textures\\spr_adv_selected.tga", - - // Dice buttons - "single_roll": "Interface\\AddOns\\MythicPlusData\\Textures\\single_roll.tga", - "double_roll": "Interface\\AddOns\\MythicPlusData\\Textures\\double_roll.tga", - "triple_roll": "Interface\\AddOns\\MythicPlusData\\Textures\\triple_roll.tga", - "single_roll_selected": "Interface\\AddOns\\MythicPlusData\\Textures\\single_roll_selected.tga", - "double_roll_selected": "Interface\\AddOns\\MythicPlusData\\Textures\\double_roll_selected.tga", - "triple_roll_selected": "Interface\\AddOns\\MythicPlusData\\Textures\\triple_roll_selected.tga", - - // Advancement Bars - "bars": "Interface\\AddOns\\MythicPlusData\\Textures\\adv_bars.tga", - - // Roll Numbers - "numbers": "Interface\\AddOns\\MythicPlusData\\Textures\\big_numbers.tga", - } - - interface ItemSlot extends WoWAPI.Button { - hasItem?: boolean; - itemLink?: string; - } - - function GetTexture(name: string): string { - return customTextures[name] || ""; - } - - function UpdateDiceVisibility(show: boolean): void { - const buttons = ['single_roll', 'double_roll', 'triple_roll']; - buttons.forEach(name => { - const button = GetComponent(`${name}_button`, "Button"); - if (button) { - if (show) { - button.SetAlpha(0.8); - button.Enable(); - } else { - button.SetAlpha(0.0); - button.Disable(); - } - } - }); - } - - function SelectAdvancement(name: string, button: WoWAPI.Button): void { - - // if the button click is itself, reset it - if (advancementState.GetAdvancement() === name) { - button.SetNormalTexture(GetTexture(name)); - advancementState.SetAdvancement(null); - UpdateDiceVisibility(false); - } else { - // Set the new advancement - button.SetNormalTexture(GetTexture(`${name}_selected`)); - - // Handle opposing button - const opposingStats = { - 'int': 'spr', - 'spr': 'int', - 'str': 'agi', - 'agi': 'str' - }; - - const opposingStat = opposingStats[name]; - if (opposingStat) { - const opposingButton = GetComponent(`${opposingStat}_button`, "Button"); - if (opposingButton) { - opposingButton.SetNormalTexture(GetTexture(opposingStat)); - } - } - - // Update advancement state and show dice buttons - advancementState.SetAdvancement(name); - UpdateDiceVisibility(true); - } - } - - /** - * Add icons icons used for advancement upgrades. - * @param frame Main Frame - */ - function CreateAdvIcons(frame: WoWAPI.Frame): void { - - const ICON_POS_LEFT = 38; - const ICON_POS_TOP = -150; - - let topIcon: string = ""; - let bottomIcon: string = ""; - let topText: string = ""; - let bottomText: string = ""; - - if (advancementState.GetAdvType() === "Magic") { - topIcon = "spr"; - bottomIcon = "int"; - topText = "Celestial Grace"; - bottomText = "Forbidden Knowledge"; - } - else if (advancementState.GetAdvType() === "Attack") { - topIcon = "str"; - bottomIcon = "agi"; - topText = "Titan's Strength"; - bottomText = "Spectral Reflexes"; - } - else if (advancementState.GetAdvType() === "Defense") { - topIcon = "sta"; - topText = "Steel Forged" - } - - const topButton = CreateFrame("Button", id(`${topIcon}_button`), frame); - topButton.SetSize(132, 132); - topButton.SetPoint("TOPLEFT", ICON_POS_LEFT, ICON_POS_TOP); - topButton.SetNormalTexture(GetTexture(topIcon)); - topButton.SetHighlightTexture(GetTexture("icon_overlay")); - topButton.SetScript("OnClick", function(self: WoWAPI.Button) { - SelectAdvancement(topIcon, self); - }); - - topButton.Show(); - - const bottomButton = CreateFrame("Button", id(`${bottomIcon}_button`), frame); - bottomButton.SetSize(132, 132); - bottomButton.SetPoint("TOPLEFT", topButton, "BOTTOMLEFT", 0, -20); - bottomButton.SetNormalTexture(GetTexture(bottomIcon)); - bottomButton.SetHighlightTexture(GetTexture("icon_overlay")); - bottomButton.SetScript("OnClick", function(self: WoWAPI.Button) { - SelectAdvancement(bottomIcon, self); - }); - - bottomButton.Show(); - - // Add advancement bars - const topbarTexture = frame.CreateTexture(id("topbar_gold"), "ARTWORK"); - topbarTexture.SetPoint("LEFT", topButton, "RIGHT", -4, -10); - topbarTexture.SetSize(187, 37); - topbarTexture.SetTexture(GetTexture("bars")); - topbarTexture.SetTexCoord(36/256, 218/256, 0/256, 37/256); - - const bottombarTexture = frame.CreateTexture(id("bottombar_gold"), "ARTWORK"); - bottombarTexture.SetPoint("LEFT", bottomButton, "RIGHT", -4, -10); - bottombarTexture.SetSize(187, 37); - bottombarTexture.SetTexture(GetTexture("bars")); - bottombarTexture.SetTexCoord(36/256, 218/256, 0/256, 37/256); - - const topbarText = frame.CreateFontString(id("topbar_text"), "OVERLAY"); - topbarText.SetPoint("CENTER", topbarTexture, "CENTER", 0, 33); - topbarText.SetTextColor(1, 1, 1, 1) // White - topbarText.SetFont("Fonts\\FRIZQT__.TTF", 16) - topbarText.SetText(topText); - - const bottombarText = frame.CreateFontString(id("bottombar_text"), "OVERLAY"); - bottombarText.SetPoint("CENTER", bottombarTexture, "CENTER", 0, 33); - bottombarText.SetTextColor(1, 1, 1, 1) // White - bottombarText.SetFont("Fonts\\FRIZQT__.TTF", 16) - bottombarText.SetText(bottomText); - } - - /** - * - */ - - /** - * Creates the dice roll buttons that appear below the roll frame - * @param frame Main Frame - * @param rollFrame The frame containing the roll numbers - */ - function CreateDiceButtons(frame: WoWAPI.Frame, rollFrame: WoWAPI.Frame): void { - const buttonWidth = 72; - const buttonHeight = 72; - const spacing = 20; - const totalWidth = (buttonWidth * 3) + (spacing * 2); - const startX = -(totalWidth / 2) + (buttonWidth / 2); - - const buttons = [ - { name: 'single_roll', rolls: 1 }, - { name: 'double_roll', rolls: 2 }, - { name: 'triple_roll', rolls: 3 } - ]; - - let selectedButton = GetComponent("selected_dice_button", "Button"); - - buttons.forEach((buttonInfo, index) => { - const buttonId = `${buttonInfo.name}_button`; - let button = GetComponent(buttonId, "Button"); - - if (!button) { - button = CreateFrame("Button", id(buttonId), frame) as WoWAPI.Button; - button.SetSize(buttonWidth, buttonHeight); - button.SetPoint("TOP", rollFrame, "BOTTOM", startX + (index * (buttonWidth + spacing)), -75); - - const normalTexture = button.CreateTexture(null, "BACKGROUND"); - normalTexture.SetTexture(GetTexture(buttonInfo.name)); - normalTexture.SetAllPoints(button); - button.SetNormalTexture(normalTexture); - - const highlightTexture = button.CreateTexture(null, "HIGHLIGHT"); - highlightTexture.SetTexture(GetTexture(`${buttonInfo.name}_selected`)); - highlightTexture.SetAllPoints(button); - button.SetHighlightTexture(highlightTexture); - - // Start hidden by default - button.SetAlpha(0.0); - button.SetScript("OnClick", function() { - if (selectedButton) { - const prevButtonInfo = buttons.find(b => b.name === selectedButton.GetName().split('_')[0]); - if (prevButtonInfo) { - selectedButton.SetNormalTexture(GetTexture(prevButtonInfo.name)); - } - } - - if (selectedButton === button) { - selectedButton = null; - } else { - selectedButton = button; - button.SetNormalTexture(GetTexture(`${buttonInfo.name}_selected`)); - // Here you would typically trigger the roll with the number of dice - frame["rollNumbers"](buttonInfo.rolls, 25 * buttonInfo.rolls); - } - }); - } - }); - - // Ensure buttons are hidden/shown based on current advancement state - UpdateDiceVisibility(advancementState.GetAdvancement() !== null); - } - - /** - * Add title text to the frame. - * @param frame Main Frame - */ - function AddTitle(frame: WoWAPI.Frame): void { - // Add title text - const titleBar = frame.CreateFontString(id("TitleBar"), "OVERLAY"); - titleBar.SetPoint("TOP", -150, -40); - titleBar.SetTextColor(1, 0.84, 0, 1) // Golden yellow - titleBar.SetFont("Interface/Modules/MythicPlus/Fonts/NOTO.TTF", 16) - titleBar.SetText(`Mythic Upgrades`); - } - - /** - * This adds in the big numbers that will flash to simulate a dice rolls... - * even though the dice roll actually happens on the server in the module. - * @param frame - */ - function ShowRollNumbers(frame: WoWAPI.Frame): void { - - let rollFrame = GetComponent("roll_frame"); - if (!rollFrame) { - rollFrame = CreateFrame("Frame", id("roll_frame"), frame); - rollFrame.SetSize(120, 120); - rollFrame.SetPoint("CENTER", 200, -24); - rollFrame.SetBackdrop({ - bgFile: GetTexture("darkBg"), - tile: false, - tileSize: 120, - insets: { left: 1, right: 1, top: 1, bottom: 1 }, - }); - rollFrame.SetBackdropColor(0, 0, 0, 0.3); // RGB + alpha - } - rollFrame.Show(); - - // create a texture that will change the graphic every few seconds between 1-25 using big_number tga - // for numbers greater than 9 it will need to add to smaller textures. Below are coordinates of the - // big_number tga [UL, UR, LL, LR] - - const coords: {[key: number]: number[]} = { - 0: [35, 96, 8, 81], - 1: [174, 210, 8, 81], - 2: [292, 345, 8, 81], - 3: [424, 472, 8, 81], - 4: [33, 95, 98, 163], - 5: [167, 217, 98, 163], - 6: [291, 346, 98, 163], - 7: [425, 471, 98, 163], - 8: [38, 89, 182, 247], - 9: [165, 218, 182, 247], - } - - let currentTextures: WoWAPI.Texture[] = []; - - function clearTextures() { - currentTextures.forEach(texture => { - texture.Hide(); - texture.ClearAllPoints(); - }); - currentTextures = []; - } - - function createNumberTexture(digit: number, xOffset: number = 0) { - const rollTexture = rollFrame.CreateTexture(null, "ARTWORK"); - rollTexture.SetSize(60, 60); - rollTexture.SetPoint("CENTER", rollFrame, "CENTER", xOffset, 0); - rollTexture.SetTexture(GetTexture("numbers")); - - - if (coords[digit]) { - rollTexture.SetTexCoord( - coords[digit][0] / 512, - coords[digit][1] / 512, - coords[digit][2] / 256, - coords[digit][3] / 256 - ); - } - currentTextures.push(rollTexture); - return rollTexture; - } - - function showNumber(num: number) { - clearTextures(); - if (num >= 10) { - const tens = Math.floor(num / 10); - const ones = num % 10; - createNumberTexture(tens, -30).Show(); - createNumberTexture(ones, 30).Show(); - } else { - createNumberTexture(num, 0).Show(); // Explicitly set offset to 0 for single digits - } - } - - let rolling = false; - let lastUpdate = 0; - - // Make rollNumbers accessible on the frame for external calls - frame["rollNumbers"] = function(min: number, max: number, duration: number = 2000) { - if (rolling) return; - clearTextures(); - rolling = true; - let elapsed = 0; - - frame.SetScript("OnUpdate", function(_, deltaTime) { - elapsed = elapsed + deltaTime * 1000; - lastUpdate += deltaTime * 1000; - - // Update number every 100ms - if (lastUpdate >= 100) { - lastUpdate = 0; - const randomNum = Math.floor(Math.random() * (max - min + 1)) + min; - showNumber(randomNum); - } - - if (elapsed >= duration) { - frame.SetScript("OnUpdate", null); - rolling = false; - } - }); - } - } - - /** - * Create the main upgrade window frame. - * @returns Main Frame - */ - function CreateUpgradeWindow(state: AdvancementState): WoWAPI.Frame { - - // Main frame creation - const frame = CreateFrame("Frame", id("main"), UIParent); - frame.SetSize(mainWidth, mainHeight); - frame.SetPoint("CENTER"); - frame.SetMovable(true); - frame.EnableMouse(true); - frame.RegisterForDrag("LeftButton"); - frame.SetScript("OnDragStart", frame.StartMoving); - frame.SetScript("OnDragStop", frame.StopMovingOrSizing); - frame.SetFrameLevel(100); // Set high frame level to stay on top - - // Background texture - const bgTexture = frame.CreateTexture(id("background"), "BACKGROUND"); - bgTexture.SetPoint('TOPLEFT'); - bgTexture.SetWidth(mainWidth); - bgTexture.SetHeight(mainHeight); - bgTexture.SetTexture(GetTexture("bgFrameHq")); - bgTexture.SetTexCoord(0, 768/1024, 0, 1); // Show 75% of width (768/1024) and full height - - // Add components - CreateAdvIcons(frame); - AddTitle(frame); - ShowRollNumbers(frame); - - - - const rollFrame = GetComponent("roll_frame"); - if (rollFrame) { - CreateDiceButtons(frame, rollFrame); - } - - return frame; - } - - // Remove the template's close button - // const templateCloseButton = frame.GetChildren()[0] as WoWAPI.Frame; - // if (templateCloseButton) { - // templateCloseButton.Hide(); - // } - - // Add our custom close button - // const closeButton = CreateFrame("Button", id("CloseButton"), frame, "UIPanelCloseButton"); - // closeButton.SetPoint("TOPRIGHT", -5, -5); - // closeButton.SetScript("OnClick", () => { - // frame.Hide(); - // }); - - // Header Row: Skill Icons & Ranks - // for (let i = 0; i < 3; i++) { - // const skillFrame = CreateFrame("Frame", id(`Skill_${i}`), frame); - // skillFrame.SetSize(64, 64); - // skillFrame.SetPoint("TOP", -125 + i * 125, -55); - - // const skillIcon = skillFrame.CreateTexture(id(`SkillIcon_${i}`), "ARTWORK"); - // skillIcon.SetTexture("Interface\\Icons\\INV_Misc_QuestionMark"); - // skillIcon.SetAllPoints(); - - // const skillName = skillFrame.CreateFontString(id(`SkillName_${i}`), "OVERLAY", "GameFontNormalLarge"); - // skillName.SetPoint("TOP", skillFrame, "BOTTOM", 0, -5); - // skillName.SetText(`Skill ${i + 1}`); - - // const skillRank = skillFrame.CreateFontString(id(`SkillRank_${i}`), "OVERLAY", "GameFontHighlightLarge"); - // skillRank.SetPoint("TOP", skillName, "BOTTOM", 0, -2); - // skillRank.SetText("0 / 50"); - // } - - // Add a new texture in the middle of the frame that is 512x512 and the middle layer - // const centerTexture = frame.CreateTexture(id("DiceTextureBack"), "ARTWORK"); - // centerTexture.SetDrawLayer("ARTWORK", 3); - // centerTexture.SetSize(128, 128); - // centerTexture.SetPoint("CENTER", frame, "CENTER", 0, -20); - // centerTexture.SetTexture("Interface\\MythicPlus\\adv-dice-light.blp"); - - // const circleTexture = frame.CreateTexture(id("DiceTextureBack"), "BACKGROUND"); - // circleTexture.SetDrawLayer("ARTWORK", 5); - // circleTexture.SetSize(512, 512); - // circleTexture.SetAlpha(0.20); - // circleTexture.SetPoint("CENTER", frame, "CENTER", 0, -20); - // circleTexture.SetTexture("Interface\\MythicPlus\\gold-circle.blp"); - - // // Add a glowing effect behind the dice - // const glowTexture = frame.CreateTexture(id("DiceGlow"), "ARTWORK"); - // glowTexture.SetDrawLayer("ARTWORK", -2); - // glowTexture.SetSize(300, 300); - // glowTexture.SetPoint("CENTER", centerTexture, "CENTER", 0, 0); - // glowTexture.SetTexture("Interface\\GLUES\\MODELS\\UI_MainMenu_Legion\\UI_MainMenu_Legion3"); - // glowTexture.SetAlpha(0.3); - - // Roll Display with better font handling - // const rollDisplay = frame.CreateFontString(id("RollDisplay"),"ARTWORK"); - // rollDisplay.SetFont("Interface\\MythicPlus\\NOTO.TTF", 256, "THICKOUTLINE"); - // rollDisplay.SetPoint("CENTER", frame, "CENTER", 0, -80); - // rollDisplay.SetTextColor(1, 0.84, 0, 1); // More golden yellow color - // rollDisplay.SetText("-"); - - - // Dice Multipliers with Selection Logic - // const diceMultipliers = ["1x", "2x", "3x"]; - // for (let k = 0; k < diceMultipliers.length; k++) { - // const diceButton = CreateFrame("Button", id(`Dice_${k}`), frame); - // diceButton.SetSize(24, 24); - // diceButton.SetPoint("TOPLEFT", 150 + (k * 30), -450); - - // const diceText = diceButton.CreateFontString(id(`DiceText_${k}`), "OVERLAY", "GameFontHighlight"); - // diceText.SetPoint("CENTER", diceButton, "CENTER", 0, 0); - // diceText.SetText(diceMultipliers[k]); - - // diceButton.SetScript("OnClick", function() { - // if (selectedDice) { - // selectedDice.SetAlpha(1.0); // Reset previous selection - // } - // selectedDice = diceButton; - // selectedDice.SetAlpha(1.5); // Glow effect - // }); - // } - - // Roll Button with animation logic - // const rollButton = CreateFrame("Button", id("RollButton"), frame, "UIPanelButtonTemplate"); - // rollButton.SetSize(100, 30); - // rollButton.SetPoint("BOTTOM", frame, "BOTTOM", 0, 50); - // rollButton.SetText("Roll"); - - // function rollDice(min: number, max: number, duration: number = 5000) { - // if (rolling) return; - // rolling = true; - // let elapsed = 0; - // let lastUpdate = 0; - - // frame.SetScript("OnUpdate", function(_, deltaTime) { - // elapsed = elapsed + deltaTime * 5000; - // lastUpdate += deltaTime * 1000; - - // // Only update every 200ms to slow down the rolling animation - // if (lastUpdate >= 100) { - // lastUpdate = 0; - // rollDisplay.SetText(`${Math.floor(Math.random() * (max - min + 1)) + min}`); - // } - - // if (elapsed >= duration) { - // frame.SetScript("OnUpdate", null); - // rolling = false; - // // Set final roll - // rollDisplay.SetText(`${Math.floor(Math.random() * (max - min + 1)) + min}`); - // } - // }); - // } - - // rollButton.SetScript("OnClick", function() { - // rollDice(2, 23); // Default to 2-23 range for backward compatibility - // }); - - // Roll History - // const historyFrame = CreateFrame("Frame", id("HistoryFrame"), frame); - // historyFrame.SetSize(380, 80); - // historyFrame.SetPoint("BOTTOM", frame, "BOTTOM", 0, 10); - - // const historyText = historyFrame.CreateFontString(id("HistoryText"), "OVERLAY", "GameFontHighlight"); - // historyText.SetPoint("TOPLEFT", historyFrame, "TOPLEFT", 10, -10); - // historyText.SetText("Roll History:"); - - - let frame: WoWAPI.Frame | undefined = undefined; - - if(!UpgradeUIFrames.has(advancementState.GetAdvType())) { - // frame = CreateUpgradeWindow(advancementState); - } else { - // if we have the frame already show it - // frame = UpgradeUIFrames.get(advancementState.GetAdvType()); - } - - // For debugging purposes show the window - //frame.Show(); - - // Triggered from ths server to be set up later - upgradeUIHandlers.ShowUpgradeWindow = () => { - // if (!UpgradeUIFrames.has(1)) { - // CreateUpgradeWindow(); - // } - // UpgradeUIFrames.get(1).Show(); - }; -} diff --git a/modules/UI/mythicplus/mythic_advancement.server.ts b/modules/UI/mythicplus/mythic_advancement.server.ts deleted file mode 100644 index e235ce5..0000000 --- a/modules/UI/mythicplus/mythic_advancement.server.ts +++ /dev/null @@ -1,223 +0,0 @@ -/** @ts-expect-error */ -let aio: AIO = {}; - -const SCRIPT_NAME = 'UpgradeUI'; -import { Logger } from "../../classes/logger"; -const log = new Logger(SCRIPT_NAME); - -// Flag to track if materials have been loaded -let materialsLoaded = false; - -type ItemType = { - entry: number; - name: string; -} - -type Materials = { - name: string; - items: Array -} - -const upgradeMaterials: Record = {}; - -/** - * Helper function to safely get items from a material - */ -const getItemsFromMaterial = (material: Materials): Array => { - if (!material) { - return []; - } - - if (!material.items) { - material.items = []; - } - - return material.items; -}; - -/** - * Handles the logic for showing the upgrade UI when a player types .advanceme - */ -const ShowUpgradeUI: player_event_on_command = (event: number, player: Player, command: string): boolean => { - if (command === "advanceme") { - log.info(`Showing Upgrade UI for player: ${player.GetName()}`); - aio.Handle(player, 'UpgradeUI', 'ShowUpgradeWindow'); - return false; - } - return true; -}; - -/** - * Get a list of materials from the database that can be used for mythic plus advancement - * @param event World startup event - */ -// const GetMaterialsList: eluna_event_on_lua_state_open = (event: number) => { - -// const query = WorldDBQuery(`select materialId, entry, name from mp_material_types`); - -// const categoryMap: Record = { -// 1: "Cloth", -// 2: "Rare Cloth", -// 3: "Plants", -// 4: "Rare Plants", -// 5: "Ore", -// 6: "Rare Ore", -// 7: "Leather", -// 8: "Rare Leather", -// 9: "Gems", -// 10: "Rare Gems", -// 11: "Enchanting", -// 12: "Rare Enchanting", -// 13: "Water Elements", -// 14: "Rare Water Elements", -// 15: "Fire Elements", -// 16: "Rare Fire Elements", -// 17: "Nature Elements", -// 18: "Rare Earth Elements", -// 19: "Shadow Elements", -// 20: "Rare Shadow Elements", -// 21: "Arcane Elements", -// 22: "Rare Arcane Elements", -// 23: "Veilstone", -// }; - -// if (query) { -// do { -// const materialId = query.GetUInt32(0); -// const entry = query.GetUInt32(1); -// const categoryName = categoryMap[materialId] || "Unknown"; - -// // Initialize the material group if it doesn't exist -// if (!upgradeMaterials[materialId]) { -// upgradeMaterials[materialId] = { -// name: categoryName, -// items: [] -// }; -// } - -// // Add the item to the material group -// upgradeMaterials[materialId].items.push({ -// entry: entry, -// name: query.GetString(2) -// }); - -// } while (query.NextRow()); -// } - -// log.info(`Loaded ${Object.keys(upgradeMaterials).length} material groups with items for mythic plus advancement`); -// materialsLoaded = true; -// }; - -// /** -// * This will show all the counts for a player by from the upgradeMaterials object -// */ -// function GetMaterials(this:void, player: Player) { - -// // Create a readable string representation of the materials and their counts -// let materialsString = 'Your Mythic+ Advancement Materials:\n'; -// log.info("Showing material counts"); - -// // Track total materials by category -// const materialCounts: Record = {}; - -// // Initialize counts for all categories -// const materialIds = Object.keys(upgradeMaterials); -// log.info(`Found ${materialIds.length} material groups`); - -// // Initialize all material counts to 0 -// for (let i = 0; i < materialIds.length; i++) { -// const materialId = materialIds[i]; -// materialCounts[materialId] = 0; -// } - -// // Process each material group -// for (let i = 0; i < materialIds.length; i++) { -// const materialId = materialIds[i]; -// log.info(`Processing material ID: ${materialId}`); - -// // Get the material object and verify it exists -// const material = upgradeMaterials[materialId]; -// if (!material) { -// log.info(`Material with ID ${materialId} is undefined`); -// continue; -// } - -// // Get the material name -// const materialName = material.name || "Unknown Material"; -// materialsString = materialsString + '\n' + materialName + ':\n'; - -// // Get items using our helper function to ensure it's not nil -// const items = getItemsFromMaterial(material); -// log.info(`Material ${materialName} has ${items.length} items`); - -// if (items.length === 0) { -// log.info(`No items found for material ${materialName}`); -// materialsString = materialsString + ' No items found in this category\n'; -// continue; -// } - -// // Process each item in the material category -// let categoryTotal = 0; -// for (let j = 0; j < items.length; j++) { -// // Get the item and verify it exists -// const item = items[j]; -// if (!item) { -// log.info(`Item at index ${j} is undefined for material ${materialName}`); -// continue; -// } - -// // Get the item entry and name -// const itemEntry = item.entry; -// const itemName = item.name || "Unknown Item"; - -// log.info(`Checking item ${itemName} (${itemEntry})`); - -// try { -// // Get the item count -// const count = player.GetItemCount(itemEntry, true); // true = include bank -// log.info(`Player has ${count} of item ${itemName}`); - -// // Add to category total -// categoryTotal = categoryTotal + count; - -// // Only show items the player has -// if (count > 0) { -// materialsString = materialsString + ' - ' + itemName + ': ' + count + '\n'; -// } -// } catch (error) { -// log.info(`Error getting count for item ${itemName}: ${error}`); -// } -// } - -// // Store the category total -// materialCounts[materialId] = categoryTotal; - -// // Add total for this category -// materialsString = materialsString + ' Total ' + materialName + ': ' + categoryTotal + '\n'; -// } - -// log.info("Initialized material counts"); - -// // Send the material counts to the player -// player.SendBroadcastMessage(materialsString); - -// // Log the material counts for debugging -// log.info('Showed material counts for player: ' + player.GetName()); - -// return true; -// } - -// const UpgradeHandlers = aio.AddHandlers("UpgradeUI", { -// ShowMaterialCount -// }); - -/** - * Register the command event to listen for ".advanceme" - */ -RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => ShowUpgradeUI(...args)); - -/** - * Get all the material types from the database - * RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN, (...args) => GetMaterialsList(...args)); - */ - diff --git a/modules/UI/mythicplus/mythic_custom_spells.ts b/modules/UI/mythicplus/mythic_custom_spells.ts index 59f49d1..fc19f06 100644 --- a/modules/UI/mythicplus/mythic_custom_spells.ts +++ b/modules/UI/mythicplus/mythic_custom_spells.ts @@ -317,8 +317,6 @@ PrintInfo(`materialId: ${materialId} and spell: ${spell.GetEntry()}`); return true; }; - - // // Get the item // const stackCount = GetTotalStackCount(item); diff --git a/modules/UI/mythicplus/mythic_items.ts b/modules/UI/mythicplus/mythic_items.ts index f4268e9..d2a1200 100644 --- a/modules/UI/mythicplus/mythic_items.ts +++ b/modules/UI/mythicplus/mythic_items.ts @@ -25,6 +25,14 @@ export const FUSED_MYTHIC_DARK_CRYSTAL = 911022; export const FUSED_RARE_EARTH_STONE = 911023; export const FUSED_MYTHIC_EARTH_STONE = 911024; +export const VOID_BADGE = 911050; +export const EMBLEM_OF_UNDEATH = 911051; +export const EMBLEM_OF_CHAOS = 911052; +export const EMBLEM_OF_VEIL = 911053; +export const MYTHIC_TOKEN = 911054; + + + export const MYTHIC_MATERIALS = { ANCIENT_DICE, ONYX_SPIKE_RELIC, diff --git a/modules/UI/mythicplus/mythic_npcs.ts b/modules/UI/mythicplus/mythic_npcs.ts index 3b9d9e6..1568723 100644 --- a/modules/UI/mythicplus/mythic_npcs.ts +++ b/modules/UI/mythicplus/mythic_npcs.ts @@ -3,6 +3,8 @@ let aio: AIO = {}; import { MapNames, MapIds, BossIDs } from "../../classes/mapzones"; import * as Spells from "./mythic_custom_spells"; +import { SetTrigger, GetTrigger } from "../../classes/triggers"; + /** * This is the file for managing new NPC interactions * - Mick Ashwild - 9500561 teaches leather/fire fusions @@ -12,27 +14,48 @@ import * as Spells from "./mythic_custom_spells"; * - ??? - 9500565 teaches gem/essence fusions * - ??? - Old Witch teaches shadow fusion * + * The player will meet different characters at different times so the hello will check to see whch + * audio file and gossip menu needs to be shown. The list of locations an npc will show up is below + * + * Mick + * Rare Leather Fusion : Wailing Caverns Verdan the everliving + * Mythic Leather Fusion : Sartharion Obsidian Sanctum + * Rare Fire Fusion : Hellfire Ramparts Nazan + Vazruden + * Mythic Fire Fusion : Onyxia Lair Flamegor + * Casual Spawns : World ends Tavern Shatrath + * + * Thorin + * Rare Ore Fusion : BRD Magmus + * Mythic Ore Fusion : Ragnaros + * Casual Spawns : The Great Forge */ export enum NPCType { MICK_ASHWILD = 'mick', THORIN_FIREHAND = 'thorin', - ELOWYN_THREADBINDER = 'elowyn', + ELOWYN_THREADBINDER = 'elowen', SHIVEY = 'shivey', - OLD_WITCH = 'old_witch' -} + STEVE = 'steve', + VAERIC = 'vaeric', + AGATHA = 'agatha', + SYLVIA = 'sylvia', + +} export const NPCIds: Record = { [NPCType.MICK_ASHWILD]: 9500561, [NPCType.THORIN_FIREHAND]: 9500562, [NPCType.ELOWYN_THREADBINDER]: 9500563, [NPCType.SHIVEY]: 9500564, - [NPCType.OLD_WITCH]: 9500565 + [NPCType.STEVE]: 9500565, + [NPCType.VAERIC]: 9500566, + [NPCType.AGATHA]: 9500567, + [NPCType.SYLVIA]: 9500568, + }; export enum GobjectType { - PORTAL = 'portal', - + PORTAL = 'portal', } export const GobjectIds: Record = { @@ -44,9 +67,12 @@ const AUDIO_BASE_PATH = "Interface\\Modules\\MythicPlus\\Audio\\"; export const AudioPaths: Record = { [NPCType.MICK_ASHWILD]: AUDIO_BASE_PATH + "Mick\\mick-", [NPCType.THORIN_FIREHAND]: AUDIO_BASE_PATH + "Thorin\\thorin-", - [NPCType.ELOWYN_THREADBINDER]: AUDIO_BASE_PATH + "Elowyn\\elowyn-", + [NPCType.ELOWYN_THREADBINDER]: AUDIO_BASE_PATH + "Elowen\\elowen-", [NPCType.SHIVEY]: AUDIO_BASE_PATH + "Shivey\\shivey-", - [NPCType.OLD_WITCH]: AUDIO_BASE_PATH + "OldWitch\\old-witch-" + [NPCType.STEVE]: AUDIO_BASE_PATH + "Steve\\steve-", + [NPCType.VAERIC]: AUDIO_BASE_PATH + "Vaeric\\vaeric-", + [NPCType.AGATHA]: AUDIO_BASE_PATH + "Agatha\\agatha-", + [NPCType.SYLVIA]: AUDIO_BASE_PATH + "Sylvia\\sylvia-", }; function getAudioFile(npcName: NPCType, file: string): string { @@ -61,26 +87,6 @@ function isInMythicPlus(playerId: number, instanceId: number): boolean { return false; } -/** - * the player will meet different characters at different times so the hello will check to see whch - * audio file and gossip menu needs to be shown. The list of locations an npc will show up is below - * - * Mick - * Rare Leather Fusion : Wailing Caverns Verdan the everliving - * Mythic Leather Fusion : Sartharion Obsidian Sanctum - * Rare Fire Fusion : Hellfire Ramparts Nazan + Vazruden - * Mythic Fire Fusion : Onyxia Lair Flamegor - * Casual Spawns : World ends Tavern Shatrath - * - * Thorin - * Rare Ore Fusion : BRD Magmus - * Mythic Ore Fusion : Ragnaros - * Casual Spawns : The Great Forge - - * - */ - - // Track NPC dialog animation state interface ActiveNpcState { time: number; @@ -90,24 +96,67 @@ interface ActiveNpcState { lastEmote?: number; outro?: string[]; // list of players that have heard the outro } - interface PlayedAudioState { playerName: string; audioFile: string; played: boolean; } +// Track the audio that has been played for each for this instance id. +// key: InstanceId value: playerId: audioFile +let playedAudio: Record> = {}; + + +// This will prevent audio from being played more than once for the same player using a global map +function PlayAudioOnce(player: Player, audioFile: string, npcType?: NPCType, forcePlay?: boolean): void { + const instanceId = player.GetInstanceId(); + const mapId = player.GetMapId(); + const playerName = player.GetName(); + + // Get audio options from NPC config if provided + let audioOptions: {volume: number, duration: number} | undefined; + if (npcType) { + const npcConfig = getNPCMapConfig(npcType, mapId); + if (npcConfig?.audioOptions) { + audioOptions = npcConfig.audioOptions; + } + } + + // Default audio options if not specified in NPC config + if (!audioOptions) { + audioOptions = { + volume: 0.5, + duration: 45 + }; + } + + if(!playedAudio[instanceId]) { + playedAudio[instanceId] = {}; + } + + // If nothing has been played to the player create the audio entry + if(!playedAudio[instanceId][playerName]) { + playedAudio[instanceId][playerName] = []; + playedAudio[instanceId][playerName].push(audioFile); + aio.Handle(player, 'AIOAudioPlayer', 'PlaySingleSound', audioFile, audioOptions, playerName); + return; + } + + if(playedAudio[instanceId][playerName].includes(audioFile) && forcePlay !== true) { + return; + } + + playedAudio[instanceId][playerName].push(audioFile); + aio.Handle(player, 'AIOAudioPlayer', 'PlaySingleSound', audioFile, audioOptions, playerName); +} + + // Track the ai update loop for each instance of a NPC which let npcState: Record = {}; // Create emote maps for npcs while they are talking keys are seconds into audio and values are emote types const emotesMap: Record> = {}; -// Track the audio that has been played for each for this instance id. -// key: InstanceId value: playerId: audioFile -let playedAudio: Record> = {}; - -// Mick + WC emotesMap[`${NPCIds[NPCType.MICK_ASHWILD]}-${MapIds[MapNames.WAILING_CAVERNS]}`] = { 1: EmoteType.STATE_TALK, 6: EmoteType.STATE_EXCLAIM, @@ -122,11 +171,119 @@ emotesMap[`${NPCIds[NPCType.MICK_ASHWILD]}-${MapIds[MapNames.WAILING_CAVERNS]}`] 37: EmoteType.STATE_TALK, 41: EmoteType.STATE_POINT, 43: EmoteType.ONESHOT_NONE -}; +}; + +emotesMap[`${NPCIds[NPCType.SHIVEY]}-${MapIds[MapNames.SCHOLOMANCE]}`] = { + 1: EmoteType.STATE_TALK, + 3: EmoteType.STATE_EXCLAIM, + 6: EmoteType.STATE_TALK, + 10: EmoteType.STATE_LAUGH, + 12: EmoteType.STATE_TALK, + 15: EmoteType.STATE_EXCLAIM, + 17: EmoteType.STATE_TALK, + 23: EmoteType.STATE_EXCLAIM, + 25: EmoteType.ONESHOT_NONE, + 26: EmoteType.STATE_POINT, + 28: EmoteType.ONESHOT_NONE, +}; +emotesMap[`${NPCIds[NPCType.THORIN_FIREHAND]}-${MapIds[MapNames.BLACKROCK_SPIRE_UPPER]}`] = { + 1: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.ONESHOT_NO, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_NO, + 31: EmoteType.ONESHOT_TALK, + 34: EmoteType.ONESHOT_POINT, + 36: EmoteType.ONESHOT_NONE +}; + +emotesMap[`${NPCIds[NPCType.ELOWYN_THREADBINDER]}-${MapIds[MapNames.STRATHOLME]}`] = { + 1: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.STATE_EXCLAIM, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_YES, + 30: EmoteType.ONESHOT_TALK, + 31: EmoteType.ONESHOT_NONE +}; + +emotesMap[`${NPCIds[NPCType.STEVE]}-${MapIds[MapNames.UTGARDE_PINNACLE]}`] = { + 1: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.STATE_EXCLAIM, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_YES, + 30: EmoteType.ONESHOT_TALK, + 38: EmoteType.ONESHOT_EXCLAMATION, + 40: EmoteType.ONESHOT_NO, + 42: EmoteType.ONESHOT_TALK, + 43: EmoteType.ONESHOT_POINT, + 45: EmoteType.ONESHOT_EXCLAMATION, + 47: EmoteType.ONESHOT_TALK, + 54: EmoteType.ONESHOT_YES, + 56: EmoteType.ONESHOT_TALK, + 64: EmoteType.ONESHOT_NONE +}; + +emotesMap[`${NPCIds[NPCType.THORIN_FIREHAND]}-${MapIds[MapNames.HALLS_OF_LIGHTNING]}`] = { + 1: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.STATE_EXCLAIM, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_YES, + 30: EmoteType.ONESHOT_TALK, + 46: EmoteType.ONESHOT_YES, + 48: EmoteType.ONESHOT_TALK, + 52: EmoteType.ONESHOT_NONE, +}; + +emotesMap[`${NPCIds[NPCType.MICK_ASHWILD]}-${MapIds[MapNames.HELLFIRE_RAMPARTS]}`] = { + 1: EmoteType.STATE_EXCLAIM, + 3: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.STATE_EXCLAIM, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_YES, + 30: EmoteType.ONESHOT_TALK, + 38: EmoteType.ONESHOT_EXCLAMATION, + 40: EmoteType.ONESHOT_NO, + 42: EmoteType.ONESHOT_TALK, + 43: EmoteType.ONESHOT_POINT, + 45: EmoteType.ONESHOT_EXCLAMATION, + 47: EmoteType.ONESHOT_TALK, + 54: EmoteType.ONESHOT_YES, + 56: EmoteType.ONESHOT_TALK, + 84: EmoteType.ONESHOT_NONE +}; + +emotesMap[`${NPCIds[NPCType.SHIVEY]}-${MapIds[MapNames.NEXUS]}`] = { + 1: EmoteType.STATE_TALK, + 10: EmoteType.ONESHOT_YES, + 12: EmoteType.ONESHOT_TALK, + 17: EmoteType.ONESHOT_NO, + 19: EmoteType.ONESHOT_TALK, + 28: EmoteType.ONESHOT_NO, + 31: EmoteType.ONESHOT_TALK, + 34: EmoteType.ONESHOT_POINT, + 36: EmoteType.ONESHOT_TALK, + 39: EmoteType.ONESHOT_NONE +}; // Spell to spell MapId const spellToMap: Record = { - [MapIds[MapNames.WAILING_CAVERNS]]: Spells.SPELL_LEATHER_FUSION + [MapIds[MapNames.WAILING_CAVERNS]]: Spells.SPELL_LEATHER_FUSION, + [MapIds[MapNames.SCHOLOMANCE]]: Spells.SPELL_ALCHEMY_FUSION, + [MapIds[MapNames.BLACKROCK_SPIRE_UPPER]]: Spells.SPELL_ORE_FUSION, + [MapIds[MapNames.STRATHOLME]]: Spells.SPELL_CLOTH_FUSION, + [MapIds[MapNames.UTGARDE_PINNACLE]]: Spells.SPELL_ESSENCE_FUSION, + [MapIds[MapNames.HALLS_OF_LIGHTNING]]: Spells.SPELL_GEM_FUSION, + [MapIds[MapNames.HELLFIRE_RAMPARTS]]: Spells.SPELL_FLAME_FUSION, + [MapIds[MapNames.NEXUS]]: Spells.SPELL_COLD_FUSION, }; // Does this player already know what the special NPC is offering. @@ -138,32 +295,6 @@ function PlayerHasSpell(player: Player): boolean { return false; } - -// This will prevent audio from being played more than once for the same player using a global map -function PlayAudioOnce(player: Player, audioFile: string): void { - const instanceId = player.GetInstanceId(); - - if(!playedAudio[instanceId]) { - playedAudio[instanceId] = {}; - } - // If nothing has been played to the player create the audio entry - if(!playedAudio[instanceId][player.GetName()]) { - playedAudio[instanceId][player.GetName()] = []; - playedAudio[instanceId][player.GetName()].push(audioFile); - PrintDebug(`Playing audio ${audioFile} for player ${player.GetName()} in instance ${instanceId}`); - aio.Handle(player, 'AIOAudioPlayer', 'PlaySingleSound', audioFile); - return; - } - - if(playedAudio[instanceId][player.GetName()].includes(audioFile)) { - return; - } - - playedAudio[instanceId][player.GetName()].push(audioFile); - aio.Handle(player, 'AIOAudioPlayer', 'PlaySingleSound', audioFile); - -} - // Get the instance state of the NPC for this group and instance. function GetNPCState(creature: Creature): ActiveNpcState { const instanceId = creature.GetInstanceId(); @@ -183,115 +314,417 @@ function GetNPCState(creature: Creature): ActiveNpcState { return state; } +interface NPCMapConfig { + introAudio: string; + outroAudio: string; + teachYesAudio?: string; + teachNoAudio?: string; + completionTime: number; + spellId?: number; + gossipOptions: { + knownSpell: string; // Text shown when player already knows the spell + learnSpell: string; // Text for learning the spell + decline: string; // Text for declining to learn + }; + audioOptions?: { + volume: number; + duration: number; + }; + // Spawn configuration when this NPC appears after a boss kill + spawnConfig?: { + bossId: number; + portalLocation: { x: number; y: number; z: number; o: number }; // Where to spawn the portal and NPC + moveToLocation: { x: number; y: number; z: number }; // Where the NPC should walk to + despawnTime?: number; // How long before the NPC despawns (ms) + }; +} -/** - * Handle AI Dialogs for Mick and others. - */ -const handleMickAIUpdates: creature_event_on_aiupdate = (event: number, creature: Creature, diff: number): boolean => { +const NpcConfigMap: Record> = { + [NPCType.MICK_ASHWILD]: { + [MapIds[MapNames.WAILING_CAVERNS]]: { + introAudio: "rare-hello", + outroAudio: "rare-goodbye", + teachYesAudio: "teach-rare-yes", + teachNoAudio: "teach-rare-no", + completionTime: 43, + spellId: Spells.SPELL_LEATHER_FUSION, + gossipOptions: { + knownSpell: "Got nuthin' for ya friend.", + learnSpell: "Learn Leather Fusion (requires grandmaster)", + decline: "Best to come another time" + }, + audioOptions: { + volume: 1.0, + duration: 45 + }, + spawnConfig: { + bossId: 5775, // Verdan the Everliving + portalLocation: { x: -79.273, y: 4.999, z: -30.962, o: 2.20 }, + moveToLocation: { x: -83.252, y: 19.723, z: -31.076 }, + despawnTime: 1200000 // 20 minutes + } + }, + [MapIds[MapNames.HELLFIRE_RAMPARTS]]: { + introAudio: "fire-hello", + outroAudio: "fire-goodbye", + teachYesAudio: "teach-fire-yes", + teachNoAudio: "teach-fire-no", + completionTime: 85, + spellId: Spells.SPELL_FLAME_FUSION, + gossipOptions: { + knownSpell: "Got nuthin' for ya friend.", + learnSpell: "Learn Flame Fusion (Requires 10,000g and 1 Jug of Badlands Bourbon)", + decline: "Best to come another time" + }, + audioOptions: { + volume: 1.0, + duration: 85 + }, + spawnConfig: { + bossId: 17536, // Nazan + portalLocation: { x: -1439, y: 1764, z: 81.98, o: 5.55 }, + moveToLocation: { x: -1433, y: 1761, z: 81.80 }, + despawnTime: 1200000 // 20 minutes + } + }, + // Add other maps for Mick + }, + [NPCType.SHIVEY]: { + [MapIds[MapNames.SCHOLOMANCE]]: { + introAudio: "rare-hello", + outroAudio: "rare-goodbye", + teachYesAudio: "teach-rare-yes", + teachNoAudio: "teach-rare-no", + completionTime: 29, + spellId: Spells.SPELL_ALCHEMY_FUSION, + gossipOptions: { + knownSpell: "Why you staring at me like that, get lost.", + learnSpell: "Learn Alchemy Fusion (requires grandmaster)", + decline: "No thanks" + }, + audioOptions: { + volume: 0.5, + duration: 29 + }, + spawnConfig: { + bossId: 10508, // Ras Frostwhisper + portalLocation: { x: 25.457, y: 152.83, z: 83.54, o: 0.54 }, + moveToLocation: { x: 40.22, y: 159.23, z: 83.54 }, + despawnTime: 1200000 // 20 minutes + } + }, + [MapIds[MapNames.NEXUS]]: { + introAudio: "cold-hello", + outroAudio: "cold-goodbye", + teachYesAudio: "teach-cold-yes", + teachNoAudio: "teach-cold-no", + completionTime: 40, + spellId: Spells.SPELL_COLD_FUSION, + gossipOptions: { + knownSpell: "Why you staring at me like that, get lost.", + learnSpell: "Learn Cold Fusion (10,000g and Flask of Death)", + decline: "No thanks" + }, + audioOptions: { + volume: 0.7, + duration: 40 + }, + spawnConfig: { + bossId: 26794, // Ormorok The Tree Shaper + portalLocation: { x: 264.9, y: -255.4, z: -8.1, o: 5.89 }, + moveToLocation: { x: 283.5, y: -239, z: -8.25 }, + despawnTime: 1200000 // 20 minutes + } + } + // Add other maps for Shivey + }, + [NPCType.THORIN_FIREHAND]: { + [MapIds[MapNames.BLACKROCK_SPIRE_UPPER]]: { + introAudio: "rare-hello", + outroAudio: "rare-goodbye", + teachYesAudio: "teach-rare-yes", + teachNoAudio: "teach-rare-no", + completionTime: 36, + spellId: Spells.SPELL_ORE_FUSION, + gossipOptions: { + knownSpell: "...Leave me alone", + learnSpell: "Learn Ore Fusion (requires grandmaster)", + decline: "No thanks" + }, + audioOptions: { + volume: 1.0, + duration: 36 + }, + spawnConfig: { + bossId: 9938, // Magmus + portalLocation: { x: 1394.31, y: -703.50, z: -92.08, o: 1.08 }, + moveToLocation: { x: 1388.74, y: -692, z: -92.05 }, + despawnTime: 1200000 // 20 minutes + } + }, + [MapIds[MapNames.HALLS_OF_LIGHTNING]]: { + introAudio: "rare-lightning-hello", + outroAudio: "rare-lightning-goodbye", + teachYesAudio: "teach-rare-lightning-yes", + teachNoAudio: "teach-rare-lightning-no", + completionTime: 52, + spellId: Spells.SPELL_GEM_FUSION, + gossipOptions: { + knownSpell: "...Leave me alone", + learnSpell: "Learn Gem Fusion (requires grandmaster)", + decline: "No thanks" + }, + audioOptions: { + volume: 1.0, + duration: 52 + }, + spawnConfig: { + bossId: 28587, // Volkan + portalLocation: { x: 1331.91, y: -126.63, z: 56.71, o: 4.71 }, + moveToLocation: { x: 1331.91, y: -139.77, z: 53.27 }, + despawnTime: 1200000 // 20 minutes + } + } + // Add other maps for Shivey + }, + [NPCType.ELOWYN_THREADBINDER]: { + [MapIds[MapNames.STRATHOLME]]: { + introAudio: "rare-hello", + outroAudio: "rare-goodbye", + teachYesAudio: "teach-rare-yes", + teachNoAudio: "teach-rare-no", + completionTime: 31, + spellId: Spells.SPELL_CLOTH_FUSION, + gossipOptions: { + knownSpell: "Please leave me to mourn.", + learnSpell: "Learn Cloth Fusion (requires grandmaster)", + decline: "Another time" + }, + audioOptions: { + volume: 1.0, + duration: 31 + }, + spawnConfig: { + bossId: 10436, // Baroness Anastari + portalLocation: { x: 3866.14, y: -3702.15, z: 141.78, o: 2.12 }, + moveToLocation: { x: 3865.73, y: -3696.5, z: 141.90 }, + despawnTime: 1200000 // 20 minutes + } + } + // Add other maps for Shivey + }, + [NPCType.STEVE]: { + [MapIds[MapNames.UTGARDE_PINNACLE]]: { + introAudio: "rare-hello", + outroAudio: "rare-goodbye", + teachYesAudio: "teach-rare-yes", + teachNoAudio: "teach-rare-no", + completionTime: 65, + spellId: Spells.SPELL_ESSENCE_FUSION, + gossipOptions: { + knownSpell: "Queues are taking forever...", + learnSpell: "Learn Essence Fusion (requires grandmaster)", + decline: "Another time" + }, + audioOptions: { + volume: 0.8, + duration: 65 + }, + spawnConfig: { + bossId: 26687, // Gortok + portalLocation: { x: 314.63, y: -461.73, z: 104.71, o: 2.725 }, + moveToLocation: { x: 313.21, y: -452.52, z: 104.71 }, + despawnTime: 1200000 // 20 minutes + } + } + // Add other maps for Shivey + }, + // Add other NPCs +}; + +function getNPCMapConfig(npcType: NPCType, mapId: number): NPCMapConfig | undefined { + return NpcConfigMap[npcType]?.[mapId]; +} + +// Helper function to get NPC type from entry +function getNPCTypeFromEntry(entry: number): NPCType | undefined { + for (const [type, id] of Object.entries(NPCIds)) { + if (id === entry) { + return type as NPCType; + } + } + return undefined; +} + +const handleNPCAIUpdates: creature_event_on_aiupdate = (event: number, creature: Creature, diff: number): boolean => { const creatureGuid = creature.GetGUIDLow(); const instanceId = creature.GetInstanceId(); + const mapId = creature.GetMapId(); + const npcEntry = creature.GetEntry(); const state = npcState[`${instanceId}-${creatureGuid}`]; const previousTime = state.time || 0; + // Get NPC type and config + const npcType = getNPCTypeFromEntry(npcEntry); + if (!npcType) return true; + + const npcConfig = getNPCMapConfig(npcType, mapId); + if (!npcConfig) return true; + state.time = (previousTime + diff); const seconds = Math.ceil(state.time / 1000); - const npcEmoteMap = emotesMap[`${creature.GetEntry()}-${creature.GetMapId()}`]; + // Handle emotes based on the emote map for this NPC in this map + const npcEmoteMap = emotesMap[`${npcEntry}-${mapId}`]; if(npcEmoteMap && npcEmoteMap[seconds] && npcEmoteMap[seconds] !== state.lastEmote) { - - PrintDebug(`Mick player state: ${state.players.length}`); + PrintDebug(`Emote for ${npcEntry} at ${seconds} seconds`); creature.EmoteState(npcEmoteMap[seconds]); state.lastEmote = npcEmoteMap[seconds]; } - // Handle the AI Updates for Wailing Caverns - if(MapIds[MapNames.WAILING_CAVERNS] === creature.GetMapId()) { - if(seconds >= 43) { - ClearUniqueCreatureEvents(creature.GetGUID(), instanceId); - state.audioActive = false; - state.intro = true; - for(let i=0; i < state.players.length; i++) { - const playerId = state.players[i]; + // Check if the audio/dialog sequence has completed based on config + if(seconds >= npcConfig.completionTime) { + ClearUniqueCreatureEvents(creature.GetGUID(), instanceId); + state.audioActive = false; + state.intro = true; + + // Show gossip menu to all players who were in range when the NPC started talking + for(let i=0; i < state.players.length; i++) { + const playerId = state.players[i]; - if(!playerId) { - PrintError(`${creature.GetName()} gossip menu failed no valid player in state`); - continue; - } - const player = GetPlayerByName(playerId); - if(player) { - npcHello(player, creature, player.GetMapId()); - } + if(!playerId) { + PrintError(`${creature.GetName()} gossip menu failed no valid player in state`); + continue; + } + const player = GetPlayerByName(playerId); + if(player) { + npcHello(player, creature, player.GetMapId()); } - } } return true; } -/** - * the player will meet different characters at different times so the hello will check to see whch - * audio file and gossip menu needs to be shown. The list of locations an npc will show up is below - * - * Mick - * Rare Leather Fusion : Wailing Caverns Verdan the everliving - * Mythic Leather Fusion : Sartharion Obsidian Sanctum - * Rare Fire Fusion : Hellfire Ramparts Nazan + Vazruden - * Mythic Fire Fusion : Onyxia Lair Flamegor - * Casual Spawns : World ends Tavern Shatrath - * - * Thorin - * Rare Ore Fusion : BRD Magmus - * Mythic Ore Fusion : Ragnaros - * Casual Spawns : The Great Forge +const BossMapping: Record = { + [5775]: NPCType.MICK_ASHWILD, // Verdan the Everliving + [10508]: NPCType.SHIVEY, // Ras Frostwhisper + [9938]: NPCType.THORIN_FIREHAND, // Magmus + [10436]: NPCType.ELOWYN_THREADBINDER, // Baroness Anastari + [26687]: NPCType.STEVE, // Gortok + [28587]: NPCType.THORIN_FIREHAND, // Volkahn + [17536]: NPCType.MICK_ASHWILD, // Nazan + [26794]: NPCType.SHIVEY, // Ormorok The Tree Shaper +}; - * - */ +// Generic function for handling boss deaths and spawning NPCs +const handleBossDeath: creature_event_on_died = (event: number, creature: Creature, killer: Creature): boolean => { + const mapId = creature.GetMapId(); + const bossId = creature.GetEntry(); + const npcType = BossMapping[bossId]; -// When verdan dies Mike should show phase in from a portal -const verdanDied: creature_event_on_died = (event: number, creature: Creature, killer: Creature): boolean => { + if(!npcType) { + PrintError(`No NPC type found for boss ID ${bossId}`); + return false; + } + + const config = getNPCMapConfig(npcType, mapId); + if(!config) { + PrintError(`No NPC configured to spawn for boss ID ${bossId} on map ${mapId}`); + return false; + } + + // Spawn the blue portal + const startLoc = config.spawnConfig.portalLocation; + const endLoc = config.spawnConfig.moveToLocation; + const despawnTime = config.spawnConfig.despawnTime || 1200000; + + PrintDebug(`${creature.GetName()} died, spawning ${npcType}`); + + const portal = creature.SummonGameObject( + GobjectIds[GobjectType.PORTAL], + startLoc.x, startLoc.y, startLoc.z, startLoc.o + ); + + // Spawn the special NPC at the portal location + const npc = portal.SpawnCreature( + NPCIds[npcType], + startLoc.x, startLoc.y, startLoc.z, startLoc.o, + TempSummonType.TEMPSUMMON_TIMED_DESPAWN, despawnTime + ); + + if(!npc) { + PrintError(`Failed to spawn ${npcType} for boss ID ${bossId} on map ${mapId}`); + return false; + } + + // Make the NPC walk to the destination + npc.SetWalk(true); + npc.MoveTo(1, endLoc.x, endLoc.y, endLoc.z); - // Spawn the portal and Mick - creature.SummonGameObject(GobjectIds[GobjectType.PORTAL], -79.273, 4.999, -30.962, 2.20); - const mick = creature.SpawnCreature(NPCIds[NPCType.MICK_ASHWILD], -79.273, 4.999, -30.962, 2.20, TempSummonType.TEMPSUMMON_TIMED_DESPAWN, 1200000); - mick.SetWalk(true); - mick.MoveTo(1, -83.252, 19.723, -31.076); - return false; // return false to continue normal action }; -function npcHello(player: Player, creature: Creature, mapId: number, known?: boolean): void { - player.GossipClearMenu(); - PrintDebug("sending menu to player: " + player.GetName()); - - if(mapId === MapIds[MapNames.WAILING_CAVERNS]) { - if(known) { - player.GossipMenuAddItem(0, "Got nuthin' for ya friend.", 1, 999); - player.GossipSendMenu(1, creature, 90000); - return; +// Helper function to get all map configs for an NPC type +function getNPCMapConfigs(npcType: NPCType): Record { + const configs: Record> = { + [NPCType.MICK_ASHWILD]: { + [MapIds[MapNames.WAILING_CAVERNS]]: getNPCMapConfig(NPCType.MICK_ASHWILD, MapIds[MapNames.WAILING_CAVERNS])! + // Add other maps for Mick + }, + [NPCType.SHIVEY]: { + [MapIds[MapNames.SCHOLOMANCE]]: getNPCMapConfig(NPCType.SHIVEY, MapIds[MapNames.SCHOLOMANCE])! + // Add other maps for Shivey } - - player.GossipMenuAddItem(3, "Learn Leather Fusion (requires grandmaster)",1, Spells.SPELL_LEATHER_FUSION); - player.GossipMenuAddItem(0, "Best to come another time", 1, 999); - } - - player.GossipSendMenu(1, creature, 90000); + // Add other NPCs + }; + + return configs[npcType] || {}; } -const mickSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, selection: number): boolean => { +// Generic menu handler used by all special trainers +function npcHello(player: Player, creature: Creature, mapId: number, known?: boolean): void { + player.GossipClearMenu(); + + const npcEntry = creature.GetEntry(); + const npcType = getNPCTypeFromEntry(npcEntry); + if (!npcType) return; + + const npcConfig = getNPCMapConfig(npcType, mapId); + if (!npcConfig) return; + + if(known) { + player.GossipMenuAddItem(0, npcConfig.gossipOptions.knownSpell, 1, 999); + player.GossipSendMenu(1, creature, 90000); + return; + } + + if (npcConfig.spellId) { + player.GossipMenuAddItem(3, npcConfig.gossipOptions.learnSpell, 1, npcConfig.spellId); + } + player.GossipMenuAddItem(0, npcConfig.gossipOptions.decline, 1, 999); + player.GossipSendMenu(1, creature, 90000); + +} + +// This will handle the selection of the spell and granting the player the spell. +const handleNpcSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, selection: number): boolean => { const state = GetNPCState(creature); + const npcEntry = creature.GetEntry(); + const npcType = getNPCTypeFromEntry(npcEntry); + if (!npcType) return; + + const npcConfig = getNPCMapConfig(npcType, player.GetMapId()); + if (!npcConfig) return; PrintDebug(`Player ${player.GetName()} selected ${selection}`); // 999 is a signal nothing to do if(selection === 999) { - // play the outro audio for the player if they are done. - if(!state.outro[player.GetName()]) { - aio.Handle(player, 'AIOAudioPlayer', 'PlaySingleSound', getAudioFile(NPCType.MICK_ASHWILD, "rare-goodbye")); - state.outro[player.GetName()] = true; - } + // play the outro audio for the player if they have not heard it yet. + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.outroAudio), npcType); player.GossipClearMenu(); player.GossipComplete(); return true; @@ -302,25 +735,59 @@ const mickSelect: gossip_event_on_select = (event: number, player: Player, creat PrintError(`The selection ${selection} is not in the range of learnable spells check coding!!`); return true; } - PrintDebug(`Learning spell ${selection} for player ${player.GetName()}`); - PrintDebug(`Player skill ${player.GetSkillValue(165)}`); - switch(player.GetMapId()) { + const skillRequirements: Record = { + [Spells.SPELL_LEATHER_FUSION]: { skillId: 165, requiredLevel: 450 }, // Leatherworking + [Spells.SPELL_ORE_FUSION]: { skillId: 164, requiredLevel: 450 }, // Blacksmithing + [Spells.SPELL_CLOTH_FUSION]: { skillId: 197, requiredLevel: 450 }, // Tailoring + [Spells.SPELL_ALCHEMY_FUSION]: { skillId: 171, requiredLevel: 450 }, // Alchemy + [Spells.SPELL_GEM_FUSION]: { skillId: 755, requiredLevel: 450 }, // Jewelcrafting + [Spells.SPELL_ESSENCE_FUSION]: { skillId: 333, requiredLevel: 450 } // Enchanting + }; - case MapIds[MapNames.WAILING_CAVERNS]: - if(player.GetSkillValue(165) == 450) { // if they are a grandmaster leather worker. - player.LearnSpell(selection); - - PrintDebug(`Learning spell ${selection} for player ${player.GetName()}`); - PlayAudioOnce(player, getAudioFile(NPCType.MICK_ASHWILD, "teach-rare-yes")); - } else { - PrintDebug(`FAILING ${selection} for player ${player.GetName()}`); - PlayAudioOnce(player, getAudioFile(NPCType.MICK_ASHWILD, "teach-rare-no")); - } - break; - - default: - break; + // these are 10,000 a piece and a special item + const costRequirement: Record = { + [Spells.SPELL_FLAME_FUSION]: { cost: 10000*10000, itemId: 2595, itemQty: 1 }, // Jug of Badlands Bourbon + [Spells.SPELL_COLD_FUSION]: { cost: 10000*10000, itemId: 35716, itemQty: 1 }, // Flask of Pure Death + [Spells.SPELL_DARK_FUSION]: { cost: 10000*10000, itemId: 197, itemQty: 1 }, + [Spells.SPELL_ARCANE_FUSION]: { cost: 10000*10000, itemId: 171, itemQty: 1 }, + [Spells.SPELL_EARTH_FUSION]: { cost: 10000*10000, itemId: 755, itemQty: 1 }, + }; + + const requirement = skillRequirements[selection]; + const cost = costRequirement[selection]; + + if (requirement) { + const playerSkill = player.GetSkillValue(requirement.skillId); + PrintDebug(`Learning spell ${selection} for player ${player.GetName()}`); + PrintDebug(`Player skill ${playerSkill} for skill ID ${requirement.skillId}`); + + if (playerSkill >= requirement.requiredLevel) { + // Player has required skill level, teach the spell + player.LearnSpell(selection); + PrintDebug(`Learning spell ${selection} for player ${player.GetName()}`); + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.teachYesAudio || "teach-rare-yes"), npcType); + player.CastSpell(player, 40333); + } else { + // Player doesn't have required skill level + PrintDebug(`FAILING ${selection} for player ${player.GetName()}`); + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.teachNoAudio || "teach-rare-no"), npcType); + } + } else if(cost) { + const playerMoney = player.GetCoinage(); + const playerItem = player.GetItemCount(cost.itemId); + if(playerMoney >= cost.cost && playerItem >= cost.itemQty) { + player.SetCoinage(playerMoney - cost.cost); + player.RemoveItem(cost.itemId, cost.itemQty); + player.LearnSpell(selection); + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.teachYesAudio), npcType); + player.CastSpell(player, 40333); + } else { + PrintDebug(`FAILING ${selection} for player ${player.GetName()}`); + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.teachNoAudio), npcType); + } + } else { + PrintError(`No skill requirement defined for spell ${selection}`); } player.GossipComplete(); @@ -328,66 +795,107 @@ const mickSelect: gossip_event_on_select = (event: number, player: Player, creat } // Micks events -const mickHello: gossip_event_on_hello = (event: number, player: Player, creature: Creature): boolean => { - const zoneId = player.GetMapId(); +const handleNpcHello: gossip_event_on_hello = (event: number, player: Player, creature: Creature): boolean => { + const npcEntry = creature.GetEntry(); + const mapId = player.GetMapId(); const instanceId = player.GetInstanceId(); + const npcType = getNPCTypeFromEntry(npcEntry); + if (!npcType) { + return false; // Not one of our special NPCs + } + // Get the global creature state for special NPCs const myState = GetNPCState(creature); - - // if(isInMythicPlus(player.GetGUID(), instanceId)) { - if (MapIds[MapNames.WAILING_CAVERNS] === zoneId) { - - creature.SetFacingToObject(player); - - // Do play outro dialog if they already know the spell. - if(PlayerHasSpell(player)) { - npcHello(player, creature, zoneId, true); - if(!myState.outro[player.GetName()]) { - PlayAudioOnce(player, getAudioFile(NPCType.MICK_ASHWILD, "rare-goodbye")); - myState.outro[player.GetName()] = true; - } - return true; - } - - // Audio should play for all players in range when the NPC spawns.. - // however the menu will show up only to the player that clicked hello, - // or other players after the audio has played. - if (!myState.audioActive) { - - - const nearPlayers = creature.GetPlayersInRange(35); - for (let i = 0; i < nearPlayers.length; i++) { - myState.players.push(nearPlayers[i].GetName()); - PlayAudioOnce(player, getAudioFile(NPCType.MICK_ASHWILD, "rare-hello")); - } - - creature.EmoteState(EmoteType.ONESHOT_NONE); - myState.audioActive = true; - ClearUniqueCreatureEvents(creature.GetGUID(), instanceId, CreatureEvents.CREATURE_EVENT_ON_AIUPDATE); - RegisterUniqueCreatureEvent(creature.GetGUID(), instanceId, CreatureEvents.CREATURE_EVENT_ON_AIUPDATE, (...args) => handleMickAIUpdates(...args)); - } else { - myState.players.push(player.GetName()); // player wants to interact with the NPC - if(myState.players.length === 1 && myState.intro) { - npcHello(player, creature, player.GetMapId()); - } - } - + const npcConfig = getNPCMapConfig(npcType, mapId); + if (!npcConfig) { + return false; // NPC not configured for this map } + + creature.SetFacingToObject(player); + + // Check if player already knows the spell for this location + if (PlayerHasSpell(player)) { + npcHello(player, creature, mapId, true); + PlayAudioOnce(player, getAudioFile(npcType, npcConfig.outroAudio)); + return true; + } + + if (!myState.audioActive) { + // Get all nearby players + const nearPlayers = creature.GetPlayersInRange(35); + + for (let i = 0; i < nearPlayers.length; i++) { + const nearPlayer = nearPlayers[i]; + myState.players.push(nearPlayer.GetName()); + + // Play appropriate audio based on whether player knows the spell + if (PlayerHasSpell(nearPlayer)) { + // Player already knows the spell, play outro audio + PlayAudioOnce(nearPlayer, getAudioFile(npcType, npcConfig.outroAudio), npcType); + } else { + // Player doesn't know the spell, play intro audio + PlayAudioOnce(nearPlayer, getAudioFile(npcType, npcConfig.introAudio), npcType); + } + } + + creature.EmoteState(EmoteType.ONESHOT_NONE); + myState.audioActive = true; + ClearUniqueCreatureEvents(creature.GetGUID(), instanceId, CreatureEvents.CREATURE_EVENT_ON_AIUPDATE); + RegisterUniqueCreatureEvent(creature.GetGUID(), instanceId, CreatureEvents.CREATURE_EVENT_ON_AIUPDATE, + (...args) => handleNPCAIUpdates(...args)); + + + } else { + // NPC already active, just add this player if not already tracked + if (!myState.players.includes(player.GetName())) { + myState.players.push(player.GetName()); + } + + // If intro is complete, show appropriate gossip menu + if (myState.intro) { + npcHello(player, creature, mapId, PlayerHasSpell(player)); + } + } + return true; }; /**** Boss Kill Handlers ****/ -// Wailing Caverns - Verdan the Everliving is killed -RegisterCreatureEvent(5775, CreatureEvents.CREATURE_EVENT_ON_DIED, (...args) => verdanDied(...args)); +// Register boss death events based on NPC configurations +function registerBossDeathEvents() { + // Set to track which boss IDs we've already registered + const registeredBossIds = new Set(); -/**** NPC Gossip Events Handlers ****/ + // Loop through all NPCs and their map configs + for (const npcType in NpcConfigMap) { + const mapConfigs = NpcConfigMap[npcType]; -// Mick Ashwild -RegisterCreatureGossipEvent(NPCIds[NPCType.MICK_ASHWILD], GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => mickHello(...args)); -RegisterCreatureGossipEvent(NPCIds[NPCType.MICK_ASHWILD], GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => mickSelect(...args)); + // Check each map config for this NPC + for (const mapIdStr in mapConfigs) { + const config = mapConfigs[mapIdStr]; + + PrintDebug(`Registering boss death events for ${npcType} in map ${mapIdStr}`); + + // If this NPC has a spawn config with a boss ID + if (config.spawnConfig?.bossId) { + const bossId = config.spawnConfig.bossId; + + // Only register each boss ID once + if (!registeredBossIds.has(bossId)) { + RegisterCreatureEvent(bossId, CreatureEvents.CREATURE_EVENT_ON_DIED, (...args) => handleBossDeath(...args)); + PrintDebug(`Registered death event for boss ID ${bossId}`); + registeredBossIds.add(bossId); + } + } + } + } +} + +// Register all boss death events +registerBossDeathEvents(); /**** NPC Events Handlers ****/ @@ -403,15 +911,44 @@ function commonCreatureRegister(creature: Creature) { }; } -// Micks Events -RegisterCreatureEvent(NPCIds[NPCType.MICK_ASHWILD], CreatureEvents.CREATURE_EVENT_ON_SPAWN, (event: number, creature: Creature): boolean => { - commonCreatureRegister(creature); - return false; -}); -RegisterCreatureEvent(NPCIds[NPCType.MICK_ASHWILD], CreatureEvents.CREATURE_EVENT_ON_REMOVE, (event: number, creature: Creature): boolean => { - commonCreatureRegister(creature); - return false; -}); +// Register events only for specific, known NPCs +const validNPCs = [ + NPCType.MICK_ASHWILD, + NPCType.SHIVEY, + NPCType.THORIN_FIREHAND, + NPCType.ELOWYN_THREADBINDER, + NPCType.STEVE, + // Add other valid NPCs here as you implement them +]; + +for (let i = 0; i < validNPCs.length; i++) { + const npcType = validNPCs[i]; + const npcId = NPCIds[npcType]; + + if (npcId) { + // Register spawn event + RegisterCreatureEvent(npcId, CreatureEvents.CREATURE_EVENT_ON_SPAWN, (event: number, creature: Creature): boolean => { + PrintDebug(`NPC ${npcType} (ID: ${npcId}) spawned`); + commonCreatureRegister(creature); + return false; + }); + + // Register remove event + RegisterCreatureEvent(npcId, CreatureEvents.CREATURE_EVENT_ON_REMOVE, (event: number, creature: Creature): boolean => { + PrintDebug(`NPC ${npcType} (ID: ${npcId}) removed`); + commonCreatureRegister(creature); + return false; + }); + + // Register gossip events + RegisterCreatureGossipEvent(npcId, GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => handleNpcHello(...args)); + RegisterCreatureGossipEvent(npcId, GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => handleNpcSelect(...args)); + + PrintDebug(`Registered all events for NPC ${npcType} (ID: ${npcId})`); + } else { + PrintError(`Failed to register events for NPC ${npcType} - ID not found`); + } +} /**** Server events for state management around instances ****/ @@ -438,7 +975,197 @@ const resetPlayedAudioClose: eluna_event_on_lua_state_close = (event: number) => playedAudio = {}; } - // Register Server Event on Lua State Open RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN, (...args) => resetPlayedAudio(...args)); -RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_CLOSE, (...args) => resetPlayedAudioClose(...args)); \ No newline at end of file +RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_CLOSE, (...args) => resetPlayedAudioClose(...args)); + +// Lore Audio Player + +function showVaericGossip(player: Player, creature: Creature) { + player.GossipClearMenu(); + player.GossipMenuAddItem(0, "Tell me what has happened, again", 1,1); + player.GossipMenuAddItem(9, "Increase my strength and agility", 1,2); + player.GossipMenuAddItem(0, "Goodbye, Vaeric", 1,999); + player.GossipSendMenu(60566, creature, 90566); +} + +const vaericIntro: gossip_event_on_hello = (event: number, player: Player, creature: Creature): boolean => { + creature.SetFacingToObject(player); + + if(!GetTrigger(player.GetGUID(), "VAERIC_INTRO")) { + PlayAudioOnce(player, getAudioFile(NPCType.VAERIC, "lore-intro")); + SetTrigger({triggerName: "VAERIC_INTRO", characterGuid: player.GetGUID(), isSet: true}); + creature.EmoteState(EmoteType.ONESHOT_TALK); + } else { + PlayAudioOnce(player, getAudioFile(NPCType.VAERIC, "hello-1"), null, true); + } + + // player.RegisterEvent((delay: number, repeats: number, player: Player) => { + showVaericGossip(player, creature); + // }, 150); + + creature.RegisterEvent((delay: number, repeats: number, creature: Creature) => { + creature.EmoteState(EmoteType.ONESHOT_NONE); + }, 12000); + + return true; +}; + +const vaericSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, selection: number): boolean => { + + PrintInfo(`Vaeric select: ${selection} from sender ${sender}`); + + if(selection === 1) { + creature.EmoteState(EmoteType.ONESHOT_TALK); + PlayAudioOnce(player, getAudioFile(NPCType.VAERIC, "lore-intro"), undefined, true); + creature.RegisterEvent((delay: number, repeats: number, creature: Creature) => { + creature.EmoteState(EmoteType.ONESHOT_NONE); + }, 12000); + } else if(selection === 2) { + PlayAudioOnce(player, getAudioFile(NPCType.VAERIC, "stronger"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "Attack"); + } else if(selection === 999) { + PlayAudioOnce(player, getAudioFile(NPCType.VAERIC, "goodbye-1"), undefined, true); + player.GossipComplete(); + creature.EmoteState(EmoteType.ONESHOT_NONE); + return false; + } + + showVaericGossip(player, creature); + + return false; +}; + +RegisterCreatureGossipEvent(NPCIds[NPCType.VAERIC], GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => vaericIntro(...args)); +RegisterCreatureGossipEvent(NPCIds[NPCType.VAERIC], GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => vaericSelect(...args)); + + +// Agatha +function showAgathaGossip(player: Player, creature: Creature) { + player.GossipClearMenu(); + player.GossipMenuAddItem(0, "Who are you again?", 1,1); + player.GossipMenuAddItem(0, "Tell me about the relics.", 1,2); + player.GossipMenuAddItem(0, "How else can you assist me?", 1,3); + player.GossipMenuAddItem(0, "Why can't you erase Kel'Thuzad?", 1,4); + player.GossipMenuAddItem(3, "Improve my mind and spirit", 1,5); + player.GossipMenuAddItem(3, "Help me resist shadow energy", 1,6); + player.GossipMenuAddItem(0, "Goodbye, Agatha", 1,999); + player.GossipSendMenu(60567, creature, 90567); +} + +const agathaIntro: gossip_event_on_hello = (event: number, player: Player, creature: Creature): boolean => { + creature.SetFacingToObject(player); + + if(!GetTrigger(player.GetGUID(), "AGATHA_INTRO")) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "intro-lore")); + SetTrigger({triggerName: "AGATHA_INTRO", characterGuid: player.GetGUID(), isSet: true}); + } else { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "hello-1"), null, true); + } + + showAgathaGossip(player, creature); + + return true; +}; + +const agathaSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, selection: number): boolean => { + + PrintInfo(`Agatha select: ${selection} from sender ${sender}`); + + if(selection === 1) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "intro-lore"), undefined, true); + } else if(selection === 2) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "dice"), undefined, true); + } else if(selection === 3) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "meetings"), undefined, true); + } + else if(selection === 4) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "stop-asking"), undefined, true); + } else if(selection === 5) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "stronger"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "Magic"); + } else if(selection === 6) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "shadow"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "Shadow"); + } + + else if(selection === 999) { + PlayAudioOnce(player, getAudioFile(NPCType.AGATHA, "goodbye"), undefined, true); + player.GossipComplete(); + return false; + } + + showAgathaGossip(player, creature); + + return false; +}; + +RegisterCreatureGossipEvent(NPCIds[NPCType.AGATHA], GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => agathaIntro(...args)); +RegisterCreatureGossipEvent(NPCIds[NPCType.AGATHA], GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => agathaSelect(...args)); + +// Slyvia +function showSylviaGossip(player: Player, creature: Creature) { + player.GossipClearMenu(); + player.GossipMenuAddItem(0, "Who are you again?", 1,1); + player.GossipMenuAddItem(3, "Improve my stamina", 1,2); + player.GossipMenuAddItem(3, "Grant me resistance against the elements", 1,3); + player.GossipMenuAddItem(3, "Grant me resistance against arcane and poisons", 1,4); + player.GossipMenuAddItem(0, "Goodbye, ", 1,999); + player.GossipSendMenu(60568, creature, 90568); +} + +const sylviaIntro: gossip_event_on_hello = (event: number, player: Player, creature: Creature): boolean => { + + if(!creature || !player) { + AIO_debug("Sylvia intro: creature is null"); + return false; + } + + if(!GetTrigger(player.GetGUID(), "SYLVIA_INTRO")) { + creature.EmoteState(EmoteType.ONESHOT_TALK); + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "intro")); + SetTrigger({triggerName: "SYLVIA_INTRO", characterGuid: player.GetGUID(), isSet: true}); + creature.RegisterEvent((delay: number, repeats: number, creature: Creature) => { + creature.EmoteState(EmoteType.ONESHOT_NONE); + }, 10000); + } else { + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "hello"), null, true); + } + + showSylviaGossip(player, creature); + + return true; +}; + +const sylviaSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, selection: number): boolean => { + + if(selection === 1) { + creature.EmoteState(EmoteType.ONESHOT_TALK); + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "intro"), undefined, true); + creature.RegisterEvent((delay: number, repeats: number, creature: Creature) => { + creature.EmoteState(EmoteType.ONESHOT_NONE); + }, 10000); + } else if(selection === 2) { + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "stronger"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "Defense"); + } else if(selection === 3) { + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "fire-ice"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "FireFrost"); + } + else if(selection === 4) { + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "arcane-nature"), undefined, true); + aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", "NatureArcane"); + + } else if(selection === 999) { + PlayAudioOnce(player, getAudioFile(NPCType.SYLVIA, "goodbye"), undefined, true); + player.GossipComplete(); + return false; + } + + showSylviaGossip(player, creature); + + return false; +}; + +RegisterCreatureGossipEvent(NPCIds[NPCType.SYLVIA], GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => sylviaIntro(...args)); +RegisterCreatureGossipEvent(NPCIds[NPCType.SYLVIA], GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => sylviaSelect(...args)); \ No newline at end of file diff --git a/modules/UI/mythicplus/mythicplus.client.ts b/modules/UI/mythicplus/mythicplus.client.ts index 725a56e..804516b 100644 --- a/modules/UI/mythicplus/mythicplus.client.ts +++ b/modules/UI/mythicplus/mythicplus.client.ts @@ -1,463 +1,463 @@ -/** @ts-expect-error */ -let aio: AIO = {}; +// /** @ts-expect-error */ +// let aio: AIO = {}; -import { MythicPlusState } from "./mythicplus.state"; +// import { MythicPlusState } from "./mythicplus.state"; -if(!aio.AddAddon()) { +// if(!aio.AddAddon()) { -const mythicPlusHandlers = aio.AddHandlers('MythicPlus', {}); +// const mythicPlusHandlers = aio.AddHandlers('MythicPlus', {}); -const selectImages = [ - "Interface/Modules/MythicPlus/Textures/mythic", - "Interface/Modules/MythicPlus/Textures/mythic-selected", - "Interface/Modules/MythicPlus/Textures/legendary", - "Interface/Modules/MythicPlus/Textures/legendary-selected", - "Interface/Modules/MythicPlus/Textures/ascendant", - "Interface/Modules/MythicPlus/Textures/ascendant-selected" -]; +// const selectImages = [ +// "Interface/Modules/MythicPlus/Textures/mythic", +// "Interface/Modules/MythicPlus/Textures/mythic-selected", +// "Interface/Modules/MythicPlus/Textures/legendary", +// "Interface/Modules/MythicPlus/Textures/legendary-selected", +// "Interface/Modules/MythicPlus/Textures/ascendant", +// "Interface/Modules/MythicPlus/Textures/ascendant-selected" +// ]; -const Difficulty = { - Mythic: 2, - Legendary: 3, - Ascendant: 4 -}; +// const Difficulty = { +// Mythic: 2, +// Legendary: 3, +// Ascendant: 4 +// }; -const MPanelStyles = { - // Main Window Config - width: 538, - height: 466, +// const MPanelStyles = { +// // Main Window Config +// width: 538, +// height: 466, - // Skull Frame Config - skullAlpha: 0.65, - skullWidth: 180, - skullHeight: 180, - fontFace: "Fonts\\MORPHEUS.ttf", - fontSize: 16, +// // Skull Frame Config +// skullAlpha: 0.65, +// skullWidth: 180, +// skullHeight: 180, +// fontFace: "Fonts\\MORPHEUS.ttf", +// fontSize: 16, - // Text Panel Config for information text - infoWidth: 488, - infoHeight: 240, - infoFontFace: "Fonts\\FRIZQT__.ttf", - infoFontSize: 14 +// // Text Panel Config for information text +// infoWidth: 488, +// infoHeight: 240, +// infoFontFace: "Fonts\\FRIZQT__.ttf", +// infoFontSize: 14 -}; +// }; -const MPanelSounds = { - open: "GAMEDIALOGOPEN", - close: "GAMEDIALOGCLOSE", - select: "PVPTHROUGHQUEUE" -}; +// const MPanelSounds = { +// open: "GAMEDIALOGOPEN", +// close: "GAMEDIALOGCLOSE", +// select: "PVPTHROUGHQUEUE" +// }; -let MythicUIPanel: WoWAPI.Frame; -let MythicClientState: MythicPlusState = { - difficulty: 0, - groupId: -1, - groupLeader: -1, - inGroup: false, - isLeader: false, -}; +// let MythicUIPanel: WoWAPI.Frame; +// let MythicClientState: MythicPlusState = { +// difficulty: 0, +// groupId: -1, +// groupLeader: -1, +// inGroup: false, +// isLeader: false, +// }; -let Text = { - MYTHIC_TITLE: `MYTHIC DUNGEON`, - MYTHIC_DESC1: `Enemy Strength: x2`, - MYTHIC_DESC2: ` - Level: 83`, - MYTHIC_DESC3: `Potential Affixes: 0`, - MYTHIC_DESC4: `Party Deaths: |cff1eff00 Unlimited`, - MYTHIC_REWARD1: `Drops: |cff9F3FFF Epic up to 320`, - MYTHIC_REWARD2: `Bonus Stats: Mid Tier`, +// let Text = { +// MYTHIC_TITLE: `MYTHIC DUNGEON`, +// MYTHIC_DESC1: `Enemy Strength: x2`, +// MYTHIC_DESC2: ` - Level: 83`, +// MYTHIC_DESC3: `Potential Affixes: 0`, +// MYTHIC_DESC4: `Party Deaths: |cff1eff00 Unlimited`, +// MYTHIC_REWARD1: `Drops: |cff9F3FFF Epic up to 320`, +// MYTHIC_REWARD2: `Bonus Stats: Mid Tier`, - LEGENDARY_TITLE: `LEGENDARY DUNGEON`, - LEGENDARY_DESC1: `Enemy Strength: x3`, - LEGENDARY_DESC2: ` - Level: 85`, - LEGENDARY_DESC3: `Potential Affixes: 1`, - LEGENDARY_DESC4: `Party Deaths: |cff1eff00 Unlimited`, - LEGENDARY_REWARD1: `Drops: |cff9F3FFF Epic up to 340`, - LEGENDARY_REWARD2: `Bonus Stats: High Tier`, +// LEGENDARY_TITLE: `LEGENDARY DUNGEON`, +// LEGENDARY_DESC1: `Enemy Strength: x3`, +// LEGENDARY_DESC2: ` - Level: 85`, +// LEGENDARY_DESC3: `Potential Affixes: 1`, +// LEGENDARY_DESC4: `Party Deaths: |cff1eff00 Unlimited`, +// LEGENDARY_REWARD1: `Drops: |cff9F3FFF Epic up to 340`, +// LEGENDARY_REWARD2: `Bonus Stats: High Tier`, - ASCENDANT_TITLE: `ASCENDANT DUNGEON`, - ASCENDANT_DESC1: `Enemy Strength: x5`, - ASCENDANT_DESC2: ` - Level: 85 `, - ASCENDANT_DESC3: `Potential Affixes: 2`, - ASCENDANT_DESC4: `Party Deaths:|cffff0000 15 (Instance Reset at 0 lives)`, - ASCENDANT_REWARD1: `Drops:|cffFF8400 Legendary up to 360 `, - ASCENDANT_REWARD2: `Bonus Stats: Epic Tier`, +// ASCENDANT_TITLE: `ASCENDANT DUNGEON`, +// ASCENDANT_DESC1: `Enemy Strength: x5`, +// ASCENDANT_DESC2: ` - Level: 85 `, +// ASCENDANT_DESC3: `Potential Affixes: 2`, +// ASCENDANT_DESC4: `Party Deaths:|cffff0000 15 (Instance Reset at 0 lives)`, +// ASCENDANT_REWARD1: `Drops:|cffFF8400 Legendary up to 360 `, +// ASCENDANT_REWARD2: `Bonus Stats: Epic Tier`, - DEFAULT_DESC1: `Harder difficulty dungeon not set.`, - DEFAULT_DESC2: `Select a dungeon difficulty to view information.` -} +// DEFAULT_DESC1: `Harder difficulty dungeon not set.`, +// DEFAULT_DESC2: `Select a dungeon difficulty to view information.` +// } -// These are used to store the textures and fonts for the Mythic+ UI panel so they can -// be referenced in different functions -const MPTextures: Record = {}; -const MPFonts: Record = {}; +// // These are used to store the textures and fonts for the Mythic+ UI panel so they can +// // be referenced in different functions +// const MPTextures: Record = {}; +// const MPFonts: Record = {}; -function refreshUIState() { - updateInfoText(MythicClientState.difficulty); - updateSkulls(MythicClientState.difficulty); -} +// function refreshUIState() { +// updateInfoText(MythicClientState.difficulty); +// updateSkulls(MythicClientState.difficulty); +// } -// Updates the skull images based on the selected difficulty passed in -function updateSkulls(selected: number): void { - switch(selected) { - case Difficulty.Mythic: { - MPTextures[`SkullImg2`].SetTexture(selectImages[1]); - MPTextures[`SkullImg3`].SetTexture(selectImages[2]); - MPTextures[`SkullImg4`].SetTexture(selectImages[4]); - MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); - MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); - break; - } - case Difficulty.Legendary: { - MPTextures[`SkullImg2`].SetTexture(selectImages[0]); - MPTextures[`SkullImg3`].SetTexture(selectImages[3]); - MPTextures[`SkullImg4`].SetTexture(selectImages[4]); - MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); - MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); - _G[`SkullFrame${Difficulty.Legendary}`].SetPoint("LEFT", `SkullFrame${Difficulty.Mythic}`, "RIGHT", -10,2); - _G[`SkullFrame${Difficulty.Ascendant}`].SetPoint("LEFT", `SkullFrame${Difficulty.Legendary}`, "RIGHT", -10,-6); - break; - } - case Difficulty.Ascendant: { - MPTextures[`SkullImg2`].SetTexture(selectImages[0]); - MPTextures[`SkullImg3`].SetTexture(selectImages[2]); - MPTextures[`SkullImg4`].SetTexture(selectImages[5]); - MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); - MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); - _G[`SkullFrame${Difficulty.Legendary}`].SetPoint("LEFT", `SkullFrame${Difficulty.Mythic}`, "RIGHT", -10,-2); - _G[`SkullFrame${Difficulty.Ascendant}`].SetPoint("LEFT", `SkullFrame${Difficulty.Legendary}`, "RIGHT", -10,2); - break; - } +// // Updates the skull images based on the selected difficulty passed in +// function updateSkulls(selected: number): void { +// switch(selected) { +// case Difficulty.Mythic: { +// MPTextures[`SkullImg2`].SetTexture(selectImages[1]); +// MPTextures[`SkullImg3`].SetTexture(selectImages[2]); +// MPTextures[`SkullImg4`].SetTexture(selectImages[4]); +// MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); +// MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); +// break; +// } +// case Difficulty.Legendary: { +// MPTextures[`SkullImg2`].SetTexture(selectImages[0]); +// MPTextures[`SkullImg3`].SetTexture(selectImages[3]); +// MPTextures[`SkullImg4`].SetTexture(selectImages[4]); +// MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); +// MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); +// _G[`SkullFrame${Difficulty.Legendary}`].SetPoint("LEFT", `SkullFrame${Difficulty.Mythic}`, "RIGHT", -10,2); +// _G[`SkullFrame${Difficulty.Ascendant}`].SetPoint("LEFT", `SkullFrame${Difficulty.Legendary}`, "RIGHT", -10,-6); +// break; +// } +// case Difficulty.Ascendant: { +// MPTextures[`SkullImg2`].SetTexture(selectImages[0]); +// MPTextures[`SkullImg3`].SetTexture(selectImages[2]); +// MPTextures[`SkullImg4`].SetTexture(selectImages[5]); +// MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); +// MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); +// _G[`SkullFrame${Difficulty.Legendary}`].SetPoint("LEFT", `SkullFrame${Difficulty.Mythic}`, "RIGHT", -10,-2); +// _G[`SkullFrame${Difficulty.Ascendant}`].SetPoint("LEFT", `SkullFrame${Difficulty.Legendary}`, "RIGHT", -10,2); +// break; +// } - default: { - MPTextures[`SkullImg2`].SetTexture(selectImages[0]); - MPTextures[`SkullImg3`].SetTexture(selectImages[2]); - MPTextures[`SkullImg4`].SetTexture(selectImages[4]); - MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); - MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); - MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); - break; - } - } -} +// default: { +// MPTextures[`SkullImg2`].SetTexture(selectImages[0]); +// MPTextures[`SkullImg3`].SetTexture(selectImages[2]); +// MPTextures[`SkullImg4`].SetTexture(selectImages[4]); +// MPTextures[`SkullImg2`].SetAlpha(MPanelStyles.skullAlpha); +// MPTextures[`SkullImg3`].SetAlpha(MPanelStyles.skullAlpha); +// MPTextures[`SkullImg4`].SetAlpha(MPanelStyles.skullAlpha); +// break; +// } +// } +// } -// Updates the information text based on the selected difficulty passed in -function updateInfoText(difficulty: Difficulty) { - const titleFont = MPFonts[`InfoTitle`]; - const descFont1 = MPFonts[`InfoDesc1`]; - const descFont2 = MPFonts[`InfoDesc2`]; - const descFont3 = MPFonts[`InfoDesc3`]; - const descFont4 = MPFonts[`InfoDesc4`]; - const reward1 = MPFonts[`Reward1`]; - const reward2 = MPFonts[`Reward2`]; +// // Updates the information text based on the selected difficulty passed in +// function updateInfoText(difficulty: Difficulty) { +// const titleFont = MPFonts[`InfoTitle`]; +// const descFont1 = MPFonts[`InfoDesc1`]; +// const descFont2 = MPFonts[`InfoDesc2`]; +// const descFont3 = MPFonts[`InfoDesc3`]; +// const descFont4 = MPFonts[`InfoDesc4`]; +// const reward1 = MPFonts[`Reward1`]; +// const reward2 = MPFonts[`Reward2`]; - switch(difficulty) { - case Difficulty.Mythic: { - titleFont.SetText(Text.MYTHIC_TITLE); - descFont1.SetText(Text.MYTHIC_DESC1); - descFont2.SetText(Text.MYTHIC_DESC2); - descFont3.SetText(Text.MYTHIC_DESC3); - descFont4.SetText(Text.MYTHIC_DESC4); - reward1.SetText(Text.MYTHIC_REWARD1); - reward2.SetText(Text.MYTHIC_REWARD2); +// switch(difficulty) { +// case Difficulty.Mythic: { +// titleFont.SetText(Text.MYTHIC_TITLE); +// descFont1.SetText(Text.MYTHIC_DESC1); +// descFont2.SetText(Text.MYTHIC_DESC2); +// descFont3.SetText(Text.MYTHIC_DESC3); +// descFont4.SetText(Text.MYTHIC_DESC4); +// reward1.SetText(Text.MYTHIC_REWARD1); +// reward2.SetText(Text.MYTHIC_REWARD2); - break; - } - case Difficulty.Legendary: { - titleFont.SetText(Text.LEGENDARY_TITLE); - descFont1.SetText(Text.LEGENDARY_DESC1); - descFont2.SetText(Text.LEGENDARY_DESC2); - descFont3.SetText(Text.LEGENDARY_DESC3); - descFont4.SetText(Text.LEGENDARY_DESC4); - reward1.SetText(Text.LEGENDARY_REWARD1); - reward2.SetText(Text.LEGENDARY_REWARD2); +// break; +// } +// case Difficulty.Legendary: { +// titleFont.SetText(Text.LEGENDARY_TITLE); +// descFont1.SetText(Text.LEGENDARY_DESC1); +// descFont2.SetText(Text.LEGENDARY_DESC2); +// descFont3.SetText(Text.LEGENDARY_DESC3); +// descFont4.SetText(Text.LEGENDARY_DESC4); +// reward1.SetText(Text.LEGENDARY_REWARD1); +// reward2.SetText(Text.LEGENDARY_REWARD2); - break; - } - case Difficulty.Ascendant: { - titleFont.SetText(Text.ASCENDANT_TITLE); - descFont1.SetText(Text.ASCENDANT_DESC1); - descFont2.SetText(Text.ASCENDANT_DESC2); - descFont3.SetText(Text.ASCENDANT_DESC3); - descFont4.SetText(Text.ASCENDANT_DESC4); - reward1.SetText(Text.ASCENDANT_REWARD1); - reward2.SetText(Text.ASCENDANT_REWARD2); +// break; +// } +// case Difficulty.Ascendant: { +// titleFont.SetText(Text.ASCENDANT_TITLE); +// descFont1.SetText(Text.ASCENDANT_DESC1); +// descFont2.SetText(Text.ASCENDANT_DESC2); +// descFont3.SetText(Text.ASCENDANT_DESC3); +// descFont4.SetText(Text.ASCENDANT_DESC4); +// reward1.SetText(Text.ASCENDANT_REWARD1); +// reward2.SetText(Text.ASCENDANT_REWARD2); - break; - } +// break; +// } - default: { +// default: { - if(difficulty == 0) { - titleFont.SetText("NORMAL DUNGEON"); - } else { - titleFont.SetText("HEROIC DUNGEON"); - } +// if(difficulty == 0) { +// titleFont.SetText("NORMAL DUNGEON"); +// } else { +// titleFont.SetText("HEROIC DUNGEON"); +// } - descFont1.SetText(Text.DEFAULT_DESC1); - descFont2.SetText(""); - descFont3.SetText(Text.DEFAULT_DESC2); - descFont4.SetText(""); - reward1.SetText("None"); - reward2.SetText(""); - break; - } - } -} +// descFont1.SetText(Text.DEFAULT_DESC1); +// descFont2.SetText(""); +// descFont3.SetText(Text.DEFAULT_DESC2); +// descFont4.SetText(""); +// reward1.SetText("None"); +// reward2.SetText(""); +// break; +// } +// } +// } -// Creates the information text for the Mythic+ UI panel -function CreateInfoText(parent: WoWAPI.Frame, difficulty: Difficulty = null): void { +// // Creates the information text for the Mythic+ UI panel +// function CreateInfoText(parent: WoWAPI.Frame, difficulty: Difficulty = null): void { - const infoFrame = CreateFrame("Frame", `MPInfoFrame`, parent); - infoFrame.SetSize(MPanelStyles.infoWidth,MPanelStyles.infoHeight); - infoFrame.SetPoint("TOPLEFT", parent, "TOPLEFT", 10,-218); +// const infoFrame = CreateFrame("Frame", `MPInfoFrame`, parent); +// infoFrame.SetSize(MPanelStyles.infoWidth,MPanelStyles.infoHeight); +// infoFrame.SetPoint("TOPLEFT", parent, "TOPLEFT", 10,-218); - const bgTexture = infoFrame.CreateTexture("InfoFrameBG", "BACKGROUND"); - bgTexture.SetAllPoints(infoFrame); - bgTexture.SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-HEROIC") - infoFrame.Show(); +// const bgTexture = infoFrame.CreateTexture("InfoFrameBG", "BACKGROUND"); +// bgTexture.SetAllPoints(infoFrame); +// bgTexture.SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-HEROIC") +// infoFrame.Show(); - const titleFont = infoFrame.CreateFontString("InfoTitle", "OVERLAY", "QuestTitleFontBlackShadow"); - titleFont.SetPoint("TOPLEFT", infoFrame, "TOPLEFT", 16, -16); - MPFonts[`InfoTitle`] = titleFont; +// const titleFont = infoFrame.CreateFontString("InfoTitle", "OVERLAY", "QuestTitleFontBlackShadow"); +// titleFont.SetPoint("TOPLEFT", infoFrame, "TOPLEFT", 16, -16); +// MPFonts[`InfoTitle`] = titleFont; - const descFont1: WoWAPI.FontString = infoFrame.CreateFontString("InfoDesc1", "OVERLAY", "GameFontHighlight"); - descFont1.SetPoint("TOPLEFT", titleFont, "TOPLEFT", 0, -27); - MPFonts[`InfoDesc1`] = descFont1; +// const descFont1: WoWAPI.FontString = infoFrame.CreateFontString("InfoDesc1", "OVERLAY", "GameFontHighlight"); +// descFont1.SetPoint("TOPLEFT", titleFont, "TOPLEFT", 0, -27); +// MPFonts[`InfoDesc1`] = descFont1; - const descFont2 = infoFrame.CreateFontString("InfoDesc2", "OVERLAY", "GameFontHighlight"); - descFont2.SetPoint("LEFT", descFont1, "RIGHT", 0, 0); - descFont2.SetJustifyH("LEFT"); - MPFonts[`InfoDesc2`] = descFont2; +// const descFont2 = infoFrame.CreateFontString("InfoDesc2", "OVERLAY", "GameFontHighlight"); +// descFont2.SetPoint("LEFT", descFont1, "RIGHT", 0, 0); +// descFont2.SetJustifyH("LEFT"); +// MPFonts[`InfoDesc2`] = descFont2; - const descFont3 = infoFrame.CreateFontString("InfoDesc3", "OVERLAY", "GameFontHighlight"); - descFont3.SetPoint("TOPLEFT", descFont1, "TOPLEFT", 0, -18); - descFont3.SetJustifyH("LEFT"); - MPFonts[`InfoDesc3`] = descFont3; +// const descFont3 = infoFrame.CreateFontString("InfoDesc3", "OVERLAY", "GameFontHighlight"); +// descFont3.SetPoint("TOPLEFT", descFont1, "TOPLEFT", 0, -18); +// descFont3.SetJustifyH("LEFT"); +// MPFonts[`InfoDesc3`] = descFont3; - const descFont4 = infoFrame.CreateFontString("InfoDesc4", "OVERLAY", "GameFontHighlight"); - descFont4.SetPoint("TOPLEFT", descFont3, "TOPLEFT", 0, -18); - descFont4.SetJustifyH("LEFT"); - MPFonts[`InfoDesc4`] = descFont4; +// const descFont4 = infoFrame.CreateFontString("InfoDesc4", "OVERLAY", "GameFontHighlight"); +// descFont4.SetPoint("TOPLEFT", descFont3, "TOPLEFT", 0, -18); +// descFont4.SetJustifyH("LEFT"); +// MPFonts[`InfoDesc4`] = descFont4; - const rewardTitle = infoFrame.CreateFontString("InfoTitleReward", "OVERLAY", "QuestTitleFontBlackShadow"); - rewardTitle.SetPoint("TOPLEFT", descFont4, "TOPLEFT", 0, -30); - rewardTitle.SetText("REWARDS"); - MPFonts[`RewardTitle`] = rewardTitle; +// const rewardTitle = infoFrame.CreateFontString("InfoTitleReward", "OVERLAY", "QuestTitleFontBlackShadow"); +// rewardTitle.SetPoint("TOPLEFT", descFont4, "TOPLEFT", 0, -30); +// rewardTitle.SetText("REWARDS"); +// MPFonts[`RewardTitle`] = rewardTitle; - const reward1: WoWAPI.FontString = infoFrame.CreateFontString("Reward1", "OVERLAY", "GameFontHighlight"); - reward1.SetPoint("TOPLEFT", rewardTitle, "TOPLEFT", 0, -27); - MPFonts[`Reward1`] = reward1; +// const reward1: WoWAPI.FontString = infoFrame.CreateFontString("Reward1", "OVERLAY", "GameFontHighlight"); +// reward1.SetPoint("TOPLEFT", rewardTitle, "TOPLEFT", 0, -27); +// MPFonts[`Reward1`] = reward1; - const reward2 = infoFrame.CreateFontString("Reward2", "OVERLAY", "GameFontHighlight"); - reward2.SetPoint("TOPLEFT", reward1, "TOPLEFT", 0, -18); - reward2.SetJustifyH("LEFT"); - MPFonts[`Reward2`] = reward2; -} +// const reward2 = infoFrame.CreateFontString("Reward2", "OVERLAY", "GameFontHighlight"); +// reward2.SetPoint("TOPLEFT", reward1, "TOPLEFT", 0, -18); +// reward2.SetJustifyH("LEFT"); +// MPFonts[`Reward2`] = reward2; +// } -// Creates the skull frames UI elements and artwork for the Mythic+ UI panel -function CreateSkullFrame(difficulty: Difficulty, title: string, imageIndex: number): void { +// // Creates the skull frames UI elements and artwork for the Mythic+ UI panel +// function CreateSkullFrame(difficulty: Difficulty, title: string, imageIndex: number): void { - const parent = MythicUIPanel; - const MythicFrame = CreateFrame("Frame", `SkullFrame${difficulty}`, parent, null, difficulty); - MythicFrame.SetSize(MPanelStyles.skullWidth, MPanelStyles.skullHeight); +// const parent = MythicUIPanel; +// const MythicFrame = CreateFrame("Frame", `SkullFrame${difficulty}`, parent, null, difficulty); +// MythicFrame.SetSize(MPanelStyles.skullWidth, MPanelStyles.skullHeight); - if(imageIndex === 0) { - MythicFrame.SetPoint("TOPLEFT", 10, -29); - } else { - MythicFrame.SetPoint("LEFT", `SkullFrame${difficulty-1}`, "RIGHT", -10,-2); - MythicFrame.SetFrameLevel(difficulty); - } +// if(imageIndex === 0) { +// MythicFrame.SetPoint("TOPLEFT", 10, -29); +// } else { +// MythicFrame.SetPoint("LEFT", `SkullFrame${difficulty-1}`, "RIGHT", -10,-2); +// MythicFrame.SetFrameLevel(difficulty); +// } - MythicFrame.EnableMouse(true); - MythicFrame.SetScript("OnEnter", function(f: WoWAPI.Frame) { - const texture = MPTextures[`SkullImg${difficulty}`]; - texture.SetAlpha(1); - }); - MythicFrame.SetScript("OnLeave", function(f: WoWAPI.Frame) { - if(MythicClientState.difficulty == f.GetID()) { - return; - } - const texture = MPTextures[`SkullImg${difficulty}`]; - texture.SetAlpha(MPanelStyles.skullAlpha); - }); +// MythicFrame.EnableMouse(true); +// MythicFrame.SetScript("OnEnter", function(f: WoWAPI.Frame) { +// const texture = MPTextures[`SkullImg${difficulty}`]; +// texture.SetAlpha(1); +// }); +// MythicFrame.SetScript("OnLeave", function(f: WoWAPI.Frame) { +// if(MythicClientState.difficulty == f.GetID()) { +// return; +// } +// const texture = MPTextures[`SkullImg${difficulty}`]; +// texture.SetAlpha(MPanelStyles.skullAlpha); +// }); - MythicFrame.SetScript("OnMouseDown", function(f: WoWAPI.Frame, button: string) { - if(button != "LeftButton") { - return; - } +// MythicFrame.SetScript("OnMouseDown", function(f: WoWAPI.Frame, button: string) { +// if(button != "LeftButton") { +// return; +// } - PlaySound("PVPTHROUGHQUEUE"); +// PlaySound("PVPTHROUGHQUEUE"); - // if(MythicClientState.difficulty == f.GetID()) { - // MythicClientState.difficulty = GetDungeonDifficultyID() - 1; - // refreshUIState(); - // } else { - // MythicClientState.difficulty = f.GetID(); - // // always assume heoric for map setting for scaling under the hood. - // SetDungeonDifficulty(2); - // } +// // if(MythicClientState.difficulty == f.GetID()) { +// // MythicClientState.difficulty = GetDungeonDifficultyID() - 1; +// // refreshUIState(); +// // } else { +// // MythicClientState.difficulty = f.GetID(); +// // // always assume heoric for map setting for scaling under the hood. +// // SetDungeonDifficulty(2); +// // } - aio.Handle("MythicPlus", "SetDifficulty", MythicClientState.difficulty); - refreshUIState(); - }); +// aio.Handle("MythicPlus", "SetDifficulty", MythicClientState.difficulty); +// refreshUIState(); +// }); - const artTexture = MythicFrame.CreateTexture("MythicTexture", "ARTWORK"); - artTexture.SetAllPoints(MythicFrame); - artTexture.SetTexture(selectImages[imageIndex]); - artTexture.SetAlpha(0.80); - MPTextures[`SkullImg${difficulty}`] = artTexture; +// const artTexture = MythicFrame.CreateTexture("MythicTexture", "ARTWORK"); +// artTexture.SetAllPoints(MythicFrame); +// artTexture.SetTexture(selectImages[imageIndex]); +// artTexture.SetAlpha(0.80); +// MPTextures[`SkullImg${difficulty}`] = artTexture; - const titleFont = MythicFrame.CreateFontString("MythicText", "OVERLAY"); - titleFont.SetPoint("BOTTOM", MythicFrame, "BOTTOM", 0, 10); - titleFont.SetFont(MPanelStyles.fontFace, MPanelStyles.fontSize, "THICKOUTLINE"); - titleFont.SetText(title); -} +// const titleFont = MythicFrame.CreateFontString("MythicText", "OVERLAY"); +// titleFont.SetPoint("BOTTOM", MythicFrame, "BOTTOM", 0, 10); +// titleFont.SetFont(MPanelStyles.fontFace, MPanelStyles.fontSize, "THICKOUTLINE"); +// titleFont.SetText(title); +// } -// Main launch pad for the Mythic+ UI panel -function ShowUIPanel(): void { +// // Main launch pad for the Mythic+ UI panel +// function ShowUIPanel(): void { - if(MythicUIPanel) { - MythicUIPanel.Show(); - return; - } +// if(MythicUIPanel) { +// MythicUIPanel.Show(); +// return; +// } - const mainFrame = CreateFrame("Frame", "MythicPlusPanel", UIParent, "UIPanelDialogTemplate"); - mainFrame.SetSize(MPanelStyles.width,MPanelStyles.height); - mainFrame.SetPoint("TOPLEFT", UIParent, "LEFT", 17, 300); - mainFrame.SetBackdrop({ - bgFile: "Interface/DialogFrame/UI-DialogBox-Background-Dark", - edgeFile: "Interface/DialogFrame/UI-DialogBox-Border", - tile: true, - tileSize: 32, - edgeSize: 32, - insets: { - left: 11, - right: 12, - top: 12, - bottom: 11 - } - }); - mainFrame.EnableMouse(true); +// const mainFrame = CreateFrame("Frame", "MythicPlusPanel", UIParent, "UIPanelDialogTemplate"); +// mainFrame.SetSize(MPanelStyles.width,MPanelStyles.height); +// mainFrame.SetPoint("TOPLEFT", UIParent, "LEFT", 17, 300); +// mainFrame.SetBackdrop({ +// bgFile: "Interface/DialogFrame/UI-DialogBox-Background-Dark", +// edgeFile: "Interface/DialogFrame/UI-DialogBox-Border", +// tile: true, +// tileSize: 32, +// edgeSize: 32, +// insets: { +// left: 11, +// right: 12, +// top: 12, +// bottom: 11 +// } +// }); +// mainFrame.EnableMouse(true); - MythicUIPanel = mainFrame; +// MythicUIPanel = mainFrame; - // This is used to create an all black background for the Mythic+ UI panel - const bgTexture = mainFrame.CreateTexture("MythicBGTexture", "OVERLAY"); - bgTexture.SetAllPoints(mainFrame); - bgTexture.SetTexture("Interface\\Buttons\\WHITE8X8") - bgTexture.SetVertexColor(0.0, 0.0, 0.0, 0.8); - bgTexture.SetSize(MPanelStyles.width,MPanelStyles.height); +// // This is used to create an all black background for the Mythic+ UI panel +// const bgTexture = mainFrame.CreateTexture("MythicBGTexture", "OVERLAY"); +// bgTexture.SetAllPoints(mainFrame); +// bgTexture.SetTexture("Interface\\Buttons\\WHITE8X8") +// bgTexture.SetVertexColor(0.0, 0.0, 0.0, 0.8); +// bgTexture.SetSize(MPanelStyles.width,MPanelStyles.height); - // This creates all the skull selectors for the mythic board. - CreateSkullFrame(Difficulty.Mythic, "Mythic +", 0); - CreateSkullFrame(Difficulty.Legendary, "Legendary ++", 2); - CreateSkullFrame(Difficulty.Ascendant, "Ascendant +++", 4); +// // This creates all the skull selectors for the mythic board. +// CreateSkullFrame(Difficulty.Mythic, "Mythic +", 0); +// CreateSkullFrame(Difficulty.Legendary, "Legendary ++", 2); +// CreateSkullFrame(Difficulty.Ascendant, "Ascendant +++", 4); - // Create the info text frames (we could do this just swap the text but this will work easier for now. ) - CreateInfoText(mainFrame); +// // Create the info text frames (we could do this just swap the text but this will work easier for now. ) +// CreateInfoText(mainFrame); - mainFrame.Show(); -} +// mainFrame.Show(); +// } -mythicPlusHandlers.ShowUI = (state: MythicPlusState) : void => { - MythicClientState = state; - ShowUIPanel(); - refreshUIState(); -}; +// mythicPlusHandlers.ShowUI = (state: MythicPlusState) : void => { +// MythicClientState = state; +// ShowUIPanel(); +// refreshUIState(); +// }; -mythicPlusHandlers.UpdateState = (state: MythicPlusState) : void => { - MythicClientState = state; - refreshUIState(); -} +// mythicPlusHandlers.UpdateState = (state: MythicPlusState) : void => { +// MythicClientState = state; +// refreshUIState(); +// } -// Shows the button that opens the Mythic+ UI -function ShowUIButton(): void { - const button = CreateFrame("Button", "MythicPlusButton", UIParent); - button.SetSize(32, 32); - button.SetPoint("TOPRIGHT", -25, -225); - button.EnableMouse(true); - // button.SetBackdrop({ - // edgeFile: "Interface/DialogFrame/UI-DialogBox-Border", - // tile: true, - // tileSize: 32, - // edgeSize: 32, - // insets: { - // left: 11, - // right: 12, - // top: 12, - // bottom: 11 - // } - // }); - button.SetScript("OnClick", function(f: WoWAPI.Frame, button: string) { - if(button != "LeftButton") { - return; - } - PlaySound("GAMEDIALOGOPEN"); - aio.Handle("MythicPlus", "ShowUI"); - }); +// // Shows the button that opens the Mythic+ UI +// function ShowUIButton(): void { +// const button = CreateFrame("Button", "MythicPlusButton", UIParent); +// button.SetSize(32, 32); +// button.SetPoint("TOPRIGHT", -25, -225); +// button.EnableMouse(true); +// // button.SetBackdrop({ +// // edgeFile: "Interface/DialogFrame/UI-DialogBox-Border", +// // tile: true, +// // tileSize: 32, +// // edgeSize: 32, +// // insets: { +// // left: 11, +// // right: 12, +// // top: 12, +// // bottom: 11 +// // } +// // }); +// button.SetScript("OnClick", function(f: WoWAPI.Frame, button: string) { +// if(button != "LeftButton") { +// return; +// } +// PlaySound("GAMEDIALOGOPEN"); +// aio.Handle("MythicPlus", "ShowUI"); +// }); - const btnBg = button.CreateTexture("MythicPlusButtonBG", "BACKGROUND"); - btnBg.SetAllPoints(button); - btnBg.SetTexture("Interface\\Buttons\\WHITE8X8"); - btnBg.SetVertexColor(0, 0, 0, 1); +// const btnBg = button.CreateTexture("MythicPlusButtonBG", "BACKGROUND"); +// btnBg.SetAllPoints(button); +// btnBg.SetTexture("Interface\\Buttons\\WHITE8X8"); +// btnBg.SetVertexColor(0, 0, 0, 1); - const btnTexture = button.CreateTexture("MythicPlusButtonTexture", "ARTWORK"); - btnTexture.SetPoint("CENTER", 0, 0); - btnTexture.SetSize(32, 32); - btnTexture.SetTexture(selectImages[0]); +// const btnTexture = button.CreateTexture("MythicPlusButtonTexture", "ARTWORK"); +// btnTexture.SetPoint("CENTER", 0, 0); +// btnTexture.SetSize(32, 32); +// btnTexture.SetTexture(selectImages[0]); - // const btnTexture = button.CreateTexture("MythicPlusButtonTexture", "OVERLAY"); - // btnTexture.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Up"); - // btnTexture.SetPoint("CENTER", 0, 0); - // btnTexture.SetSize(32, 32); - // btnTexture.SetTexture(selectImages[0]); -} +// // const btnTexture = button.CreateTexture("MythicPlusButtonTexture", "OVERLAY"); +// // btnTexture.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Up"); +// // btnTexture.SetPoint("CENTER", 0, 0); +// // btnTexture.SetSize(32, 32); +// // btnTexture.SetTexture(selectImages[0]); +// } -ShowUIPanel(); -function AddMythicPlusMicroButton(): void { - // Attach to MicroButtonAndBagsBar or UIParent for visibility - const anchorButton = _G["HelpMicroButton"] ?? _G["SpellbookMicroButton"] ?? _G["MicroButtonAndBagsBar"] ?? UIParent; +// ShowUIPanel(); +// function AddMythicPlusMicroButton(): void { +// // Attach to MicroButtonAndBagsBar or UIParent for visibility +// const anchorButton = _G["HelpMicroButton"] ?? _G["SpellbookMicroButton"] ?? _G["MicroButtonAndBagsBar"] ?? UIParent; - // Create the button using Blizzard UI conventions with TypeScript syntax - const microButton: WoWAPI.Button = CreateFrame("Button", "MythicPlusMicroButton", _G["MicroButtonAndBagsBar"] ?? UIParent); - microButton.SetSize(25, 53); - microButton.SetPoint("LEFT", anchorButton, "RIGHT", 2, 0); - microButton.SetFrameLevel(anchorButton.GetFrameLevel() + 1); - microButton.SetFrameStrata("DIALOG"); - microButton.EnableMouse(true); - microButton.RegisterForClicks("LeftButtonUp", "RightButtonUp"); +// // Create the button using Blizzard UI conventions with TypeScript syntax +// const microButton: WoWAPI.Button = CreateFrame("Button", "MythicPlusMicroButton", _G["MicroButtonAndBagsBar"] ?? UIParent); +// microButton.SetSize(25, 53); +// microButton.SetPoint("LEFT", anchorButton, "RIGHT", 2, 0); +// microButton.SetFrameLevel(anchorButton.GetFrameLevel() + 1); +// microButton.SetFrameStrata("DIALOG"); +// microButton.EnableMouse(true); +// microButton.RegisterForClicks("LeftButtonUp", "RightButtonUp"); - // Set Blizzard-style micro button textures using TypeScript API - const normalTex = microButton.CreateTexture("MythicPlusNormalTex", "BACKGROUND"); - normalTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Up"); - normalTex.SetAllPoints(); - microButton.SetNormalTexture(normalTex); +// // Set Blizzard-style micro button textures using TypeScript API +// const normalTex = microButton.CreateTexture("MythicPlusNormalTex", "BACKGROUND"); +// normalTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Up"); +// normalTex.SetAllPoints(); +// microButton.SetNormalTexture(normalTex); - const highlightTex = microButton.CreateTexture("MythicPlusHighlightTex", "HIGHLIGHT"); - highlightTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Highlight"); - highlightTex.SetAllPoints(); - microButton.SetHighlightTexture(highlightTex); +// const highlightTex = microButton.CreateTexture("MythicPlusHighlightTex", "HIGHLIGHT"); +// highlightTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Highlight"); +// highlightTex.SetAllPoints(); +// microButton.SetHighlightTexture(highlightTex); - const pushedTex = microButton.CreateTexture("MythicPlusPushedTex", "ARTWORK"); - pushedTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Down"); - pushedTex.SetAllPoints(); - microButton.SetPushedTexture(pushedTex); +// const pushedTex = microButton.CreateTexture("MythicPlusPushedTex", "ARTWORK"); +// pushedTex.SetTexture("Interface\\Buttons\\UI-MicroButton-Socials-Down"); +// pushedTex.SetAllPoints(); +// microButton.SetPushedTexture(pushedTex); - microButton.SetScript("OnClick", (f: WoWAPI.Frame, button: string) => { - if(button !== "LeftButton") { - return; - } - PlaySound("GAMEDIALOGOPEN"); - aio.Handle("MythicPlus", "ShowUI"); - }); +// microButton.SetScript("OnClick", (f: WoWAPI.Frame, button: string) => { +// if(button !== "LeftButton") { +// return; +// } +// PlaySound("GAMEDIALOGOPEN"); +// aio.Handle("MythicPlus", "ShowUI"); +// }); - microButton.Show(); -} +// microButton.Show(); +// } -// Call this function to add the button to the Micro Menu on load - AddMythicPlusMicroButton(); -} +// // Call this function to add the button to the Micro Menu on load +// AddMythicPlusMicroButton(); +// } diff --git a/modules/UI/mythicplus/mythicplus.server.ts b/modules/UI/mythicplus/mythicplus.server.ts index 373d7a9..910936c 100644 --- a/modules/UI/mythicplus/mythicplus.server.ts +++ b/modules/UI/mythicplus/mythicplus.server.ts @@ -1,168 +1,168 @@ -/** @ts-expect-error */ -let aio: AIO = {}; +// /** @ts-expect-error */ +// let aio: AIO = {}; -import { Logger } from "../../classes/logger"; -import type { MythicPlusState } from "./mythicplus.state"; +// import { Logger } from "../../classes/logger"; +// import type { MythicPlusState } from "./mythicplus.state"; -const logger = new Logger("MythicPlusMod"); +// const logger = new Logger("MythicPlusMod"); -// PlayerGUID -> MythicPlusState -const StateStorage: Map = new Map(); +// // PlayerGUID -> MythicPlusState +// const StateStorage: Map = new Map(); -// This looks up the current group id for the player -1 indicates no group -function getPlayerGroupId(player: Player): number { - const result = CharDBQuery(`SELECT m.guid FROM acore_characters.characters c left join acore_characters.group_member m on c.guid = m.memberGuid where c.guid = ${player.GetGUID()}`); +// // This looks up the current group id for the player -1 indicates no group +// function getPlayerGroupId(player: Player): number { +// const result = CharDBQuery(`SELECT m.guid FROM acore_characters.characters c left join acore_characters.group_member m on c.guid = m.memberGuid where c.guid = ${player.GetGUID()}`); - if(!result) { - return -1; - } +// if(!result) { +// return -1; +// } - return result.GetUInt32(0); -} +// return result.GetUInt32(0); +// } -// Get the difficulty alread set for the player or group -function _getDifficulty(player: Player): number { - const difficulty = player.GetDifficulty(); - const groupId = getPlayerGroupId(player); +// // Get the difficulty alread set for the player or group +// function _getDifficulty(player: Player): number { +// const difficulty = player.GetDifficulty(); +// const groupId = getPlayerGroupId(player); - logger.debug(`MythicPlusMod: Getting difficulty for ${player.GetName()} with difficulty ${difficulty} and group ${groupId}`); +// logger.debug(`MythicPlusMod: Getting difficulty for ${player.GetName()} with difficulty ${difficulty} and group ${groupId}`); - if(groupId == -1) { - aio.Handle(player, "MythicPlus", "SetDifficulty", difficulty); - } +// if(groupId == -1) { +// aio.Handle(player, "MythicPlus", "SetDifficulty", difficulty); +// } - const result = CharDBQuery(`SELECT difficulty FROM group_difficulty WHERE guid = ${groupId}`); - if(result) { - logger.debug(`MythicPlusMod: Setting difficulty for ${player.GetName()} to ${result.GetUInt32(0)}`); - return result.GetUInt32(0); - } -} +// const result = CharDBQuery(`SELECT difficulty FROM group_difficulty WHERE guid = ${groupId}`); +// if(result) { +// logger.debug(`MythicPlusMod: Setting difficulty for ${player.GetName()} to ${result.GetUInt32(0)}`); +// return result.GetUInt32(0); +// } +// } -// Set the difficulty for the encounter -function _setDifficulty(player: Player, difficulty: number): void { - const groupId = getPlayerGroupId(player); - const group = player.GetGroup(); - if(groupId == -1) { - player.SendNotification('You must be in a group to set a mythic+ difficulty'); - return; - } - logger.debug(`Setting difficulty for ${player.GetName()} to ${difficulty}`); +// // Set the difficulty for the encounter +// function _setDifficulty(player: Player, difficulty: number): void { +// const groupId = getPlayerGroupId(player); +// const group = player.GetGroup(); +// if(groupId == -1) { +// player.SendNotification('You must be in a group to set a mythic+ difficulty'); +// return; +// } +// logger.debug(`Setting difficulty for ${player.GetName()} to ${difficulty}`); - if(! group.IsLeader(player.GetGUID())) { - return; - } +// if(! group.IsLeader(player.GetGUID())) { +// return; +// } - const map = player.GetMap(); - if(map.IsDungeon() != false) { - player.SendNotification('You can not change the difficulty in a dungeon'); - return; - } +// const map = player.GetMap(); +// if(map.IsDungeon() != false) { +// player.SendNotification('You can not change the difficulty in a dungeon'); +// return; +// } - // 0 is the lowest difficulty and 4 is the highest - if(difficulty > 4) { - logger.error(`Invalid difficulty set: ${difficulty}`); - } +// // 0 is the lowest difficulty and 4 is the highest +// if(difficulty > 4) { +// logger.error(`Invalid difficulty set: ${difficulty}`); +// } - if(difficulty == 0) { - CharDBExecute(`DELETE FROM group_difficulty WHERE guid = ${groupId}`); - return; - } +// if(difficulty == 0) { +// CharDBExecute(`DELETE FROM group_difficulty WHERE guid = ${groupId}`); +// return; +// } - CharDBExecute(`REPLACE INTO group_difficulty (guid, difficulty) VALUES (${groupId}, ${difficulty})`); -} +// CharDBExecute(`REPLACE INTO group_difficulty (guid, difficulty) VALUES (${groupId}, ${difficulty})`); +// } -function SetDifficulty(this:void, player: Player, difficulty: number): void { - _setDifficulty(player, difficulty); - aio.Handle(player, 'MythicPlus', 'UpdateState', StateStorage.get(player.GetGUIDLow())); -} +// function SetDifficulty(this:void, player: Player, difficulty: number): void { +// _setDifficulty(player, difficulty); +// aio.Handle(player, 'MythicPlus', 'UpdateState', StateStorage.get(player.GetGUIDLow())); +// } -// This is used to -function _refreshState(player: Player) { - if(player.IsInGroup()) { - const groupId = getPlayerGroupId(player); - const groupLeader = player.GetGroup().GetLeaderGUID(); - const isLeader = player.GetGUID() == groupLeader; - const difficulty = _getDifficulty(player); - StateStorage.set(player.GetGUIDLow(), {difficulty, inGroup: true, groupId, groupLeader, isLeader}); - return; - } else { - StateStorage.set(player.GetGUIDLow(), {difficulty: _getDifficulty(player), inGroup: false, groupId: -1, groupLeader: -1, isLeader: false}); - } -} - -// Update the state from what is on the server and send it back to the client. -function GetState(this:void, player: Player): void { - _refreshState(player); - const state = StateStorage.get(player.GetGUIDLow()); - aio.Handle(player, 'MythicPlus', 'UpdateState', state); -} - -// This is the command to open the mythic plus panel -const OpenUI: player_event_on_command = (event: number,player: Player, command: string): boolean => { - if(command == 'mythicplus') { - const state = StateStorage.get(player.GetGUIDLow()); - logger.debug(`OpenUI command - player: ${player.GetName()}, - difficulty ${state.difficulty}, - groupId: ${state.groupId}, - groupLeader: ${state.groupLeader}, - isLeader: ${state.isLeader}` - ); - aio.Handle(player, 'MythicPlus', 'ShowUI', StateStorage.get(player.GetGUIDLow())); - return false; - } - return true; -}; - -// This enables the client to fire a request to open the mythic plus panel after updating state -function ShowUI(this:void, player: Player): void { - _refreshState(player); - aio.Handle(player, 'MythicPlus', 'ShowUI', StateStorage.get(player.GetGUIDLow())); -} - -RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => OpenUI(...args)); - -const MPStartState: player_event_on_login = (_event: number, player: Player): void => { - _refreshState(player); - aio.Handle(player, 'MythicPlus', 'UpdateState', StateStorage.get(player.GetGUIDLow())); -}; - -// On login set up the mythic panel mod state for the player -RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => MPStartState(...args)); - -// const MPGroupDisband: group_event_on_disband = (_event: number, group: Group): void => { -// const members = group.GetMembers(); - -// for(let i = 0; i < members.length; i++) { -// _refreshState(members[i]); -// aio.Handle(members[i], 'MythicPlus', 'UpdateState', StateStorage.get(members[i].GetGUIDLow())); +// // This is used to +// function _refreshState(player: Player) { +// if(player.IsInGroup()) { +// const groupId = getPlayerGroupId(player); +// const groupLeader = player.GetGroup().GetLeaderGUID(); +// const isLeader = player.GetGUID() == groupLeader; +// const difficulty = _getDifficulty(player); +// StateStorage.set(player.GetGUIDLow(), {difficulty, inGroup: true, groupId, groupLeader, isLeader}); +// return; +// } else { +// StateStorage.set(player.GetGUIDLow(), {difficulty: _getDifficulty(player), inGroup: false, groupId: -1, groupLeader: -1, isLeader: false}); // } // } -// RegisterGroupEvent(GroupEvents.GROUP_EVENT_ON_DISBAND, (...args) => MPGroupDisband(...args)); - -// When a leader change happens need to update the state storage for each leader to enable changes in the panel. -// const MPLeaderChange: group_event_on_leader_change = (_event: number,group: Group, leader: number, oldLeader: number): void => { -// _refreshState(GetPlayerByGUID(leader)); -// aio.Handle(GetPlayerByGUID(leader), 'MythicPlus', 'UpdateState', StateStorage.get(leader)); - -// _refreshState(GetPlayerByGUID(oldLeader)); -// aio.Handle(GetPlayerByGUID(oldLeader), 'MythicPlus', 'UpdateState', StateStorage.get(oldLeader)); +// // Update the state from what is on the server and send it back to the client. +// function GetState(this:void, player: Player): void { +// _refreshState(player); +// const state = StateStorage.get(player.GetGUIDLow()); +// aio.Handle(player, 'MythicPlus', 'UpdateState', state); // } -// RegisterGroupEvent(GroupEvents.GROUP_EVENT_ON_LEADER_CHANGE, (...args) => MPLeaderChange(...args)); +// // This is the command to open the mythic plus panel +// const OpenUI: player_event_on_command = (event: number,player: Player, command: string): boolean => { +// if(command == 'mythicplus') { +// const state = StateStorage.get(player.GetGUIDLow()); +// logger.debug(`OpenUI command +// player: ${player.GetName()}, +// difficulty ${state.difficulty}, +// groupId: ${state.groupId}, +// groupLeader: ${state.groupLeader}, +// isLeader: ${state.isLeader}` +// ); +// aio.Handle(player, 'MythicPlus', 'ShowUI', StateStorage.get(player.GetGUIDLow())); +// return false; +// } +// return true; +// }; + +// // This enables the client to fire a request to open the mythic plus panel after updating state +// function ShowUI(this:void, player: Player): void { +// _refreshState(player); +// aio.Handle(player, 'MythicPlus', 'ShowUI', StateStorage.get(player.GetGUIDLow())); +// } + +// RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => OpenUI(...args)); + +// const MPStartState: player_event_on_login = (_event: number, player: Player): void => { +// _refreshState(player); +// aio.Handle(player, 'MythicPlus', 'UpdateState', StateStorage.get(player.GetGUIDLow())); +// }; + +// // On login set up the mythic panel mod state for the player +// RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => MPStartState(...args)); + +// // const MPGroupDisband: group_event_on_disband = (_event: number, group: Group): void => { +// // const members = group.GetMembers(); + +// // for(let i = 0; i < members.length; i++) { +// // _refreshState(members[i]); +// // aio.Handle(members[i], 'MythicPlus', 'UpdateState', StateStorage.get(members[i].GetGUIDLow())); +// // } +// // } + +// // RegisterGroupEvent(GroupEvents.GROUP_EVENT_ON_DISBAND, (...args) => MPGroupDisband(...args)); + +// // When a leader change happens need to update the state storage for each leader to enable changes in the panel. +// // const MPLeaderChange: group_event_on_leader_change = (_event: number,group: Group, leader: number, oldLeader: number): void => { +// // _refreshState(GetPlayerByGUID(leader)); +// // aio.Handle(GetPlayerByGUID(leader), 'MythicPlus', 'UpdateState', StateStorage.get(leader)); + +// // _refreshState(GetPlayerByGUID(oldLeader)); +// // aio.Handle(GetPlayerByGUID(oldLeader), 'MythicPlus', 'UpdateState', StateStorage.get(oldLeader)); +// // } + +// // RegisterGroupEvent(GroupEvents.GROUP_EVENT_ON_LEADER_CHANGE, (...args) => MPLeaderChange(...args)); -const DeletePlayerState: player_event_on_logout = (event: number, player: Player) => { - StateStorage.delete(player.GetGUIDLow()); -}; +// const DeletePlayerState: player_event_on_logout = (event: number, player: Player) => { +// StateStorage.delete(player.GetGUIDLow()); +// }; -RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGOUT, (...args) => DeletePlayerState(...args)); +// RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGOUT, (...args) => DeletePlayerState(...args)); -// API Handlers available to the client -const MPHandlers = aio.AddHandlers("MythicPlus", { - ShowUI, - SetDifficulty, - GetState, -}); \ No newline at end of file +// // API Handlers available to the client +// const MPHandlers = aio.AddHandlers("MythicPlus", { +// ShowUI, +// SetDifficulty, +// GetState, +// }); \ No newline at end of file