mirror of
https://github.com/araxiaonline/ets-module-collection.git
synced 2026-06-13 02:52:20 -04:00
Added advancement + dungeon looting
This commit is contained in:
934
modules/UI/mythicplus/advance.client.ts
Normal file
934
modules/UI/mythicplus/advance.client.ts
Normal file
@@ -0,0 +1,934 @@
|
||||
/** @noSelfInFile **/
|
||||
/** @ts-expect-error */
|
||||
let aio: AIO = {};
|
||||
|
||||
/**
|
||||
* 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_lichs_bane_aura'),
|
||||
* ('80000010','spell_mp_glacial_fortress_aura');
|
||||
*/
|
||||
import { AdvanceState, PlayerAdvancement, AdvancementType } from "./advstate";
|
||||
import { CreateItemButton, EscapeCloseable, MakeDraggable } from "../../classes/ui-utils";
|
||||
import { rollDice } from "../../classes/server-utils";
|
||||
|
||||
|
||||
if (!aio.AddAddon()) {
|
||||
|
||||
// Frame Map of all frames being used.
|
||||
const UpgradeUIFrames: Map<string, WoWAPI.Frame> = new Map();
|
||||
|
||||
// Handler Map for all event Handlers from server
|
||||
const AdvanceUIHandlers = aio.AddHandlers('MythicAdvUI', {});
|
||||
|
||||
// Application State
|
||||
const advancementState = new AdvanceState();
|
||||
|
||||
const id = (name: string) => {
|
||||
const advType = advancementState.GetAdvType();
|
||||
if(!advType) {
|
||||
return `MythicAdvUI_${name}`;
|
||||
}
|
||||
return `MythicAdvUI_${name}_${advType}`;
|
||||
};
|
||||
|
||||
function GetComponent<T extends WoWAPI.Frame = WoWAPI.Frame>(name: string, type: string = "Frame"): T | null {
|
||||
const component = _G[id(name)];
|
||||
return component ? component as T : null;
|
||||
}
|
||||
|
||||
function GetAnyComponent<T>(name: string): T | null {
|
||||
const component = _G[id(name)];
|
||||
return component ? component as T : null;
|
||||
}
|
||||
|
||||
|
||||
// UI Configuration Settings
|
||||
const mainWidth = 768;
|
||||
const mainHeight = 512;
|
||||
const centerOffset = mainWidth / 2;
|
||||
|
||||
function SendServerEvent(method: string, args: any[]): void {
|
||||
|
||||
const playerGuid = advancementState.GetPlayerGuid();
|
||||
|
||||
let message = "";
|
||||
message += `p|${playerGuid}|`;
|
||||
message += `${method}|`;
|
||||
|
||||
for(let i = 0; i < args.length; i++) {
|
||||
message += `${args[i]}|`;
|
||||
}
|
||||
// remove last pipe
|
||||
message = message.slice(0, -1);
|
||||
|
||||
SendAddonMessage("MPUi", message, "WHISPER", GetUnitName("player", false));
|
||||
}
|
||||
|
||||
|
||||
const customTextures = {
|
||||
// frame background elements
|
||||
"bgFrame": "Interface\\Modules\\MythicPlus\\Textures\\mythic-adv-frame",
|
||||
"bgFrameHq": "Interface\\Modules\\MythicPlus\\Textures\\mythic-adv-frame-hq",
|
||||
"darkBg": "Interface\\Modules\\MythicPlus\\Textures\\DialogBox-Background-Dark",
|
||||
"diceFrame": "Interface\\Modules\\MythicPlus\\Textures\\advancement_frame",
|
||||
|
||||
// advancement icons buttons
|
||||
"str": "Interface\\Modules\\MythicPlus\\Textures\\str_adv.tga",
|
||||
"agi": "Interface\\Modules\\MythicPlus\\Textures\\agi_adv.tga",
|
||||
"int": "Interface\\Modules\\MythicPlus\\Textures\\int_adv.tga",
|
||||
"spr": "Interface\\Modules\\MythicPlus\\Textures\\spr_adv.tga",
|
||||
"sta": "Interface\\Modules\\MythicPlus\\Textures\\sta_adv.tga",
|
||||
"fire": "Interface\\Modules\\MythicPlus\\Textures\\fire_adv.tga",
|
||||
"frost": "Interface\\Modules\\MythicPlus\\Textures\\frost_adv.tga",
|
||||
"nature": "Interface\\Modules\\MythicPlus\\Textures\\nature_adv.tga",
|
||||
"arcane": "Interface\\Modules\\MythicPlus\\Textures\\arcane_adv.tga",
|
||||
"shadow": "Interface\\Modules\\MythicPlus\\Textures\\shadow_adv.tga",
|
||||
"icon_overlay": "Interface\\Modules\\MythicPlus\\Textures\\icon_overlay.tga",
|
||||
"int_selected": "Interface\\Modules\\MythicPlus\\Textures\\int_adv_selected.tga",
|
||||
"spr_selected": "Interface\\Modules\\MythicPlus\\Textures\\spr_adv_selected.tga",
|
||||
"sta_selected": "Interface\\Modules\\MythicPlus\\Textures\\sta_adv_selected.tga",
|
||||
"str_selected": "Interface\\Modules\\MythicPlus\\Textures\\str_adv_selected.tga",
|
||||
"agi_selected": "Interface\\Modules\\MythicPlus\\Textures\\agi_adv_selected.tga",
|
||||
"fire_selected": "Interface\\Modules\\MythicPlus\\Textures\\fire_adv_selected.tga",
|
||||
"frost_selected": "Interface\\Modules\\MythicPlus\\Textures\\frost_adv_selected.tga",
|
||||
"nature_selected": "Interface\\Modules\\MythicPlus\\Textures\\nature_adv_selected.tga",
|
||||
"arcane_selected": "Interface\\Modules\\MythicPlus\\Textures\\arcane_adv_selected.tga",
|
||||
"shadow_selected": "Interface\\Modules\\MythicPlus\\Textures\\shadow_adv_selected.tga",
|
||||
|
||||
|
||||
// Dice buttons
|
||||
"single_roll": "Interface\\Modules\\MythicPlus\\Textures\\single_roll.tga",
|
||||
"double_roll": "Interface\\Modules\\MythicPlus\\Textures\\double_roll.tga",
|
||||
"triple_roll": "Interface\\Modules\\MythicPlus\\Textures\\triple_roll.tga",
|
||||
"single_roll_selected": "Interface\\Modules\\MythicPlus\\Textures\\single_roll_selected.tga",
|
||||
"double_roll_selected": "Interface\\Modules\\MythicPlus\\Textures\\double_roll_selected.tga",
|
||||
"triple_roll_selected": "Interface\\Modules\\MythicPlus\\Textures\\triple_roll_selected.tga",
|
||||
|
||||
// Advancement Bars
|
||||
"bars": "Interface\\Modules\\MythicPlus\\Textures\\adv_bars.tga",
|
||||
|
||||
// Roll Numbers
|
||||
"numbers": "Interface\\Modules\\MythicPlus\\Textures\\big_numbers.tga",
|
||||
|
||||
// Buttons
|
||||
"close_button": "Interface\\Buttons\\UI-Panel-MinimizeButton-Up",
|
||||
"close_button_hl": "Interface\\Buttons\\UI-Panel-MinimizeButton-Highlight",
|
||||
"close_button_pushed": "Interface\\Buttons\\UI-Panel-MinimizeButton-Down"
|
||||
}
|
||||
|
||||
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<WoWAPI.Button>(`${name}_button`, "Button");
|
||||
if (button) {
|
||||
if (show) {
|
||||
button.SetAlpha(0.8);
|
||||
button.Enable();
|
||||
} else {
|
||||
button.SetAlpha(0.0);
|
||||
button.Disable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function UpdateCostVisibility(show: boolean): void {
|
||||
const costFrame = GetComponent<WoWAPI.Frame>("cost_frame", "Frame");
|
||||
if(costFrame) {
|
||||
costFrame.SetAlpha(show ? 1.0 : 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
function SelectAdvancement(name: string, button: WoWAPI.Button): void {
|
||||
|
||||
// if the button click is itself, reset it
|
||||
if (advancementState.GetAdvancement() === name) {
|
||||
AIO_debug("Resetting advancement");
|
||||
|
||||
button.SetNormalTexture(GetTexture(name));
|
||||
advancementState.SetAdvancement(null);
|
||||
UpdateDiceVisibility(false);
|
||||
UpdateCostVisibility(false);
|
||||
} else {
|
||||
// Set the new advancement
|
||||
button.SetNormalTexture(GetTexture(`${name}_selected`));
|
||||
|
||||
// Handle opposing button
|
||||
const opposingStats = {
|
||||
'int': 'spr',
|
||||
'spr': 'int',
|
||||
'str': 'agi',
|
||||
'agi': 'str',
|
||||
'fire': 'frost',
|
||||
'frost': 'fire',
|
||||
'nature': 'arcane',
|
||||
'arcane': 'nature',
|
||||
};
|
||||
|
||||
const opposingStat = opposingStats[name];
|
||||
if (opposingStat) {
|
||||
const opposingButton = GetComponent<WoWAPI.Button>(`${opposingStat}_button`, "Button");
|
||||
if (opposingButton) {
|
||||
opposingButton.SetNormalTexture(GetTexture(opposingStat));
|
||||
}
|
||||
}
|
||||
// Update advancement state and show dice buttons
|
||||
advancementState.SetAdvancement(name);
|
||||
aio.Handle("MythicAdvUI", "GetNextLevelCost", advancementState.GetAdvancementId());
|
||||
|
||||
UpdateCostVisibility(true);
|
||||
UpdateDiceVisibility(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Advancement bar creation and update logic
|
||||
function CreateAdvColorBar(frame: WoWAPI.Frame, goldBar: WoWAPI.Texture, uniqId: string ): void {
|
||||
let bar = GetAnyComponent<WoWAPI.Texture>(`adv_bar_${uniqId}`);
|
||||
if(!bar) {
|
||||
bar = frame.CreateTexture(id(`adv_bar_${uniqId}`), "ARTWORK");
|
||||
bar.SetPoint("LEFT", goldBar, "LEFT", 27, 0);
|
||||
bar.SetSize(1, 25); // Default/empty
|
||||
bar.SetTexture(GetTexture("bars"));
|
||||
bar.SetTexCoord(58/256, 142/256, 85/256, 101/256); // Default lowest bar
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateAdvColorBar(uniqId: string, rank: number): void {
|
||||
let percent = rank / 50;
|
||||
let coords: number[];
|
||||
if(percent >= 0.67) {
|
||||
coords = [58/256, 142/256, 42/256, 61/256]; // green
|
||||
} else if(percent >= 0.33 && percent < 0.67) {
|
||||
coords = [58/256, 142/256, 64/256, 81/256]; // yellow
|
||||
} else {
|
||||
coords = [58/256, 142/256, 85/256, 101/256]; // red
|
||||
}
|
||||
let width = Math.round(167 * percent);
|
||||
if(width === 0) width = 1;
|
||||
|
||||
let bar = GetAnyComponent<WoWAPI.Texture>(`adv_bar_${uniqId}`);
|
||||
if(bar) {
|
||||
bar.SetSize(width, 25);
|
||||
bar.SetTexCoord(coords[0], coords[1], coords[2], coords[3]);
|
||||
} else {
|
||||
AIO_debug(`Could not find bar ${uniqId}`);
|
||||
}
|
||||
}
|
||||
// This will create the advancement color bars that show player progress
|
||||
|
||||
|
||||
// /**
|
||||
// * 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 = "int";
|
||||
bottomIcon = "spr";
|
||||
topText = "Forbidden Knowledge";
|
||||
bottomText = "Celestial Grace";
|
||||
|
||||
}
|
||||
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"
|
||||
}
|
||||
else if (advancementState.GetAdvType() === "FireFrost") {
|
||||
topIcon = "fire";
|
||||
bottomIcon = "frost";
|
||||
topText = "Hellfire Shielding";
|
||||
bottomText = "Glacial Fortress";
|
||||
}
|
||||
else if (advancementState.GetAdvType() === "NatureArcane") {
|
||||
topIcon = "nature";
|
||||
bottomIcon = "arcane";
|
||||
topText = "Primal Endurance";
|
||||
bottomText = "Eldritch Barrier";
|
||||
}
|
||||
else if (advancementState.GetAdvType() === "Shadow") {
|
||||
topIcon = "shadow";
|
||||
topText = "Lich's Bane";
|
||||
}
|
||||
|
||||
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) {
|
||||
PlaySound("GLUESCREENLARGEBUTTONMOUSEDOWN");
|
||||
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) {
|
||||
PlaySound("GLUESCREENLARGEBUTTONMOUSEDOWN");
|
||||
SelectAdvancement(bottomIcon, self);
|
||||
});
|
||||
|
||||
bottomButton.Show();
|
||||
|
||||
// Add advancement bars
|
||||
const topbarTexture = frame.CreateTexture(id("topbar_gold"), "OVERLAY");
|
||||
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"), "OVERLAY");
|
||||
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);
|
||||
|
||||
// Always create the advancement bars here (default visuals)
|
||||
CreateAdvColorBar(frame, topbarTexture, "top");
|
||||
CreateAdvColorBar(frame, bottombarTexture, "bottom");
|
||||
|
||||
|
||||
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);
|
||||
|
||||
// Add placeholder for current rank:
|
||||
const topbarRankText = frame.CreateFontString(id("topbar_rank"), "OVERLAY");
|
||||
topbarRankText.SetPoint("CENTER", topButton, "CENTER", 3, -66);
|
||||
topbarRankText.SetTextColor(1, 1, 1, 1) // White
|
||||
topbarRankText.SetFont("Fonts\\FRIZQT__.TTF", 14)
|
||||
topbarRankText.SetText("Rank: ");
|
||||
|
||||
const bottombarRankText = frame.CreateFontString(id("bottombar_rank"), "OVERLAY");
|
||||
bottombarRankText.SetPoint("CENTER", bottomButton, "CENTER", 3, -66);
|
||||
bottombarRankText.SetTextColor(1, 1, 1, 1) // White
|
||||
bottombarRankText.SetFont("Fonts\\FRIZQT__.TTF", 14)
|
||||
bottombarRankText.SetText("Rank: ");
|
||||
|
||||
const topbarRankBonusText = frame.CreateFontString(id("topbar_bonus"), "OVERLAY");
|
||||
topbarRankBonusText.SetPoint("CENTER", topbarTexture, "CENTER", 0, -27);
|
||||
topbarRankBonusText.SetFont("Fonts\\FRIZQT__.TTF", 13)
|
||||
topbarRankBonusText.SetTextColor(1, 0.84, 0, 1) // Golden yellow
|
||||
topbarRankBonusText.SetText(`Bonus: `);
|
||||
|
||||
const bottombarRankBonusText = frame.CreateFontString(id("bottombar_bonus"), "OVERLAY");
|
||||
bottombarRankBonusText.SetPoint("CENTER", bottombarTexture, "CENTER", 0, -27);
|
||||
bottombarRankBonusText.SetFont("Fonts\\FRIZQT__.TTF", 13)
|
||||
bottombarRankBonusText.SetTextColor(1, 0.84, 0, 1) // Golden yellow
|
||||
bottombarRankBonusText.SetText(`Bonus: `) ;
|
||||
|
||||
}
|
||||
|
||||
function CreateCostFrame(frame: WoWAPI.Frame): void {
|
||||
|
||||
const myWidth = 300;
|
||||
let costFrame = GetComponent("cost_frame");
|
||||
if(!costFrame) {
|
||||
costFrame = CreateFrame("Frame", id("cost_frame"), frame);
|
||||
costFrame.SetSize(myWidth, 68);
|
||||
costFrame.SetPoint("LEFT", frame, "TOPLEFT", mainWidth * 0.5 + 45, -120);
|
||||
|
||||
// Set a dark background with border
|
||||
costFrame.SetBackdrop({
|
||||
bgFile: "Interface/Tooltips/UI-Tooltip-Background",
|
||||
edgeFile: "Interface/Tooltips/UI-Tooltip-Border",
|
||||
tile: true,
|
||||
tileSize: 16,
|
||||
edgeSize: 16,
|
||||
insets: {
|
||||
left: 4,
|
||||
right: 4,
|
||||
top: 4,
|
||||
bottom: 4
|
||||
}
|
||||
});
|
||||
|
||||
costFrame.SetAlpha(0.0);
|
||||
|
||||
// Set the background color to dark
|
||||
costFrame.SetBackdropColor(0.1, 0.1, 0.1, 0.8); // Dark gray, slightly transparent
|
||||
|
||||
// Set the border color - using the available method
|
||||
costFrame.SetBackdropBorderColor(0.4, 0.4, 0.4, 1.0); // Medium gray border
|
||||
|
||||
// Add a title above the frame
|
||||
const titleText = costFrame.CreateFontString(id("cost_frame_title"), "OVERLAY", "GameFontNormal");
|
||||
titleText.SetPoint("BOTTOM", costFrame, "TOP", 0, 5);
|
||||
titleText.SetText("Required Items");
|
||||
titleText.SetTextColor(1, 0.84, 0, 1); // Golden yellow
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<WoWAPI.Button>("selected_dice_button", "Button");
|
||||
|
||||
buttons.forEach((buttonInfo, index) => {
|
||||
const buttonId = `${buttonInfo.name}_button`;
|
||||
let button = GetComponent<WoWAPI.Button>(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`));
|
||||
|
||||
UpgradeAdvancement(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`);
|
||||
}
|
||||
|
||||
function CreateCloseButton(frame: WoWAPI.Frame): void {
|
||||
const closeBtn = CreateFrame("Button", id("close_button"), frame);
|
||||
closeBtn.SetSize(52, 52);
|
||||
closeBtn.SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -20);
|
||||
closeBtn.SetNormalTexture(GetTexture("close_button"));
|
||||
closeBtn.SetHighlightTexture(GetTexture("close_button_hl"));
|
||||
closeBtn.SetPushedTexture(GetTexture("close_button_pushed"));
|
||||
closeBtn.SetScript("OnClick", function(self: WoWAPI.Button) {
|
||||
frame.Hide();
|
||||
});
|
||||
closeBtn.Show();
|
||||
}
|
||||
|
||||
function CreateRollFrame(frame: WoWAPI.Frame): WoWAPI.Frame {
|
||||
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
|
||||
}
|
||||
return rollFrame;
|
||||
}
|
||||
|
||||
|
||||
let diceTextures: WoWAPI.Texture[] = [];
|
||||
/**
|
||||
* 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 RollDice(min: number, max: number, endValue: number): void {
|
||||
|
||||
const rollFrame = GetComponent("roll_frame");
|
||||
if(!rollFrame) {
|
||||
AIO_debug(`RollDice: roll_frame not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// create a texture that will change the graphic number being rolled 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],
|
||||
}
|
||||
|
||||
function clearTextures() {
|
||||
diceTextures.forEach(texture => {
|
||||
texture.Hide();
|
||||
texture.ClearAllPoints();
|
||||
});
|
||||
diceTextures = [];
|
||||
}
|
||||
clearTextures();
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
diceTextures.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;
|
||||
let elapsed = 0;
|
||||
let played = false;
|
||||
|
||||
PlaySound("GLUESCREENSMALLBUTTONMOUSEDOWN")
|
||||
rollFrame.SetScript("OnUpdate", function(_, deltaTime) {
|
||||
elapsed = elapsed + deltaTime * 1000;
|
||||
lastUpdate += deltaTime * 1000;
|
||||
|
||||
// Show a new number every 100ms
|
||||
if (lastUpdate >= 100) {
|
||||
lastUpdate = 0;
|
||||
const randomNum = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
showNumber(randomNum);
|
||||
}
|
||||
|
||||
if(elapsed >= 1200 && !played) {
|
||||
PlaySoundFile("Interface\\Modules\\MythicPlus\\Audio\\mythiclevel.ogg");
|
||||
played = true;
|
||||
}
|
||||
|
||||
// Stop rolling after the duration is reached
|
||||
if (elapsed >= 1500) {
|
||||
|
||||
|
||||
rollFrame.SetScript("OnUpdate", null);
|
||||
clearTextures();
|
||||
showNumber(endValue);
|
||||
rolling = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function getMessageArgs(message: string): string[] {
|
||||
return message.split("|");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the main upgrade window frame.
|
||||
* @returns Main Frame
|
||||
*/
|
||||
function CreateUpgradeWindow(type: AdvancementType): WoWAPI.Frame {
|
||||
|
||||
// Main frame creation
|
||||
const frame = CreateFrame("Frame", id(`main_${type}`), UIParent);
|
||||
frame.SetSize(mainWidth, mainHeight);
|
||||
frame.SetPoint("CENTER");
|
||||
frame.SetFrameLevel(100); // Set high frame level to stay on top
|
||||
|
||||
// Add typical frame behaviors
|
||||
MakeDraggable(frame);
|
||||
EscapeCloseable(frame);
|
||||
|
||||
// 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
|
||||
AddTitle(frame);
|
||||
CreateCloseButton(frame);
|
||||
CreateAdvIcons(frame);
|
||||
CreateRollFrame(frame);
|
||||
// ShowRollNumbers(frame);
|
||||
CreateCostFrame(frame);
|
||||
|
||||
const rollFrame = GetComponent("roll_frame");
|
||||
if (rollFrame) {
|
||||
CreateDiceButtons(frame, rollFrame);
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
/**
|
||||
* Internal Event Handlers
|
||||
*/
|
||||
function SimulateRoll(rank: number, endValue: number) {
|
||||
|
||||
let min = 1;
|
||||
let max = 11;
|
||||
|
||||
if(rank >= 10 && rank < 20) {
|
||||
min = 3;
|
||||
max = 18;
|
||||
}
|
||||
if(rank >= 20 && rank < 30) {
|
||||
min = 5;
|
||||
max = 20;
|
||||
}
|
||||
if(rank >= 30 && rank < 40) {
|
||||
min = 7;
|
||||
max = 34;
|
||||
}
|
||||
if(rank >= 40 && rank <= 50) {
|
||||
min = 9;
|
||||
max = 42;
|
||||
}
|
||||
|
||||
RollDice(min, max, endValue);
|
||||
}
|
||||
|
||||
// This needs to tell the c++ server event listener in the mythic mod to upgrade the advancement
|
||||
// for this player
|
||||
function UpgradeAdvancement(diceLevel: number) {
|
||||
AIO_debug(`Upgrading Player ${advancementState.GetPlayerGuid()} advancement ${advancementState.GetAdvancementId()} with dice level ${diceLevel}`);
|
||||
SendServerEvent("UpgradeAdvancement", [advancementState.GetAdvancementId(), diceLevel]);
|
||||
}
|
||||
|
||||
// This handles updating rank text when advancement state change
|
||||
function UpdateRanks() {
|
||||
const topRankText = GetAnyComponent<WoWAPI.FontString>("topbar_rank");
|
||||
const bottomRankText = GetAnyComponent<WoWAPI.FontString>("bottombar_rank");
|
||||
const topBonusRankText = GetAnyComponent<WoWAPI.FontString>("topbar_bonus");
|
||||
const bottomBonusRankText = GetAnyComponent<WoWAPI.FontString>("bottombar_bonus");
|
||||
|
||||
const ids = advancementState.GetShownIds();
|
||||
const topId = ids[0];
|
||||
const topRank = advancementState.GetRank(topId);
|
||||
AIO_debug("Top rank", topRank);
|
||||
|
||||
topRankText.SetText("Rank: " + topRank.toString());
|
||||
const topBonus = advancementState.GetBonus(topId);
|
||||
const bonusText = `${advancementState.AdvIdToName(topId)}: +${topBonus}`;
|
||||
topBonusRankText.SetText(bonusText);
|
||||
|
||||
// Update the top bar level experience.
|
||||
const goldBar = GetAnyComponent<WoWAPI.Texture>("topbar_gold");
|
||||
UpdateAdvColorBar("top", topRank);
|
||||
|
||||
// If the panel is showing 2 stats also do the bottom one.
|
||||
if(ids.length == 2) {
|
||||
const bottomId = ids[1];
|
||||
const bottomRank = advancementState.GetRank(bottomId);
|
||||
bottomRankText.SetText("Rank: " + bottomRank.toString());
|
||||
const bottomBonus = advancementState.GetBonus(bottomId);
|
||||
const bonusText = `${advancementState.AdvIdToName(bottomId)}: +${bottomBonus}`;
|
||||
bottomBonusRankText.SetText(bonusText);
|
||||
// Update the bottom bar level experience.
|
||||
UpdateAdvColorBar("bottom", bottomRank);
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the display of the cost to the user
|
||||
function UpdateCosts(cost: any) {
|
||||
// Get the cost frame
|
||||
const costFrame = GetComponent<WoWAPI.Frame>("cost_frame");
|
||||
if (!costFrame) {
|
||||
AIO_debug("Cost frame not found");
|
||||
return;
|
||||
}
|
||||
|
||||
const itemEntries = [cost.itemEntry1, cost.itemEntry2, cost.itemEntry3];
|
||||
const itemCosts = [cost.itemCost1, cost.itemCost2, cost.itemCost3];
|
||||
|
||||
const validItems = [];
|
||||
for (let i = 0; i < itemEntries.length; i++) {
|
||||
if (itemEntries[i] && itemEntries[i] > 0 && itemCosts[i] > 0) {
|
||||
validItems.push({
|
||||
entry: itemEntries[i],
|
||||
cost: itemCosts[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const ICON_SIZE = 48;
|
||||
const SPACING = 10;
|
||||
|
||||
for(let i =0 ; i <3; i++) {
|
||||
const button: WoWAPI.Button = GetAnyComponent(`cost_item_${i}`);
|
||||
if (button) {
|
||||
button.Hide();
|
||||
AIO_debug(`>>>>>>>>>>>>>>>>>>>>>>>> Hiding existing button ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < validItems.length; i++) {
|
||||
const item = validItems[i];
|
||||
const name = id(`cost_item_${i}`);
|
||||
|
||||
// Create the item button
|
||||
const iconButton = CreateItemButton(
|
||||
costFrame,
|
||||
name,
|
||||
item.entry,
|
||||
48,
|
||||
10 + (i * (ICON_SIZE + SPACING + 40)),
|
||||
0
|
||||
);
|
||||
|
||||
// Create or get cost text
|
||||
let costText = GetAnyComponent<WoWAPI.FontString>(`cost_text_${i}`);
|
||||
if (!costText) {
|
||||
costText = iconButton.CreateFontString(id(`cost_text_${i}`), "OVERLAY", "GameFontNormal");
|
||||
costText.SetFont("Fonts\\FRIZQT__.TTF", 16);
|
||||
costText.SetPoint("LEFT", iconButton, "RIGHT", 5, 0);
|
||||
}
|
||||
|
||||
if(GetItemCount(item.entry) >= item.cost) {
|
||||
costText.SetTextColor(0.117, 1, 0, 1); // green
|
||||
} else {
|
||||
costText.SetTextColor(1, 0.125, 0, 1); // red
|
||||
}
|
||||
|
||||
// Set the cost text
|
||||
costText.SetText(`x${item.cost}`);
|
||||
|
||||
// Show the button
|
||||
iconButton.Show();
|
||||
}
|
||||
|
||||
for(let i =0 ; i <3; i++) {
|
||||
|
||||
// Get the dice button to create the text against.
|
||||
|
||||
const diceButtonNames = ['single_roll_button', 'double_roll_button', 'triple_roll_button'];
|
||||
let diceText: WoWAPI.FontString;
|
||||
let diceButton = GetComponent<WoWAPI.Button>(diceButtonNames[i], "Button");
|
||||
|
||||
if (diceButton) {
|
||||
// Clear the dice text if it exists
|
||||
diceText = GetAnyComponent<WoWAPI.FontString>(`dice_text_${i}`);
|
||||
if (!diceText) {
|
||||
diceText = diceButton.CreateFontString(id(`dice_text_${i}`), "OVERLAY");
|
||||
diceText.SetFont("Fonts\\FRIZQT__.TTF", 13);
|
||||
}
|
||||
let chanceCost = cost[`chanceCost${i+1}`];
|
||||
|
||||
|
||||
diceText.SetPoint("TOP", diceButton, "BOTTOM", 0, 10);
|
||||
diceText.SetText(`x${chanceCost}`);
|
||||
|
||||
// set the color based on if they have the materials
|
||||
if(GetItemCount(911000) >= chanceCost) {
|
||||
// WoW green: #1eff00 (RGB: 0.117, 1, 0)
|
||||
diceText.SetTextColor(0.117, 1, 0, 1); // WoW green
|
||||
} else {
|
||||
// WoW red: #ff2020 (RGB: 1, 0.125, 0)
|
||||
diceText.SetTextColor(1, 0.125, 0, 1); // WoW red
|
||||
}
|
||||
diceText.Show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mythic Event Handlers
|
||||
* Events that come from calling into the MythicPlus Mod via AddOn channel
|
||||
*/
|
||||
const eventFrame = CreateFrame("Frame", id("event_frame"));
|
||||
eventFrame.RegisterEvent("CHAT_MSG_ADDON")
|
||||
eventFrame.SetScript("OnEvent", function(self, event, prefix, message, sender) {
|
||||
|
||||
// If it is coming in on our channel
|
||||
if (prefix == "MPUi") {
|
||||
|
||||
const result = getMessageArgs(message);
|
||||
if(!result || result.length < 1) {
|
||||
AIO_debug("Received event with no data");
|
||||
return;
|
||||
}
|
||||
// only look at server events
|
||||
if(result[0] != "s") {
|
||||
return;
|
||||
}
|
||||
|
||||
// log if it is an error but do not continue
|
||||
if(result[2] == 'Error') {
|
||||
AIO_debug(`ERROR: Received event ${result[3]} Details: ${result[4]}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const method = result[2];
|
||||
switch(method) {
|
||||
case "UpgradeAdvancement":
|
||||
|
||||
// Send an update to the server to update shared state of client.
|
||||
const thisRoll = result[4];
|
||||
const rank = result[5];
|
||||
const totalBonus = result[6];
|
||||
|
||||
// Send the roll over to simulate the roll but end on the correct number
|
||||
SimulateRoll(Number(rank), Number(thisRoll));
|
||||
|
||||
// refresh the state.
|
||||
aio.Handle("MythicAdvUI", "GetAdvancementState", advancementState.GetAdvancementId(), rank, totalBonus);
|
||||
break;
|
||||
default:
|
||||
AIO_debug(`Unknown method: ${method}`);
|
||||
break;
|
||||
}
|
||||
|
||||
aio.Handle("MythicAdvUI", "GetAdvancementState", advancementState.GetAdvancementId(), result[5], result[6]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Server Event State Handlers
|
||||
*/
|
||||
|
||||
// This will update the advancement state from the server
|
||||
AdvanceUIHandlers.UpdateAdvancementState = (playerId: number, advancements: PlayerAdvancement[]) => {
|
||||
advancementState.SetPlayerGuid(playerId);
|
||||
advancementState.LoadAdvancements(advancements);
|
||||
|
||||
const advId = advancementState.GetAdvancementId();
|
||||
if(advId) {
|
||||
aio.Handle("MythicAdvUI", "GetNextLevelCost", advId);
|
||||
}
|
||||
|
||||
UpdateRanks();
|
||||
};
|
||||
|
||||
AdvanceUIHandlers.UpdateNextLevelCost = (cost: any) => {
|
||||
AIO_debug("I received next level cost from the server", cost.itemEntry1);
|
||||
UpdateCosts(cost);
|
||||
};
|
||||
|
||||
|
||||
// This will show the advancement upgrade window
|
||||
let frame: WoWAPI.Frame | undefined = undefined;
|
||||
AdvanceUIHandlers.ShowUpgradeWindow = (type: AdvancementType) => {
|
||||
advancementState.ClearState();
|
||||
advancementState.SetType(type);
|
||||
aio.Handle("MythicAdvUI", "GetAdvancementState");
|
||||
|
||||
if(!UpgradeUIFrames.has(type)) {
|
||||
frame = CreateUpgradeWindow(type);
|
||||
UpgradeUIFrames.set(type, frame);
|
||||
} else {
|
||||
frame = UpgradeUIFrames.get(type);
|
||||
}
|
||||
|
||||
let ids = advancementState.GetShownIds();
|
||||
AIO_debug("Shown ids", ids[0]);
|
||||
|
||||
frame?.Show();
|
||||
// if (advancementState.GetShownIds().length > 0 && frame) {
|
||||
// UpdateRanks();
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
363
modules/UI/mythicplus/advance.server.ts
Normal file
363
modules/UI/mythicplus/advance.server.ts
Normal file
@@ -0,0 +1,363 @@
|
||||
/** @ts-expect-error */
|
||||
let aio: AIO = {};
|
||||
|
||||
const SCRIPT_NAME = "UpgradeUI";
|
||||
import { Logger } from "../../classes/logger";
|
||||
import { PlayerAdvancement } from "./advstate";
|
||||
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<ItemType>;
|
||||
};
|
||||
|
||||
const upgradeMaterials: Record<number, Materials> = {};
|
||||
const playerAdvData: Map<number, PlayerAdvancement[]> = new Map();
|
||||
|
||||
/*
|
||||
Advancement IDs in Database
|
||||
|
||||
MP_ADV_INTELLECT = 0,
|
||||
MP_ADV_SPIRIT = 1,
|
||||
MP_ADV_STRENGTH = 2,
|
||||
MP_ADV_AGILITY = 3,
|
||||
MP_ADV_STAMINA = 4,
|
||||
MP_ADV_RESIST_ARCANE = 5,
|
||||
MP_ADV_RESIST_FIRE = 6,
|
||||
MP_ADV_RESIST_NATURE = 7,
|
||||
MP_ADV_RESIST_FROST = 8,
|
||||
MP_ADV_RESIST_SHADOW = 9,
|
||||
*/
|
||||
|
||||
export interface AdvCost {
|
||||
upgradeRank: number; // The rank of the upgrade
|
||||
advancementId: number; // Which advancement this applies to
|
||||
itemEntry1: number; // First item required for upgrade
|
||||
itemEntry2: number; // Second item required for upgrade
|
||||
itemEntry3: number; // Third item required for upgrade
|
||||
itemCost1: number; // Quantity of first item
|
||||
itemCost2: number; // Quantity of second item
|
||||
itemCost3: number; // Quantity of third item
|
||||
minIncrease1: number; // Minimum stat increase for option 1
|
||||
maxIncrease1: number; // Maximum stat increase for option 1
|
||||
minIncrease2: number; // Minimum stat increase for option 2
|
||||
maxIncrease2: number; // Maximum stat increase for option 2
|
||||
minIncrease3: number; // Minimum stat increase for option 3
|
||||
maxIncrease3: number; // Maximum stat increase for option 3
|
||||
chanceCost1: number; // Success chance cost for option 1
|
||||
chanceCost2: number; // Success chance cost for option 2
|
||||
chanceCost3: number; // Success chance cost for option 3
|
||||
}
|
||||
|
||||
export function GetAdvCostNextLevel(
|
||||
advId: number,
|
||||
player: Player
|
||||
): AdvCost | null {
|
||||
// First, get the player's current upgrade rank for this advancement
|
||||
const playerGuid = player.GetGUID();
|
||||
const playerAdvQuery = CharDBQuery(
|
||||
`SELECT upgradeRank FROM mp_player_advancements WHERE guid = ${playerGuid} AND advancementId = ${advId}`
|
||||
);
|
||||
|
||||
// Default to rank 0 if player doesn't have this advancement yet
|
||||
const currentRank = playerAdvQuery ? playerAdvQuery.GetUInt32(0) : 0;
|
||||
|
||||
// Get the next rank (current + 1)
|
||||
const nextRank = currentRank + 1;
|
||||
|
||||
// Now get the upgrade costs for the next rank
|
||||
const costsQuery = WorldDBQuery(
|
||||
`SELECT * FROM mp_upgrade_ranks WHERE upgradeRank = ${nextRank} AND advancementId = ${advId}`
|
||||
);
|
||||
|
||||
if (!costsQuery) {
|
||||
// No more upgrades available for this advancement
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
upgradeRank: costsQuery.GetUInt32(0),
|
||||
advancementId: costsQuery.GetUInt32(1),
|
||||
itemEntry1: costsQuery.GetUInt32(2),
|
||||
itemEntry2: costsQuery.GetUInt32(3),
|
||||
itemEntry3: costsQuery.GetUInt32(4),
|
||||
itemCost1: costsQuery.GetUInt32(5),
|
||||
itemCost2: costsQuery.GetUInt32(6),
|
||||
itemCost3: costsQuery.GetUInt32(7),
|
||||
minIncrease1: costsQuery.GetUInt32(8),
|
||||
maxIncrease1: costsQuery.GetUInt32(9),
|
||||
minIncrease2: costsQuery.GetUInt32(10),
|
||||
maxIncrease2: costsQuery.GetUInt32(11),
|
||||
minIncrease3: costsQuery.GetUInt32(12),
|
||||
maxIncrease3: costsQuery.GetUInt32(13),
|
||||
chanceCost1: costsQuery.GetUInt32(14),
|
||||
chanceCost2: costsQuery.GetUInt32(15),
|
||||
chanceCost3: costsQuery.GetUInt32(16),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to safely get items from a material
|
||||
*/
|
||||
const getItemsFromMaterial = (material: Materials): Array<ItemType> => {
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the command event to listen for ".advanceme"
|
||||
*/
|
||||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) =>
|
||||
ShowUpgradeUI(...args)
|
||||
);
|
||||
|
||||
const ShowNextLevelCost: player_event_on_chat = (
|
||||
event: number,
|
||||
player: Player,
|
||||
msg: string,
|
||||
Type: ChatMsg,
|
||||
lang: Language
|
||||
): string | boolean => {
|
||||
log.info(`Player ${player.GetName()} typed ${msg}`);
|
||||
if (msg.includes("#nextlevelcost")) {
|
||||
const args = msg.split(" ");
|
||||
const advId = Number(args[1]);
|
||||
|
||||
const nextLevelCost = GetAdvCostNextLevel(advId, player);
|
||||
player.SendBroadcastMessage(
|
||||
`Next level cost: Chance: ${nextLevelCost.chanceCost1}, Item: ${nextLevelCost.itemEntry1} x ${nextLevelCost.itemCost1}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(msg.includes("#advancedata")) {
|
||||
const data = playerAdvData.get(player.GetGUIDLow());
|
||||
if(!data) {
|
||||
PrintInfo(`Player ${player.GetName()} does not have any advancement data`);
|
||||
return true;
|
||||
}
|
||||
|
||||
for(let i=0; i<data.length; i++) {
|
||||
PrintInfo(`Player ${player.GetName()} advancement ${data[i].advancementId} is at rank ${data[i].upgradeRank} total history ${data[i].history.length}`);
|
||||
}
|
||||
|
||||
aio.Handle(player, "MythicAdvUI", "UpdateAdvancements", data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize advancement data for a player if they do not have any
|
||||
* @param player
|
||||
*/
|
||||
function _initPlayerAdvancements(player: Player): void {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
// If it already exists then skip it.
|
||||
const checkQuery = CharDBQuery(
|
||||
`SELECT * FROM mp_player_advancements WHERE guid = ${player.GetGUID()} AND advancementId = ${i}`
|
||||
);
|
||||
if (checkQuery) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CharDBQuery(
|
||||
`INSERT INTO mp_player_advancements (guid, advancementId, bonus, upgradeRank, diceSpent) VALUES (${player.GetGUID()}, ${i}, 0, 0, 0)`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// this will get the advancement data for a player and pass back empty data if they do not have one.
|
||||
function _getAdvancementData(player: Player): PlayerAdvancement[] {
|
||||
let result = CharDBQuery(
|
||||
`SELECT * FROM mp_player_advancements WHERE guid = ${player.GetGUID()} ORDER BY advancementId ASC`
|
||||
);
|
||||
|
||||
const advancements: PlayerAdvancement[] = [];
|
||||
if (!result) {
|
||||
_initPlayerAdvancements(player);
|
||||
|
||||
// now grab the new initialized results
|
||||
result = CharDBQuery(
|
||||
`SELECT * FROM mp_player_advancements WHERE guid = ${player.GetGUID()} ORDER BY advancementId ASC`
|
||||
);
|
||||
}
|
||||
|
||||
if (result.GetRowCount() !== 10) {
|
||||
_initPlayerAdvancements(player);
|
||||
result = CharDBQuery(
|
||||
`SELECT * FROM mp_player_advancements WHERE guid = ${player.GetGUID()} ORDER BY advancementId ASC`
|
||||
);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
PrintError(`Failed to get advancement data for player ${player.GetName()}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
for(let i=0; i<result.GetRowCount(); i++) {
|
||||
const row = result.GetRow();
|
||||
advancements[Number(row.advancementId)] = {
|
||||
advancementId: Number(row.advancementId),
|
||||
upgradeRank: Number(row.upgradeRank),
|
||||
diceSpent: Number(row.diceSpent),
|
||||
bonus: Number(row.bonus),
|
||||
history: []
|
||||
};
|
||||
|
||||
const historyQuery = CharDBQuery(
|
||||
`SELECT * FROM mp_player_advancement_history WHERE guid = ${player.GetGUID()} AND advancementId = ${
|
||||
row.advancementId
|
||||
}`
|
||||
);
|
||||
|
||||
if(historyQuery) {
|
||||
for(let j=0; j<historyQuery.GetRowCount(); j++) {
|
||||
const historyRow = historyQuery.GetRow();
|
||||
advancements[Number(row.advancementId)].history.push({
|
||||
rank: Number(historyRow.upgradeRank),
|
||||
diceSpent: Number(historyRow.diceSpent),
|
||||
bonus: Number(historyRow.bonus),
|
||||
});
|
||||
historyQuery.NextRow();
|
||||
}
|
||||
}
|
||||
|
||||
result.NextRow();
|
||||
}
|
||||
|
||||
PrintInfo(`Loaded Advancements for player ${player.GetName()} total ${advancements.length}...`);
|
||||
|
||||
return advancements;
|
||||
}
|
||||
|
||||
const GetAdvancementData: player_event_on_login = (
|
||||
event: number,
|
||||
player: Player
|
||||
) => {
|
||||
const advancements = _getAdvancementData(player);
|
||||
playerAdvData.set(player.GetGUIDLow(), advancements);
|
||||
aio.Handle(player, "MythicAdvUI", "UpdateAdvancementState", player.GetGUIDLow(), advancements);
|
||||
};
|
||||
|
||||
// Get the player state when the login and push to client for storage.
|
||||
// RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) =>
|
||||
// GetAdvancementData(...args)
|
||||
// );
|
||||
|
||||
const ReloadAdvancements: eluna_event_on_lua_state_open = (event: number) => {
|
||||
|
||||
PrintInfo("Lua State Closed");
|
||||
// Need to capture all players online and reload their state.
|
||||
const players = GetPlayersInWorld();
|
||||
for(let i=0; i<players.length; i++) {
|
||||
GetAdvancementData(event, players[i]);
|
||||
}
|
||||
};
|
||||
|
||||
// Register Server Event on Lua State Ope
|
||||
// RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN, (...args) => ReloadAdvancements(...args));
|
||||
|
||||
// RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_CLOSE, (...args) => {
|
||||
// PrintInfo("Lua State Closed");
|
||||
// });
|
||||
|
||||
|
||||
// Register
|
||||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) =>
|
||||
ShowNextLevelCost(...args)
|
||||
);
|
||||
|
||||
/**
|
||||
* Get all the material types from the database
|
||||
* RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_OPEN, (...args) => GetMaterialsList(...args));
|
||||
*/
|
||||
|
||||
// AIO Handlers for Mythic Advancement UI
|
||||
const MythicAdvUIHandlers = {
|
||||
// Handle the GetNextLevelCost request from client
|
||||
GetNextLevelCost: function (this: void, player: Player, advId: number): void {
|
||||
log.info(
|
||||
`GetNextLevelCost called for player ${player.GetName()} with advId ${advId}`
|
||||
);
|
||||
|
||||
// Get the next level cost information
|
||||
const nextLevelCost = GetAdvCostNextLevel(advId, player);
|
||||
|
||||
if (!nextLevelCost) {
|
||||
log.error(`No next level cost found for advId ${advId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the cost information back to the client
|
||||
aio.Handle(player, "MythicAdvUI", "UpdateNextLevelCost", nextLevelCost);
|
||||
|
||||
log.info(
|
||||
`Sent next level cost for advId ${advId} to player ${player.GetName()}`
|
||||
);
|
||||
},
|
||||
|
||||
GetAdvancementState: function (this: void, player: Player, advId?: number, rank?: number, bonus?: number): void {
|
||||
|
||||
const advancements = _getAdvancementData(player);
|
||||
|
||||
// if the client passes us an override from the backend then apply it before sending it back.
|
||||
if(advId && rank && bonus) {
|
||||
advancements[advId].upgradeRank = rank;
|
||||
advancements[advId].bonus = Math.round(bonus);
|
||||
}
|
||||
playerAdvData.set(player.GetGUIDLow(), advancements);
|
||||
|
||||
aio.Handle(player, "MythicAdvUI", "UpdateAdvancementState", player.GetGUIDLow(), advancements);
|
||||
},
|
||||
};
|
||||
|
||||
// Register the handlers with AIO
|
||||
aio.AddHandlers("MythicAdvUI", MythicAdvUIHandlers);
|
||||
|
||||
const ShowUpgradeWindow: player_event_on_chat = (event: number, player: Player, msg: string, Type: ChatMsg, lang: Language): string | boolean => {
|
||||
// Implementation
|
||||
if(msg === "#advanceme") {
|
||||
|
||||
const parts = msg.split(" ");
|
||||
const type = parts[1];
|
||||
|
||||
aio.Handle(player, "MythicAdvUI", "ShowUpgradeWindow", type);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Register
|
||||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => ShowUpgradeWindow(...args));
|
||||
199
modules/UI/mythicplus/advstate.ts
Normal file
199
modules/UI/mythicplus/advstate.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
// Force transpiler to rebuild - temporary comment
|
||||
export type AdvancementType = "Magic" | "Attack" | "Defense" | "FireFrost" | "NatureArcane" | "Shadow";
|
||||
|
||||
/*
|
||||
Advancement IDs in Database
|
||||
|
||||
MP_ADV_INTELLECT = 0,
|
||||
MP_ADV_SPIRIT = 1,
|
||||
MP_ADV_STRENGTH = 2,
|
||||
MP_ADV_AGILITY = 3,
|
||||
MP_ADV_STAMINA = 4,
|
||||
MP_ADV_RESIST_ARCANE = 5,
|
||||
MP_ADV_RESIST_FIRE = 6,
|
||||
MP_ADV_RESIST_NATURE = 7,
|
||||
MP_ADV_RESIST_FROST = 8,
|
||||
MP_ADV_RESIST_SHADOW = 9,
|
||||
*/
|
||||
|
||||
export interface PlayerAdvancement {
|
||||
advancementId: number;
|
||||
upgradeRank: number;
|
||||
diceSpent: number;
|
||||
bonus: number;
|
||||
history: Array<{rank: number, diceSpent: number, bonus: number}>;
|
||||
}
|
||||
|
||||
export class AdvanceState {
|
||||
|
||||
// Server Side Player Guid
|
||||
private playerGuid: number = 0;
|
||||
|
||||
private advancement: string | null = null;
|
||||
|
||||
// Type of panel it is
|
||||
private advType: AdvancementType | null = null;
|
||||
|
||||
// Actively selected stat id
|
||||
private advId: number | null = null;
|
||||
|
||||
// All the advancements for the player
|
||||
private advancements: PlayerAdvancement[] = [];
|
||||
|
||||
// Ids that are being shown in the panel
|
||||
private shownIds: number[] = []
|
||||
|
||||
LoadAdvancements(advancements: PlayerAdvancement[]): void {
|
||||
this.advancements = advancements;
|
||||
}
|
||||
|
||||
SetType(type: AdvancementType): void {
|
||||
this.advType = type;
|
||||
|
||||
if(this.advType === "Magic") {
|
||||
this.shownIds = [0, 1];
|
||||
}
|
||||
else if(this.advType === "Attack") {
|
||||
this.shownIds = [2, 3];
|
||||
}
|
||||
else if(this.advType === "Defense") {
|
||||
this.shownIds = [4];
|
||||
}
|
||||
else if(this.advType === "FireFrost") {
|
||||
this.shownIds = [6, 8];
|
||||
}
|
||||
else if(this.advType === "NatureArcane") {
|
||||
this.shownIds = [7, 5];
|
||||
}
|
||||
else if(this.advType === "Shadow") {
|
||||
this.shownIds = [9];
|
||||
}
|
||||
}
|
||||
|
||||
GetShownIds(): number[] {
|
||||
return this.shownIds;
|
||||
}
|
||||
|
||||
GetAdvType(): AdvancementType | null {
|
||||
return this.advType;
|
||||
}
|
||||
|
||||
SetAdvancement(icon: string): void {
|
||||
this.advancement = icon;
|
||||
|
||||
if(!icon) {
|
||||
this.advId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const advId = this.AdvNameToId(icon);
|
||||
if(advId !== -1) {
|
||||
this.advId = advId;
|
||||
} else {
|
||||
throw new Error("Invalid advancement name: " + icon);
|
||||
}
|
||||
}
|
||||
|
||||
GetAdvancement(): string | null {
|
||||
return this.advancement;
|
||||
}
|
||||
|
||||
GetAdvancementId(): number {
|
||||
return this.advId;
|
||||
}
|
||||
|
||||
AdvNameToId(name: string): number {
|
||||
switch(name) {
|
||||
case "int":
|
||||
return 0;
|
||||
case "spr":
|
||||
return 1;
|
||||
case "str":
|
||||
return 2;
|
||||
case "agi":
|
||||
return 3;
|
||||
case "sta":
|
||||
return 4;
|
||||
case "arcane":
|
||||
return 5;
|
||||
case "fire":
|
||||
return 6;
|
||||
case "nature":
|
||||
return 7;
|
||||
case "frost":
|
||||
return 8;
|
||||
case "shadow":
|
||||
return 9;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
AdvIdToName(id: number): string {
|
||||
switch(id) {
|
||||
case 0:
|
||||
return "Intellect";
|
||||
case 1:
|
||||
return "Spirit";
|
||||
case 2:
|
||||
return "Strength";
|
||||
case 3:
|
||||
return "Agility";
|
||||
case 4:
|
||||
return "Stamina";
|
||||
case 5:
|
||||
return "Arcane";
|
||||
case 6:
|
||||
return "Fire";
|
||||
case 7:
|
||||
return "Nature";
|
||||
case 8:
|
||||
return "Frost";
|
||||
case 9:
|
||||
return "Shadow";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
GetRank(id: number): number {
|
||||
if(!this.advancements[id]) {
|
||||
AIO_debug("Invalid advancement id: " + id);
|
||||
AIO_debug("Advancements Length: ", this.advancements.length);
|
||||
return -1;
|
||||
}
|
||||
return this.advancements[id].upgradeRank;
|
||||
}
|
||||
|
||||
GetBonus(id: number): number {
|
||||
if(!this.advancements[id]) {
|
||||
AIO_debug("Invalid advancement id: " + id);
|
||||
AIO_debug("Advancements Length: ", this.advancements.length);
|
||||
return -1;
|
||||
}
|
||||
return this.advancements[id].bonus;
|
||||
}
|
||||
|
||||
ClearAdvancement(): void {
|
||||
this.advancement = null;
|
||||
}
|
||||
|
||||
SetPlayerGuid(guid: number): void {
|
||||
this.playerGuid = guid;
|
||||
}
|
||||
|
||||
GetPlayerGuid(): number {
|
||||
return this.playerGuid;
|
||||
}
|
||||
|
||||
ClearState(): void {
|
||||
this.advancement = null;
|
||||
this.advType = null;
|
||||
this.advId = null;
|
||||
this.shownIds = [];
|
||||
this.advancements = [];
|
||||
this.playerGuid = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
150
modules/UI/mythicplus/mythic_dungeons.ts
Normal file
150
modules/UI/mythicplus/mythic_dungeons.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import {
|
||||
isBossDbCheck,
|
||||
MapIds,
|
||||
MapNames,
|
||||
DungeonLevels,
|
||||
isFinalBoss,
|
||||
} from "../../classes/mapzones";
|
||||
import {
|
||||
MYTHIC_TOKEN,
|
||||
EMBLEM_OF_UNDEATH,
|
||||
EMBLEM_OF_CHAOS,
|
||||
EMBLEM_OF_VEIL,
|
||||
VOID_BADGE,
|
||||
} from "./mythic_items";
|
||||
import { Logger } from "../../classes/logger";
|
||||
const SCRIPT_NAME = "MythicDungeonsLoot";
|
||||
const log = new Logger(SCRIPT_NAME);
|
||||
|
||||
log.info(`Mythic Dungeons Loot Module Loaded`);
|
||||
|
||||
function isInMythicPlus(playerId: number, instanceId: number): boolean {
|
||||
const result = CharDBQuery(
|
||||
"select guid, instanceId, difficulty from mp_player_instance_data where guid = " +
|
||||
playerId +
|
||||
" and instanceId = " +
|
||||
instanceId
|
||||
);
|
||||
if (result && result.GetUInt32(2) >= 3) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const mythicBossKill: player_event_on_kill_creature = (
|
||||
_: number,
|
||||
killer: Player,
|
||||
killed: Creature
|
||||
) => {
|
||||
// if the creature that is killed is a boss from a mythic plus instance lets check the chart to figure out the
|
||||
// token reward.
|
||||
if (
|
||||
isInMythicPlus(killer.GetGUID(), killer.GetInstanceId()) &&
|
||||
isBossDbCheck(killed.GetEntry())
|
||||
) {
|
||||
const reward = getRewardAmount(killer.GetMap(), killed);
|
||||
const token = getRewardTokenEntry(killer.GetMap(), killed);
|
||||
|
||||
// Give the player the right amount of tokens for their hard work.
|
||||
if (reward > 0 && token > 0) {
|
||||
killer.AddItem(token, reward);
|
||||
|
||||
// send a message to the player to let them know they have been awarded tokens
|
||||
killer.SendChatMessageToPlayer(
|
||||
ChatMsg.CHAT_MSG_ACHIEVEMENT,
|
||||
Language.LANG_COMMON,
|
||||
`|cff00ff00You have been awarded ${reward} ${getTokenName(
|
||||
token
|
||||
)} for defeating ${killed.GetName()}!|r`,
|
||||
killer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return false; // return true to stop normal action
|
||||
};
|
||||
|
||||
// Get the number of token that will be awarded to the group.
|
||||
function getRewardAmount(map: EMap, creature: Creature): number {
|
||||
const mapId = map.GetMapId();
|
||||
const creatureEntry = creature.GetEntry();
|
||||
const isCreatureFinalBoss = isFinalBoss(creatureEntry);
|
||||
|
||||
// Find the corresponding map name for this map ID
|
||||
let dungeonLevel = 0;
|
||||
for (const [mapName, id] of Object.entries(MapIds)) {
|
||||
if (id === mapId) {
|
||||
dungeonLevel = DungeonLevels[mapName as MapNames];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply reward rules based on dungeon level
|
||||
if (dungeonLevel < 35) {
|
||||
return 1; // 1 per boss regardless of final boss status
|
||||
} else if (dungeonLevel >= 35 && dungeonLevel <= 59) {
|
||||
return isCreatureFinalBoss ? 2 : 1; // 1 per boss, 2 for final boss
|
||||
} else if (dungeonLevel === 60) {
|
||||
return isCreatureFinalBoss ? 4 : 2; // 2 per boss, 4 if final boss
|
||||
} else if (dungeonLevel >= 61 && dungeonLevel <= 69) {
|
||||
return isCreatureFinalBoss ? 3 : 2; // 2 per boss, 3 on final bosses
|
||||
} else if (dungeonLevel === 70) {
|
||||
return isCreatureFinalBoss ? 5 : 2; // 2 per boss, 5 on final bosses
|
||||
} else if (dungeonLevel >= 71 && dungeonLevel <= 79) {
|
||||
return isCreatureFinalBoss ? 3 : 2; // 2 per boss, 3 on final bosses
|
||||
} else if (dungeonLevel === 80) {
|
||||
return isCreatureFinalBoss ? 5 : 3; // 3 per boss, 5 on final bosses
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This will need expanded later to account for legendary status.
|
||||
function getRewardTokenEntry(map: EMap, boss: Creature): number {
|
||||
// if the map is a normal instance return the mythic token id
|
||||
if (map.IsDungeon()) {
|
||||
if (map.IsHeroic()) {
|
||||
return VOID_BADGE;
|
||||
} else {
|
||||
return MYTHIC_TOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
// Only mythic raids launched at this time will be these 3
|
||||
if (map.IsRaid()) {
|
||||
// undeath tier gear raids MoltenCore, BlackwingLair, ZulGurub
|
||||
const undeathRaids = [
|
||||
MapIds[MapNames.MOLTEN_CORE],
|
||||
MapIds[MapNames.BLACKWING_LAIR],
|
||||
MapIds[MapNames.ZUL_GURUB],
|
||||
];
|
||||
if (undeathRaids.includes(map.GetMapId())) {
|
||||
return EMBLEM_OF_UNDEATH;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getTokenName(token: number): string {
|
||||
switch (token) {
|
||||
case MYTHIC_TOKEN:
|
||||
return "Mythic Token";
|
||||
case EMBLEM_OF_UNDEATH:
|
||||
return "Emblem of Undeath";
|
||||
case EMBLEM_OF_CHAOS:
|
||||
return "Emblem of Chaos";
|
||||
case EMBLEM_OF_VEIL:
|
||||
return "Emblem of Veil";
|
||||
case VOID_BADGE:
|
||||
return "Void Badge";
|
||||
default:
|
||||
return "Unknown Token";
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) =>
|
||||
mythicBossKill(...args)
|
||||
);
|
||||
|
||||
59
modules/UI/mythicplus/mythic_gameobjects.ts
Normal file
59
modules/UI/mythicplus/mythic_gameobjects.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
// This gives reward chests a glow on spawn to signify their value, using invisible creatures to cast the visual spell.
|
||||
|
||||
const InvisTrigger = 12999;
|
||||
|
||||
const VisualSpells = {
|
||||
"SmokeAuraBlue": 12898,
|
||||
"HellfireWarding": 33827,
|
||||
"GhostVisualRed": 35847,
|
||||
};
|
||||
|
||||
const RewardChests = {
|
||||
"Normal": 951002,
|
||||
"Elite": 951000,
|
||||
"Badass": 951004
|
||||
}
|
||||
|
||||
const showVisualSpell: gameobject_event_on_spawn = (event: number, gameObject: GameObject) => {
|
||||
|
||||
const invisCaster = gameObject.SpawnCreature(InvisTrigger, gameObject.GetX(), gameObject.GetY(), gameObject.GetZ(), 0, TempSummonType.TEMPSUMMON_MANUAL_DESPAWN);
|
||||
|
||||
const entry = gameObject.GetEntry();
|
||||
PrintInfo(`Entry: ${entry}`);
|
||||
|
||||
switch(entry) {
|
||||
case RewardChests.Normal:
|
||||
invisCaster.CastSpellAoF(gameObject.GetX(), gameObject.GetY(), gameObject.GetZ(), VisualSpells.SmokeAuraBlue);
|
||||
break;
|
||||
case RewardChests.Elite:
|
||||
invisCaster.CastSpellAoF(gameObject.GetX(), gameObject.GetY(), gameObject.GetZ(), VisualSpells.GhostVisualRed);
|
||||
break;
|
||||
case RewardChests.Badass:
|
||||
invisCaster.SetScale(2);
|
||||
invisCaster.CastSpell(invisCaster, VisualSpells.HellfireWarding);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const removeVisualSpell: gameobject_event_on_use = (event: number, gameObject: GameObject) => {
|
||||
const creatures = gameObject.GetCreaturesInRange(3, InvisTrigger);
|
||||
|
||||
for(let i = 0; i < creatures.length; i++) {
|
||||
creatures[i].DespawnOrUnsummon();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Register All visuals by chest.
|
||||
RegisterGameObjectEvent(RewardChests.Normal, GameObjectEvents.GAMEOBJECT_EVENT_ON_SPAWN, (...args) => showVisualSpell(...args));
|
||||
RegisterGameObjectEvent(RewardChests.Normal, GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, (...args) => removeVisualSpell(...args));
|
||||
|
||||
RegisterGameObjectEvent(RewardChests.Elite, GameObjectEvents.GAMEOBJECT_EVENT_ON_SPAWN, (...args) => showVisualSpell(...args));
|
||||
RegisterGameObjectEvent(RewardChests.Elite, GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, (...args) => removeVisualSpell(...args));
|
||||
|
||||
RegisterGameObjectEvent(RewardChests.Badass, GameObjectEvents.GAMEOBJECT_EVENT_ON_SPAWN, (...args) => showVisualSpell(...args));
|
||||
RegisterGameObjectEvent(RewardChests.Badass,GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, (...args) => removeVisualSpell(...args));
|
||||
Reference in New Issue
Block a user