You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13027 lines
499 KiB

--Plater main software file
--Calls with : are functions imported from the framework
--whenever a variable or function has a --private comment attached to it, means scripts cannot access it (read, write, override), anything else can be overriden with scripts
--with that, you can make your own version of Plater by modifying and overriding functions entirelly using a hooking script, them you can export the script and upload to wago.io (have fun :)
--check the list of available functions and members to override at 'Plater.CanOverride_Functions' and 'Plater.CanOverride_Members'
--Weakauras Scripters: if you need to attach something to Plater nameplates:
-- local namePlate = C_NamePlate.GetNamePlateForUnit (unitID)
-- local unitFrame = namePlate.unitFrame --unitFrame is the main frame where all things is attached, it has SetAllPoints() on the namePlate frame.
-- local healthBar = unitFrame.healthBar
-- local castBar = unitFrame.castBar
-- navigate within the code using search tags: ~color ~border, etc...
if (true) then
--return
--but not today
end
--> details! framework
local DF = _G ["DetailsFramework"]
if (not DF) then
print ("|cFFFFAA00Plater: framework not found, if you just installed or updated the addon, please restart your client.|r")
return
end
--/run UIErrorsFrame:HookScript ("OnEnter", function() UIErrorsFrame:EnableMouse (false);Plater:Msg("UIErrorsFrame had MouseEnabled, its disabled now.") end)
--> some WA or addon are enabling the mouse on the error frame making nameplates unclickable
if (UIErrorsFrame) then
UIErrorsFrame:HookScript ("OnEnter", function()
--safe disable the mouse on error frame avoiding mouse interactions and warn the user
UIErrorsFrame:EnableMouse (false)
Plater:Msg ("something enabled the mouse on UIErrorsFrame, Plater disabled.")
end)
UIErrorsFrame:EnableMouse (false)
end
--> blend nameplates with the worldframe
local AlphaBlending = ALPHA_BLEND_AMOUNT + 0.0654785
--> locals
local unpack = unpack
local ipairs = ipairs
local rawset = rawset
local rawget = rawget
local setfenv = setfenv
local pcall = pcall
local InCombatLockdown = InCombatLockdown
local UnitIsPlayer = UnitIsPlayer
local UnitClassification = UnitClassification
local UnitDetailedThreatSituation = UnitDetailedThreatSituation
local UnitCanAttack = UnitCanAttack
local IsSpellInRange = IsSpellInRange
local abs = math.abs
local format = string.format
local GetSpellInfo = GetSpellInfo
local UnitIsUnit = UnitIsUnit
local type = type
local select = select
local UnitGUID = UnitGUID
local strsplit = strsplit
local lower = string.lower
local floor = floor
local max = math.max
local min = math.min
local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
local IS_WOW_PROJECT_CLASSIC_ERA = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
local IS_WOW_PROJECT_CLASSIC_WRATH = IS_WOW_PROJECT_NOT_MAINLINE and ClassicExpansionAtLeast and LE_EXPANSION_WRATH_OF_THE_LICH_KING and ClassicExpansionAtLeast(LE_EXPANSION_WRATH_OF_THE_LICH_KING)
local PixelUtil = PixelUtil or DFPixelUtil
local LibSharedMedia = LibStub:GetLibrary ("LibSharedMedia-3.0") -- https://www.curseforge.com/wow/addons/libsharedmedia-3-0
local LCG = LibStub:GetLibrary("LibCustomGlow-1.0") -- https://github.com/Stanzilla/LibCustomGlow
local LibRangeCheck = LibStub:GetLibrary ("LibRangeCheck-2.0") -- https://www.curseforge.com/wow/addons/librangecheck-2-0/
local LibTranslit = LibStub:GetLibrary ("LibTranslit-1.0") -- https://github.com/Vardex/LibTranslit
local LDB = LibStub ("LibDataBroker-1.1", true)
local LDBIcon = LDB and LibStub ("LibDBIcon-1.0", true)
local _
local Plater = DF:CreateAddOn ("Plater", "PlaterDB", PLATER_DEFAULT_SETTINGS, InterfaceOptionsFrame and { --options table --TODO: DISABLED FOR DRAGONFLIGHT FOR NOW!
name = "Plater Nameplates",
type = "group",
args = {
openOptions = {
name = "Open Plater Options",
desc = "Opens the Plater Options Menu.",
type = "execute",
func = function()
if InterfaceOptionsFrame then
InterfaceOptionsFrame:Hide()
elseif SettingsPanel then
SettingsPanel:Hide()
end
HideUIPanel(GameMenuFrame)
Plater.OpenOptionsPanel()
end,
},
}
})
Plater.versionString = GetAddOnMetadata("Plater_dev", "Version") or GetAddOnMetadata("Plater", "Version")
Plater.fullVersionInfo = Plater.versionString .. " - DF v" .. select(2,LibStub:GetLibrary("DetailsFramework-1.0")) .. " - " .. GetBuildInfo()
function Plater.GetVersionInfo(printOut)
-- update, just in case...
Plater.versionString = GetAddOnMetadata("Plater_dev", "Version") or GetAddOnMetadata("Plater", "Version")
Plater.fullVersionInfo = Plater.versionString .. " - DF v" .. select(2,LibStub:GetLibrary("DetailsFramework-1.0")) .. " - " .. GetBuildInfo()
if printOut then print("Plater version info:\n" .. Plater.fullVersionInfo) end
return Plater.fullVersionInfo
end
--> when a hook script is compiled, it increases the build version, so the handler for running scripts will notice in the change and update the script in real time
local PLATER_HOOK_BUILD = 1
function Plater.IncreaseHookBuildID() --private
PLATER_HOOK_BUILD = PLATER_HOOK_BUILD + 1
end
--> if a widget has a RefreshID lower than the addon, it needs to be updated
local PLATER_REFRESH_ID = 1
function Plater.IncreaseRefreshID() --private
PLATER_REFRESH_ID = PLATER_REFRESH_ID + 1
Plater.IncreaseRefreshID_Auras()
end
--> namespaces:
--resources
Plater.Resources = {}
Plater.Auras = {}
--store npcIds for npcs which flood the screen with nameplates and can be quickly processed
--search .isPerformanceUnit for locations where there code for improve performance
--unitFrame.isPerformanceUnit healthBar.isPerformanceUnit
Plater.PerformanceUnits = {
--[189706] = true, --chaotic essence (shadowlands season 4 raid affixes) --this is only one single orb which casts. no need for performance
[189707] = true, --chaotic essence (shadowlands season 4 raid affixes) --these are the multiple spawns from the above
[167999] = true, --Echo of Sin (shadowlands, Castle Nathria, Sire Denathrius)
[176920] = true, --Domination Arrow (shadowlands, Sanctum of Domination, Sylvanas)
}
--setter
Plater.AddPerformanceUnits = function (npcID)
if type(npcID) == "number" then
Plater.PerformanceUnits[npcID] = true
end
end
Plater.RemovePerformanceUnits = function (npcID)
if type(npcID) == "number" then
Plater.PerformanceUnits[npcID] = nil
end
end
Plater.ForceBlizzardNameplateUnits = {
--
}
Plater.AddForceBlizzardNameplateUnits = function(npcID)
if type(npcID) == "number" then
Plater.ForceBlizzardNameplateUnits[npcID] = true
end
end
Plater.RemoveForceBlizzardNameplateUnits = function(npcID)
if type(npcID) == "number" then
Plater.ForceBlizzardNameplateUnits[npcID] = nil
end
end
--all functions below can be overridden by scripts, hooks or any external code
--this allows the user to fully modify Plater at a high level
--how to override a function:
--create a script in the hooking tab, add a 'Constructor' and a 'Nameplate Created'
--copy the entire function from this file and paste in the constructor, hit save.
--then when the first nameplate appears in the screen the function get rewritten
--for fast debugging is recomended to paste the function in a 'Nameplate Updated' hook so just by saving the script (SHIFT + ENTER) you get the function to update immediately.
Plater.CanOverride_Functions = {
RefreshDBUpvalues = true, --refresh cache
RefreshDBLists = true, --refresh cache
UpdateAuraCache = true, --refresh cache
CreateShowAuraIconAnimation = true, --creates the animation for aura icons played when they are shown
GetHealthCutoffValue = true, --check if the character has a execute range and enable or disable the health cut off indicators
CheckRange = true, --check if the player is in range of the unit
GetSpellForRangeCheck = true, --get a spell to be used in the range check
SetFontOutlineAndShadow = true, --apply the outline and shadow of a text
UpdatePersonalBar = true, --update the personal bar
UpdateResourceFrame = true, --anchors the resource frame (soul shards, combo points, etc)
UpdateCastbarTargetText = true, --update the settings of the cast target (font color, size, etc)
UpdateSpellNameSize = true, --receive a fontString and set the length of the spell name size in the cast bar
QuickHealthUpdate = true, --update the health bar during NAMEPLATE_ADDED
OnUpdateHealth = true, --when the healthbar get a new health value
OnUpdateHealthMax = true, --when the maxhealth of the healthbar get updated
UpdateIconAspecRatio = true, --adjust the icon texcoords depending on its size
FormatTime = true, --get a number and return it formated into time, e.g. 63 return "1m" 1 minute
FormatTimeDecimal = true, --get a number and return it formated into time with decimals below 10sec, e.g. 9.5 return "9.5s"
GetAuraIcon = true, --return an icon to be use to show an aura
AddAura = true, --adds an aura into the nameplate, require all the aura data and an icon
AddExtraIcon = true, --adds an aura into the extra buff row of icons, require the aura data
HideNonUsedAuraIcons = true, --after an aura refresh, hide all non used icons in the aura container
ResetAuraContainer = true, --reset the aura container to be ready to a refresh
TrackSpecificAuras = true, --refresh the aura container using a list of auras to track
UpdateAuras_Manual = true, --start an aura refresh for manual aura tracking
UpdateAuras_Automatic = true, --start an aura refresh for automatic aura tracking
UpdateAuras_Self_Automatic = true, --start an aura refresh on the personal bar nameplate
ColorOverrider = true, --control which color que nameplate will have when the Override Default Colors are enabled
FindAndSetNameplateColor = true, --Plater tries to find a color for the nameplate
SetTextColorByClass = true, --adds the class color into a text with scape sequence
UpdatePlateSize = true, --control the size of health, cast, power bars
SetPlateBackground = true, --set the backdrop when showing the nameplate area
UpdateNameplateThread = true, --change the nameplate color based on threat
UpdateTargetHighlight = true, --adjust the highlight on the player target nameplate
UpdateTargetIndicator = true, --adjust the target indicator on the player target nameplate
UpdateLifePercentVisibility = true, --control when the life percent text is shown
UpdateLifePercentText = true, --update the health shown in the nameplate
AddGuildNameToPlayerName = true, --adds the guild name into the player name
UpdateUnitName = true, --update the unit name
UpdateUnitNameTextSize = true, --controls the length of the unit name text
UpdateBorderColor = true, --update the color of the border
UpdatePlateBorderThickness = true, --adjust how thick is the border around the health bar
UpdatePlateRaidMarker = true, --update the raid marker in the nameplate
UpdateIndicators = true, --check which indicators will be shown in the nameplate (rare, elite, etc)
AddIndicator = true, --adds an indicator
ClearIndicators = true, --clear all indicators in the nameplate
GetPlateAlpha = true, --get the absolute alpha amount for the nameplate (when in range)
CheckHighlight = true, --check if the mouse is over the nameplate and show the highlight
EnableHighlight = true, --enable the highlight check
DisableHighlight = true, --disable the highlight check
GetUnitType = true, --return if an unit is a pet, minor or regular
AnimateLeftWithAccel = true, --move the health bar to left when health animation is enabled
AnimateRightWithAccel = true, --move the health bar to right when health animation is enabled
IsQuestObjective = true, --check if the npc from the nameplate is a quest mob
}
--store functions and members which can be overridden by scripts
Plater.CanOverride_Members = {
TargetIndicators = true, --table with all options for target indicators
TargetHighlights = true, --table with all options for target highlight
SparkTextures = true, --table with all textures available for castbar sparks
CooldownEdgeTextures = true, --table with all textures available for cooldown edges
AurasHorizontalPadding = true, --space in pixels between each row of buffs
WideIconCoords = true, --used on buff special icons, are the texcoordinates when using wide icons
BorderLessIconCoords = true, --used on buff special icons, when not using wide icons
PlayerIsTank = true, --for aggro checks, if true the function will consider the player as tank
CombatTime = true, --GetTime() of when the player entered in combat, affect aggro animations
CurrentEncounterID = true, --store the current encounter ID if in combat and fighiting a boss
LatestEncounter = true, --store time() from the latest ENCOUNTER_END
ZoneInstanceType = true, --from GetInstanceInfo zone type, can be party, raid, arena, pvp, none
ZonePvpType = true, --from GetZonePVPInfo
PlayerGuildName = true, --name of the player's guild
SpellForRangeCheck = true, --spell name used for range check
PlayerGUID = true, --store the GUID of the player
PlayerClass = true, --store the name for the player (non localized)
}
--store npc names and spell names from the current/latest combat
--used to sort data in the options panel: Spell List, Spell Colors and Npc Colors
Plater.LastCombat = {
npcNames = {},
spellNames = {},
}
--store spell cache. spell cache is loaded when adding new auras to track
Plater.SpellHashTable = {}
Plater.SpellIndexTable = {}
--> export strings identification
Plater.Export_CastColors = "CastColor"
Plater.Export_NpcColors = "NpcColor"
--> types of codes for each script in the Scripting tab (do not change these inside scripts)
Plater.CodeTypeNames = { --private
[1] = "UpdateCode",
[2] = "ConstructorCode",
[3] = "OnHideCode",
[4] = "OnShowCode",
[5] = "Initialization",
}
--hook options
--> types of codes available to add in a script in the Hooking tab
Plater.HookScripts = { --private
"Initialization",
"Deinitialization",
"Constructor",
"Destructor",
"Nameplate Created",
"Nameplate Added",
"Nameplate Removed",
"Nameplate Updated",
"Cast Start",
"Cast Update",
"Cast Stop",
"Target Changed",
"Raid Target",
"Enter Combat",
"Leave Combat",
"Player Power Update",
"Player Talent Update",
"Health Update",
"Zone Changed",
"Name Updated",
"Load Screen",
"Player Logon",
"Receive Comm Message",
"Send Comm Message",
}
Plater.HookScriptsDesc = { --private
["Initialization"] = "Executed once for the mod every time it is loaded or compiled. Used to initialize the global mod environment 'modTable'.",
["Deinitialization"] = "Executed once for the mod every time it is unloaded. Used to de-initialize the global mod environment 'modTable' and the mod.",
["Constructor"] = "Executed once when the nameplate run the hook for the first time.\n\nUse to initialize configs in the environment.\n\nAlways receive unitFrame in 'self' parameter.",
["Destructor"] = "Run when the hook is Disabled or unloaded due to Load Conditions.\n\nUse to hide all frames created.\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Nameplate Created"] = "Executed when a nameplate is created.\n\nRequires a |cFFFFFF22/reload|r after changing the code.",
["Nameplate Added"] = "Run after a nameplate is added to the screen.",
["Nameplate Removed"] = "Run when the nameplate is removed from the screen.",
["Nameplate Updated"] = "Run after the nameplate gets an updated from Plater.\n\n|cFFFFFF22Important:|r doesn't run every frame.",
["Cast Start"] = "When the unit starts to cast a spell.\n\n|cFFFFFF22self|r is unitFrame.castBar",
["Cast Update"] = "When the cast bar receives an update from Plater.\n\n|cFFFFFF22Important:|r doesn't run every frame.\n\n|cFFFFFF22self|r is unitFrame.castBar",
["Cast Stop"] = "When the cast is finished for any reason or the nameplate has been removed from the screen.\n\n|cFFFFFF22self|r is unitFrame.castBar",
["Target Changed"] = "Run after the player selects a new target.\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Raid Target"] = "A raid target mark has added, modified or removed (skull, cross, etc).\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Enter Combat"] = "Executed shortly after the player enter combat.\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Leave Combat"] = "Executed shortly after the player leave combat.\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Player Power Update"] = "Run when the player power, such as combo points, gets an update.\n\n|cFF44FF44Run only on the nameplate of your current target|r.",
["Player Talent Update"] = "When the player changes a talent or specialization.\n\n|cFF44FF44Run on all nameplates shown in the screen|r.",
["Health Update"] = "When the health of the unit changes.",
["Zone Changed"] = "Run when the player enter into a new zone.\n\n|cFF44FF44Run on all nameplates already created, on screen or not|r.",
["Name Updated"] = "Executed when the name of the unit shown in the nameplate receives an update.",
["Load Screen"] = "Run when a load screen finishes.\n\nUse to change settings for a specific area or map.\n\n|cFF44FF44Do not run on nameplates|r.",
["Player Logon"] = "Run when the player login into the game.\n\nUse to register textures, indicators, etc.\n\n|cFF44FF44Do not run on nameplates,\nrun only once after login\nor /reload|r.",
["Receive Comm Message"] = "Executed when a comm is received, a comm can be sent using Plater.SendComm(payload) in 'Send Comm Message' hook.",
["Send Comm Message"] = "Executed on an internal timer for each mod. Used to send comm data via Plater.SendComm(payload).",
}
-- ~hook (hook scripts are cached in the indexed part of these tales, for performance the member ScriptAmount caches the amount of scripts inside the indexed table)
local HOOK_NAMEPLATE_ADDED = {ScriptAmount = 0}
local HOOK_NAMEPLATE_CREATED = {ScriptAmount = 0}
local HOOK_NAMEPLATE_REMOVED = {ScriptAmount = 0}
local HOOK_NAMEPLATE_UPDATED = {ScriptAmount = 0}
local HOOK_TARGET_CHANGED = {ScriptAmount = 0}
local HOOK_CAST_START = {ScriptAmount = 0}
local HOOK_CAST_UPDATE = {ScriptAmount = 0}
local HOOK_CAST_STOP = {ScriptAmount = 0}
local HOOK_RAID_TARGET = {ScriptAmount = 0}
local HOOK_COMBAT_ENTER = {ScriptAmount = 0}
local HOOK_COMBAT_LEAVE = {ScriptAmount = 0}
local HOOK_NAMEPLATE_CONSTRUCTOR = {ScriptAmount = 0}
local HOOK_PLAYER_POWER_UPDATE = {ScriptAmount = 0}
local HOOK_PLAYER_TALENT_UPDATE = {ScriptAmount = 0}
local HOOK_HEALTH_UPDATE = {ScriptAmount = 0}
local HOOK_ZONE_CHANGED = {ScriptAmount = 0}
local HOOK_UNITNAME_UPDATE = {ScriptAmount = 0}
local HOOK_LOAD_SCREEN = {ScriptAmount = 0}
local HOOK_PLAYER_LOGON = {ScriptAmount = 0}
local HOOK_MOD_INITIALIZATION = {ScriptAmount = 0}
local HOOK_MOD_DEINITIALIZATION = {ScriptAmount = 0}
local HOOK_COMM_RECEIVED_MESSAGE = {ScriptAmount = 0}
local HOOK_COMM_SEND_MESSAGE = {ScriptAmount = 0}
local HOOK_NAMEPLATE_DESTRUCTOR = {ScriptAmount = 0}
local PLATER_GLOBAL_MOD_ENV = {} -- contains modEnv for each mod, identified by "<mod name>"
local PLATER_GLOBAL_SCRIPT_ENV = {} -- contains modEnv for each script, identified by "<script name>"
--> addon comm
Plater.COMM_PLATER_PREFIX = "PLT"
Plater.COMM_SCRIPT_GROUP_EXPORTED = "GE"
Plater.COMM_SCRIPT_MSG = "PLTM"
--> cvars just to make them easier to read
local CVAR_ENABLED = "1"
local CVAR_DISABLED = "0"
--> unit reaction (saved 3 global locals)
Plater.UnitReaction = {
UNITREACTION_HOSTILE = 3,
UNITREACTION_NEUTRAL = 4,
UNITREACTION_FRIENDLY = 5,
}
--> cache some common used member strings for better reading
local MEMBER_UNITID = "namePlateUnitToken"
local MEMBER_GUID = "namePlateUnitGUID"
local MEMBER_NPCID = "namePlateNpcId"
local MEMBER_QUEST = "namePlateIsQuestObjective"
local MEMBER_REACTION = "namePlateUnitReaction"
local MEMBER_RANGE = "namePlateInRange"
local MEMBER_NOCOMBAT = "namePlateNoCombat"
local MEMBER_NAME = "namePlateUnitName"
local MEMBER_NAMELOWER = "namePlateUnitNameLower"
local MEMBER_TARGET = "namePlateIsTarget"
--> cache nameplate types for better reading the code
local ACTORTYPE_FRIENDLY_PLAYER = "friendlyplayer"
local ACTORTYPE_FRIENDLY_NPC = "friendlynpc"
local ACTORTYPE_ENEMY_PLAYER = "enemyplayer"
local ACTORTYPE_ENEMY_NPC = "enemynpc"
local ACTORTYPE_PLAYER = "player"
--these tables store all bars created by boss mods
Plater.BossModsTimeBarDBM = {}
Plater.BossModsTimeBarBW = {}
--> icon texcoords
Plater.WideIconCoords = {.1, .9, .1, .6} --used in extra icons frame, constant, can be changed with scripts
Plater.BorderLessIconCoords = {.1, .9, .1, .9} --used in extra icons frame,constant, can be changed with scripts
--note: regular icons has their texcoords automatically adjusted
--> limit the cast bar text to this (this is dynamically adjusted at run time)
Plater.MaxCastBarTextLength = nil -- global overwrite
--> auras
Plater.MaxAurasPerRow = 10 --can change during runtime
--> textures used in the cooldown animation, scripts can add more values to it, profile holds only the path to it
Plater.CooldownEdgeTextures = {
[[Interface\AddOns\Plater\images\cooldown_edge_1]],
[[Interface\AddOns\Plater\images\cooldown_edge_2]],
"Interface\\Cooldown\\edge",
"Interface\\Cooldown\\edge-LoC",
"Interface\\GLUES\\loadingOld",
}
--> textures used in the castbar, scripts can add more values to it, profile holds only the path to it
Plater.SparkTextures = {
[[Interface\AddOns\Plater\images\spark1]],
[[Interface\AddOns\Plater\images\spark2]],
[[Interface\AddOns\Plater\images\spark3]],
[[Interface\AddOns\Plater\images\spark4]],
[[Interface\AddOns\Plater\images\spark5]],
[[Interface\AddOns\Plater\images\spark6]],
[[Interface\AddOns\Plater\images\spark7]],
[[Interface\AddOns\Plater\images\spark8]],
}
--> textures used to indicate which nameplate is the current target, scripts can add more values to it, profile holds only the path to it
Plater.TargetHighlights = {
[[Interface\AddOns\Plater\images\selection_indicator1]],
[[Interface\AddOns\Plater\images\selection_indicator2]],
[[Interface\AddOns\Plater\images\selection_indicator3]],
[[Interface\AddOns\Plater\images\selection_indicator4]],
[[Interface\AddOns\Plater\images\selection_indicator5]],
[[Interface\AddOns\Plater\images\selection_indicator6]],
[[Interface\AddOns\Plater\images\selection_indicator7]],
[[Interface\AddOns\Plater\images\selection_indicator8]],
}
--> icons available for any purpose
Plater.Media = {
Icons = {
[[Interface\AddOns\Plater\media\arrow_apple_64]],
[[Interface\AddOns\Plater\media\arrow_double_right_64]],
[[Interface\AddOns\Plater\media\arrow_right_64]],
[[Interface\AddOns\Plater\media\arrow_simple_right_64]],
[[Interface\AddOns\Plater\media\arrow_single_right_64]],
[[Interface\AddOns\Plater\media\arrow_thin_right_64]],
[[Interface\AddOns\Plater\media\blocked_center_64]],
[[Interface\AddOns\Plater\media\crown_64]],
[[Interface\AddOns\Plater\media\drop_64]],
[[Interface\AddOns\Plater\media\duck_64]],
[[Interface\AddOns\Plater\media\exclamation_64]],
[[Interface\AddOns\Plater\media\exclamation2_64]],
[[Interface\AddOns\Plater\media\fire_64]],
[[Interface\AddOns\Plater\media\glasses_64]],
[[Interface\AddOns\Plater\media\glow_horizontal_256]],
[[Interface\AddOns\Plater\media\glow_radial_128]],
[[Interface\AddOns\Plater\media\glow_square_64]],
[[Interface\AddOns\Plater\media\hat_64]],
[[Interface\AddOns\Plater\media\heart_center_64]],
[[Interface\AddOns\Plater\media\line_horizontal_256]],
[[Interface\AddOns\Plater\media\line_vertical_256]],
[[Interface\AddOns\Plater\media\radio_64]],
[[Interface\AddOns\Plater\media\skullbones_64]],
[[Interface\AddOns\Plater\media\stop_64]],
[[Interface\AddOns\Plater\media\star_empty_64]],
[[Interface\AddOns\Plater\media\star_full_64]],
[[Interface\AddOns\Plater\media\x_64]],
[[Interface\AddOns\Plater\media\checked_64]],
[[Interface\AddOns\Plater\media\sphere_full_64]],
[[Interface\AddOns\Plater\media\eye_64]],
[[Interface\AddOns\Plater\media\cross_64]],
},
}
--> these are the images shown in the nameplate of the current target, they are placed in the left and right side of the health bar, scripts can add more options
--> if the coords has 2 tables, it uses two textures attach in the left and right sides of the health bar
--> if the coords has 4 tables, it uses 4 textures attached in top left, bottom left, top right and bottom right corners
Plater.TargetIndicators = {
["NONE"] = {
path = [[Interface\ACHIEVEMENTFRAME\UI-Achievement-WoodBorder-Corner]],
coords = {{.9, 1, .9, 1}, {.9, 1, .9, 1}, {.9, 1, .9, 1}, {.9, 1, .9, 1}}, --texcoords, support 4 or 8 coords method
desaturated = false,
width = 10,
height = 10,
x = 1, --offset
y = 1, --offset
},
["Magneto"] = {
path = [[Interface\Artifacts\RelicIconFrame]],
coords = {{0, .5, 0, .5}, {0, .5, .5, 1}, {.5, 1, .5, 1}, {.5, 1, 0, .5}},
desaturated = false,
width = 8,
height = 10,
autoScale = true,
--scale = 1,
x = 2,
y = 2,
},
["Gray Bold"] = {
path = [[Interface\ContainerFrame\UI-Icon-QuestBorder]],
coords = {{0, .5, 0, .5}, {0, .5, .5, 1}, {.5, 1, .5, 1}, {.5, 1, 0, .5}},
desaturated = true,
width = 10,
height = 10,
autoScale = true,
--scale = 1,
x = 2,
y = 2,
},
["Pins"] = {
path = [[Interface\ITEMSOCKETINGFRAME\UI-ItemSockets]],
coords = {{145/256, 161/256, 3/256, 19/256}, {145/256, 161/256, 19/256, 3/256}, {161/256, 145/256, 19/256, 3/256}, {161/256, 145/256, 3/256, 19/256}},
desaturated = 1,
width = 4,
height = 4,
autoScale = false,
--scale = 1,
x = 2,
y = 2,
},
["Silver"] = {
path = [[Interface\PETBATTLES\PETBATTLEHUD]],
coords = {
{848/1024, 868/1024, 454/512, 474/512},
{848/1024, 868/1024, 474/512, 495/512},
{868/1024, 889/1024, 474/512, 495/512},
{868/1024, 889/1024, 454/512, 474/512}
}, --848 889 454 495
desaturated = false,
width = 6,
height = 6,
autoScale = true,
--scale = 1,
x = 1,
y = 1,
},
["Ornament"] = {
path = [[Interface\PETBATTLES\PETJOURNAL]],
coords = {
{124/512, 161/512, 71/1024, 99/1024},
{119/512, 156/512, 29/1024, 57/1024}
},
desaturated = false,
width = 18,
height = 12,
wscale = 1,
hscale = 1.2,
autoScale = true,
--scale = 1,
x = 14,
y = 0,
},
["Golden"] = {
path = [[Interface\Artifacts\Artifacts]],
coords = {
{137/1024, (137+29)/1024, 920/1024, 978/1024},
{(137+30)/1024, 195/1024, 920/1024, 978/1024},
},
desaturated = false,
width = 8,
height = 12,
wscale = 1,
hscale = 1.2,
autoScale = true,
--scale = 1,
x = 0,
y = 0,
},
["Ornament Gray"] = {
path = [[Interface\Challenges\challenges-besttime-bg]],
coords = {
{89/512, 123/512, 0, 1},
{123/512, 89/512, 0, 1},
},
desaturated = false,
width = 8,
height = 12,
alpha = 0.7,
wscale = 1,
hscale = 1.2,
autoScale = true,
--scale = 1,
x = 0,
y = 0,
color = "red",
},
["Epic"] = {
path = [[Interface\UNITPOWERBARALT\WowUI_Horizontal_Frame]],
coords = {
{30/256, 40/256, 15/64, 49/64},
{40/256, 30/256, 15/64, 49/64},
},
desaturated = false,
width = 6,
height = 12,
wscale = 1,
hscale = 1.2,
autoScale = true,
--scale = 1,
x = 3,
y = 0,
blend = "ADD",
},
}
--> which specs each class has available
Plater.SpecList = { --private
["DEMONHUNTER"] = {
[577] = true,
[581] = true,
},
["DEATHKNIGHT"] = {
[250] = true,
[251] = true,
[252] = true,
},
["WARRIOR"] = {
[71] = true,
[72] = true,
[73] = true,
},
["MAGE"] = {
[62] = true,
[63] = true,
[64] = true,
},
["ROGUE"] = {
[259] = true,
[260] = true,
[261] = true,
},
["DRUID"] = {
[102] = true,
[103] = true,
[104] = true,
[105] = true,
},
["HUNTER"] = {
[253] = true,
[254] = true,
[255] = true,
},
["SHAMAN"] = {
[262] = true,
[263] = true,
[264] = true,
},
["PRIEST"] = {
[256] = true,
[257] = true,
[258] = true,
},
["WARLOCK"] = {
[265] = true,
[266] = true,
[267] = true,
},
["PALADIN"] = {
[65] = true,
[66] = true,
[70] = true,
},
["MONK"] = {
[268] = true,
[269] = true,
[270] = true,
},
["EVOKER"] = {
[1467] = true,
[1468] = true,
},
}
--> default ranges to use in the range check proccess against enemies, player can select a different range in the options panel
Plater.DefaultSpellRangeList = {
--classes
[1] = 10, --Warrior
[2] = 30, --Paladin
[3] = 30, --Hunter
[4] = 10, --Rogue
[5] = 30, --Priest
[6] = 10, --DeathKnight
[7] = 30, --Shaman
[8] = 30, --Mage
[9] = 30, --Warlock
[10] = 10, --Monk
[11] = 30, --Druid
[12] = 10, --DH
[577] = 30, --> havoc demon hunter
[581] = 30, --> vengeance demon hunter
[250] = 30, --> blood dk
[251] = 30, --> frost dk
[252] = 30, --> unholy dk
[102] = 45, --> druid balance
[103] = 40, --> druid feral
[104] = 30, --> druid guardian
[105] = 40, --> druid resto
[253] = 40, --> hunter bm - Cobra Shot
[254] = 40, --> hunter marks - Aimed Shot
[255] = 40, --> hunter survivor - Serpent Sting
[62] = 40, --> mage arcane
[63] = 40, --> mage fire
[64] = 40, --> mage frost
[268] = 30 , --> monk bm
[269] = 40, --> monk ww
[270] = 40, --> monk mw
[65] = 40, --> paladin holy
[66] = 30, --> paladin protect
[70] = 30, --> paladin ret
[256] = 40, --> priest disc
[257] = 40, --> priest holy
[258] = 40, --> priest shadow
[259] = 30, --> rogue assassination
[260] = 20, --> rogue outlaw
[261] = 30, --> rogue sub
[262] = 40, --> shaman elemental
[263] = 40, --> shaman enhancement
[264] = 40, --> shaman resto
[265] = 40, --> warlock aff
[266] = 40, --> warlock demo
[267] = 40, --> warlock destro
[71] = 30, --> warrior arms
[72] = 30, --> warrior fury
[73] = 30, --> warrior protect
-- low-level (without spec)
[1444] = 40, --> Initial SHAMAN
[1446] = 40, --> Initial WARRIOR
[1447] = 40, --> Initial DRUID
[1448] = 40, --> Initial HUNTER
[1449] = 40, --> Initial MAGE
[1450] = 40, --> Initial MONK
[1451] = 40, --> Initial PALADIN
[1452] = 40, --> Initial PRIEST
[1453] = 40, --> Initial ROGUE
[1454] = 40, --> Initial WARLOCK
[1455] = 40, --> Initial DK
[1456] = 40, --> Initial DH
}
--> default ranges to use in the range check proccess against friendlies, player can select a different range in the options panel
Plater.DefaultSpellRangeListF = {
--classes
[1] = 30, --Warrior
[2] = 40, --Paladin
[3] = 40, --Hunter
[4] = 30, --Rogue
[5] = 40, --Priest
[6] = 30, --DeathKnight
[7] = 40, --Shaman
[8] = 40, --Mage
[9] = 40, --Warlock
[10] = 40, --Monk
[11] = 40, --Druid
[12] = 30, --DH
[577] = 30, --> havoc demon hunter
[581] = 30, --> vengeance demon hunter
[250] = 30, --> blood dk
[251] = 30, --> frost dk
[252] = 30, --> unholy dk
[102] = 45, --> druid balance
[103] = 40, --> druid feral
[104] = 30, --> druid guardian
[105] = 40, --> druid resto
[253] = 40, --> hunter bm - Cobra Shot
[254] = 40, --> hunter marks - Aimed Shot
[255] = 40, --> hunter survivor - Serpent Sting
[62] = 40, --> mage arcane
[63] = 40, --> mage fire
[64] = 40, --> mage frost
[268] = 30 , --> monk bm
[269] = 40, --> monk ww
[270] = 40, --> monk mw
[65] = 40, --> paladin holy
[66] = 30, --> paladin protect
[70] = 30, --> paladin ret
[256] = 40, --> priest disc
[257] = 40, --> priest holy
[258] = 40, --> priest shadow
[259] = 30, --> rogue assassination
[260] = 20, --> rogue outlaw
[261] = 30, --> rogue sub
[262] = 40, --> shaman elemental
[263] = 40, --> shaman enhancement
[264] = 40, --> shaman resto
[265] = 40, --> warlock aff
[266] = 40, --> warlock demo
[267] = 40, --> warlock destro
[71] = 30, --> warrior arms
[72] = 30, --> warrior fury
[73] = 30, --> warrior protect
-- low-level (without spec)
[1444] = 40, --> Initial SHAMAN
[1446] = 40, --> Initial WARRIOR
[1447] = 40, --> Initial DRUID
[1448] = 40, --> Initial HUNTER
[1449] = 40, --> Initial MAGE
[1450] = 40, --> Initial MONK
[1451] = 40, --> Initial PALADIN
[1452] = 40, --> Initial PRIEST
[1453] = 40, --> Initial ROGUE
[1454] = 40, --> Initial WARLOCK
[1455] = 40, --> Initial DK
[1456] = 40, --> Initial DH
}
local class_specs_coords = {
[577] = {128/512, 192/512, 256/512, 320/512}, --> havoc demon hunter
[581] = {192/512, 256/512, 256/512, 320/512}, --> vengeance demon hunter
[250] = {0, 64/512, 0, 64/512}, --> blood dk
[251] = {64/512, 128/512, 0, 64/512}, --> frost dk
[252] = {128/512, 192/512, 0, 64/512}, --> unholy dk
[102] = {192/512, 256/512, 0, 64/512}, --> druid balance
[103] = {256/512, 320/512, 0, 64/512}, --> druid feral
[104] = {320/512, 384/512, 0, 64/512}, --> druid guardian
[105] = {384/512, 448/512, 0, 64/512}, --> druid resto
[253] = {448/512, 512/512, 0, 64/512}, --> hunter bm
[254] = {0, 64/512, 64/512, 128/512}, --> hunter marks
[255] = {64/512, 128/512, 64/512, 128/512}, --> hunter survivor
[62] = {(128/512) + 0.001953125, 192/512, 64/512, 128/512}, --> mage arcane
[63] = {192/512, 256/512, 64/512, 128/512}, --> mage fire
[64] = {256/512, 320/512, 64/512, 128/512}, --> mage frost
[268] = {320/512, 384/512, 64/512, 128/512}, --> monk bm
[269] = {448/512, 512/512, 64/512, 128/512}, --> monk ww
[270] = {384/512, 448/512, 64/512, 128/512}, --> monk mw
[65] = {0, 64/512, 128/512, 192/512}, --> paladin holy
[66] = {64/512, 128/512, 128/512, 192/512}, --> paladin protect
[70] = {(128/512) + 0.001953125, 192/512, 128/512, 192/512}, --> paladin ret
[256] = {192/512, 256/512, 128/512, 192/512}, --> priest disc
[257] = {256/512, 320/512, 128/512, 192/512}, --> priest holy
[258] = {(320/512) + (0.001953125 * 4), 384/512, 128/512, 192/512}, --> priest shadow
[259] = {384/512, 448/512, 128/512, 192/512}, --> rogue assassination
[260] = {448/512, 512/512, 128/512, 192/512}, --> rogue combat
[261] = {0, 64/512, 192/512, 256/512}, --> rogue sub
[262] = {64/512, 128/512, 192/512, 256/512}, --> shaman elemental
[263] = {128/512, 192/512, 192/512, 256/512}, --> shamel enhancement
[264] = {192/512, 256/512, 192/512, 256/512}, --> shaman resto
[265] = {256/512, 320/512, 192/512, 256/512}, --> warlock aff
[266] = {320/512, 384/512, 192/512, 256/512}, --> warlock demo
[267] = {384/512, 448/512, 192/512, 256/512}, --> warlock destro
[71] = {448/512, 512/512, 192/512, 256/512}, --> warrior arms
[72] = {0, 64/512, 256/512, 320/512}, --> warrior fury
[73] = {64/512, 128/512, 256/512, 320/512}, --> warrior protect
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> cached value ~cache
--Plater allocate several values in memory to save performance (cpu), this may increase memory usage
--example: intead of querying Plater.db.profile.tank it just hold a pointer to that table in the variable DB_AGGRO_TANK_COLORS, and this pointer is updated when the user changes something in the options panel
local DB_NUMBER_REGION_EAST_ASIA
local DB_TICK_THROTTLE
local DB_LERP_COLOR
local DB_LERP_COLOR_SPEED
local DB_PLATE_CONFIG
local DB_HOVER_HIGHLIGHT
local DB_CLASS_COLORS
--auras
local DB_AURA_ENABLED
local DB_AURA_ALPHA
local DB_AURA_SEPARATE_BUFFS
local DB_USE_UIPARENT
local DB_UNITCOLOR_CACHE = {}
local DB_UNITCOLOR_SCRIPT_CACHE = {}
local IS_USING_DETAILS_INTEGRATION
local DB_TRACK_METHOD
local DB_BORDER_COLOR_R
local DB_BORDER_COLOR_G
local DB_BORDER_COLOR_B
local DB_BORDER_COLOR_A
local DB_BORDER_THICKNESS
local DB_AGGRO_CHANGE_HEALTHBAR_COLOR
local DB_AGGRO_CHANGE_NAME_COLOR
local DB_AGGRO_CHANGE_BORDER_COLOR
local DB_AGGRO_CAN_CHECK_NOTANKAGGRO
local DB_TARGET_SHADY_ENABLED
local DB_TARGET_SHADY_ALPHA
local DB_TARGET_SHADY_COMBATONLY
local DB_NAME_NPCENEMY_ANCHOR
local DB_NAME_NPCFRIENDLY_ANCHOR
local DB_NAME_PLAYERENEMY_ANCHOR
local DB_NAME_PLAYERFRIENDLY_ANCHOR
local DB_DO_ANIMATIONS
local DB_ANIMATION_TIME_DILATATION
local DB_USE_RANGE_CHECK
local DB_USE_NON_TARGETS_ALPHA
local DB_USE_FOCUS_TARGET_ALPHA
local DB_USE_ALPHA_FRIENDLIES
local DB_USE_ALPHA_ENEMIES
local DB_USE_QUICK_HIDE
local DB_SHOW_HEALTHBARS_FOR_NOT_ATTACKABLE
local DB_TEXTURE_CASTBAR
local DB_TEXTURE_CASTBAR_BG
local DB_TEXTURE_HEALTHBAR
local DB_TEXTURE_HEALTHBAR_BG
local DB_CASTBAR_HIDE_ENEMIES
local DB_CASTBAR_HIDE_FRIENDLY
local DB_CAPTURED_SPELLS = {}
local DB_CAPTURED_CASTS = {}
--store the aggro color table for tanks and dps
local DB_AGGRO_TANK_COLORS
local DB_AGGRO_DPS_COLORS
--store if the no combat alpha is enabled
local DB_NOT_COMBAT_ALPHA_ENABLED
local DB_USE_HEALTHCUTOFF = false
local DB_HEALTHCUTOFF_AT = 0.2
local DB_HEALTHCUTOFF_AT_UPPER = 0.8
--store translit option
local DB_USE_NAME_TRANSLIT = false
local TRANSLIT_MARK = "*"
--store the npc id cache
local DB_NPCIDS_CACHE = {}
Plater.ScriptAura = {}
local SCRIPT_AURA_TRIGGER_CACHE = Plater.ScriptAura
Plater.ScriptCastBar = {}
local SCRIPT_CASTBAR_TRIGGER_CACHE = Plater.ScriptCastBar
Plater.ScriptUnit = {}
local SCRIPT_UNIT_TRIGGER_CACHE = Plater.ScriptUnit
--spell animations - store a table with information about animation for spells
local SPELL_WITH_ANIMATIONS = {}
--cache this inside plater object to access it from the animation editor
Plater.SPELL_WITH_ANIMATIONS = SPELL_WITH_ANIMATIONS
--store players which have the tank role in the group
local TANK_CACHE = {}
--store pet GUIDs
local PET_CACHE = {}
--store pets summoned by the player it self
Plater.PlayerPetCache = {}
--store if the player is in combat (not reliable, toggled at regen switch)
local PLAYER_IN_COMBAT
--store if the player is not inside an instance
local IS_IN_OPEN_WORLD = true
--store if the player is inside a instance (raid or dungeon)
local IS_IN_INSTANCE = false
--if true, the animation will update its settings before play
local IS_EDITING_SPELL_ANIMATIONS = false
local HOOKED_BLIZZARD_PLATEFRAMES = {}
local ENABLED_BLIZZARD_PLATEFRAMES = {}
local SUPPORT_BLIZZARD_PLATEFRAMES = false
local NUM_NAMEPLATES_ON_SCREEN = 0
local NAMEPLATES_ON_SCREEN_CACHE = {}
local CLASS_INFO_CACHE = {}
--store a list of friendly players in the player friends list
Plater.FriendsCache = {}
--store quests the player is in
Plater.QuestCache = {}
--store only campaign quests
Plater.QuestCacheCampaign = {}
--cache the profile settings for each actor type on this table, so scripts can have access to profile
Plater.ActorTypeSettingsCache = { --private
RefreshID = -1,
--plate holder tables, they will be overriden when updating the cache
[ACTORTYPE_FRIENDLY_PLAYER] = {},
[ACTORTYPE_FRIENDLY_NPC] = {},
[ACTORTYPE_ENEMY_PLAYER] = {},
[ACTORTYPE_ENEMY_NPC] = {},
[ACTORTYPE_PLAYER] = {},
}
Plater.ForceInCombatUnits = {
--[] = true, --
[168326] = true, --Shattered Visage, Mueh'zala De Other Side
[170927] = true, --Erupting Ooze, Doctor Ickus Plaguefall
[171887] = true, --Slimy Smorgasbord, Globgrog Plaguefall
[164362] = true, --Slimy Morsel, Globgrog Plaguefall
[169159] = true, --Unstable Canister, Plaguefall
[168394] = true, --Slimy Morsel, Plaguefall
[176581] = true, --Spiked Ball, Painsmith Raznal SoD
[176920] = true, --Domination Arrow, Sylvanas SoD
[178008] = true, --Decrepit Orb, Sylvanas SoD
[179963] = true, --Terror Orb, Sylvanas SoD
[175861] = true, --Glacial Spike, Kel'Thusad SoD
[182778] = true, --Collapsing Quasar, Rygelon SotFO
[182823] = true, --Cosmic Core, Rygelon SotFO
[183945] = true, --Unstable Matter, Rygelon SotFO
[183745] = true, --Protoform Schematic, Lihuvim SotFO
[188302] = true, --Reconfiguration Emitter, Shadowlands S4 Fated affix
[188703] = true, --Protoform Barrier, Shadowlands S4 Fated affix
[176026] = true, --Dancing Fools, Council of Blood CN
}
--update the settings cache for scritps
--this is a table with a copy of the settings from the profile so can be safelly accessed by scripts
function Plater.UpdateSettingsCache() --private
if (Plater.ActorTypeSettingsCache.RefreshID >= PLATER_REFRESH_ID) then
return
end
local namePlateConfig = Plater.db.profile.plate_config
Plater.ActorTypeSettingsCache [ACTORTYPE_FRIENDLY_PLAYER] = DF.table.copy ({}, namePlateConfig [ACTORTYPE_FRIENDLY_PLAYER])
Plater.ActorTypeSettingsCache [ACTORTYPE_FRIENDLY_NPC] = DF.table.copy ({}, namePlateConfig [ACTORTYPE_FRIENDLY_NPC])
Plater.ActorTypeSettingsCache [ACTORTYPE_ENEMY_PLAYER] = DF.table.copy ({}, namePlateConfig [ACTORTYPE_ENEMY_PLAYER])
Plater.ActorTypeSettingsCache [ACTORTYPE_ENEMY_NPC] = DF.table.copy ({}, namePlateConfig [ACTORTYPE_ENEMY_NPC])
Plater.ActorTypeSettingsCache [ACTORTYPE_PLAYER] = DF.table.copy ({}, namePlateConfig [ACTORTYPE_PLAYER])
Plater.ActorTypeSettingsCache.RefreshID = PLATER_REFRESH_ID
end
function Plater.InitLDB()
if LDB then
local databroker = LDB:NewDataObject ("Plater", {
type = "data source",
icon = [[Interface\AddOns\Plater\images\cast_bar]],
text = "Plater",
HotCornerIgnore = true,
OnClick = function (self, button)
if (button == "LeftButton") then
if (PlaterOptionsPanelFrame and PlaterOptionsPanelFrame:IsShown()) then
PlaterOptionsPanelFrame:Hide()
return true
end
Plater.OpenOptionsPanel()
elseif (button == "RightButton") then
GameTooltip:Hide()
local GameCooltip = GameCooltip2
GameCooltip:Reset()
GameCooltip:SetType ("menu")
GameCooltip:SetOption ("ButtonsYMod", -5)
GameCooltip:SetOption ("HeighMod", 5)
GameCooltip:SetOption ("TextSize", 10)
--> disable minimap icon
local disable_minimap = function()
PlaterDBChr.minimap.hide = not PlaterDBChr.minimap.hide
if (PlaterDBChr.minimap.hide) then
LDBIcon:Hide ("Plater")
else
LDBIcon:Show ("Plater")
end
LDBIcon:Refresh ("Plater", PlaterDBChr.minimap)
end
GameCooltip:AddMenu (1, function() Plater.EnableProfiling(true) end, true, nil, nil, "Start profiling", nil, true)
GameCooltip:AddIcon ([[Interface\Addons\Plater\media\sphere_full_64]], 1, 1, 14, 14, 0, 1, 0, 1, "red")
GameCooltip:AddMenu (1, function() Plater.DisableProfiling() end, true, nil, nil, "Stop profiling", nil, true)
GameCooltip:AddIcon ([[Interface\Addons\Plater\media\square_64]], 1, 1, 14, 14, 0, 1, 0, 1, "blue")
GameCooltip:AddMenu (1, function() Plater.ShowPerfData() end, true, nil, nil, "Show profiling data", nil, true)
GameCooltip:AddIcon ([[Interface\Addons\Plater\media\eye_64]], 1, 1, 14, 14, 0, 1, 0, 1, "green")
GameCooltip:AddLine ("$div")
GameCooltip:AddMenu (1, disable_minimap, true, nil, nil, "Hide/Show Minimap Icon", nil, true)
GameCooltip:AddIcon ([[Interface\Buttons\UI-Panel-HideButton-Disabled]], 1, 1, 14, 14, 7/32, 24/32, 8/32, 24/32, "gray")
--GameCooltip:SetBackdrop (1, _detalhes.tooltip_backdrop, nil, _detalhes.tooltip_border_color)
GameCooltip:SetWallpaper (1, [[Interface\SPELLBOOK\Spellbook-Page-1]], {.6, 0.1, 0.64453125, 0}, {.8, .8, .8, 0.2}, true)
GameCooltip:SetOwner (self, "topright", "bottomleft")
GameCooltip:ShowCooltip()
end
end,
OnTooltipShow = function (tooltip)
tooltip:AddLine ("Plater Nameplates", 1, 1, 1)
tooltip:AddLine ("|cFFCFCFCFLeft click|r: Show/Hide Options Window")
tooltip:AddLine ("|cFFCFCFCFRight click|r: Quick Menu")
end,
})
if (databroker and not LDBIcon:IsRegistered ("Plater")) then
PlaterDBChr.minimap = PlaterDBChr.minimap or {}
LDBIcon:Register ("Plater", databroker, PlaterDBChr.minimap)
end
Plater.databroker = databroker
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> character specific abilities and spells ~spells
-- ~execute
--> update if can use execute indicators - this function needs to be updated when a new execute spell is added, removed, modified
--> in scripts you can use Plater.SetExecuteRange or override this function completelly
function Plater.GetHealthCutoffValue()
Plater.SetExecuteRange (false)
local lowerEnabled, upperEnabled = Plater.db.profile.health_cutoff, Plater.db.profile.health_cutoff_upper
if (not (lowerEnabled or upperEnabled)) then
return
end
local lowExecute, highExecute = nil, nil
if IS_WOW_PROJECT_MAINLINE then
--retail
local classLoc, class = UnitClass ("player")
local spec = GetSpecialization()
if (spec and class) then
if (class == "PRIEST") then
-- SW:D is available to all priest specs
if IsPlayerSpell(32379) then
lowExecute = 0.2
end
elseif (class == "MAGE") then
if IsPlayerSpell(269644) then -- Searing Touch
lowExecute = 0.3
elseif IsPlayerSpell(205026) then --Firestarter
highExecute = 0.9
end
elseif (class == "WARRIOR") then
-- Execute is baseline
if IsPlayerSpell(163201) then
local using_Massacre = IsPlayerSpell(281001) or IsPlayerSpell(206315)
lowExecute = using_Massacre and 0.35 or 0.2
local using_Condemn = IsPlayerSpell(317320)
highExecute = using_Condemn and 0.8 or nil
end
elseif (class == "HUNTER") then
if IsPlayerSpell(53351) then -- Kill Shot
lowExecute = 0.2
if IsPlayerSpell(273887) then --> is using killer instinct?
lowExecute = 0.35
end
if IsPlayerSpell(260228) and upperEnabled then --> Careful Aim
highExecute = 0.7
end
end
elseif (class == "PALADIN") then
-- hammer of wrath
if IsPlayerSpell(24275) then
lowExecute = 0.2
end
elseif (class == "MONK") then
--Touch of Death
if IsPlayerSpell(322109) then
lowExecute = 0.15
end
elseif (class == "WARLOCK") then
if IsPlayerSpell(17877) then --Shadowburn
lowExecute = 0.20
elseif IsPlayerSpell(198590) then --Drain Soul
lowExecute = 0.20
end
elseif (class == "ROGUE") then
if IsPlayerSpell(328085) then --Blindside
lowExecute = 0.35
end
elseif (class == "DEATHKNIGHT") then
if IsPlayerSpell(343294) then --Soul Reaper
lowExecute = 0.35
end
end
end
else
-- WotLK and classic
local classLoc, class = UnitClass ("player")
if (class) then
if (class == "WARRIOR") then
-- Execute
if GetSpellInfo(GetSpellInfo(5308)) then
lowExecute = 0.2
end
elseif (class == "PALADIN") then
-- Hammer of Wrath
if GetSpellInfo(GetSpellInfo(24275)) then
lowExecute = 0.2
end
elseif (class == "WARLOCK") then
-- Decimation
if IsPlayerSpell(63156) or IsPlayerSpell(63158) then
lowExecute = 0.35
else
lowExecute = 0.25
end
elseif (class == "HUNTER") then
-- Kill Shot
if GetSpellInfo(GetSpellInfo(53351)) then
lowExecute = 0.2
end
elseif (class == "PRIEST") then
for i = 1, 6 do
local enabled, _, glyphSpellID = GetGlyphSocketInfo(i)
if enabled and glyphSpellID then
if glyphSpellID == 55682 then --Glyph of Shadow Word: Death
lowExecute = 0.35
break
end
end
end
end
end
end
Plater.SetExecuteRange (true, lowerEnabled and lowExecute or nil, upperEnabled and highExecute or nil)
end
--> range check ~range
function Plater.CheckRange (plateFrame, onAdded)
Plater.StartLogPerformanceCore("Plater-Core", "Update", "CheckRange")
local profile = Plater.db.profile
local unitFrame = plateFrame.unitFrame
local castBarFade = unitFrame.castBar.fadeOutAnimation:IsPlaying() --and profile.cast_statusbar_use_fade_effects
local nameplateAlpha = 1
if DB_USE_UIPARENT and profile.honor_blizzard_plate_alpha then
--if DB_USE_UIPARENT end
nameplateAlpha = plateFrame:GetAlpha()
end
unitFrame.IsInRange = nil
--if is using the no combat alpha and the unit isn't in combat, ignore the range check, no combat alpha is disabled by default
if (unitFrame.IsSelf) then
unitFrame.IsInRange = true --player plate is always in range
unitFrame:SetAlpha (nameplateAlpha)
unitFrame.healthBar:SetAlpha (1)
if not castBarFade then
unitFrame.castBar:SetAlpha (1)
end
unitFrame.powerBar:SetAlpha (1)
unitFrame.BuffFrame:SetAlpha (DB_AURA_ALPHA)
unitFrame.BuffFrame2:SetAlpha (DB_AURA_ALPHA)
Plater.EndLogPerformanceCore("Plater-Core", "Update", "CheckRange")
return
elseif (plateFrame [MEMBER_NOCOMBAT] or unitFrame.isWidgetOnlyMode) then
if unitFrame.isWidgetOnlyMode then
unitFrame:SetAlpha (1)
elseif nameplateAlpha < profile.not_affecting_combat_alpha then
unitFrame:SetAlpha (nameplateAlpha)
end
--unitFrame:SetAlpha (profile.not_affecting_combat_alpha) -- already set if necessary
unitFrame.healthBar:SetAlpha (1)
if not castBarFade then
unitFrame.castBar:SetAlpha (1)
end
unitFrame.powerBar:SetAlpha (1)
unitFrame.BuffFrame:SetAlpha (DB_AURA_ALPHA)
unitFrame.BuffFrame2:SetAlpha (DB_AURA_ALPHA)
Plater.EndLogPerformanceCore("Plater-Core", "Update", "CheckRange")
return
--the unit is friendly or not using range check and non targets alpha
elseif ((not DB_USE_ALPHA_FRIENDLIES and plateFrame [MEMBER_REACTION] >= 5) or (not DB_USE_ALPHA_ENEMIES and plateFrame [MEMBER_REACTION] < 5) or (not DB_USE_RANGE_CHECK and not DB_USE_NON_TARGETS_ALPHA)) then
unitFrame:SetAlpha (nameplateAlpha)
unitFrame.healthBar:SetAlpha (1)
if not castBarFade then
unitFrame.castBar:SetAlpha (1)
end
unitFrame.powerBar:SetAlpha (1)
unitFrame.BuffFrame:SetAlpha (DB_AURA_ALPHA)
unitFrame.BuffFrame2:SetAlpha (DB_AURA_ALPHA)
plateFrame [MEMBER_RANGE] = true
unitFrame [MEMBER_RANGE] = true
Plater.EndLogPerformanceCore("Plater-Core", "Update", "CheckRange")
return
end
--alpha values
local inRangeAlpha
local overallRangeCheckAlpha
local healthBar_rangeCheckAlpha
local castBar_rangeCheckAlpha
local buffFrames_rangeCheckAlpha
local powerBar_rangeCheckAlpha
local rangeChecker
local rangeCheckRange
if plateFrame [MEMBER_REACTION] < 5 then
-- enemy
inRangeAlpha = profile.range_check_in_range_or_target_alpha
overallRangeCheckAlpha = profile.range_check_alpha
healthBar_rangeCheckAlpha = profile.range_check_health_bar_alpha
castBar_rangeCheckAlpha = profile.range_check_cast_bar_alpha
buffFrames_rangeCheckAlpha = profile.range_check_buffs_alpha
powerBar_rangeCheckAlpha = profile.range_check_power_bar_alpha
rangeChecker = Plater.RangeCheckFunctionEnemy or LibRangeCheck:GetHarmMaxChecker(Plater.RangeCheckRangeEnemy or 40)
rangeCheckRange = Plater.RangeCheckRangeEnemy
else
-- friendly
inRangeAlpha = profile.range_check_in_range_or_target_alpha_friendlies
overallRangeCheckAlpha = profile.range_check_alpha_friendlies
healthBar_rangeCheckAlpha = profile.range_check_health_bar_alpha_friendlies
castBar_rangeCheckAlpha = profile.range_check_cast_bar_alpha_friendlies
buffFrames_rangeCheckAlpha = profile.range_check_buffs_alpha_friendlies
powerBar_rangeCheckAlpha = profile.range_check_power_bar_alpha_friendlies
rangeChecker = Plater.RangeCheckFunctionFriendly or LibRangeCheck:GetFriendMaxChecker(Plater.RangeCheckRangeFriendly or 40)
rangeCheckRange = Plater.RangeCheckRangeFriendly
end
if not rangeChecker then
rangeChecker = function (unit)
Plater.EndLogPerformanceCore("Plater-Core", "Update", "CheckRange")
return (LibRangeCheck:GetRange(unit) or 0) < (rangeCheckRange or 40)
end
Plater.GetSpellForRangeCheck()
end
--this unit is target
local unitIsTarget
local notTheTarget = false
--when the unit is out of range and isnt target, alpha is multiplied by this amount
local alphaMultiplier = 0.70
local healthBar = unitFrame.healthBar
local castBar = unitFrame.castBar
local powerBar = unitFrame.powerBar
local buffFrame1 = unitFrame.BuffFrame
local buffFrame2 = unitFrame.BuffFrame2
--if "units which is not target" is enabled and the player is targetting something else than the player it self
if ((DB_USE_NON_TARGETS_ALPHA and Plater.PlayerHasTargetNonSelf) or (DB_USE_FOCUS_TARGET_ALPHA and Plater.PlayerHasFocusTargetNonSelf)) then
if (plateFrame [MEMBER_TARGET]) then
unitIsTarget = true
elseif (DB_USE_FOCUS_TARGET_ALPHA and unitFrame.IsFocus) then
unitIsTarget = true
else
notTheTarget = true
if (profile.transparency_behavior_use_division) then
alphaMultiplier = 0.5
end
end
end
--is using the range check by ability
if (DB_USE_RANGE_CHECK and rangeChecker) then
--check when the unit just has been added to the screen
local isInRange = rangeChecker (plateFrame [MEMBER_UNITID])
if (isInRange) then
--unit is in rage
unitFrame.IsInRange = true
if (onAdded) then
--plateFrame.FadedIn = true
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha * (notTheTarget and overallRangeCheckAlpha or 1))
healthBar:SetAlpha (inRangeAlpha * (notTheTarget and healthBar_rangeCheckAlpha or 1))
if not castBarFade then
castBar:SetAlpha (inRangeAlpha * (notTheTarget and castBar_rangeCheckAlpha or 1))
end
powerBar:SetAlpha (inRangeAlpha * (notTheTarget and powerBar_rangeCheckAlpha or 1))
buffFrame1:SetAlpha (inRangeAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
buffFrame2:SetAlpha (inRangeAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
plateFrame [MEMBER_RANGE] = true
plateFrame.unitFrame [MEMBER_RANGE] = true
else
local newAlpha = nameplateAlpha * inRangeAlpha * (notTheTarget and overallRangeCheckAlpha or 1)
if (not DF:IsNearlyEqual (unitFrame:GetAlpha(), newAlpha, 0.01)) then
--play animations (animation aren't while in development)
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha * (notTheTarget and overallRangeCheckAlpha or 1))
healthBar:SetAlpha (inRangeAlpha * (notTheTarget and healthBar_rangeCheckAlpha or 1))
if not castBarFade then
castBar:SetAlpha (inRangeAlpha * (notTheTarget and castBar_rangeCheckAlpha or 1))
end
powerBar:SetAlpha (inRangeAlpha * (notTheTarget and powerBar_rangeCheckAlpha or 1))
buffFrame1:SetAlpha (inRangeAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
buffFrame2:SetAlpha (inRangeAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
end
plateFrame [MEMBER_RANGE] = true
plateFrame.unitFrame [MEMBER_RANGE] = true
end
else
--unit is out of range
unitFrame.IsInRange = false
if (onAdded) then
plateFrame.FadedIn = nil
-- unitFrame:SetAlpha (overallRangeCheckAlpha * (notTheTarget and overallRangeCheckAlpha or 1))
-- healthBar:SetAlpha (healthBar_rangeCheckAlpha * (notTheTarget and healthBar_rangeCheckAlpha or 1))
-- castBar:SetAlpha (castBar_rangeCheckAlpha * (notTheTarget and castBar_rangeCheckAlpha or 1))
-- powerBar:SetAlpha (powerBar_rangeCheckAlpha * (notTheTarget and powerBar_rangeCheckAlpha or 1))
-- buffFrame1:SetAlpha (buffFrames_rangeCheckAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
-- buffFrame2:SetAlpha (buffFrames_rangeCheckAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
unitFrame:SetAlpha ((unitIsTarget and inRangeAlpha or overallRangeCheckAlpha) * nameplateAlpha * (notTheTarget and alphaMultiplier or 1))
healthBar:SetAlpha ((unitIsTarget and inRangeAlpha or healthBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
if not castBarFade then
castBar:SetAlpha ((unitIsTarget and inRangeAlpha or castBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
end
powerBar:SetAlpha ((unitIsTarget and inRangeAlpha or powerBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
buffFrame1:SetAlpha ((unitIsTarget and inRangeAlpha or buffFrames_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
buffFrame2:SetAlpha ((unitIsTarget and inRangeAlpha or buffFrames_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
plateFrame [MEMBER_RANGE] = false
plateFrame.unitFrame [MEMBER_RANGE] = false
else
local newAlpha = nameplateAlpha * overallRangeCheckAlpha * (notTheTarget and alphaMultiplier or 1)
if (not DF:IsNearlyEqual (unitFrame:GetAlpha(), newAlpha, 0.01)) then
--play animations (animation aren't while in development)
-- unitFrame:SetAlpha (overallRangeCheckAlpha * (notTheTarget and overallRangeCheckAlpha or 1))
-- healthBar:SetAlpha (healthBar_rangeCheckAlpha * (notTheTarget and healthBar_rangeCheckAlpha or 1))
-- castBar:SetAlpha (castBar_rangeCheckAlpha * (notTheTarget and castBar_rangeCheckAlpha or 1))
-- powerBar:SetAlpha (powerBar_rangeCheckAlpha * (notTheTarget and powerBar_rangeCheckAlpha or 1))
-- buffFrame1:SetAlpha (buffFrames_rangeCheckAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
-- buffFrame2:SetAlpha (buffFrames_rangeCheckAlpha * (notTheTarget and buffFrames_rangeCheckAlpha or 1))
unitFrame:SetAlpha ((unitIsTarget and inRangeAlpha or overallRangeCheckAlpha) * nameplateAlpha * (notTheTarget and alphaMultiplier or 1))
healthBar:SetAlpha ((unitIsTarget and inRangeAlpha or healthBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
if not castBarFade then
castBar:SetAlpha ((unitIsTarget and inRangeAlpha or castBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
end
powerBar:SetAlpha ((unitIsTarget and inRangeAlpha or powerBar_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
buffFrame1:SetAlpha ((unitIsTarget and inRangeAlpha or buffFrames_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
buffFrame2:SetAlpha ((unitIsTarget and inRangeAlpha or buffFrames_rangeCheckAlpha) * (notTheTarget and alphaMultiplier or 1))
end
plateFrame [MEMBER_RANGE] = false
plateFrame.unitFrame [MEMBER_RANGE] = false
end
end
--range check isnt enabled, check is no target alpha is
elseif (DB_USE_NON_TARGETS_ALPHA) then
--player has a target other than him self?
if (Plater.PlayerHasTargetNonSelf) then
--is this unit is the current player target?
if (unitIsTarget) then
if (not DF:IsNearlyEqual (unitFrame:GetAlpha(), nameplateAlpha * inRangeAlpha, 0.01)) then
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha)
healthBar:SetAlpha (inRangeAlpha)
if not castBarFade then
castBar:SetAlpha (inRangeAlpha)
end
powerBar:SetAlpha (inRangeAlpha)
buffFrame1:SetAlpha (DB_AURA_ALPHA)
buffFrame2:SetAlpha (DB_AURA_ALPHA)
end
plateFrame.FadedIn = true
else
--this unit isnt the current player target
if (not DF:IsNearlyEqual (unitFrame:GetAlpha(), nameplateAlpha * inRangeAlpha * overallRangeCheckAlpha, 0.01)) then
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha * overallRangeCheckAlpha)
healthBar:SetAlpha (inRangeAlpha * healthBar_rangeCheckAlpha)
if not castBarFade then
castBar:SetAlpha (inRangeAlpha * castBar_rangeCheckAlpha)
end
powerBar:SetAlpha (inRangeAlpha * powerBar_rangeCheckAlpha)
buffFrame1:SetAlpha (inRangeAlpha * buffFrames_rangeCheckAlpha)
buffFrame2:SetAlpha (inRangeAlpha * buffFrames_rangeCheckAlpha)
end
plateFrame.FadedIn = nil
end
else
--player does not have a target, so just set to regular alpha
plateFrame.FadedIn = true
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha)
healthBar:SetAlpha (1)
if not castBarFade then
castBar:SetAlpha (1)
end
powerBar:SetAlpha (1)
buffFrame1:SetAlpha (DB_AURA_ALPHA)
buffFrame2:SetAlpha (DB_AURA_ALPHA)
end
else
-- no alpha settings, so just go to default
plateFrame.FadedIn = true
unitFrame:SetAlpha (nameplateAlpha * inRangeAlpha)
healthBar:SetAlpha (1)
if not castBarFade then
castBar:SetAlpha (1)
end
powerBar:SetAlpha (1)
buffFrame1:SetAlpha (DB_AURA_ALPHA)
buffFrame2:SetAlpha (DB_AURA_ALPHA)
end
Plater.EndLogPerformanceCore("Plater-Core", "Update", "CheckRange")
end
local re_GetSpellForRangeCheck = function()
Plater.GetSpellForRangeCheck()
end
--> execute after player logon or when the player changes its spec
local tryingToUpdateRangeChecker = false
function Plater.GetSpellForRangeCheck()
if tryingToUpdateRangeChecker then return end
Plater.RangeCheckRangeEnemy = nil
Plater.RangeCheckRangeFriendly = nil
Plater.RangeCheckFunctionEnemy = nil
Plater.RangeCheckFunctionFriendly = nil
local specIndex = (IS_WOW_PROJECT_MAINLINE) and GetSpecialization() or 0
if (specIndex) then
local specID = (IS_WOW_PROJECT_MAINLINE) and GetSpecializationInfo (specIndex) or select (3, UnitClass ("player"))
if (specID and specID ~= 0) then
--the local character saved variable hold the spell name used for the range check
Plater.RangeCheckRangeFriendly = PlaterDBChr.spellRangeCheckRangeFriendly [specID] or Plater.DefaultSpellRangeListF [specID] or 40
Plater.RangeCheckRangeEnemy = PlaterDBChr.spellRangeCheckRangeEnemy [specID] or Plater.DefaultSpellRangeList [specID] or 40
Plater.RangeCheckFunctionFriendly = LibRangeCheck:GetFriendMaxChecker(Plater.RangeCheckRangeFriendly)
Plater.RangeCheckFunctionEnemy = LibRangeCheck:GetHarmMaxChecker(Plater.RangeCheckRangeEnemy)
tryingToUpdateRangeChecker = false
else
tryingToUpdateRangeChecker = true
C_Timer.After (1, re_GetSpellForRangeCheck)
end
else
tryingToUpdateRangeChecker = true
C_Timer.After (1, re_GetSpellForRangeCheck)
end
end
-- ~tank --todo: make these functions be inside the Plater object
--true if the 'player' unit is a tank
--parameter "hasTankAura" is used to force aura scan skip for paladins -> UpdatePlayerTankState -> SPELL_AURA_APPLIED/REMOVED (CLASSIC)
local function IsPlayerEffectivelyTank(hasTankAura)
if IS_WOW_PROJECT_MAINLINE then
local assignedRole = UnitGroupRolesAssigned ("player")
if (assignedRole == "NONE") then
local spec = GetSpecialization()
return spec and GetSpecializationRole (spec) == "TANK"
end
return assignedRole == "TANK"
elseif IS_WOW_PROJECT_CLASSIC_WRATH then
local assignedRole = UnitGroupRolesAssigned ("player")
if assignedRole == "NONE" and UnitLevel ("player") >= 10 then
assignedRole = GetTalentGroupRole(GetActiveTalentGroup())
end
local playerIsTank = assignedRole == "TANK"
if not playerIsTank then
playerIsTank = GetPartyAssignment("MAINTANK", "player") or false
end
return playerIsTank
else
local playerIsTank = hasTankAura or false
if not hasTankAura then
local playerClass = Plater.PlayerClass
if playerClass == "WARRIOR" then
playerIsTank = GetShapeshiftForm() == 2 or IsEquippedItemType("Shields") -- Defensive Stance or shield
elseif playerClass == "DRUID" then
playerIsTank = GetShapeshiftForm() == 1 -- Bear Form
elseif playerClass == "PALADIN" then
for i=1,40 do
local spellId = select(10, UnitBuff("player",i))
if spellId == 25780 then
playerIsTank = true
end
end
end
end
-- if the player is assigned as MAINTANK, then treat him as one:
if not playerIsTank then
playerIsTank = GetPartyAssignment("MAINTANK", "player") or false
end
return playerIsTank
end
end
--return true if the unit is in tank role
local function IsUnitEffectivelyTank (unit)
if IS_WOW_PROJECT_MAINLINE then
return UnitGroupRolesAssigned (unit) == "TANK"
elseif IS_WOW_PROJECT_CLASSIC_WRATH then
if IsInRaid() then
return GetPartyAssignment("MAINTANK", unit)
else
return UnitGroupRolesAssigned (unit) == "TANK"
end
else
return GetPartyAssignment("MAINTANK", unit)
end
end
-- toggle Threat Color Mode between tank / dps (CLASSIC)
function Plater.ToggleThreatColorMode()
if IS_WOW_PROJECT_NOT_MAINLINE and not IS_WOW_PROJECT_CLASSIC_WRATH then
Plater.db.profile.tank_threat_colors = not Plater.db.profile.tank_threat_colors
Plater.RefreshTankCache()
if Plater.PlayerIsTank then
print("Plater: Using Tank Threat Colors")
else
print("Plater: Using DPS Threat Colors")
end
end
end
local function UpdatePlayerTankState(hasAura)
if (IsPlayerEffectivelyTank(hasAura)) then
TANK_CACHE [UnitName ("player")] = true
Plater.PlayerIsTank = true
else
TANK_CACHE [UnitName ("player")] = false
if IS_WOW_PROJECT_MAINLINE or IS_WOW_PROJECT_CLASSIC_WRATH then
Plater.PlayerIsTank = false
else
Plater.PlayerIsTank = false or Plater.db.profile.tank_threat_colors
end
end
end
--iterate among group members and store the names of all tanks in the group
--this is called when the player enter, leave or when the group roster is changed
--tank cache is used mostly in the aggro check to know if the player is a tank
function Plater.RefreshTankCache() --private
Plater.PlayerIsTank = false
wipe (TANK_CACHE)
--add the player to the tank pool if the player is a tank
UpdatePlayerTankState()
--search for tanks in the raid
if (IsInRaid()) then
for i = 1, GetNumGroupMembers() do
if (IsUnitEffectivelyTank ("raid" .. i)) then
if (not UnitIsUnit ("raid" .. i, "player")) then
local unitName = UnitName ("raid" .. i)
if unitName ~= UNKNOWN then
TANK_CACHE [unitName] = true
end
end
end
end
--is in group and is inside a dungeon
--there's only one tank on dungeon but dps may see if a unit is not in the tank aggro
elseif (IsInGroup() and Plater.ZoneInstanceType == "party") then
for i = 1, GetNumGroupMembers() -1 do
if (IsUnitEffectivelyTank ("party" .. i)) then
if (not UnitIsUnit ("party" .. i, "player")) then
local unitName = UnitName ("party" .. i)
if unitName ~= UNKNOWN then
TANK_CACHE [unitName] = true
end
end
end
end
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> general unit functions
--> return a table with points on where the unitFrame is attached
--these points are hardcoded in the UpdatePlateSize() function
function Plater.GetPoints (unitFrame)
local points = {
{"topleft", unitFrame.PlateFrame, "topleft", 0, 0},
{"bottomright", unitFrame.PlateFrame, "bottomright", 0, 0},
}
return points
end
--> return an iterator with all namepaltes on the screen
function Plater.GetAllShownPlates() --private
return C_NamePlate.GetNamePlates()
end
--> returns if the unit is tapped (gray health color when another player hit the unit first)
function Plater.IsUnitTapDenied (unitID)
return unitID and not UnitPlayerControlled (unitID) and UnitIsTapDenied (unitID)
end
--> returns what member from the profile need to be used, since there's entries for in combat and out of combat
function Plater.GetHashKey (inCombat) --private
if (inCombat or (inCombat == nil and PLAYER_IN_COMBAT)) then
return "cast_incombat", "health_incombat", "mana_incombat"
else
return "cast", "health", "mana"
end
end
--> return true if the resource bar should shown above the nameplate in the current target nameplate
function Plater.IsShowingResourcesOnTarget() --private
return PlaterDBChr.resources_on_target
end
--> when the player left a zone but is in combat, wait 1 second and trigger the zone changed again
local wait_for_leave_combat = function()
Plater.RunFunctionForEvent ("ZONE_CHANGED_NEW_AREA")
end
--> when the auto toggle function is called but the player is in combat
local re_RefreshAutoToggle = function()
return Plater.RefreshAutoToggle()
end
--> when the player enter in the world, wait a few seconds to get the guild name data
local delayed_guildname_check = function()
Plater.PlayerGuildName = GetGuildInfo ("player")
if (not Plater.PlayerGuildName or Plater.PlayerGuildName == "") then
Plater.PlayerGuildName = "ThePlayerHasNoGuildName/30Char"
end
end
--> run a scheduled update for a nameplate, functions can create schedules when some events are triggered when the client doesn't have the data yet
function Plater.RunScheduledUpdate (timerObject) --private
local plateFrame = timerObject.plateFrame
local unitGUID = timerObject.GUID
--checking the serial of the unit is the same in case this nameplate is being used on another unit
if (plateFrame:IsShown() and unitGUID == plateFrame [MEMBER_GUID]) then
--save user input data (usualy set from scripts) before call the unit added event
local unitFrame = plateFrame.unitFrame
if not unitFrame.PlaterOnScreen then
return
end
local customHealthBarWidth = unitFrame.customHealthBarWidth
local customHealthBarHeight = unitFrame.customHealthBarHeight
local customCastBarWidth = unitFrame.customCastBarWidth
local customCastBarHeight = unitFrame.customCastBarHeight
local customPowerBarWidth = unitFrame.customPowerBarWidth
local customPowerBarHeight = unitFrame.customPowerBarHeight
local customBorderColor = unitFrame.customBorderColor
--full refresh the nameplate, this will override user data from scripts
Plater.RunFunctionForEvent ("NAME_PLATE_UNIT_ADDED", unitFrame [MEMBER_UNITID])
--restore user input data
unitFrame.customHealthBarWidth = customHealthBarWidth
unitFrame.customHealthBarHeight = customHealthBarHeight
unitFrame.customCastBarWidth = customCastBarWidth
unitFrame.customCastBarHeight = customCastBarHeight
unitFrame.customPowerBarWidth = customPowerBarWidth
unitFrame.customPowerBarHeight = customPowerBarHeight
if ( customHealthBarWidth or
customHealthBarHeight or
customCastBarWidth or
customCastBarHeight or
customPowerBarWidth or
customPowerBarHeight
) then
Plater.UpdatePlateSize (plateFrame)
end
unitFrame.customBorderColor = customBorderColor
if (unitFrame.customBorderColor) then
Plater.UpdateBorderColor (plateFrame.unitFrame)
end
end
end
--run a delayed update on the namepalte, this is used when the client receives an information from the server but does not update the state immediately
--this usualy happens with faction and flag changes
function Plater.ScheduleUpdateForNameplate (plateFrame) --private
if not plateFrame.unitFrame.PlaterOnScreen then
return
end
--check if there's already an update scheduled for this unit
if (plateFrame.HasUpdateScheduled and not plateFrame.HasUpdateScheduled._cancelled) then
return
else
plateFrame.HasUpdateScheduled = C_Timer.NewTimer (0, Plater.RunScheduledUpdate) --next frame
plateFrame.HasUpdateScheduled.plateFrame = plateFrame
plateFrame.HasUpdateScheduled.GUID = plateFrame [MEMBER_GUID]
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> settings functions
-- ~profile
--refreshes the values for the profile when the profile is loaded or changed
function Plater:RefreshConfig() --private
Plater.IncreaseRefreshID()
Plater.RefreshDBUpvalues()
Plater.UpdateAllPlates()
if (PlaterOptionsPanelFrame) then
PlaterOptionsPanelFrame.RefreshOptionsFrame()
end
Plater.UpdateSettingsCache()
end
function Plater:RefreshConfigProfileChanged() --private
Plater:RefreshConfig()
--call the user to /reload his UI
DF:ShowPromptPanel ("Plater profile changed, do you want /reload now (recommended)?", function() ReloadUI() end, function() end, true, 500)
end
--~save ~cvar
local cvars_to_store = {
["NamePlateClassificationScale"] = true,
["NamePlateHorizontalScale"] = true,
["NamePlateVerticalScale"] = true,
["ShowClassColorInNameplate"] = true,
["ShowNamePlateLoseAggroFlash"] = true,
["nameplateGlobalScale"] = true,
["nameplateLargerScale"] = true,
["nameplateLargeTopInset"] = true,
["nameplateMaxDistance"] = true,
["nameplateMinScale"] = true,
["nameplateMotion"] = true,
["nameplateMotionSpeed"] = true,
["nameplateOccludedAlphaMult"] = true,
["nameplateOtherAtBase"] = true,
["nameplateOtherTopInset"] = true,
["nameplateOverlapV"] = true,
["nameplateOverlapH"] = true,
["nameplatePersonalHideDelaySeconds"] = true,
["nameplatePersonalShowAlways"] = true,
["nameplatePersonalShowInCombat"] = true,
["nameplatePersonalShowWithTarget"] = true,
["nameplateResourceOnTarget"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateSelectedScale"] = true,
["nameplateSelfAlpha"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateSelfBottomInset"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateSelfScale"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateSelfTopInset"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateShowAll"] = true,
["nameplateShowEnemies"] = true,
["nameplateShowEnemyGuardians"] = true,
["nameplateShowEnemyMinions"] = true,
["nameplateShowEnemyMinus"] = true,
["nameplateShowEnemyPets"] = true,
["nameplateShowEnemyTotems"] = true,
["nameplateShowFriends"] = true,
["nameplateShowFriendlyGuardians"] = true,
["nameplateShowFriendlyNPCs"] = true,
["nameplateShowFriendlyMinions"] = true,
["nameplateShowFriendlyPets"] = true,
["nameplateShowFriendlyTotems"] = true,
["nameplateShowOnlyNames"] = true,
["nameplateShowSelf"] = (IS_WOW_PROJECT_MAINLINE),
["nameplateTargetBehindMaxDistance"] = true,
["clampTargetNameplateToScreen"] = true,
["nameplateTargetRadialPosition"] = true,
["nameplateSelectedAlpha"] = true,
["nameplateNotSelectedAlpha"] = (IS_WOW_PROJECT_NOT_MAINLINE),
["nameplateRemovalAnimation"] = (IS_WOW_PROJECT_NOT_MAINLINE),
["nameplateMinAlpha"] = true,
["nameplateMinAlphaDistance"] = true,
["nameplateShowDebuffsOnFriendly"] = true,
}
function get_cvar_value(value)
if value == nil then return nil end
--bool checks
if type(value) == "boolean" then
value = value and 1 or 0 --store as 1/0
elseif value == "true" then
value = 1
elseif value == "false" then
value = 0
end
return tostring(value) --to store string representation
end
local canSaveCVars = false --only allow storing after plater has restored
--on logout or on profile change, or when they are actually set, save some important cvars inside the profile
function Plater.SaveConsoleVariables(cvar, value) --private
if not canSaveCVars then return end
--print("save cvars", cvar, value, debugstack())
local cvarTable = Plater.db.profile.saved_cvars
local cvarLastChangedTable = Plater.db.profile.saved_cvars_last_change
if (not cvarTable) then
--return
Plater.db.profile.saved_cvars = {}
cvarTable = Plater.db.profile.saved_cvars
end
if not cvar then -- store all
for CVarName, enabled in pairs (cvars_to_store) do
if enabled then
cvarTable [CVarName] = get_cvar_value(GetCVar (CVarName))
end
end
elseif cvars_to_store [cvar] then
cvarTable [cvar] = get_cvar_value(value)
local callstack = debugstack(2) -- starts at "SetCVar" or caller
local caller, line = callstack:match("\"@([^\"]+)\"%]:(%d+)")
if not caller then
caller, line = callstack:match("in function <([^:%[>]+):(%d+)>")
end
if not caller or (caller and not caller:lower():find("[\\/]sharedxml[\\/]cvarutil%.lua")) then
--print((caller and caller .. ":" .. line) or callstack)
cvarLastChangedTable [cvar] = (caller and (caller .. ":" .. line)) or callstack
end
end
end
--restore profile cvars
function Plater.RestoreProfileCVars()
if (InCombatLockdown()) then
C_Timer.After (1, function() Plater.RestoreProfileCVars() end)
return
end
--> try to restore cvars from the profile
local savedCVars = Plater.db and Plater.db.profile and Plater.db.profile.saved_cvars
if (savedCVars) then
--pre-sort restore order:
local orderKeys = {}
for k in pairs (cvars_to_store) do
tinsert(orderKeys, k)
end
table.sort(orderKeys)
for CVarName in pairs (orderKeys) do
local CVarValue = savedCVars [CVarName]
if CVarValue then --only restore what we want to store/restore!
SetCVar (CVarName, get_cvar_value(CVarValue))
end
end
end
canSaveCVars = true --allow storing after restoring the first time
end
function Plater.DebugCVars(cvar)
cvar = cvar and cvar:gsub(" ", "") or nil
if cvar and cvar ~= "" then
if cvars_to_store[cvar] then
print("CVar info:\nName: '" .. cvar .. "'\nCurrent Value: " .. (get_cvar_value(GetCVar (cvar)) or "<not set>") .. "\nStored Value: " .. (Plater.db.profile.saved_cvars[cvar] or "<not stored>") .. "\nLast changed by: " .. (Plater.db.profile.saved_cvars_last_change[cvar] and ("\n" .. Plater.db.profile.saved_cvars_last_change[cvar]) or "<no info>"))
else
print("CVar '" .. cvar .. "' is not stored in Plater.")
end
else
print("No CVar name provided. Printing all stored CVar names. Use '/plater cvar <cvar name> for more details.'")
local savedCVars = Plater.db and Plater.db.profile and Plater.db.profile.saved_cvars or {}
for CVarName, CVarValue in pairs (savedCVars) do
print("'" .. CVarName .. "' = " .. (get_cvar_value(CVarValue) or "<not set>"))
end
end
end
--refresh call back will run all functions in its table when Plater refreshes the dynamic upvales for the file
Plater.DBRefreshCallback = {}
function Plater.RegisterRefreshDBCallback (func) --private
DF.table.addunique (Plater.DBRefreshCallback, func)
end
function Plater.FireRefreshDBCallback() --private
for _, func in ipairs (Plater.DBRefreshCallback) do
DF:Dispatch (func)
end
end
function Plater.DisableAuraTrackingForAuraTest()
DB_AURA_ENABLED = false
end
--> place most used data into local upvalues to save process time
--> scripts need to call this function if they change something in the profile ~refresh ~db ~upvalues
function Plater.RefreshDBUpvalues()
local profile = Plater.db.profile
DB_AURA_ENABLED = profile.aura_enabled
DB_AURA_ALPHA = profile.aura_alpha
DB_AURA_SEPARATE_BUFFS = profile.buffs_on_aura2
DB_NUMBER_REGION_EAST_ASIA = Plater.db.profile.number_region == "eastasia"
DB_TICK_THROTTLE = profile.update_throttle
DB_LERP_COLOR = profile.use_color_lerp
--class colors
DB_CLASS_COLORS = profile.class_colors
--update colorStr
for className, colorTable in pairs(profile.class_colors) do
colorTable.colorStr = DetailsFramework:FormatColor("hex", colorTable.r, colorTable.g, colorTable.b, 1)
end
DB_LERP_COLOR_SPEED = profile.color_lerp_speed
DB_PLATE_CONFIG = profile.plate_config
DB_TRACK_METHOD = profile.aura_tracker.track_method
DB_DO_ANIMATIONS = profile.use_health_animation
DB_ANIMATION_TIME_DILATATION = profile.health_animation_time_dilatation
DB_HOVER_HIGHLIGHT = profile.hover_highlight
DB_USE_RANGE_CHECK = profile.range_check_enabled
DB_USE_NON_TARGETS_ALPHA = profile.non_targeted_alpha_enabled
DB_USE_FOCUS_TARGET_ALPHA = profile.focus_as_target_alpha
DB_USE_ALPHA_FRIENDLIES = profile.transparency_behavior_on_friendlies
DB_USE_ALPHA_ENEMIES = profile.transparency_behavior_on_enemies
DB_USE_QUICK_HIDE = profile.quick_hide
DB_SHOW_HEALTHBARS_FOR_NOT_ATTACKABLE = profile.show_healthbars_on_not_attackable
DB_NPCIDS_CACHE = Plater.db.profile.npc_cache
DB_USE_UIPARENT = profile.use_ui_parent
DB_BORDER_COLOR_R = profile.border_color [1]
DB_BORDER_COLOR_G = profile.border_color [2]
DB_BORDER_COLOR_B = profile.border_color [3]
DB_BORDER_COLOR_A = profile.border_color [4]
DB_BORDER_THICKNESS = profile.border_thickness
DB_AGGRO_CHANGE_HEALTHBAR_COLOR = profile.aggro_modifies.health_bar_color
DB_AGGRO_CHANGE_BORDER_COLOR = profile.aggro_modifies.border_color
DB_AGGRO_CHANGE_NAME_COLOR = profile.aggro_modifies.actor_name_color
DB_AGGRO_CAN_CHECK_NOTANKAGGRO = profile.aggro_can_check_notank
DB_AGGRO_TANK_COLORS = profile.tank.colors
DB_AGGRO_DPS_COLORS = profile.dps.colors
DB_NOT_COMBAT_ALPHA_ENABLED = profile.not_affecting_combat_enabled
DB_TARGET_SHADY_ENABLED = profile.target_shady_enabled
DB_TARGET_SHADY_ALPHA = profile.target_shady_alpha
DB_TARGET_SHADY_COMBATONLY = profile.target_shady_combat_only
DB_NAME_NPCENEMY_ANCHOR = profile.plate_config.enemynpc.actorname_text_anchor.side
DB_NAME_NPCFRIENDLY_ANCHOR = profile.plate_config.friendlynpc.actorname_text_anchor.side
DB_NAME_PLAYERENEMY_ANCHOR = profile.plate_config.enemyplayer.actorname_text_anchor.side
DB_NAME_PLAYERFRIENDLY_ANCHOR = profile.plate_config.friendlyplayer.actorname_text_anchor.side
DB_TEXTURE_CASTBAR = LibSharedMedia:Fetch ("statusbar", profile.cast_statusbar_texture)
DB_TEXTURE_CASTBAR_BG = LibSharedMedia:Fetch ("statusbar", profile.cast_statusbar_bgtexture)
DB_TEXTURE_HEALTHBAR = LibSharedMedia:Fetch ("statusbar", profile.health_statusbar_texture)
DB_TEXTURE_HEALTHBAR_BG = LibSharedMedia:Fetch ("statusbar", profile.health_statusbar_bgtexture)
DB_CASTBAR_HIDE_ENEMIES = profile.hide_enemy_castbars
DB_CASTBAR_HIDE_FRIENDLY = profile.hide_friendly_castbars
DB_CAPTURED_CASTS = PlaterDB.captured_casts
DB_CAPTURED_SPELLS = PlaterDB.captured_spells
DB_USE_NAME_TRANSLIT = profile.use_name_translit
--refresh lists
Plater.RefreshDBLists()
--refresh auras
Plater.RefreshAuraCache() --on Plater_Auras.lua
Plater.RefreshAuraDBUpvalues() --on Plater_Auras.lua
Plater.UpdateAuraCache() --on Plater_Auras.lua
--refresh resources
Plater.Resources.RefreshResourcesDBUpvalues() --Plater_Resources.lua
end
function Plater.RefreshDBLists()
local profile = Plater.db.profile
wipe (SPELL_WITH_ANIMATIONS)
if (profile.spell_animations) then
for spellId, animations in pairs (profile.spell_animation_list) do
local frameAnimations = {}
local spellName = GetSpellInfo (spellId)
if (spellName) then
for animationIndex, animationOptions in ipairs (animations) do
if (animationOptions.enabled) then
local data = DF.table.deploy ({}, animationOptions)
data.animationCooldown = {} --store nameplate references with [nameplateRef] = GetTime() + cooldown
tinsert (frameAnimations, data)
end
end
SPELL_WITH_ANIMATIONS [spellName] = frameAnimations
end
end
end
IS_USING_DETAILS_INTEGRATION = false
--details integration
if (Details and Details.plater) then
local detailsPlaterConfig = Details.plater
if (detailsPlaterConfig.realtime_dps_enabled) then
IS_USING_DETAILS_INTEGRATION = true
elseif (detailsPlaterConfig.realtime_dps_player_enabled) then
IS_USING_DETAILS_INTEGRATION = true
elseif (detailsPlaterConfig.damage_taken_enabled) then
IS_USING_DETAILS_INTEGRATION = true
end
end
--> build the list of npcs with special colors
wipe (DB_UNITCOLOR_CACHE) --regular color overrides the threat color
wipe (DB_UNITCOLOR_SCRIPT_CACHE) --color only used for scripts, plater does not use them
for npcID, infoTable in pairs (Plater.db.profile.npc_colors) do
local enabled1 = infoTable [1] --this is the overall enabled
local enabled2 = infoTable [2] --if this is true, this color is only used for scripts
local colorID = infoTable [3] --the color
if (enabled1 and not enabled2) then
local r, g, b, a = DF:ParseColors (colorID)
DB_UNITCOLOR_CACHE [npcID] = {r, g, b, a}
elseif (enabled1 and enabled2) then
local r, g, b, a = DF:ParseColors (colorID)
DB_UNITCOLOR_SCRIPT_CACHE [npcID] = {r, g, b, a}
end
end
Plater.IncreaseRefreshID()
Plater.FireRefreshDBCallback()
end
--a patch is a function stored in the Plater_ScriptLibrary file and are executed only once to change a profile setting, remove or add an aura into the tracker or modify a script
--patch versions are stored within the profile, so importing or creating a new profile will apply all patches that wasn't applyed into it yet
function Plater.ApplyPatches() --private
if (PlaterPatchLibrary) then
local currentPatch = Plater.db.profile.patch_version
for i = currentPatch+1, #PlaterPatchLibrary do
local patch = PlaterPatchLibrary [i]
Plater:Msg ("Applied Patch #" .. i .. ":")
for o = 1, #patch.Notes do
print (patch.Notes [o])
end
DF:Dispatch (patch.Func)
Plater.db.profile.patch_version = i
end
--do not clear patch library, when creating a new profile it'll need to re-apply patches
--PlaterPatchLibrary = nil
end
end
function Plater.SetNameplateScale(unitFrame, scale)
scale = tonumber(scale)
unitFrame.nameplateScaleAdjust = scale and (scale > 0) and scale or 1
if (DB_USE_UIPARENT) then
Plater.UpdateUIParentScale (unitFrame.PlateFrame)
else
unitFrame:SetScale (unitFrame.nameplateScaleAdjust)
Plater.UpdatePlateSize(unitFrame.PlateFrame)
end
end
--when using UIParent as the parent for the unitFrame, this function is hooked in the plateFrame OnSizeChanged script
--the goal is to adjust the the unitFrame scale when the plateFrame scale changes
--this approach also solves the issue to the unitFrame not playing correctly the animation when the nameplate is removed from the screen
--self is plateFrame, w, h aren't reliable
function Plater.UpdateUIParentScale (self, w, h) --private
local unitFrame = self.unitFrame
if (unitFrame) then
local defaultScale = self:GetEffectiveScale()
--local defaultScale = UIParent:GetEffectiveScale()
if (defaultScale < 0.4) then
--assuming the nameplate is in process of being removed from the screen if the scale if lower than .4
unitFrame:SetScale (defaultScale)
else
--scale (adding a fine tune knob)
local scaleFineTune = max (Plater.db.profile.ui_parent_scale_tune, 0.3)
--@Ariani - March, 9
unitFrame:SetScale (defaultScale * scaleFineTune * (tonumber(unitFrame.nameplateScaleAdjust) or 1))
end
end
end
--this reset the UIParent levels to user default set on the UIParent tab
--there's an api that calls this function called Plater.RefreshNameplateStrata()
function Plater.UpdateUIParentLevels (unitFrame) --private
if (DB_USE_UIPARENT) then
--setup frame strata and levels
local profile = Plater.db.profile
local castBar = unitFrame.castBar
local buffFrame1 = unitFrame.BuffFrame
local buffFrame2 = unitFrame.BuffFrame2
local buffSpecial = unitFrame.ExtraIconFrame
--strata
unitFrame:SetFrameStrata (profile.ui_parent_base_strata)
castBar:SetFrameStrata (profile.ui_parent_cast_strata)
buffFrame1:SetFrameStrata (profile.ui_parent_buff_strata)
buffFrame2:SetFrameStrata (profile.ui_parent_buff2_strata)
buffSpecial:SetFrameStrata (profile.ui_parent_buff_special_strata)
--level
local baseLevel = unitFrame:GetFrameLevel()
local tmplevel = baseLevel + profile.ui_parent_cast_level + 3
castBar:SetFrameLevel ((tmplevel > 0) and tmplevel or 0)
tmplevel = baseLevel + profile.ui_parent_buff_level + 3
buffFrame1:SetFrameLevel ((tmplevel > 0) and tmplevel or 0)
tmplevel = baseLevel + profile.ui_parent_buff2_level + 10
buffFrame2:SetFrameLevel ((tmplevel > 0) and tmplevel or 0)
tmplevel = baseLevel + profile.ui_parent_buff_special_level + 10
buffSpecial:SetFrameLevel ((tmplevel > 0) and tmplevel or 0)
--raid-target marker adjust:
unitFrame.PlaterRaidTargetFrame:SetFrameStrata(unitFrame.healthBar:GetFrameStrata())
unitFrame.PlaterRaidTargetFrame:SetFrameLevel(unitFrame.healthBar:GetFrameLevel() + 25)
end
end
--move the target nameplate to its strata
--also need to move other frame components of this nameplate as well so the entire nameplate is up front
function Plater.UpdateUIParentTargetLevels (unitFrame) --private
if (DB_USE_UIPARENT) then
--move all frames to target strata
local targetStrata = Plater.db.profile.ui_parent_target_strata
unitFrame:SetFrameStrata (targetStrata)
unitFrame.castBar:SetFrameStrata (targetStrata)
unitFrame.BuffFrame:SetFrameStrata (targetStrata)
unitFrame.BuffFrame2:SetFrameStrata (targetStrata)
end
end
--> regional format numbers
do
local eastAsiaMyriads_1k, eastAsiaMyriads_10k, eastAsiaMyriads_1B
if (GetLocale() == "koKR") then
eastAsiaMyriads_1k, eastAsiaMyriads_10k, eastAsiaMyriads_1B = "", "", ""
elseif (GetLocale() == "zhCN") then
eastAsiaMyriads_1k, eastAsiaMyriads_10k, eastAsiaMyriads_1B = "", "", "亿"
elseif (GetLocale() == "zhTW") then
eastAsiaMyriads_1k, eastAsiaMyriads_10k, eastAsiaMyriads_1B = "", "", ""
else
eastAsiaMyriads_1k, eastAsiaMyriads_10k, eastAsiaMyriads_1B = "", "", ""
end
function Plater.FormatNumber (number)
if (DB_NUMBER_REGION_EAST_ASIA) then
if (number > 99999999) then
return format ("%.2f", number/100000000) .. eastAsiaMyriads_1B
elseif (number > 999999) then
return format ("%.2f", number/10000) .. eastAsiaMyriads_10k
elseif (number > 99999) then
return floor (number/10000) .. eastAsiaMyriads_10k
elseif (number > 9999) then
return format ("%.1f", (number/10000)) .. eastAsiaMyriads_10k
elseif (number > 999) then
return format ("%.1f", (number/1000)) .. eastAsiaMyriads_1k
end
return format ("%.1f", number)
else
if (number > 999999999) then
return format ("%.2f", number/1000000000) .. "B"
elseif (number > 999999) then
return format ("%.2f", number/1000000) .. "M"
elseif (number > 99999) then
return floor (number/1000) .. "K"
elseif (number > 999) then
return format ("%.1f", (number/1000)) .. "K"
end
return floor (number)
end
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> event handler
--frame which will receive events
Plater.EventHandlerFrame = CreateFrame ("frame") --private
--schedule zone change
local run_zonechanged_hook = function()
if (HOOK_ZONE_CHANGED.ScriptAmount > 0) then
--for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
local globalScope = _G
for i = 1, 40 do
--run on all nameplates already created
local plateFrame = globalScope ["NamePlate" .. i]
if (plateFrame) then
for i = 1, HOOK_ZONE_CHANGED.ScriptAmount do
local globalScriptObject = HOOK_ZONE_CHANGED [i]
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Zone Changed")
--run
unitFrame:ScriptRunHook (scriptInfo, "Zone Changed")
end
else
break
end
end
end
end
function Plater.ScheduleZoneChangeHook()
if (Plater.ScheduledZoneChangeTriggerHook) then
Plater.ScheduledZoneChangeTriggerHook:Cancel()
end
Plater.ScheduledZoneChangeTriggerHook = C_Timer.NewTimer (2, run_zonechanged_hook)
end
function Plater.RunLoadScreenHook()
for i = 1, HOOK_LOAD_SCREEN.ScriptAmount do
local hookInfo = HOOK_LOAD_SCREEN [i]
Plater.ScriptMetaFunctions.ScriptRunNoAttach (hookInfo, "Load Screen")
end
end
function Plater.PlaterDefaultWidgetLayout(widgetContainerFrame, sortedWidgets)
--ViragDevTool_AddData({ctime = GetTime(), unit = widgetContainerFrame:GetParent().unit or "nil", stack = debugstack(), wc = widgetContainerFrame, widgets = sortedWidgets, children = (widgetContainerFrame.GetLayoutChildren and widgetContainerFrame:GetLayoutChildren() or nil), wcp = widgetContainerFrame:GetParent()}, "WidgetContainer - " .. (widgetContainerFrame:GetParent().unit or "nil"))
local horizontalRowContainer = nil
local horizontalRowHeight = 0
local horizontalRowWidth = 0
local totalWidth = 0
local totalHeight = 0
widgetContainerFrame.horizontalRowContainerPool:ReleaseAll()
for index, widgetFrame in ipairs(sortedWidgets) do
widgetFrame:ClearAllPoints()
local widgetSetUsesVertical = widgetContainerFrame.widgetSetLayoutDirection == Enum.UIWidgetSetLayoutDirection.Vertical
local widgetUsesVertical = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Vertical
local useOverlapLayout = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Overlap
local useVerticalLayout = widgetUsesVertical or (widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Default and widgetSetUsesVertical)
if useOverlapLayout then
-- This widget uses overlap layout
if index == 1 then
-- But this is the first widget in the set, so just anchor it to the widget container
if widgetSetUsesVertical then
widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame)
else
widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, widgetContainerFrame)
end
else
-- This is not the first widget in the set, so anchor it so it overlaps the previous widget
local relative = sortedWidgets[index - 1]
if widgetSetUsesVertical then
-- Overlap it vertically
widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, relative, widgetContainerFrame.verticalAnchorPoint, 0, 0)
else
-- Overlap it horizontally
widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, relative, widgetContainerFrame.horizontalAnchorPoint, 0, 0)
end
end
local width, height = widgetFrame:GetSize()
if width > totalWidth then
totalWidth = width
end
if height > totalHeight then
totalHeight = height
end
widgetFrame:SetParent(widgetContainerFrame)
elseif useVerticalLayout then
-- This widget uses vertical layout
if index == 1 then
-- This is the first widget in the set, so just anchor it to the widget container
widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame)
else
-- This is not the first widget in the set, so anchor it to the previous widget (or the horizontalRowContainer if that exists)
local relative = horizontalRowContainer or sortedWidgets[index - 1]
widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, relative, widgetContainerFrame.verticalRelativePoint, 0, widgetContainerFrame.verticalAnchorYOffset)
if horizontalRowContainer then
-- This widget is vertical, so horizontalRowContainer is done. Call layout on it and clear horizontalRowContainer
--horizontalRowContainer:Layout()
horizontalRowContainer:SetSize(horizontalRowWidth, horizontalRowHeight)
totalWidth = totalWidth + horizontalRowWidth
totalHeight = totalHeight + horizontalRowHeight
horizontalRowHeight = 0
horizontalRowWidth = 0
horizontalRowContainer = nil
end
totalHeight = totalHeight + widgetContainerFrame.verticalAnchorYOffset
end
widgetFrame:SetParent(widgetContainerFrame)
local width, height = widgetFrame:GetSize()
if width > totalWidth then
totalWidth = width
end
totalHeight = totalHeight + height
else
-- This widget uses horizontal layout
local forceNewRow = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.HorizontalForceNewRow
local needNewRowContainer = not horizontalRowContainer or forceNewRow
if needNewRowContainer then
-- We either don't have a horizontalRowContainer or this widget has requested a new row be started
if horizontalRowContainer then
--horizontalRowContainer:Layout()
horizontalRowContainer:SetSize(horizontalRowWidth, horizontalRowHeight)
totalWidth = totalWidth + horizontalRowWidth
totalHeight = totalHeight + horizontalRowHeight
horizontalRowHeight = 0
horizontalRowWidth = 0
end
local newHorizontalRowContainer = widgetContainerFrame.horizontalRowContainerPool:Acquire()
newHorizontalRowContainer:Show()
if index == 1 then
-- This is the first widget in the set, so just anchor it to the widget container
newHorizontalRowContainer:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame, widgetContainerFrame.verticalAnchorPoint)
else
-- This is not the first widget in the set, so anchor it to the previous widget (or the horizontalRowContainer if that exists)
local relative = horizontalRowContainer or sortedWidgets[index - 1]
newHorizontalRowContainer:SetPoint(widgetContainerFrame.verticalAnchorPoint, relative, widgetContainerFrame.verticalRelativePoint, 0, widgetContainerFrame.verticalAnchorYOffset)
totalHeight = totalHeight + widgetContainerFrame.verticalAnchorYOffset
end
widgetFrame:SetPoint('TOPLEFT', newHorizontalRowContainer)
widgetFrame:SetParent(newHorizontalRowContainer)
horizontalRowWidth = horizontalRowWidth + (widgetFrame:GetWidth() * widgetFrame:GetScale())
-- The old horizontalRowContainer is no longer needed for anchoring, so set it to newHorizontalRowContainer
horizontalRowContainer = newHorizontalRowContainer
else
-- horizontalRowContainer already existed, so we just keep going in it, anchoring to the previous widget
local relative = sortedWidgets[index - 1]
widgetFrame:SetParent(horizontalRowContainer)
widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, relative, widgetContainerFrame.horizontalRelativePoint, widgetContainerFrame.horizontalAnchorXOffset, 0)
horizontalRowWidth = horizontalRowWidth + widgetFrame:GetWidth() + widgetContainerFrame.horizontalAnchorXOffset
end
local widgetHeight = widgetFrame:GetHeight()
if widgetHeight > horizontalRowHeight then
horizontalRowHeight = widgetHeight
end
end
end
if horizontalRowContainer then
--horizontalRowContainer:Layout()
--horizontalRowContainer:SetSize(horizontalRowWidth*horizontalRowContainer:GetEffectiveScale(), horizontalRowHeight*horizontalRowContainer:GetEffectiveScale())
horizontalRowContainer:SetSize(horizontalRowWidth, horizontalRowHeight)
totalWidth = totalWidth + horizontalRowWidth
totalHeight = totalHeight + horizontalRowHeight
end
--widgetContainerFrame:Layout()
--ViragDevTool_AddData({ctime = GetTime(), totalWidth = totalWidth, totalHeight = totalHeight, horizontalRowWidth = horizontalRowWidth, horizontalRowHeight = horizontalRowHeight}, "WidgetContainerSize - " .. (widgetContainerFrame:GetParent().unit or "nil"))
--widgetContainerFrame:SetSize(totalWidth*widgetContainerFrame:GetEffectiveScale(), totalHeight*widgetContainerFrame:GetEffectiveScale())
widgetContainerFrame:SetSize(totalWidth, totalHeight)
end
--store all functions for all events that will be registered inside OnInit
local last_UPDATE_SHAPESHIFT_FORM = GetTime()
local last_GetShapeshiftForm = GetShapeshiftForm()
local eventFunctions = {
--when a unit from unatackable change its state, this event triggers several times, a schedule is used to only update once
UNIT_FLAGS = function (_, unit)
if (unit == "player") then
return
end
local plateFrame = C_NamePlate.GetNamePlateForUnit (unit, issecure())
if (plateFrame) then
--rules if can schedule an update for unit flag event:
--nameplate is from a npc which the player cannot attack and now the player can attack
local playerCannotAttack = plateFrame.PlayerCannotAttack
--the player is in open world, dungeons and raids does trigger unit flag event but won't need a full refresh
local playerInOpenWorld = IS_IN_OPEN_WORLD
if (playerCannotAttack or playerInOpenWorld) then
--print ("UNIT_FLAG", plateFrame, issecure(), unit, unit and UnitName (unit))
Plater.ScheduleUpdateForNameplate (plateFrame)
end
end
end,
UNIT_FACTION = function (_, unit)
if (unit == "player") then
return
end
--fires when somebody changes faction near the player
local plateFrame = C_NamePlate.GetNamePlateForUnit (unit, issecure())
if (plateFrame) then
Plater.ScheduleUpdateForNameplate (plateFrame)
end
end,
ACTIVE_TALENT_GROUP_CHANGED = function()
C_Timer.After (0.5, UpdatePlayerTankState)
C_Timer.After (0.5, Plater.Resources.OnSpecChanged) --~resource
C_Timer.After (2, Plater.GetSpellForRangeCheck)
C_Timer.After (2, Plater.GetHealthCutoffValue)
C_Timer.After (1, Plater.DispatchTalentUpdateHookEvent)
end,
PLAYER_SPECIALIZATION_CHANGED = function()
C_Timer.After (0.5, Plater.Resources.OnSpecChanged) --~resource
C_Timer.After (2, Plater.GetSpellForRangeCheck)
C_Timer.After (2, Plater.GetHealthCutoffValue)
C_Timer.After (1, Plater.DispatchTalentUpdateHookEvent)
end,
TRAIT_CONFIG_UPDATED = function()
C_Timer.After (2, Plater.GetSpellForRangeCheck)
C_Timer.After (2, Plater.GetHealthCutoffValue)
C_Timer.After (1, Plater.DispatchTalentUpdateHookEvent)
end,
PLAYER_TALENT_UPDATE = function()
C_Timer.After (2, Plater.GetSpellForRangeCheck)
C_Timer.After (2, Plater.GetHealthCutoffValue)
C_Timer.After (1, Plater.DispatchTalentUpdateHookEvent)
end,
GROUP_ROSTER_UPDATE = function()
Plater.RefreshTankCache()
end,
UNIT_PET = function(_, unit)
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame and plateFrame.unitFrame.PlaterOnScreen then
if not plateFrame.unitFrame.isPerformanceUnit then
Plater.AddToAuraUpdate(plateFrame.unitFrame.unit) -- force aura update
end
Plater.ScheduleUpdateForNameplate (plateFrame)
end
end
end,
PLAYER_REGEN_DISABLED = function()
PLAYER_IN_COMBAT = true
Plater.RefreshTankCache()
--Plater.UpdateAuraCache()
Plater.UpdateAllPlates(false, false, true)
--check if can run combat enter hook and schedule it true
if (HOOK_COMBAT_ENTER.ScriptAmount > 0) then
local hookTimer = C_Timer.NewTimer (0.1, Plater.ScheduleHookForCombat)
hookTimer.Event = "Enter Combat"
end
Plater.CombatTime = GetTime()
--store names and casts from 'last' combat, this is used when showing Npcs Colors and Cast Colors to bump up stuff from the last combat
Plater.LastCombat = {
npcNames = {},
spellNames = {},
}
end,
PLAYER_REGEN_ENABLED = function()
PLAYER_IN_COMBAT = false
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
plateFrame [MEMBER_NOCOMBAT] = nil
end
--check if can run combat enter hook and schedule it true
if (HOOK_COMBAT_LEAVE.ScriptAmount > 0) then
local hookTimer = C_Timer.NewTimer (0.1, Plater.ScheduleHookForCombat)
hookTimer.Event = "Leave Combat"
end
Plater.RefreshTankCache()
Plater.UpdateAllNameplateColors()
Plater.UpdateAllPlates()
end,
FRIENDLIST_UPDATE = function()
wipe (Plater.FriendsCache)
for i = 1, C_FriendList.GetNumFriends() do
local info = C_FriendList.GetFriendInfoByIndex (i)
if (info and info.connected and info.name) then
Plater.FriendsCache [info.name] = true
Plater.FriendsCache [DF:RemoveRealmName (info.name)] = true
end
end
if IS_WOW_PROJECT_MAINLINE then
local _, numBNetOnline = BNGetNumFriends();
for i = 1, numBNetOnline do
local accountInfo = C_BattleNet.GetFriendAccountInfo(i);
if (accountInfo and accountInfo.gameAccountInfo and accountInfo.gameAccountInfo.isOnline and accountInfo.gameAccountInfo.characterName) then
Plater.FriendsCache [accountInfo.gameAccountInfo.characterName] = true
end
end
else
for i = 1, BNGetNumFriends() do
local presenceID, presenceName, battleTag, isBattleTagPresence, toonName, toonID, client, isOnline, lastOnline, isAFK, isDND, messageText, noteText, isRIDFriend, broadcastTime, canSoR = BNGetFriendInfo (i)
if (isOnline and toonName) then
Plater.FriendsCache [toonName] = true
end
end
end
--let's not trigger a full update on all plates because a friend is now online
--Plater.UpdateAllPlates()
end,
RAID_TARGET_UPDATE = function()
Plater.UpdateRaidMarkersOnAllNameplates()
end,
QUEST_REMOVED = function()
Plater.QuestLogUpdated()
end,
QUEST_ACCEPTED = function()
Plater.QuestLogUpdated()
end,
QUEST_ACCEPT_CONFIRM = function()
Plater.QuestLogUpdated()
end,
QUEST_COMPLETE = function()
Plater.QuestLogUpdated()
end,
QUEST_POI_UPDATE = function()
Plater.QuestLogUpdated()
end,
QUEST_QUERY_COMPLETE = function()
Plater.QuestLogUpdated()
end,
QUEST_DETAIL = function()
Plater.QuestLogUpdated()
end,
QUEST_FINISHED = function()
Plater.QuestLogUpdated()
end,
QUEST_GREETING = function()
Plater.QuestLogUpdated()
end,
QUEST_LOG_UPDATE = function()
Plater.QuestLogUpdated()
end,
UNIT_QUEST_LOG_CHANGED = function()
Plater.QuestLogUpdated()
end,
PLAYER_FOCUS_CHANGED = function()
Plater.OnPlayerTargetChanged()
end,
PLAYER_TARGET_CHANGED = function()
Plater.OnPlayerTargetChanged()
end,
PLAYER_UPDATE_RESTING = function()
Plater.RefreshAutoToggle()
end,
--update the unit name, triggered when the client receives the rest of the information about an unit
UNIT_NAME_UPDATE = function (_, unitID)
if (unitID) then
local plateFrame = C_NamePlate.GetNamePlateForUnit (unitID)
if (plateFrame and plateFrame.unitFrame.PlaterOnScreen) then
local unitFrame = plateFrame.unitFrame
local unitName = UnitName (unitID)
if DB_USE_NAME_TRANSLIT then
unitName = LibTranslit:Transliterate(unitName, TRANSLIT_MARK)
end
plateFrame [MEMBER_NAME] = unitName
plateFrame [MEMBER_NAMELOWER] = lower (plateFrame [MEMBER_NAME])
unitFrame [MEMBER_NAME] = plateFrame [MEMBER_NAME]
unitFrame [MEMBER_NAMELOWER] = plateFrame [MEMBER_NAMELOWER]
if (plateFrame.IsSelf) then
--name isn't shown in the personal bar
unitFrame.healthBar.unitName:SetText ("")
return
end
--schedule an name update on this nameplate
unitFrame.ScheduleNameUpdate = true
end
end
end,
ENCOUNTER_END = function()
Plater.CurrentEncounterID = nil
Plater.CurrentEncounterName = nil
Plater.CurrentEncounterDifficultyId = nil
Plater.LatestEncounter = time()
end,
ENCOUNTER_START = function (_, encounterID, encounterName, difficultyID)
Plater.CurrentEncounterID = encounterID
Plater.CurrentEncounterName = encounterName
Plater.CurrentEncounterDifficultyId = difficultyID
local _, zoneType = GetInstanceInfo()
if (zoneType == "raid") then
table.wipe (DB_CAPTURED_SPELLS)
end
end,
CHALLENGE_MODE_START = function()
table.wipe (DB_CAPTURED_SPELLS)
end,
ZONE_CHANGED_NEW_AREA = function()
if (InCombatLockdown()) then
C_Timer.After (1, wait_for_leave_combat)
return
end
Plater.CurrentEncounterID = nil
local pvpType, isFFA, faction = GetZonePVPInfo()
Plater.ZonePvpType = pvpType
Plater.UpdateBgPlayerRoleCache()
local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
--reset when entering in a battleground
if (instanceType == "pvp") then
table.wipe (DB_CAPTURED_SPELLS)
end
Plater.ZoneInstanceType = instanceType
Plater.ZoneName = name
IS_IN_OPEN_WORLD = Plater.ZoneInstanceType == "none"
IS_IN_INSTANCE = Plater.ZoneInstanceType == "raid" or Plater.ZoneInstanceType == "party"
Plater.UpdateAllPlates()
Plater.RefreshAutoToggle()
--hooks
Plater.ScheduleZoneChangeHook()
if (Plater.PlayerEnteringWorld) then
Plater.PlayerEnteringWorld = false
C_Timer.After (1, Plater.RunLoadScreenHook)
end
end,
ZONE_CHANGED_INDOORS = function()
Plater.RunFunctionForEvent ("ZONE_CHANGED_NEW_AREA")
end,
ZONE_CHANGED = function()
Plater.RunFunctionForEvent ("ZONE_CHANGED_NEW_AREA")
end,
PLAYER_ENTERING_WORLD = function()
Plater.db.profile.login_counter = Plater.db.profile.login_counter + 1
Plater.ScheduleRunFunctionForEvent (1, "ZONE_CHANGED_NEW_AREA")
Plater.ScheduleRunFunctionForEvent (1, "FRIENDLIST_UPDATE")
Plater.PlayerGuildName = GetGuildInfo ("player")
if (not Plater.PlayerGuildName or Plater.PlayerGuildName == "") then
Plater.PlayerGuildName = "ThePlayerHasNoGuildName/30Char"
--somethimes guild information isn't available at the login
C_Timer.After (10, delayed_guildname_check)
end
local pvpType, isFFA, faction = GetZonePVPInfo()
Plater.ZonePvpType = pvpType
local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
Plater.ZoneInstanceType = instanceType
--> ensure resource on target consistency after login:
local resourcesOnTarget = GetCVar ("nameplateResourceOnTarget") == CVAR_ENABLED
if resourcesOnTarget then
PlaterDBChr.resources_on_target = true
if (not InCombatLockdown()) then
SetCVar ("nameplateResourceOnTarget", CVAR_DISABLED) -- reset this to false always, as it conflicts
end
end
-- this seems to be gone as of 18.12.2020
--if Plater.db.profile.plate_config.friendlynpc.quest_enabled and not InCombatLockdown() then
--SetCVar("showQuestTrackingTooltips", 1) -- ensure it is turned on...
--end
--create the frame to hold the plater resoruce bar
Plater.Resources.CreateMainResourceFrame() --~resource
--run hooks on load screen
if (HOOK_LOAD_SCREEN.ScriptAmount > 0) then
Plater.PlayerEnteringWorld = true
end
end,
PLAYER_LOGOUT = function()
--Plater.SaveConsoleVariables()
end,
VARIABLES_LOADED = function()
C_Timer.After (0.1, Plater.ForceCVars)
C_Timer.After (0.2, Plater.RestoreProfileCVars)
C_Timer.After (0.3, Plater.UpdatePlateClickSpace)
-- hook CVar saving
hooksecurefunc('SetCVar', Plater.SaveConsoleVariables)
if C_CVar and C_CVar.SetCVar then
hooksecurefunc(C_CVar, 'SetCVar', Plater.SaveConsoleVariables)
end
hooksecurefunc('ConsoleExec', function(console)
local par1, par2, par3 = console:match('^(%S+)%s+(%S+)%s*(%S*)')
if par1 then
if par1:lower() == 'set' then -- /console SET cvar value
Plater.SaveConsoleVariables(par2, par3)
else -- /console cvar value
Plater.SaveConsoleVariables(par1, par2)
end
end
end)
end,
--many times at saved variables load the spell database isn't loaded yet
PLAYER_LOGIN = function()
--C_Timer.After (0.1, Plater.GetSpellForRangeCheck)
-- ensure OmniCC settings are up to date
C_Timer.After (1, Plater.RefreshOmniCCGroup)
--wait more time for the talents information be received from the server
C_Timer.After (4, Plater.GetHealthCutoffValue)
C_Timer.After (2, Plater.ScheduleZoneChangeHook)
C_Timer.After (5, function()
local petGUID = UnitGUID ("playerpet")
if (petGUID) then
local entry = {ownerGUID = Plater.PlayerGUID, ownerName = UnitName("player"), petName = UnitName("playerpet"), time = time()}
Plater.PlayerPetCache [petGUID] = entry
end
end)
--if the user just used a /reload to enable ui parenting, auto adjust the fine tune scale
--the uiparent fine tune scale initially: after testing and playing around with it, I think it should be 1 / UIParent:GetEffectiveScale() and scaling should be done by multiplying defaultScale * scaleFineTune
if (Plater.db.profile.use_ui_parent_just_enabled) then
Plater.db.profile.use_ui_parent_just_enabled = false
if (Plater.db.profile.ui_parent_scale_tune == 0) then
--@Ariani - march 9
Plater.db.profile.ui_parent_scale_tune = 1 / UIParent:GetEffectiveScale()
--@Tercio:
--if (UIParent:GetEffectiveScale() < 1) then
-- Plater.db.profile.ui_parent_scale_tune = 1 - UIParent:GetEffectiveScale()
--end
end
end
if (not Plater.db.profile.number_region_first_run) then
if (GetLocale() == "koKR") then
Plater.db.profile.number_region = "eastasia"
elseif (GetLocale() == "zhCN") then
Plater.db.profile.number_region = "eastasia"
elseif (GetLocale() == "zhTW") then
Plater.db.profile.number_region = "eastasia"
else
Plater.db.profile.number_region = "western"
end
Plater.db.profile.number_region_first_run = true
end
if (Plater.db.profile.reopoen_options_panel_on_tab) then
C_Timer.After (2, function()
Plater.OpenOptionsPanel()
PlaterOptionsPanelContainer:SelectIndex (Plater, Plater.db.profile.reopoen_options_panel_on_tab)
Plater.db.profile.reopoen_options_panel_on_tab = false
end)
end
--run hooks on player logon
if (HOOK_PLAYER_LOGON.ScriptAmount > 0) then
C_Timer.After (1, function()
for i = 1, HOOK_PLAYER_LOGON.ScriptAmount do
local hookInfo = HOOK_PLAYER_LOGON [i]
Plater.ScriptMetaFunctions.ScriptRunNoAttach (hookInfo, "Player Logon")
end
end)
end
--check addons incompatibility
--> Plater has issues with ElvUI due to be using the same namespace for unitFrame and healthBar
C_Timer.After (15, function()
if (IsAddOnLoaded ("ElvUI")) then
if (ElvUI[1] and ElvUI[1].private and ElvUI[1].private.nameplates and ElvUI[1].private.nameplates.enable) then
Plater:Msg ("'ElvUI Nameplates' and 'Plater Nameplates' are enabled and both nameplates won't work together.")
Plater:Msg ("You may disable ElvUI Nameplates at /elvui > Nameplates section or you may disable Plater at the addon control panel.")
end
end
end)
-- ensure resources are up to date
C_Timer.After (3, Plater.Resources.OnSpecChanged)
end,
DISPLAY_SIZE_CHANGED = function()
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
Plater.OnRetailNamePlateShow(plateFrame.UnitFrame)
end
end
Plater.UpdateAllPlates (true)
end,
UI_SCALE_CHANGED = function()
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
Plater.OnRetailNamePlateShow(plateFrame.UnitFrame)
end
Plater.UpdateAllPlates (true)
end,
--~created ~events ~oncreated
NAME_PLATE_CREATED = function (event, plateFrame)
--ViragDevTool_AddData({ctime = GetTime(), unit = plateFrame [MEMBER_UNITID] or "nil", stack = debugstack()}, "NAME_PLATE_CREATED - " .. (plateFrame [MEMBER_UNITID] or "nil"))
--> create the unitframe
local unitFrameOptions = {
ShowPowerBar = false,
ShowBorder = false,
CanModifyHealhBarColor = false,
ShowTargetOverlay = false,
ShowUnitName = false, --let Plater control the unit name
ClearUnitOnHide = false, --let Plater control when the cleanup is execute on the unit frame
}
local healthBarOptions = {
ShowHealingPrediction = false,
ShowShields = false,
}
local castBarOptions = {
FadeInTime = 0.02,
FadeOutTime = 0.66,
SparkHeight = 20,
LazyUpdateCooldown = 0.1,
}
local powerBarOptions = {
ShowAlternatePower = false,
}
--community patch by Ariani#0960 (discord)
--make the unitFrame be parented to UIParent allowing frames to be moved between strata levels
--March 3rd, 2019
local newUnitFrame
if (DB_USE_UIPARENT) then
--TODO: why is it not showing properly when V / V hide / show but when leaving / entering scren??? -> plateFrame for now...
--when using UIParent as the unit frame parent, adjust the unitFrame scale to be equal to blizzard plateFrame
newUnitFrame = DF:CreateUnitFrame (UIParent, plateFrame:GetName() .. "PlaterUnitFrame", unitFrameOptions, healthBarOptions, castBarOptions, powerBarOptions)
newUnitFrame:SetAllPoints()
newUnitFrame:SetFrameStrata ("BACKGROUND")
--plateFrame:HookScript("OnSizeChanged", Plater.UpdateUIParentScale)
--create a 33ms show animation played when the nameplate is added in the screen
--nevermind, unitFrame childs are kepping the last alpha value of the animation instead of reseting to their defaults
--i'm considering this a bug in the animation API from the game client
--at the moment this cannot be used
--newUnitFrame.ShowUIParentAnimation = DF:CreateAnimationHub (newUnitFrame, nil, function(self) Plater.UpdateUIParentScale (self:GetParent().PlateFrame) end)
--DF:CreateAnimation (newUnitFrame.ShowUIParentAnimation, "scale", 1, 0.033, .5, .5, 1, 1)
--DF:CreateAnimation (newUnitFrame.ShowUIParentAnimation, "alpha", 1, 0.033, .5, 1)
--end of patch
newUnitFrame.IsUIParent = true --expose to scripts the unitFrame is a UIParent child
else
newUnitFrame = DF:CreateUnitFrame (plateFrame, plateFrame:GetName() .. "PlaterUnitFrame", unitFrameOptions, healthBarOptions, castBarOptions, powerBarOptions)
end
plateFrame.unitFrame = newUnitFrame
--plateFrame.unitFrame:SetPoint("center", plateFrame)
plateFrame.unitFrame:EnableMouse(false)
--mix plater functions (most are for scripting support) into the unit frame
DF:Mixin(newUnitFrame, Plater.ScriptMetaFunctions)
--OnHide handler
newUnitFrame:HookScript("OnHide", newUnitFrame.OnHideWidget)
--OnHealthUpdate
newUnitFrame.healthBar:SetHook("OnHealthChange", Plater.OnHealthChange)
newUnitFrame.healthBar:SetHook("OnHealthMaxChange", Plater.OnHealthMaxChange)
--register details framework hooks
newUnitFrame.castBar:SetHook("OnShow", Plater.CastBarOnShow_Hook)
hooksecurefunc(newUnitFrame.castBar, "OnEvent", Plater.CastBarOnEvent_Hook)
hooksecurefunc(newUnitFrame.castBar, "OnTick", Plater.CastBarOnTick_Hook)
newUnitFrame.HasHooksRegistered = true
--backup the unit frame address so we can restore it in case a script messes up and override the unit frame
plateFrame.unitFramePlater = newUnitFrame
--set proprieties
plateFrame.Plater = true
plateFrame.unitFrame.Plater = true
plateFrame.unitFrame.PlateFrame = plateFrame
plateFrame.isNamePlate = true
plateFrame.unitFrame.isNamePlate = true
plateFrame.unitFrame.IsUnitNameplate = true
plateFrame.NameAnchor = 0
plateFrame.unitFrame.healthBar.isNamePlate = true
plateFrame.unitFrame.RefreshID = 0
-- "PlaterMainAuraIcon"
-- "PlaterSecondaryAuraIcon"
--> buff frames
--main buff frame
plateFrame.unitFrame.BuffFrame = CreateFrame ("frame", plateFrame.unitFrame:GetName() .. "BuffFrame1", plateFrame.unitFrame, BackdropTemplateMixin and "BackdropTemplate")
plateFrame.unitFrame.BuffFrame.amountAurasShown = 0
plateFrame.unitFrame.BuffFrame.PlaterBuffList = {}
plateFrame.unitFrame.BuffFrame.isNameplate = true
plateFrame.unitFrame.BuffFrame.unitFrame = plateFrame.unitFrame --used on resource frame anchor update
plateFrame.unitFrame.BuffFrame.healthBar = plateFrame.unitFrame.healthBar
plateFrame.unitFrame.BuffFrame.AuraCache = {}
--secondary buff frame
plateFrame.unitFrame.BuffFrame2 = CreateFrame ("frame", plateFrame.unitFrame:GetName() .. "BuffFrame2", plateFrame.unitFrame, BackdropTemplateMixin and "BackdropTemplate")
plateFrame.unitFrame.BuffFrame2.amountAurasShown = 0
plateFrame.unitFrame.BuffFrame2.PlaterBuffList = {}
plateFrame.unitFrame.BuffFrame2.isNameplate = true
plateFrame.unitFrame.BuffFrame2.unitFrame = plateFrame.unitFrame
plateFrame.unitFrame.BuffFrame2.healthBar = plateFrame.unitFrame.healthBar
plateFrame.unitFrame.BuffFrame2.AuraCache = {}
--> identify aura containers
plateFrame.unitFrame.BuffFrame.Name = "Main" --aura frame 1
plateFrame.unitFrame.BuffFrame2.Name = "Secondary" --aura frame 2
--> store the secondary anchor inside the regular buff container for speed
plateFrame.unitFrame.BuffFrame.BuffFrame2 = plateFrame.unitFrame.BuffFrame2
plateFrame.unitFrame.BuffFrame2.BuffFrame1 = plateFrame.unitFrame.BuffFrame
--> unit aura cache
plateFrame.unitFrame.AuraCache = {}
plateFrame.unitFrame.GhostAuraCache = {}
local healthBar = plateFrame.unitFrame.healthBar
--cache the unit frame within the health and cast bars, this avoid GetParent() calls
healthBar.unitFrame = plateFrame.unitFrame
plateFrame.unitFrame.castBar.unitFrame = plateFrame.unitFrame
--> pre create the scale animation used on animations for spell hits
Plater.CreateScaleAnimation (plateFrame)
--> create the animations when the unit goes out of range
Plater.CreateAlphaAnimation (plateFrame)
--store custom indicators
plateFrame.unitFrame.CustomIndicators = {}
--> cliclable area debug
plateFrame.debugAreaTexture = plateFrame:CreateTexture (nil, "background")
plateFrame.debugAreaTexture:SetColorTexture (.1, .1, .1, .834)
plateFrame.debugAreaTexture:SetAllPoints()
plateFrame.debugAreaTexture:Hide()
plateFrame.debugAreaText = plateFrame:CreateFontString (nil, "artwork", "GameFontNormal")
plateFrame.debugAreaText:SetPoint ("bottom", plateFrame.debugAreaTexture, "top", 0, 1)
plateFrame.debugAreaText:SetText ("valid area for clicks")
plateFrame.debugAreaText:SetTextColor (.7, .7, .7)
plateFrame.debugAreaText:Hide()
--> Indicators
--container to store created indicators, they are created at run time
plateFrame.IconIndicators = {}
--> flash aggro
Plater.CreateAggroFlashFrame (plateFrame)
plateFrame.playerHasAggro = false
--> target indicators
--left and right target indicators
plateFrame.unitFrame.TargetTextures2Sides = {}
plateFrame.unitFrame.TargetTextures4Sides = {}
for i = 1, 2 do
local targetTexture = healthBar:CreateTexture (nil, "overlay")
targetTexture:SetDrawLayer ("overlay", 7)
tinsert (plateFrame.unitFrame.TargetTextures2Sides, targetTexture)
end
for i = 1, 4 do
local targetTexture = healthBar:CreateTexture (nil, "overlay")
targetTexture:SetDrawLayer ("overlay", 7)
tinsert (plateFrame.unitFrame.TargetTextures4Sides, targetTexture)
end
--two extra target glow placed outside the healthbar, one above and another below the health bar
local TargetNeonUp = plateFrame.unitFrame:CreateTexture (nil, "overlay")
TargetNeonUp:SetDrawLayer ("overlay", 7)
TargetNeonUp:SetBlendMode ("ADD")
TargetNeonUp:Hide()
plateFrame.TargetNeonUp = TargetNeonUp
plateFrame.unitFrame.TargetNeonUp = TargetNeonUp
local TargetNeonDown = plateFrame.unitFrame:CreateTexture (nil, "overlay")
TargetNeonDown:SetDrawLayer ("overlay", 7)
TargetNeonDown:SetBlendMode ("ADD")
TargetNeonDown:SetTexCoord (0, 1, 1, 0)
TargetNeonDown:Hide()
plateFrame.TargetNeonDown = TargetNeonDown
plateFrame.unitFrame.TargetNeonDown = TargetNeonDown
--> target overlay (the texture added above the nameplate when the unit is selected)
plateFrame.unitFrame.targetOverlayTexture = healthBar:CreateTexture (nil, "artwork")
plateFrame.unitFrame.targetOverlayTexture:SetDrawLayer ("artwork", 2)
plateFrame.unitFrame.targetOverlayTexture:SetBlendMode ("ADD")
plateFrame.unitFrame.targetOverlayTexture:SetAllPoints()
--> create the highlight texture (when the mouse passes over the nameplate and receives a highlight)
Plater.CreateHighlightNameplate (plateFrame)
--> health bar overlay
--> create an overlay frame that sits just above the health bar
--this is ideal for adding borders and other overlays
healthBar.FrameOverlay = CreateFrame ("frame", "$parentOverlayFrame", healthBar, BackdropTemplateMixin and "BackdropTemplate")
healthBar.FrameOverlay:SetAllPoints()
--> execute range textures and animations
--health cutoff texture shown inside the health bar
local healthCutOff = healthBar:CreateTexture (nil, "overlay")
healthCutOff:SetDrawLayer ("overlay", 7)
healthCutOff:SetTexture ([[Interface\AddOns\Plater\images\health_bypass_indicator]])
healthCutOff:SetBlendMode ("ADD")
healthCutOff:Hide()
healthBar.healthCutOff = healthCutOff
healthBar.ExecuteRangeHealthCutOff = healthCutOff --alias for scripting
local cutoffAnimationOnPlay = function()
healthCutOff:Show()
end
local cutoffAnimationOnStop = function()
healthCutOff:SetAlpha (.5)
end
local healthCutOffShowAnimation = DF:CreateAnimationHub (healthCutOff, cutoffAnimationOnPlay, cutoffAnimationOnStop)
DF:CreateAnimation (healthCutOffShowAnimation, "Scale", 1, .2, .3, .3, 1.2, 1.2)
DF:CreateAnimation (healthCutOffShowAnimation, "Scale", 2, .2, 1.2, 1.2, 1, 1)
DF:CreateAnimation (healthCutOffShowAnimation, "Alpha", 1, .2, .2, 1)
DF:CreateAnimation (healthCutOffShowAnimation, "Alpha", 2, .2, 1, .5)
healthCutOff.ShowAnimation = healthCutOffShowAnimation
--shield indicator
local shieldIndicator = healthBar:CreateTexture(nil, "overlay", nil, 7)
shieldIndicator:SetPoint("bottomleft", healthBar, "bottomleft", 0, 0)
shieldIndicator:SetHeight(3)
shieldIndicator:SetTexture([[Interface\AddOns\Plater\images\shieldbar]])
shieldIndicator:SetAlpha(0.85)
shieldIndicator:Hide()
healthBar.shieldIndicator = shieldIndicator
--overlay for the healthbar showing the healthbar of the execute (shown when the unit is on execute range)
local executeRange = healthBar:CreateTexture (nil, "border")
executeRange:SetTexture ([[Interface\AddOns\Plater\images\execute_bar]])
PixelUtil.SetPoint (executeRange, "left", healthBar, "left", 0, 0)
healthBar.executeRange = executeRange
healthBar.ExecuteRangeBar = executeRange --alias for scripting
executeRange:Hide()
--two extra execute glow placed outside the healthbar (disabled by default)
local executeGlowUp = healthBar:CreateTexture (nil, "overlay")
executeGlowUp:SetTexture ([[Interface\AddOns\Plater\images\blue_neon]])
executeGlowUp:SetTexCoord (0, 1, 0, 0.5)
executeGlowUp:SetHeight (32)
executeGlowUp:SetBlendMode ("ADD")
executeGlowUp:Hide()
PixelUtil.SetPoint (executeGlowUp, "bottomright", healthBar, "topright", 0, 0)
PixelUtil.SetPoint (executeGlowUp, "bottomleft", healthBar, "topleft", 0, 0)
healthBar.ExecuteGlowUp = executeGlowUp
local executeGlowDown = healthBar:CreateTexture (nil, "overlay")
executeGlowDown:SetTexture ([[Interface\AddOns\Plater\images\blue_neon]])
executeGlowDown:SetTexCoord (0, 1, 0.5, 1)
executeGlowDown:SetHeight (32)
executeGlowDown:SetBlendMode ("ADD")
executeGlowDown:Hide()
PixelUtil.SetPoint (executeGlowDown, "topright", healthBar, "bottomright", 0, 0)
PixelUtil.SetPoint (executeGlowDown, "topleft", healthBar, "bottomleft", 0, 0)
healthBar.ExecuteGlowDown = executeGlowDown
local executeGlowAnimationOnPlay = function (self)
self:GetParent():Show()
end
local executeGlowAnimationOnStop = function()
end
executeGlowUp.ShowAnimation = DF:CreateAnimationHub (executeGlowUp, executeGlowAnimationOnPlay, executeGlowAnimationOnStop)
DF:CreateAnimation (executeGlowUp.ShowAnimation, "Scale", 1, .2, 1, .1, 1, 1.2, "bottom", 0, 0)
DF:CreateAnimation (executeGlowUp.ShowAnimation, "Scale", 1, .2, 1, 1, 1, 1)
executeGlowDown.ShowAnimation = DF:CreateAnimationHub (executeGlowDown, executeGlowAnimationOnPlay, executeGlowAnimationOnStop)
DF:CreateAnimation (executeGlowDown.ShowAnimation, "Scale", 1, .2, 1, .1, 1, 1.2, "top", 0, 0)
DF:CreateAnimation (executeGlowDown.ShowAnimation, "Scale", 1, .2, 1, 1.1, 1, 1)
--> create the raid target widgets
--raid target inside the health bar
local raidTarget = healthBar:CreateTexture (nil, "overlay")
PixelUtil.SetPoint (raidTarget, "right", raidTarget:GetParent(), "right", -2, 0)
plateFrame.RaidTarget = raidTarget
healthBar.ExtraRaidMark = raidTarget --alias for scripting
--raid target outside the health bar
plateFrame.unitFrame.PlaterRaidTargetFrame = CreateFrame ("frame", nil, plateFrame.unitFrame, BackdropTemplateMixin and "BackdropTemplate")
local targetFrame = plateFrame.unitFrame.PlaterRaidTargetFrame
targetFrame:SetSize (22, 22)
PixelUtil.SetPoint (targetFrame, "right", healthBar, "left", -15, 0)
--icon
targetFrame.RaidTargetIcon = targetFrame:CreateTexture (nil, "artwork")
targetFrame.RaidTargetIcon:SetAllPoints()
targetFrame.RaidTargetIcon:SetTexture ([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
--create show animation to play when the icon is set to show
local raidMarkAnimation = DF:CreateAnimationHub (targetFrame.RaidTargetIcon)
DF:CreateAnimation (raidMarkAnimation, "Scale", 1, .075, .1, .1, 1.2, 1.2)
DF:CreateAnimation (raidMarkAnimation, "Scale", 2, .075, 1.2, 1.2, 1, 1)
targetFrame.RaidTargetIcon.ShowAnimation = raidMarkAnimation
--> create details! integration strings
healthBar.DetailsRealTime = healthBar:CreateFontString (nil, "overlay", "GameFontNormal")
healthBar.DetailsRealTimeFromPlayer = healthBar:CreateFontString (nil, "overlay", "GameFontNormal")
healthBar.DetailsDamageTaken = healthBar:CreateFontString (nil, "overlay", "GameFontNormal")
--> tick frames (these frames are used for OnUpdate scripts)
local onTickFrame = CreateFrame ("frame", nil, plateFrame, BackdropTemplateMixin and "BackdropTemplate")
plateFrame.OnTickFrame = onTickFrame
onTickFrame.unit = plateFrame [MEMBER_UNITID]
onTickFrame.HealthBar = healthBar
onTickFrame.PlateFrame = plateFrame
onTickFrame.unitFrame = plateFrame.unitFrame
onTickFrame.BuffFrame = plateFrame.unitFrame.BuffFrame
onTickFrame.BuffFrame2 = plateFrame.unitFrame.BuffFrame2
--> create a second castbar
local castBar2 = DF:CreateCastBar (plateFrame.unitFrame, "$parentCastBar2")
plateFrame.unitFrame.castBar2 = castBar2
castBar2.Icon:ClearAllPoints()
castBar2.Icon:SetPoint("right", castBar2, "left", -1, 0)
castBar2.FrameOverlay = CreateFrame ("frame", "$parentOverlayFrame", castBar2, BackdropTemplateMixin and "BackdropTemplate")
castBar2.FrameOverlay:SetAllPoints()
--pushing the spell name up
castBar2.Text:SetParent (castBar2.FrameOverlay)
--does have a border but its alpha is zero by default
castBar2.FrameOverlay:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
castBar2.FrameOverlay:SetBackdropBorderColor (1, 1, 1, 0)
castBar2:SetPoint("topleft", plateFrame.unitFrame.castBar, "bottomleft", 0, -2)
castBar2:SetPoint("topright", plateFrame.unitFrame.castBar, "bottomright", 0, -2)
--> unit name
--regular name
plateFrame.unitFrame.unitName:SetParent (healthBar) --the name is parented to unitFrame in the framework, parent it to health bar
healthBar.unitName = plateFrame.unitFrame.unitName
healthBar.PlateFrame = plateFrame
plateFrame.unitName = plateFrame.unitFrame.unitName
plateFrame.CurrentUnitNameString = plateFrame.unitFrame.unitName
healthBar.unitName:SetDrawLayer ("overlay", 7)
--special name and title
local ActorNameSpecial = plateFrame.unitFrame:CreateFontString (nil, "artwork", "GameFontNormal")
plateFrame.unitFrame.ActorNameSpecial = ActorNameSpecial --alias for scripts
plateFrame.ActorNameSpecial = ActorNameSpecial
PixelUtil.SetPoint (plateFrame.ActorNameSpecial, "center", plateFrame, "center", 0, 0)
plateFrame.ActorNameSpecial:Hide()
local ActorTitleSpecial = plateFrame.unitFrame:CreateFontString (nil, "artwork", "GameFontNormal")
plateFrame.unitFrame.ActorTitleSpecial = ActorTitleSpecial --alias for scripts
plateFrame.ActorTitleSpecial = ActorTitleSpecial
PixelUtil.SetPoint (plateFrame.ActorTitleSpecial, "top", ActorNameSpecial, "bottom", 0, -2)
plateFrame.ActorTitleSpecial:Hide()
--> level text
local actorLevel = healthBar:CreateFontString (nil, "overlay", "GameFontNormal")
healthBar.actorLevel = actorLevel
--> life percent text
local lifePercent = healthBar:CreateFontString (nil, "overlay", "GameFontNormal")
lifePercent:SetDrawLayer ("overlay", 5)
healthBar.lifePercent = lifePercent
--> non target occlusion texture (disabled by default, it applies alayer of darkness above nameplates of units that aren't the player target)
local obscuredTexture = healthBar:CreateTexture (nil, "overlay")
obscuredTexture:SetDrawLayer ("overlay", 6)
obscuredTexture:SetAllPoints()
obscuredTexture:SetTexture ("Interface\\Tooltips\\UI-Tooltip-Background")
obscuredTexture:SetVertexColor (0, 0, 0, 1)
plateFrame.Obscured = obscuredTexture
--> create the extra icon frame (used for the special aura)
local options = {
icon_width = 20,
icon_height = 20,
texcoord = {.1, .9, .1, .9},
show_text = true,
}
plateFrame.unitFrame.ExtraIconFrame = DF:CreateIconRow (plateFrame.unitFrame, "$parentExtraIconRow", options)
plateFrame.unitFrame.ExtraIconFrame:ClearIcons()
plateFrame.unitFrame.ExtraIconFrame.RefreshID = 0
plateFrame.unitFrame.ExtraIconFrame.AuraCache = {}
--> cache the extra icon frame inside the buff frame for speed
plateFrame.unitFrame.BuffFrame.ExtraIconFrame = plateFrame.unitFrame.ExtraIconFrame
--> Support for DBM and BigWigs Nameplate Auras
Plater.CreateBossModAuraFrame(plateFrame.unitFrame)
--> 3D model frame
plateFrame.Top3DFrame = CreateFrame ("playermodel", plateFrame:GetName() .. "3DFrame", plateFrame, "ModelWithControlsTemplate")
plateFrame.Top3DFrame:SetPoint ("bottom", plateFrame, "top", 0, -100)
plateFrame.Top3DFrame:SetSize (200, 250)
plateFrame.Top3DFrame:EnableMouse (false)
plateFrame.Top3DFrame:EnableMouseWheel (false)
plateFrame.Top3DFrame:Hide()
plateFrame.unitFrame.Top3DFrame = plateFrame.Top3DFrame
--> castbar // create custom widgets for the cast bar
--[=[
castbar members:
.Text text string to show the spell name
.background default background created in the unit frame
.extraBackground an extra background shown when it has low alpha
.barTexture cast bar texture
.Icon texture to show the spell icon
.Spark texture that follows the cast progress
.percentText text showing that cast progress, usually is the time left to finish the cast
.BorderShield border shown in the icon when the cast isn't interruptible
.FrameOverlay invisible frame shown above the nameplate, useful for creating overlays
.TargetName text showing the name for the target
--]=]
--set a UnitFrame member so scripts can get a quick reference of the unit frame from the castbar without calling for GetParent()
local castBar = plateFrame.unitFrame.castBar
castBar.PlateFrame = plateFrame
castBar.unitFrame = plateFrame.unitFrame
castBar.IsCastBar = true
castBar.isNamePlate = true
castBar.ThrottleUpdate = 0
--check if Masque is enabled on Plater and reskin the cast icon
local castIconFrame = castBar.Icon
if (Plater.Masque and not castIconFrame.Masqued) then
--as masque only skins buttons and not textures alone, work around that with a dummy frame and some meta-table shenannigans to not break anything...
--create the button frame and anchor the original icon within
local dummyMasqueIconButton = CreateFrame ("Button", castBar:GetName() .. "dummyMasqueIconButton", castBar, BackdropTemplateMixin and "BackdropTemplate")
dummyMasqueIconButton:SetSize(castIconFrame:GetSize())
castIconFrame:ClearAllPoints()
castIconFrame:SetParent(dummyMasqueIconButton)
castIconFrame:SetPoint("TOPLEFT")
castIconFrame:SetPoint("BOTTOMRIGHT")
castIconFrame:Show()
--overwrite original and keep a reference
dummyMasqueIconButton.Icon = castIconFrame
castBar.IconOrig = castIconFrame
castBar.Icon = dummyMasqueIconButton
--now ensure all calls to the icon which are directed towards the original texture are re-routed to the icon texture
local origIndex = getmetatable(dummyMasqueIconButton).__index
local metaTable = {
__index = function (t,k)
--print(k, rawget(dummyMasqueIconButton, k), rawget(origIndex, k), castIconFrame[k])
local v = rawget(dummyMasqueIconButton, k) or rawget(origIndex, k)
if not v then
v = castIconFrame[k]--rawget(castIconFrame, k) or rawget(getmetatable(castIconFrame).__index, k) or rawget(t, k)
if type(v) == "function" then
return function(self, ...) return castIconFrame[k](castIconFrame, ...) end
end
end
return v
end,
__newindex = function (t,k,v)
rawset(t, k, v)
end
}
setmetatable(dummyMasqueIconButton, metaTable)
dummyMasqueIconButton:Show()
-- now skin!
local t = {
Icon = castIconFrame,
}
Plater.Masque.CastIcon:AddButton (dummyMasqueIconButton, t, "Frame", true)
Plater.Masque.CastIcon:ReSkin(dummyMasqueIconButton)
castIconFrame.Masqued = true
dummyMasqueIconButton.Masqued = true
end
--mix the plater functions into the castbar (most of the functions are for scripting support)
DF:Mixin (castBar, Plater.ScriptMetaFunctions)
castBar:HookScript ("OnHide", castBar.OnHideWidget)
--> create an overlay frame that sits just above the castbar
--this is ideal for adding borders and other overlays
castBar.FrameOverlay = CreateFrame ("frame", "$parentOverlayFrame", castBar, BackdropTemplateMixin and "BackdropTemplate")
castBar.FrameOverlay:SetAllPoints()
--pushing the spell name up
castBar.Text:SetParent (castBar.FrameOverlay)
--does have a border but its alpha is zero by default
castBar.FrameOverlay:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
castBar.FrameOverlay:SetBackdropBorderColor (1, 1, 1, 0)
--creates the target name overlay which shows who the unit is targetting while casting (this is disabled by default)
castBar.FrameOverlay.TargetName = castBar.FrameOverlay:CreateFontString (nil, "overlay", "GameFontNormal")
castBar.TargetName = castBar.FrameOverlay.TargetName --alias for scripts
--> create the spell color texture
castBar.castColorTexture = castBar:CreateTexture("$parentCastColor", "background", nil, -6)
--create custom border frame for modeling
if (Plater.CreateCustomDesignBorder) then
Plater.CreateCustomDesignBorder(castBar)
end
--> border
--create a border using default borders from the retail game
--local healthBarBorder = CreateFrame("frame", nil, plateFrame.unitFrame.healthBar, (IS_WOW_PROJECT_NOT_MAINLINE) and "PlaterNameplateFullBorderTemplate" or "NamePlateFullBorderTemplate")
local healthBarBorder = DF:CreateFullBorder(nil, plateFrame.unitFrame.healthBar)
healthBarBorder.Left:SetDrawLayer("OVERLAY", 6)
healthBarBorder.Right:SetDrawLayer("OVERLAY", 6)
healthBarBorder.Top:SetDrawLayer("OVERLAY", 6)
healthBarBorder.Bottom:SetDrawLayer("OVERLAY", 6)
plateFrame.unitFrame.healthBar.border = healthBarBorder
--local powerBarBorder = CreateFrame("frame", nil, plateFrame.unitFrame.powerBar, (IS_WOW_PROJECT_NOT_MAINLINE) and "PlaterNameplateFullBorderTemplate" or "NamePlateFullBorderTemplate")
local powerBarBorder = DF:CreateFullBorder(nil, plateFrame.unitFrame.powerBar)
powerBarBorder.Left:SetDrawLayer("OVERLAY", 6)
powerBarBorder.Right:SetDrawLayer("OVERLAY", 6)
powerBarBorder.Top:SetDrawLayer("OVERLAY", 6)
powerBarBorder.Bottom:SetDrawLayer("OVERLAY", 6)
plateFrame.unitFrame.powerBar.border = powerBarBorder
powerBarBorder:SetVertexColor (0, 0, 0, 1)
--create custom border frame for modeling
if (Plater.CreateCustomDesignBorder) then
Plater.CreateCustomDesignBorder(healthBar)
end
--create custom border frame for modeling
if (Plater.CreateCustomDesignBorder) then
Plater.CreateCustomDesignBorder(plateFrame.unitFrame.powerBar)
end
--> focus indicator
local focusIndicator = healthBar:CreateTexture(nil, "overlay")
focusIndicator:SetDrawLayer("overlay", 2)
PixelUtil.SetPoint(focusIndicator, "topleft", healthBar, "topleft", 0, 0)
PixelUtil.SetPoint(focusIndicator, "bottomright", healthBar, "bottomright", 0, 0)
focusIndicator:Hide()
healthBar.FocusIndicator = focusIndicator
plateFrame.FocusIndicator = focusIndicator
plateFrame.unitFrame.FocusIndicator = focusIndicator
--> low aggro warning
plateFrame.unitFrame.aggroGlowUpper = plateFrame:CreateTexture (nil, "background", nil, -4)
PixelUtil.SetPoint (plateFrame.unitFrame.aggroGlowUpper, "bottomleft", plateFrame.unitFrame.healthBar, "topleft", -3, 0)
PixelUtil.SetPoint (plateFrame.unitFrame.aggroGlowUpper, "bottomright", plateFrame.unitFrame.healthBar, "topright", 3, 0)
plateFrame.unitFrame.aggroGlowUpper:SetTexture ([[Interface\BUTTONS\UI-Panel-Button-Glow]])
plateFrame.unitFrame.aggroGlowUpper:SetTexCoord (0, 95/128, 0, 9/64)
plateFrame.unitFrame.aggroGlowUpper:SetBlendMode ("ADD")
plateFrame.unitFrame.aggroGlowUpper:SetHeight (4)
plateFrame.unitFrame.aggroGlowUpper:Hide()
plateFrame.unitFrame.aggroGlowLower = plateFrame:CreateTexture (nil, "background", nil, -4)
PixelUtil.SetPoint (plateFrame.unitFrame.aggroGlowLower, "topleft", plateFrame.unitFrame.healthBar, "bottomleft", -3, 0)
PixelUtil.SetPoint (plateFrame.unitFrame.aggroGlowLower, "topright", plateFrame.unitFrame.healthBar, "bottomright", 3, 0)
plateFrame.unitFrame.aggroGlowLower:SetTexture ([[Interface\BUTTONS\UI-Panel-Button-Glow]])
plateFrame.unitFrame.aggroGlowLower:SetTexCoord (0, 95/128, 30/64, 38/64)
plateFrame.unitFrame.aggroGlowLower:SetBlendMode ("ADD")
plateFrame.unitFrame.aggroGlowLower:SetHeight (4)
plateFrame.unitFrame.aggroGlowLower:Hide()
--> widget container
if IS_WOW_PROJECT_MAINLINE then
plateFrame.unitFrame.WidgetContainer = CreateFrame("frame", "", plateFrame.unitFrame, "UIWidgetContainerNoResizeTemplate")
plateFrame.unitFrame.WidgetContainer.horizontalRowContainerPool = CreateFramePool("FRAME", plateFrame.unitFrame.WidgetContainer);
Plater.SetAnchor (plateFrame.unitFrame.WidgetContainer, Plater.db.profile.widget_bar_anchor, plateFrame.unitFrame)
plateFrame.unitFrame.WidgetContainer:SetScale(Plater.db.profile.widget_bar_scale)
plateFrame.unitFrame.WidgetContainer:UnregisterForWidgetSet()
end
--> name plate created hook
if (HOOK_NAMEPLATE_CREATED.ScriptAmount > 0) then
for i = 1, HOOK_NAMEPLATE_CREATED.ScriptAmount do
local globalScriptObject = HOOK_NAMEPLATE_CREATED [i]
local scriptContainer = plateFrame.unitFrame:ScriptGetContainer()
local scriptInfo = plateFrame.unitFrame:HookGetInfo (globalScriptObject, scriptContainer, "Nameplate Created")
plateFrame.unitFrame:ScriptRunHook (scriptInfo, "Nameplate Created")
end
end
end,
-- ~added ãdded
NAME_PLATE_UNIT_ADDED = function (event, unitBarId)
--ViragDevTool_AddData({ctime = GetTime(), unit = unitBarId or "nil", stack = debugstack()}, "NAME_PLATE_UNIT_ADDED - " .. (unitBarId or "nil"))
--debug for hunter faith death
-- if (select (2, UnitClass (unitBarId)) == "HUNTER") then
-- print ("nameplate added", UnitName (unitBarId))
-- end
local unitID = unitBarId
local plateFrame = C_NamePlate.GetNamePlateForUnit (unitID)
if (not plateFrame) then
return
end
--> check the unit frame integrity, several times some weakaura or script mess with the unit frame
if (not plateFrame.unitFrame or not plateFrame.unitFrame.SetUnit) then
plateFrame.unitFrame = plateFrame.unitFramePlater
end
--get and format the reaction to always be the value of the constants, then cache the reaction in some widgets for performance
local reaction = UnitReaction (unitID, "player") or 1
reaction = reaction <= Plater.UnitReaction.UNITREACTION_HOSTILE and Plater.UnitReaction.UNITREACTION_HOSTILE or reaction >= Plater.UnitReaction.UNITREACTION_FRIENDLY and Plater.UnitReaction.UNITREACTION_FRIENDLY or Plater.UnitReaction.UNITREACTION_NEUTRAL
local isWidgetOnlyMode = (IS_WOW_PROJECT_MAINLINE) and UnitNameplateShowsWidgetsOnly (unitID) or false
local isBattlePet = (IS_WOW_PROJECT_MAINLINE) and UnitIsBattlePet(unitID) or false
local isPlayer = UnitIsPlayer (unitID)
local isSelf = UnitIsUnit (unitID, "player")
plateFrame [MEMBER_NPCID] = nil
plateFrame.unitFrame [MEMBER_NPCID] = nil
plateFrame [MEMBER_GUID] = UnitGUID (unitID) or ""
plateFrame.unitFrame [MEMBER_GUID] = plateFrame [MEMBER_GUID]
if (not isPlayer) then
Plater.GetNpcID (plateFrame)
end
local actorType
if (unitID) then
if (isSelf) then
--> personal health bar
actorType = ACTORTYPE_PLAYER
else
--> regular nameplate
if (isPlayer) then
--unit is a player
if (reaction >= Plater.UnitReaction.UNITREACTION_FRIENDLY) then
actorType = ACTORTYPE_FRIENDLY_PLAYER
else
actorType = ACTORTYPE_ENEMY_PLAYER
end
else
--the unit is a npc
if (reaction >= Plater.UnitReaction.UNITREACTION_FRIENDLY) then
actorType = ACTORTYPE_FRIENDLY_NPC
elseif isBattlePet then
actorType = ACTORTYPE_FRIENDLY_NPC
else
--includes neutral npcs
actorType = ACTORTYPE_ENEMY_NPC
end
end
end
end
local isPlateEnabled = (DB_PLATE_CONFIG [actorType].module_enabled and not isWidgetOnlyMode) or (isWidgetOnlyMode and Plater.db.profile.usePlaterWidget)
isPlateEnabled = (isPlayer or not Plater.ForceBlizzardNameplateUnits[plateFrame [MEMBER_NPCID]]) and isPlateEnabled
local blizzardPlateFrameID = tostring(plateFrame.UnitFrame)
plateFrame.unitFrame.blizzardPlateFrameID = blizzardPlateFrameID
--if (not plateFrame.UnitFrame.HasPlaterHooksRegistered) then
if not HOOKED_BLIZZARD_PLATEFRAMES[blizzardPlateFrameID] then
--print(HOOKED_BLIZZARD_PLATEFRAMES[tostring(plateFrame.UnitFrame)], tostring(plateFrame.UnitFrame), plateFrame.UnitFrame.HasPlaterHooksRegistered)
--hook the retail nameplate
--plateFrame.UnitFrame:HookScript("OnShow", Plater.OnRetailNamePlateShow)
hooksecurefunc(plateFrame.UnitFrame, "Show", Plater.OnRetailNamePlateShow)
--plateFrame.UnitFrame.HasPlaterHooksRegistered = true
HOOKED_BLIZZARD_PLATEFRAMES[blizzardPlateFrameID] = true
end
if isPlateEnabled then
ENABLED_BLIZZARD_PLATEFRAMES[blizzardPlateFrameID] = false
else
ENABLED_BLIZZARD_PLATEFRAMES[blizzardPlateFrameID] = true
plateFrame.unitFrame:Hide()
return
end
if not NAMEPLATES_ON_SCREEN_CACHE[unitID] then
NAMEPLATES_ON_SCREEN_CACHE[unitID] = true
NUM_NAMEPLATES_ON_SCREEN = NUM_NAMEPLATES_ON_SCREEN + 1
end
--hide blizzard namepaltes
--plateFrame.UnitFrame:Hide()
Plater.OnRetailNamePlateShow(plateFrame.UnitFrame)
--show plater unit frame
plateFrame.unitFrame:Show()
plateFrame.unitFrame.PlaterOnScreen = true
Plater.AddToAuraUpdate(unitID)
--save the last unit type shown in this plate
plateFrame.PreviousUnitType = plateFrame.actorType
--caching frames
local unitFrame = plateFrame.unitFrame
local castBar = unitFrame.castBar
local healthBar = unitFrame.healthBar
if (unitFrame.ShowUIParentAnimation) then
unitFrame.ShowUIParentAnimation:Play()
end
--if (not plateFrame.UnitFrame.HasPlaterHooksRegistered) then
if not HOOKED_BLIZZARD_PLATEFRAMES[tostring(plateFrame.UnitFrame)] then
--print(HOOKED_BLIZZARD_PLATEFRAMES[tostring(plateFrame.UnitFrame)], tostring(plateFrame.UnitFrame), plateFrame.UnitFrame.HasPlaterHooksRegistered)
--hook the retail nameplate
--plateFrame.UnitFrame:HookScript("OnShow", Plater.OnRetailNamePlateShow)
hooksecurefunc(plateFrame.UnitFrame, "Show", Plater.OnRetailNamePlateShow)
--plateFrame.UnitFrame.HasPlaterHooksRegistered = true
HOOKED_BLIZZARD_PLATEFRAMES[tostring(plateFrame.UnitFrame)] = true
end
unitFrame.nameplateScaleAdjust = 1
if (DB_USE_UIPARENT) then
plateFrame:HookScript("OnSizeChanged", Plater.UpdateUIParentScale)
Plater.UpdateUIParentScale(plateFrame)
else
unitFrame:SetScale (1) --reset scale
end
--check if the hide hook is registered on this Blizzard nameplate
if (not unitFrame.HasHideHookRegistered) then
--onHide for unitFrame
plateFrame.unitFrame:HookScript ("OnHide", unitFrame.OnHideWidget)
--onShow for castbar
castBar:SetHook ("OnShow", Plater.CastBarOnShow_Hook)
unitFrame.HasHideHookRegistered = true
end
--powerbar are disabled by default in the settings table, called SetUnit will make the framework hide the power bar
--SetPowerBarSize() will show the power bar or the personal resource bar update also will show it
--ensure castBar is enabled properly when switching actorType or unit (with unit changing, it will be properly enabled)
local castBarWasEnabled = (unitFrame.Settings.ShowCastBar and (plateFrame.PreviousUnitType == actorType)) or (unitFrame.unit ~= unitID)
unitFrame.Settings.ShowCastBar = true -- reset to default, clearing later.
--set the unit
unitFrame:SetUnit (unitID)
--reset performance unit
unitFrame.isPerformanceUnit = nil
unitFrame.healthBar.isPerformanceUnit = nil
if (Plater.PerformanceUnits[plateFrame[MEMBER_NPCID]]) then
--print("perf", plateFrame[MEMBER_NPCID])
unitFrame.castBar:SetUnit(nil) -- no casts
Plater.RemoveFromAuraUpdate (unitID) -- no auras
unitFrame.isPerformanceUnit = true
unitFrame.healthBar.isPerformanceUnit = true
end
--show unit name, the frame work will hide it due to ShowUnitName is set to false
unitFrame.unitName:Show()
--set the unitID in the unitFrame, several script and external addons read this member, adding different variations to be compatible with all
unitFrame.unit = unitID
unitFrame.namePlateUnitToken = unitID
unitFrame.displayedUnit = unitID
--was causing taints because MEMBER_UNITID is an actually member from the default blizzard nameplate
--so when this nameplate is reclycled to be in a proteecteed nameplate, it was causing taints
--plateFrame [MEMBER_UNITID] = unitID --causing taints
plateFrame.QuestAmountCurrent = nil
plateFrame.QuestAmountTotal = nil
plateFrame.QuestText = nil
plateFrame.QuestName = nil
plateFrame.QuestIsCampaign = nil
unitFrame.QuestAmountCurrent = nil
unitFrame.QuestAmountTotal = nil
unitFrame.QuestText = nil
unitFrame.QuestName = nil
unitFrame.QuestIsCampaign = nil
--cache the unit target id, so it doesnt need to waste cycles building up on aggro checks
unitFrame.targetUnitID = unitID .. "target"
--clear values
plateFrame.CurrentUnitNameString = plateFrame.unitName
plateFrame.isSelf = nil
plateFrame.IsSelf = nil
unitFrame.IsSelf = nil --value exposed to scripts
castBar.IsSelf = nil --value exposed to scripts
unitFrame.unitName.isRenamed = nil
plateFrame.PlayerCannotAttack = nil
plateFrame.playerGuildName = nil
plateFrame [MEMBER_NOCOMBAT] = nil
plateFrame [MEMBER_TARGET] = nil
unitFrame [MEMBER_TARGET] = nil
--reset custom size set by the user
unitFrame.customHealthBarWidth = nil
unitFrame.customHealthBarHeight = nil
unitFrame.customCastBarWidth = nil
unitFrame.customCastBarHeight = nil
unitFrame.customPowerBarWidth = nil
unitFrame.customPowerBarHeight = nil
--reset border
unitFrame.customBorderColor = nil
Plater.UpdateBorderColor (unitFrame)
--reset custom color flag
unitFrame.UsingCustomColor = nil
unitFrame.InExecuteRange = false
unitFrame.IsInRange = nil
--check if this nameplate has an update scheduled
if (plateFrame.HasUpdateScheduled) then
if (not plateFrame.HasUpdateScheduled._cancelled) then
plateFrame.HasUpdateScheduled:Cancel()
end
plateFrame.HasUpdateScheduled = nil
end
--cache values
local unitName = UnitName (unitID) or ""
if DB_USE_NAME_TRANSLIT then
unitName = LibTranslit:Transliterate(unitName, TRANSLIT_MARK)
end
plateFrame [MEMBER_NAME] = unitName
plateFrame [MEMBER_NAMELOWER] = lower (plateFrame [MEMBER_NAME])
plateFrame ["namePlateClassification"] = UnitClassification (unitID)
--clear name schedules
unitFrame.ScheduleNameUpdate = nil
unitFrame.InCombat = UnitAffectingCombat (unitID) or (Plater.ForceInCombatUnits[unitFrame [MEMBER_NPCID]] and PLAYER_IN_COMBAT) or false
--cache values into the unitFrame as well to reduce the overhead on scripts and hooks
unitFrame [MEMBER_NAME] = plateFrame [MEMBER_NAME]
unitFrame [MEMBER_NAMELOWER] = plateFrame [MEMBER_NAMELOWER]
unitFrame ["namePlateClassification"] = plateFrame ["namePlateClassification"]
unitFrame [MEMBER_UNITID] = unitID
unitFrame.namePlateThreatPercent = 0
unitFrame.namePlateThreatIsTanking = nil
unitFrame.namePlateThreatStatus = nil
unitFrame.namePlateThreatOffTankIsTanking = false
unitFrame.namePlateThreatOffTankName = nil
plateFrame [MEMBER_REACTION] = reaction
unitFrame [MEMBER_REACTION] = reaction
unitFrame.BuffFrame [MEMBER_REACTION] = reaction
unitFrame.BuffFrame2 [MEMBER_REACTION] = reaction
unitFrame.BuffFrame.unit = unitID
unitFrame.BuffFrame2.unit = unitID
unitFrame.ExtraIconFrame.unit = unitID
plateFrame.isBattlePet = isBattlePet
unitFrame.isBattlePet = isBattlePet
plateFrame.isWidgetOnlyMode = isWidgetOnlyMode
unitFrame.isWidgetOnlyMode = isWidgetOnlyMode
plateFrame.isPlayer = isPlayer
unitFrame.isPlayer = isPlayer
--clear the custom indicators table
wipe (unitFrame.CustomIndicators)
--health amount
Plater.QuickHealthUpdate (unitFrame)
healthBar.IsAnimating = false
--hide execute indicators
healthBar.healthCutOff:Hide()
healthBar.executeRange:Hide()
healthBar.ExecuteGlowUp:Hide()
healthBar.ExecuteGlowDown:Hide()
--reset color values
healthBar.R, healthBar.G, healthBar.B, healthBar.A = nil, nil, nil, nil
--reset the frame level and strata if using UIParent as the parent of the unitFrame
--the function checks if the option is enabled, no need to check here
Plater.UpdateUIParentLevels (unitFrame)
if (unitFrame.unit) then
if (isSelf) then
--> personal health bar
plateFrame.isSelf = true
plateFrame.IsSelf = true
unitFrame.IsSelf = true --this is the value exposed to scripts
castBar.IsSelf = true --this is the value exposed to scripts
plateFrame.NameAnchor = 0
--do not allow the framework to show the unit name
unitFrame.Settings.ShowUnitName = false
unitFrame.unitName:Hide()
--setup castbar
unitFrame.Settings.ShowCastBar = DB_PLATE_CONFIG.player.castbar_enabled
if (not DB_PLATE_CONFIG.player.castbar_enabled) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
plateFrame.PlateConfig = DB_PLATE_CONFIG.player
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_PLAYER, nil, true)
Plater.OnUpdateHealth (healthBar)
else
--> regular nameplate
plateFrame.PlayerCannotAttack = not UnitCanAttack ("player", unitID)
unitFrame.PlayerCannotAttack = plateFrame.PlayerCannotAttack --expose to scripts
if (isPlayer) then
--unit is a player
plateFrame.playerGuildName = GetGuildInfo (unitID)
if (reaction >= Plater.UnitReaction.UNITREACTION_FRIENDLY) then
plateFrame.NameAnchor = DB_NAME_PLAYERFRIENDLY_ANCHOR
plateFrame.PlateConfig = DB_PLATE_CONFIG.friendlyplayer
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_FRIENDLY_PLAYER, nil, true)
unitFrame.Settings.ShowCastBar = not DB_CASTBAR_HIDE_FRIENDLY
if (DB_CASTBAR_HIDE_FRIENDLY) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
else
plateFrame.NameAnchor = DB_NAME_PLAYERENEMY_ANCHOR
plateFrame.PlateConfig = DB_PLATE_CONFIG.enemyplayer
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_ENEMY_PLAYER, nil, true)
unitFrame.Settings.ShowCastBar = not DB_CASTBAR_HIDE_ENEMIES
if (DB_CASTBAR_HIDE_ENEMIES) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
end
else
--the unit is a npc
if (reaction >= Plater.UnitReaction.UNITREACTION_FRIENDLY) then
plateFrame.NameAnchor = DB_NAME_NPCFRIENDLY_ANCHOR
plateFrame.PlateConfig = DB_PLATE_CONFIG.friendlynpc
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_FRIENDLY_NPC, nil, true)
unitFrame.Settings.ShowCastBar = not DB_CASTBAR_HIDE_FRIENDLY
if (DB_CASTBAR_HIDE_FRIENDLY) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
elseif isBattlePet then
plateFrame.NameAnchor = DB_NAME_NPCFRIENDLY_ANCHOR
plateFrame.PlateConfig = DB_PLATE_CONFIG.friendlynpc
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_FRIENDLY_NPC, nil, true)
unitFrame.Settings.ShowCastBar = not DB_CASTBAR_HIDE_FRIENDLY
if (DB_CASTBAR_HIDE_FRIENDLY) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
else
--includes neutral npcs
--add the npc in the npcid cache
if (not DB_NPCIDS_CACHE [plateFrame [MEMBER_NPCID]] and (Plater.ZoneInstanceType == "raid" or Plater.ZoneInstanceType == "party" or Plater.ZoneInstanceType == "scenario") and plateFrame [MEMBER_NPCID]) then
if (UNKNOWN ~= plateFrame [MEMBER_NAME]) then --UNKNOWN is the global string from blizzard
DB_NPCIDS_CACHE [plateFrame [MEMBER_NPCID]] = {plateFrame [MEMBER_NAME], Plater.ZoneName or "UNKNOWN"}
end
end
plateFrame.NameAnchor = DB_NAME_NPCENEMY_ANCHOR
plateFrame.PlateConfig = DB_PLATE_CONFIG.enemynpc
Plater.UpdatePlateFrame (plateFrame, ACTORTYPE_ENEMY_NPC, nil, true)
unitFrame.Settings.ShowCastBar = not DB_CASTBAR_HIDE_ENEMIES
if (DB_CASTBAR_HIDE_ENEMIES) then
--CastingBarFrame_SetUnit (castBar, nil, nil, nil)
unitFrame.castBar:SetUnit(nil, nil)
elseif not castBarWasEnabled then
unitFrame.castBar:SetUnit (unitID, unitID)
end
--get threat situation to expose it to scripts already in the nameplate added hook
local isTanking, threatStatus, threatpct, threatrawpct, threatValue = UnitDetailedThreatSituation ("player", unitID)
unitFrame.namePlateThreatIsTanking = isTanking
unitFrame.namePlateThreatStatus = threatStatus
unitFrame.namePlateThreatPercent = threatpct or 0
unitFrame.namePlateThreatRawPercent = threatrawpct or 0
unitFrame.namePlateThreatValue = threatValue or 0
Plater.UpdateNameOnRenamedUnit(plateFrame)
end
end
end
end
plateFrame.actorType = actorType
unitFrame.actorType = actorType
unitFrame.ActorType = actorType --exposed to scripts
--sending true to force the color update when the color overrider is enabled
Plater.FindAndSetNameplateColor (unitFrame, true)
--icone da cast bar
Plater.UpdateCastbarIcon(castBar)
--esconde os glow de aggro
unitFrame.aggroGlowUpper:Hide()
unitFrame.aggroGlowLower:Hide()
--widget container update
if IS_WOW_PROJECT_MAINLINE then
Plater.SetAnchor (unitFrame.WidgetContainer, Plater.db.profile.widget_bar_anchor, unitFrame)
plateFrame.unitFrame.WidgetContainer:SetScale(Plater.db.profile.widget_bar_scale)
unitFrame.WidgetContainer:UnregisterForWidgetSet()
local widgetSetId = UnitWidgetSet(unitID)
local playerControlled = UnitPlayerControlled(unitID)
if widgetSetId and ((playerControlled and UnitIsOwnerOrControllerOfUnit('player', unitID)) or not playerControlled) then
--unitFrame.WidgetContainer:RegisterForWidgetSet(widgetSetId)
unitFrame.WidgetContainer:RegisterForWidgetSet(widgetSetId, Plater.PlaterDefaultWidgetLayout, nil, unitID);
unitFrame.WidgetContainer:ProcessAllWidgets()
end
end
--can check aggro
unitFrame.CanCheckAggro = unitFrame.displayedUnit == unitID and actorType == ACTORTYPE_ENEMY_NPC and not unitFrame.isPerformanceUnit
--tick-setup
plateFrame.OnTickFrame.ThrottleUpdate = DB_TICK_THROTTLE
plateFrame.OnTickFrame.actorType = actorType
plateFrame.OnTickFrame.unit = unitID
plateFrame.OnTickFrame:SetScript ("OnUpdate", Plater.NameplateTick)
--highlight check
if (DB_HOVER_HIGHLIGHT and (not plateFrame.PlayerCannotAttack or (plateFrame.PlayerCannotAttack and DB_SHOW_HEALTHBARS_FOR_NOT_ATTACKABLE)) and (actorType == ACTORTYPE_ENEMY_PLAYER or actorType == ACTORTYPE_ENEMY_NPC)) then
Plater.EnableHighlight (unitFrame)
else
Plater.DisableHighlight (unitFrame)
end
--range
--Plater.CheckRange (plateFrame, true)
--resources - TODO:
Plater.Resources.UpdateResourceFramePosition() --~resource
--hooks
if (HOOK_NAMEPLATE_ADDED.ScriptAmount > 0) then
for i = 1, HOOK_NAMEPLATE_ADDED.ScriptAmount do
local globalScriptObject = HOOK_NAMEPLATE_ADDED [i]
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Nameplate Added")
--run
unitFrame:ScriptRunHook (scriptInfo, "Nameplate Added")
end
end
--tick
Plater.NameplateTick (plateFrame.OnTickFrame, 999)
unitFrame.PlaterOnScreen = true
end,
-- ~removed
NAME_PLATE_UNIT_REMOVED = function (event, unitBarId)
--ViragDevTool_AddData({ctime = GetTime(), unit = unitBarId or "nil", stack = debugstack()}, "NAME_PLATE_UNIT_REMOVED - " .. (unitBarId or "nil"))
local plateFrame = C_NamePlate.GetNamePlateForUnit (unitBarId)
Plater.RemoveFromAuraUpdate (unitBarId) -- ensure no updates
ENABLED_BLIZZARD_PLATEFRAMES[plateFrame.unitFrame.blizzardPlateFrameID] = true -- OnRetailNamePlateShow is called first. ensure the plate might show!
if not plateFrame.unitFrame.PlaterOnScreen then
return
end
NAMEPLATES_ON_SCREEN_CACHE[unitBarId] = false
NUM_NAMEPLATES_ON_SCREEN = NUM_NAMEPLATES_ON_SCREEN - 1
--debug for hunter faith death
--if (select (2, UnitClass (unitBarId)) == "HUNTER") then
-- print ("nameplate removed", UnitName (unitBarId))
--end
--hooks
if (HOOK_NAMEPLATE_REMOVED.ScriptAmount > 0) then
for i = 1, HOOK_NAMEPLATE_REMOVED.ScriptAmount do
local globalScriptObject = HOOK_NAMEPLATE_REMOVED [i]
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Nameplate Removed")
--run
plateFrame.unitFrame:ScriptRunHook (scriptInfo, "Nameplate Removed")
end
end
plateFrame.OnTickFrame:SetScript ("OnUpdate", nil)
plateFrame.unitFrame.HighlightFrame:SetScript ("OnUpdate", nil)
plateFrame [MEMBER_QUEST] = false
plateFrame.unitFrame [MEMBER_QUEST] = false
plateFrame.QuestInfo = {}
plateFrame.unitFrame.QuestInfo = {}
plateFrame [MEMBER_TARGET] = nil
local healthBar = plateFrame.unitFrame.healthBar
if (healthBar.TargetHeight) then
healthBar:SetHeight (healthBar.TargetHeight)
end
healthBar.IsIncreasingHeight = nil
healthBar.IsDecreasingHeight = nil
--hide the highlight
--is mouse over ~highlight ~mouseover
plateFrame.unitFrame.HighlightFrame:Hide()
plateFrame.unitFrame.HighlightFrame.Shown = false
--hide target highlight
plateFrame.TargetNeonUp:Hide()
plateFrame.TargetNeonDown:Hide()
--hide threat highlight
plateFrame.unitFrame.aggroGlowUpper:Hide()
plateFrame.unitFrame.aggroGlowLower:Hide()
--> check if is running any script
plateFrame.unitFrame:OnHideWidget()
plateFrame.unitFrame.castBar:OnHideWidget()
for _, auraIconFrame in ipairs (plateFrame.unitFrame.BuffFrame.PlaterBuffList) do
auraIconFrame:OnHideWidget()
end
for _, auraIconFrame in ipairs (plateFrame.unitFrame.BuffFrame2.PlaterBuffList) do
auraIconFrame:OnHideWidget()
end
--stop animations
if plateFrame.unitFrame.BodyFlashFrame and plateFrame.unitFrame.BodyFlashFrame.animation then
plateFrame.unitFrame.BodyFlashFrame.animation:Stop()
plateFrame.unitFrame.BodyFlashFrame:Hide()
end
if plateFrame.unitFrame.healthBar.HealthFlashFrame and plateFrame.unitFrame.healthBar.HealthFlashFrame.animation then
plateFrame.unitFrame.healthBar.HealthFlashFrame.animation:Stop()
plateFrame.unitFrame.healthBar.HealthFlashFrame:Hide()
end
plateFrame.unitFrame.PlaterOnScreen = nil
--tell the framework to execute a cleanup on the unit frame, this is required since Plater set .ClearUnitOnHide to false
plateFrame.unitFrame:SetUnit (nil)
-- remove widgets
if IS_WOW_PROJECT_MAINLINE then
plateFrame.unitFrame.WidgetContainer:UnregisterForWidgetSet()
end
--community patch by Ariani#0960 (discord)
--make the unitFrame be parented to UIParent allowing frames to be moved between strata levels
--March 3rd, 2019
if (DB_USE_UIPARENT) then
-- need to explicitly hide the frame now, as it is not tethered to the blizz nameplate
plateFrame.unitFrame:Hide()
end
--end of patch
end,
UNIT_INVENTORY_CHANGED = function()
UpdatePlayerTankState()
Plater.UpdateAllNameplateColors()
Plater.UpdateAllPlates()
end,
UPDATE_SHAPESHIFT_FORM = function()
local curTime = GetTime()
--this is to work around UPDATE_SHAPESHIFT_FORM firing for all units and not just the player... causing lag...
--if (curTime - last_UPDATE_SHAPESHIFT_FORM) < 1 or last_GetShapeshiftForm == GetShapeshiftForm() then
if last_GetShapeshiftForm == GetShapeshiftForm() then
return
end
last_UPDATE_SHAPESHIFT_FORM = curTime
last_GetShapeshiftForm = GetShapeshiftForm()
UpdatePlayerTankState()
Plater.UpdateAllNameplateColors()
Plater.UpdateAllPlates()
Plater.Resources.UpdateResourceFramePosition()
end,
TALENT_GROUP_ROLE_CHANGED = function()
UpdatePlayerTankState()
Plater.UpdateAllNameplateColors()
Plater.UpdateAllPlates()
end,
}
function Plater.EventHandler (_, event, ...) --private
local func = eventFunctions [event]
if (func) then
Plater.StartLogPerformanceCore("Plater-Core", "Events", event)
func (event, ...)
Plater.EndLogPerformanceCore("Plater-Core", "Events", event)
else
Plater:Msg ("no registered function for event " .. (event or "unknown event"))
end
end
Plater.EventHandlerFrame:SetScript ("OnEvent", Plater.EventHandler)
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_ENTERING_WORLD")
function Plater.RunFunctionForEvent (event, ...) --private
Plater.EventHandler (nil, event, ...)
end
local run_scheduled_event_function = function (timerObject)
local event = timerObject.event
local args = timerObject.args
Plater.RunFunctionForEvent (event, unpack (args))
end
function Plater.ScheduleRunFunctionForEvent (delay, event, ...) --private
local timer = C_Timer.NewTimer (delay, run_scheduled_event_function)
timer.event = event
timer.args = {...}
end
--function for plateFrame.UnitFrame OnShow script
--it'll hide the retail nameplate when it shown
function Plater.OnRetailNamePlateShow (self) --private
if ENABLED_BLIZZARD_PLATEFRAMES[tostring(self)] then
-- do not hide
return
end
self:Hide()
if not SUPPORT_BLIZZARD_PLATEFRAMES then
-- should be done if events are not needed
-- CompactUnitFrame_UnregisterEvents only removes event hanlder functions
self:UnregisterAllEvents()
end
if (CompactUnitFrame_UnregisterEvents) then
CompactUnitFrame_UnregisterEvents (self)
end
end
function Plater.SetFontOutlineAndShadow (fontString, outline, shadowColor, shadowXOffSet, shadowYOffSet)
--update the outline
DF:SetFontOutline (fontString, outline)
--update shadow color and shadow offset
if (shadowColor) then
local r, g, b, a = DF:ParseColors (shadowColor)
DF:SetFontShadow (fontString, r, g, b, a, shadowXOffSet, shadowYOffSet)
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> addon initialization
function Plater.InitializeSavedVariables()
local PlaterDB = _G.PlaterDB
--table to store casts with SPELL_CAST_START
PlaterDB.captured_casts = PlaterDB.captured_casts or {}
--table to store auras and any spell cast
PlaterDB.captured_spells = PlaterDB.captured_spells or {}
end
function Plater.OnInit() --private --~oninit ~init
Plater.InitializeSavedVariables()
Plater.RefreshDBUpvalues()
-- do we need to support blizzard frames?
SUPPORT_BLIZZARD_PLATEFRAMES = (not DB_PLATE_CONFIG [ACTORTYPE_PLAYER].module_enabled) or (not DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_PLAYER].module_enabled) or (not DB_PLATE_CONFIG [ACTORTYPE_ENEMY_PLAYER].module_enabled) or (not DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_NPC].module_enabled) or (not DB_PLATE_CONFIG [ACTORTYPE_ENEMY_NPC].module_enabled)
Plater.CombatTime = GetTime()
PLAYER_IN_COMBAT = false
if (InCombatLockdown()) then
PLAYER_IN_COMBAT = true
end
Plater.Locale = GetLocale()
--Plater:BossModsLink()
--character settings
PlaterDBChr = PlaterDBChr or {first_run3 = {}}
PlaterDBChr.first_run3 = PlaterDBChr.first_run3 or {}
PlaterDBChr.debuffsBanned = PlaterDBChr.debuffsBanned or {}
PlaterDBChr.buffsBanned = PlaterDBChr.buffsBanned or {}
PlaterDBChr.spellRangeCheckRangeEnemy = PlaterDBChr.spellRangeCheckRangeEnemy or {}
PlaterDBChr.spellRangeCheckRangeFriendly = PlaterDBChr.spellRangeCheckRangeFriendly or {}
--Register LDB
Plater.InitLDB()
--to fix: attempt to index field 'spellRangeCheck' (a string value)
if (type (PlaterDBChr.spellRangeCheckRangeEnemy) ~= "table") then
PlaterDBChr.spellRangeCheckRangeEnemy = {}
end
if (type (PlaterDBChr.spellRangeCheckRangeFriendly) ~= "table") then
PlaterDBChr.spellRangeCheckRangeFriendly = {}
end
--ensure global nameplate width/height setting is initialized
Plater.db.profile.plate_config.global_health_width = Plater.db.profile.plate_config.global_health_width or Plater.db.profile.plate_config.enemynpc.health[1]
Plater.db.profile.plate_config.global_health_height = Plater.db.profile.plate_config.global_health_height or Plater.db.profile.plate_config.enemynpc.health[2]
--range check spells
if IS_WOW_PROJECT_MAINLINE then
for specID, _ in pairs (Plater.SpecList [select (2, UnitClass ("player"))]) do
--if (PlaterDBChr.spellRangeCheckRangeEnemy [specID] == nil or not LibRangeCheck:GetHarmMaxChecker (PlaterDBChr.spellRangeCheckRangeEnemy [specID])) then
if (PlaterDBChr.spellRangeCheckRangeEnemy [specID] == nil) then
PlaterDBChr.spellRangeCheckRangeEnemy [specID] = Plater.DefaultSpellRangeList [specID]
end
--if (PlaterDBChr.spellRangeCheckRangeFriendly [specID] == nil or not LibRangeCheck:GetFriendMaxChecker(PlaterDBChr.spellRangeCheckRangeFriendly [specID])) then
if (PlaterDBChr.spellRangeCheckRangeFriendly [specID] == nil) then
PlaterDBChr.spellRangeCheckRangeFriendly [specID] = Plater.DefaultSpellRangeListF [specID]
end
end
else
local playerClass = select (3, UnitClass ("player"))
--if (PlaterDBChr.spellRangeCheckRangeEnemy [playerClass] == nil or not LibRangeCheck:GetHarmMaxChecker (PlaterDBChr.spellRangeCheckRangeEnemy [playerClass])) then
if (PlaterDBChr.spellRangeCheckRangeEnemy [playerClass] == nil) then
PlaterDBChr.spellRangeCheckRangeEnemy [playerClass] = Plater.DefaultSpellRangeList [playerClass]
end
--if (PlaterDBChr.spellRangeCheckRangeFriendly [playerClass] == nil or not LibRangeCheck:GetFriendMaxChecker(PlaterDBChr.spellRangeCheckRangeFriendly [playerClass])) then
if (PlaterDBChr.spellRangeCheckRangeFriendly [playerClass] == nil) then
PlaterDBChr.spellRangeCheckRangeFriendly [playerClass] = Plater.DefaultSpellRangeListF [playerClass]
end
end
Plater.RangeCheckRangeEnemy = nil
Plater.RangeCheckRangeFriendly = nil
Plater.RangeCheckFunctionEnemy = nil
Plater.RangeCheckFunctionFriendly = nil
LibRangeCheck.RegisterCallback(Plater, LibRangeCheck.CHECKERS_CHANGED, function() Plater.GetSpellForRangeCheck() end)
--who is the player
Plater.PlayerGUID = UnitGUID ("player")
Plater.PlayerClass = select (2, UnitClass ("player"))
--track player auras
Plater.AddToAuraUpdate("player")
--load scripts from the script library
Plater.ImportScriptsFromLibrary()
Plater.ApplyPatches()
--and compile all scripts and hooks
Plater.CompileAllScripts ("script")
Plater.CompileAllScripts ("hook")
--check if masque is installed and add support for masque addon
local Masque = LibStub ("Masque", true)
if (Masque and Plater.db.profile.enable_masque_support) then
Plater.Masque = {}
Plater.Masque.AuraFrame1 = Masque:Group ("Plater Nameplates", "Aura Frame 1")
Plater.Masque.AuraFrame2 = Masque:Group ("Plater Nameplates", "Aura Frame 2")
Plater.Masque.BuffSpecial = Masque:Group ("Plater Nameplates", "Buff Special")
Plater.Masque.BossModIconFrame = Masque:Group ("Plater Nameplates", "Boss Mod Icons")
Plater.Masque.CastIcon = Masque:Group ("Plater Nameplates", "Cast Bar Icons")
end
--set some cvars that we want to set
function Plater.ForceCVars()
if (InCombatLockdown()) then
return C_Timer.After (1, function() Plater.ForceCVars() end)
end
SetCVar ("nameplateMinAlpha", 0.90135484)
SetCVar ("nameplateMinAlphaDistance", -10^5.2)
SetCVar ("nameplateSelectedAlpha", 1)
SetCVar ("nameplateNotSelectedAlpha", 1)
SetCVar ("nameplateRemovalAnimation", DB_USE_QUICK_HIDE and 0 or 1)
end
--schedule data update
--C_Timer.After (1, Plater.GetSpellForRangeCheck)
C_Timer.After (4, Plater.GetHealthCutoffValue)
--hooking scripts has load conditions, here it creates a load filter for plater
--so when a load condition is changed it reload hooks
function Plater.HookLoadCallback (encounterID) --private
Plater.EncounterID = encounterID
Plater.WipeAndRecompileAllScripts ("hook", true) --sending true to not dispatch a hotReload in the scripts
end
DF:CreateLoadFilterParser (Plater.HookLoadCallback)
--refresh the color overrider
Plater.RefreshColorOverride()
--update the current zone
local _, zoneType = GetInstanceInfo()
Plater.ZoneInstanceType = zoneType
--check if is the first time Plater is running in the account or in the character
local check_first_run = function()
if (not UnitGUID ("player")) then
C_Timer.After (1, Plater.CheckFirstRun)
return
end
if (not Plater.db.profile.first_run3) then
C_Timer.After (15, Plater.SetCVarsOnFirstRun)
--enable UIParent nameplates for new installs of Plater
--this setting is disabled by default and will be enabled for new people
Plater.db.profile.use_ui_parent = true
--adjust the fine tune to player's screen scale
Plater.db.profile.ui_parent_scale_tune = 1 / UIParent:GetEffectiveScale()
elseif (not PlaterDBChr.first_run3 [UnitGUID ("player")]) then
--do not run cvars for individual characters
C_Timer.After (15, Plater.SetCVarsOnFirstRun)
else
Plater.CreatePlaterButtonAtInterfaceOptions()
end
end
function Plater.CheckFirstRun() --private
check_first_run()
end
Plater.CheckFirstRun()
--load a table with a copy of the plateConfigs table to be accessed by scripts
Plater.UpdateSettingsCache()
--events
Plater.EventHandlerFrame:RegisterEvent ("NAME_PLATE_CREATED")
Plater.EventHandlerFrame:RegisterEvent ("NAME_PLATE_UNIT_ADDED")
Plater.EventHandlerFrame:RegisterEvent ("NAME_PLATE_UNIT_REMOVED")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_TARGET_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_FOCUS_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_REGEN_DISABLED")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_REGEN_ENABLED")
Plater.EventHandlerFrame:RegisterEvent ("ZONE_CHANGED_NEW_AREA")
Plater.EventHandlerFrame:RegisterEvent ("ZONE_CHANGED_INDOORS")
Plater.EventHandlerFrame:RegisterEvent ("ZONE_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("FRIENDLIST_UPDATE")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_LOGOUT")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_UPDATE_RESTING")
Plater.EventHandlerFrame:RegisterEvent ("RAID_TARGET_UPDATE")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_ACCEPTED")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_REMOVED")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_ACCEPT_CONFIRM")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_COMPLETE")
if IS_WOW_PROJECT_MAINLINE then
Plater.EventHandlerFrame:RegisterEvent ("QUEST_POI_UPDATE")
end
Plater.EventHandlerFrame:RegisterEvent ("QUEST_DETAIL")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_FINISHED")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_GREETING")
Plater.EventHandlerFrame:RegisterEvent ("QUEST_LOG_UPDATE")
Plater.EventHandlerFrame:RegisterEvent ("UNIT_QUEST_LOG_CHANGED")
if IS_WOW_PROJECT_MAINLINE then
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_SPECIALIZATION_CHANGED")
Plater.EventHandlerFrame:RegisterEvent (C_Traits and "TRAIT_CONFIG_UPDATED" or "PLAYER_TALENT_UPDATE")
elseif IS_WOW_PROJECT_CLASSIC_WRATH then
Plater.EventHandlerFrame:RegisterEvent ("ACTIVE_TALENT_GROUP_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_TALENT_UPDATE")
end
Plater.EventHandlerFrame:RegisterEvent ("ENCOUNTER_START")
Plater.EventHandlerFrame:RegisterEvent ("ENCOUNTER_END")
if IS_WOW_PROJECT_MAINLINE then
Plater.EventHandlerFrame:RegisterEvent ("CHALLENGE_MODE_START")
end
Plater.EventHandlerFrame:RegisterEvent ("UNIT_NAME_UPDATE")
Plater.EventHandlerFrame:RegisterEvent ("UNIT_FLAGS")
Plater.EventHandlerFrame:RegisterEvent ("UNIT_FACTION")
Plater.EventHandlerFrame:RegisterEvent ("DISPLAY_SIZE_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("UI_SCALE_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("GROUP_ROSTER_UPDATE")
Plater.EventHandlerFrame:RegisterEvent ("UNIT_PET")
if IS_WOW_PROJECT_NOT_MAINLINE then -- tank spec detection
Plater.EventHandlerFrame:RegisterEvent ("UNIT_INVENTORY_CHANGED")
Plater.EventHandlerFrame:RegisterEvent ("UPDATE_SHAPESHIFT_FORM")
if IS_WOW_PROJECT_CLASSIC_WRATH then
Plater.EventHandlerFrame:RegisterEvent ("TALENT_GROUP_ROLE_CHANGED")
end
end
Plater.EventHandlerFrame:RegisterEvent ("PLAYER_LOGIN")
Plater.EventHandlerFrame:RegisterEvent ("VARIABLES_LOADED")
--power update for hooking scripts
local hookPowerEventFrame = CreateFrame ("frame")
--hookPowerEventFrame:RegisterUnitEvent ("UNIT_POWER_UPDATE", "player")
hookPowerEventFrame:RegisterUnitEvent ("UNIT_POWER_FREQUENT", "player")
hookPowerEventFrame:RegisterUnitEvent ("UNIT_MAXPOWER", "player")
--hookPowerEventFrame:RegisterUnitEvent ("UNIT_DISPLAYPOWER", "player")
--hookPowerEventFrame:RegisterUnitEvent ("UNIT_POWER_BAR_HIDE", "player")
hookPowerEventFrame:SetScript ("OnEvent", function(self, event, target, powerType)
-- target is always 'player'
if (HOOK_PLAYER_POWER_UPDATE.ScriptAmount > 0) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame) then
for i = 1, HOOK_PLAYER_POWER_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_PLAYER_POWER_UPDATE [i]
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Player Power Update")
--run
unitFrame:ScriptRunHook (scriptInfo, "Player Power Update", unitFrame, powerType)
end
end
end
end
end)
--this should pull the resources bar up and down based on if the target has debuffs shown on it or not
function Plater.UpdateResourceFrameAnchor (buffFrame)
if (Plater.CurrentTargetResourceFrame) then
--if this buffFrame anchored in the current target?
if (buffFrame.unitFrame [MEMBER_TARGET]) then
--has any aura shown?
--algumas vezes o amtdebbufs esta retornando 0 por alguma razao...
if (buffFrame.amountAurasShown > 0 or (DB_AURA_SEPARATE_BUFFS and buffFrame.BuffFrame2.amountAurasShown > 0)) then
Plater.CurrentTargetResourceFrame:SetPoint ("bottom", buffFrame.healthBar, "top", 0, Plater.db.profile.resources.y_offset_target + Plater.db.profile.resources.y_offset_target_withauras)
else
Plater.CurrentTargetResourceFrame:SetPoint ("bottom", buffFrame.healthBar, "top", 0, Plater.db.profile.resources.y_offset_target)
end
end
end
end
--this function is declared inside 'NamePlateDriverMixin' at Blizzard_NamePlates.lua
--self if the nameplate driver frame: _G.NamePlateDriverFrame
--at the moment self isn't being used ~personal
function Plater.UpdatePersonalBar (self)
local showSelf = GetCVarBool ("nameplateShowSelf") and Plater.db.profile.plate_config.player.module_enabled
if (not showSelf) then
if PlaterDBChr.resources_on_target then
Plater.UpdateResourceFrame()
end
return
end
--show Plater power bar for the player personal nameplate
local plateFrame = C_NamePlate.GetNamePlateForUnit ("player")
if (plateFrame) then
if (not plateFrame.Plater) then
return
end
if (NamePlateDriverFrame.classNamePlatePowerBar and NamePlateDriverFrame.classNamePlatePowerBar:IsShown()) then
--hide the power bar from default ui
NamePlateDriverFrame.classNamePlatePowerBar:Hide()
NamePlateDriverFrame.classNamePlatePowerBar:UnregisterAllEvents()
end
local unitFrame = plateFrame.unitFrame
--setup the power bar and cast bar from the details! framework unit frame
local powerBar = unitFrame.powerBar
local castBar = unitFrame.castBar
local healthBar = unitFrame.healthBar
if (not DB_PLATE_CONFIG.player.healthbar_enabled) then
--the health bar is set when the nameplate is shown
healthBar:SetUnit (nil)
-- hide target glow
plateFrame.TargetNeonUp:Hide()
plateFrame.TargetNeonDown:Hide()
end
if (DB_PLATE_CONFIG.player.power_enabled) then
powerBar:SetUnit (unitFrame.unit)
--update the power percent text
local plateConfigs = DB_PLATE_CONFIG.player
if (plateConfigs.power_percent_text_enabled) then
unitFrame.powerBar.Settings.ShowPercentText = true
local textString = powerBar.percentText
textString:Show()
DF:SetFontSize (textString, plateConfigs.power_percent_text_size)
DF:SetFontFace (textString, plateConfigs.power_percent_text_font)
DF:SetFontColor (textString, plateConfigs.power_percent_text_color)
Plater.SetAnchor (textString, plateConfigs.power_percent_text_anchor)
textString:SetAlpha (plateConfigs.power_percent_text_alpha)
powerBar.border:SetVertexColor (0, 0, 0, 1) --hardcoded color
Plater.SetFontOutlineAndShadow (textString, plateConfigs.power_percent_text_outline, plateConfigs.power_percent_text_shadow_color, plateConfigs.power_percent_text_shadow_color_offset[1], plateConfigs.power_percent_text_shadow_color_offset[2])
else
unitFrame.powerBar.Settings.ShowPercentText = false
powerBar.percentText:Hide()
end
else
powerBar:SetUnit (nil)
end
--setup the cast bar from details! framework unit frame
if (DB_PLATE_CONFIG.player.castbar_enabled) then
castBar:SetUnit (unitFrame.unit)
castBar.extraBackground:Show()
else
castBar:SetUnit (nil)
end
--update resource bar
Plater.UpdateResourceFrame()
end
end
local on_personal_bar_update = function (self)
return Plater.UpdatePersonalBar (self)
end
--can also hook 'ClassNameplateBar:ShowNameplateBar()' which will show and call NamePlateDriverFrame:SetClassNameplateBar(self); which will call SetupClassNameplateBars()
if IS_WOW_PROJECT_MAINLINE then
hooksecurefunc (NamePlateDriverFrame, "SetupClassNameplateBars", on_personal_bar_update)
end
--update the resource location and anchor
function Plater.UpdateResourceFrame()
if IS_WOW_PROJECT_NOT_MAINLINE then return end
--this holds a reference of the current resource frame anchored into the 'target' namepate
--it is used when checking if the unit has auras to move the resources up to make room for the auras
Plater.CurrentTargetResourceFrame = nil
local showSelf = GetCVarBool ("nameplateShowSelf") and Plater.db.profile.plate_config.player.module_enabled
local onCurrentTarget = PlaterDBChr.resources_on_target
if (not showSelf) then
if (not onCurrentTarget) then
return
end
end
local resourceFrame = NamePlateDriverFrame.classNamePlateMechanicFrame
if (not resourceFrame or resourceFrame:IsForbidden()) then
return
end
if Plater.db.profile.resources_settings.global_settings.show then
resourceFrame:Hide()
return
end
--> set scale based on Plater user settings
resourceFrame:SetScale (Plater.db.profile.resources.scale)
resourceFrame:SetAlpha (Plater.db.profile.resources.alpha)
--check if resources are placed on the current target
if (onCurrentTarget) then
--resource bar are placed on the current target nameplate
local targetPlateFrame = C_NamePlate.GetNamePlateForUnit ("target", false) -- don't attach to secure frames to avoid tainting!
if (targetPlateFrame) then
resourceFrame:Show()
resourceFrame:SetParent (targetPlateFrame.unitFrame)
resourceFrame:ClearAllPoints()
resourceFrame:SetPoint ("bottom", targetPlateFrame.unitFrame.healthBar, "top", 0, Plater.db.profile.resources.y_offset_target)
resourceFrame:SetFrameStrata(targetPlateFrame.unitFrame.healthBar:GetFrameStrata())
resourceFrame:SetFrameLevel(targetPlateFrame.unitFrame.healthBar:GetFrameLevel() + 25)
Plater.CurrentTargetResourceFrame = resourceFrame
Plater.UpdateResourceFrameAnchor (targetPlateFrame.unitFrame.BuffFrame)
else
resourceFrame:Hide()
end
else
--resource bar are placed below the mana bar at the personal bar
local personalPlateFrame = C_NamePlate.GetNamePlateForUnit ("player", issecure())
if (personalPlateFrame) then
resourceFrame:Show()
resourceFrame:SetParent (personalPlateFrame.unitFrame)
resourceFrame:ClearAllPoints()
--> attach to powerbar if shown
if (personalPlateFrame.unitFrame.powerBar:IsShown()) then
resourceFrame:SetPoint ("top", personalPlateFrame.unitFrame.powerBar, "bottom", 0, -3 + Plater.db.profile.resources.y_offset)
else
resourceFrame:SetPoint ("top", personalPlateFrame.unitFrame.healthBar, "bottom", 0, -3 + Plater.db.profile.resources.y_offset)
end
resourceFrame:SetFrameStrata(personalPlateFrame.unitFrame.healthBar:GetFrameStrata())
resourceFrame:SetFrameLevel(personalPlateFrame.unitFrame.healthBar:GetFrameLevel() + 25)
else
resourceFrame:Hide()
end
end
end
if IS_WOW_PROJECT_MAINLINE then
--this function is declared inside 'NamePlateDriverMixin' at Blizzard_NamePlates.lua
hooksecurefunc (NamePlateDriverFrame, "UpdateNamePlateOptions", function()
Plater.UpdateSelfPlate()
end)
end
--> cast frame ~castbar
--test castbar
Plater.CastBarTestFrame = CreateFrame ("frame", nil, UIParent, BackdropTemplateMixin and "BackdropTemplate")
function Plater.StartCastBarTest()
Plater.IsShowingCastBarTest = true
Plater.DoCastBarTest()
end
function Plater.DoCastBarTest (castNoInterrupt)
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
local castBar = plateFrame.unitFrame.castBar
local spellName, _, spellIcon = GetSpellInfo(116)
castBar.Text:SetText(spellName)
castBar.Icon:SetTexture(spellIcon)
castBar.Icon:SetAlpha(1)
castBar.Icon:Show()
castBar.percentText:Show()
castBar:SetMinMaxValues(0, 3)
castBar:SetValue(0)
castBar.Spark:Show()
castBar.casting = true
castBar.finished = false
castBar.value = 0
castBar.maxValue = 3
castBar.canInterrupt = math.random (1, 2) == 1
--castBar.canInterrupt = true
castBar:UpdateCastColor()
castBar.spellName = spellName
castBar.spellID = 116
castBar.spellTexture = spellIcon
castBar.spellStartTime = GetTime()
castBar.spellEndTime = GetTime() + 3
castBar.SpellStartTime = GetTime()
castBar.SpellEndTime = GetTime() + 3
castBar.playedFinishedTest = nil
castBar.flashTexture:Hide()
castBar:Animation_StopAllAnimations()
Plater.CastBarOnEvent_Hook(castBar, "UNIT_SPELLCAST_START", plateFrame.unitFrame.unit, plateFrame.unitFrame.unit)
if (not castBar:IsShown()) then
castBar:Animation_FadeIn()
castBar:Show()
end
Plater.UpdateCastbarTargetText(castBar)
local textString = castBar.FrameOverlay.TargetName
textString:Show()
textString:SetText("Target Name")
end
end
local totalTime = 0
local forward = true
Plater.CastBarTestFrame:SetScript ("OnUpdate", function (self, deltaTime)
if (totalTime >= 3.7) then
if (Plater.IsShowingCastBarTest) then
Plater.StartCastBarTest()
end
else
totalTime = totalTime + deltaTime
end
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
local castBar = plateFrame.unitFrame.castBar
local textString = castBar.FrameOverlay.TargetName
textString:Show()
textString:SetText("Target Name")
if (castBar.finished and not castBar.playedFinishedTest) then
Plater.CastBarOnEvent_Hook (castBar, "UNIT_SPELLCAST_STOP", plateFrame.unitFrame.unit, plateFrame.unitFrame.unit)
castBar:Hide()
castBar.playedFinishedTest = true
end
end
end
if (not Plater.IsShowingCastBarTest) then
Plater.CastBarTestFrame:SetScript ("OnUpdate", nil)
end
end)
end
function Plater.StopCastBarTest()
Plater.IsShowingCastBarTest = false
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
local castBar = plateFrame.unitFrame.castBar
castBar.playedFinishedTest = true
end
end
--> when the option to show the target of the cast is enabled, this function update the text settings but not the target name
function Plater.UpdateCastbarTargetText (castBar)
local profile = Plater.db.profile
if (profile.castbar_target_show) then
local textString = castBar.FrameOverlay.TargetName
textString:Show()
DF:SetFontSize (textString, profile.castbar_target_text_size)
DF:SetFontOutline (textString, profile.castbar_target_shadow)
Plater.SetFontOutlineAndShadow (textString, profile.castbar_target_outline, profile.castbar_target_shadow_color, profile.castbar_target_shadow_color_offset[1], profile.castbar_target_shadow_color_offset[2])
DF:SetFontColor (textString, profile.castbar_target_color)
DF:SetFontFace (textString, profile.castbar_target_font)
Plater.SetAnchor (textString, profile.castbar_target_anchor)
else
castBar.FrameOverlay.TargetName:Hide()
end
end
--> self is the castBar object from the details! framework unit frame widget
--> this hook is set inside the nameplate created event
function Plater.CastBarOnShow_Hook (self, unit) --private
--> this cast bar is a nameplate widget?
if (self.isNamePlate) then
if (self.IsSelf) then
self.extraBackground:Show()
else
--in case the unit is out of range, add some background color for the cast
if (self:GetAlpha() < 0.4) then
self.extraBackground:Show()
else
self.extraBackground:Hide()
end
end
end
end
function Plater.UpdateCastbarIcon(castBar)
local profile = Plater.db.profile
local icon = castBar.Icon
local unitFrame = castBar.unitFrame
local borderShield = castBar.BorderShield
--icon:SetDrawLayer ("OVERLAY", 5)
--borderShield:SetDrawLayer ("OVERLAY", 6)
local castBarHeight = castBar:GetHeight()
if (profile.castbar_icon_customization_enabled) then
if (profile.castbar_icon_show) then
icon:ClearAllPoints()
borderShield:ClearAllPoints()
borderShield:SetTexture ([[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]])
borderShield:SetTexCoord (0, 1, 0, 1)
borderShield:SetDesaturated (true)
PixelUtil.SetSize (borderShield, castBarHeight * 0.8, castBarHeight)
if (profile.castbar_icon_attach_to_side == "left") then
if (profile.castbar_icon_size == "same as castbar") then
icon:SetPoint("topright", castBar, "topleft", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomright", castBar, "bottomleft", profile.castbar_icon_x_offset, 0)
PixelUtil.SetPoint (borderShield, "center", castBar, "left", 0, 0)
elseif (profile.castbar_icon_size == "same as castbar plus healthbar") then
local actorType = unitFrame.actorType
local plateConfigs = DB_PLATE_CONFIG [actorType]
local castBarConfigKey, healthBarConfigKey, manaConfigKey = Plater.GetHashKey (isInCombat)
local healthBarHeight = unitFrame.customHealthBarHeight or (plateConfigs and plateConfigs [healthBarConfigKey][2]) or 0
local castBarOffSetY = plateConfigs and plateConfigs.castbar_offset or 0
if castBarOffSetY > healthBarHeight then
icon:SetPoint("topright", castBar, "topleft", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomright", unitFrame.healthBar, "bottomleft", profile.castbar_icon_x_offset, 0)
else
icon:SetPoint("topright", unitFrame.healthBar, "topleft", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomright", castBar, "bottomleft", profile.castbar_icon_x_offset, 0)
end
PixelUtil.SetPoint (borderShield, "center", castBar, "left", 0, 0)
end
elseif (profile.castbar_icon_attach_to_side == "right") then
if (profile.castbar_icon_size == "same as castbar") then
icon:SetPoint("topleft", castBar, "topright", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomleft", castBar, "bottomright", profile.castbar_icon_x_offset, 0)
PixelUtil.SetPoint (borderShield, "center", castBar, "right", 0, 0)
elseif (profile.castbar_icon_size == "same as castbar plus healthbar") then
local actorType = unitFrame.actorType
local plateConfigs = DB_PLATE_CONFIG [actorType]
local castBarConfigKey, healthBarConfigKey, manaConfigKey = Plater.GetHashKey (isInCombat)
local healthBarHeight = unitFrame.customHealthBarHeight or (plateConfigs and plateConfigs [healthBarConfigKey][2]) or 0
local castBarOffSetY = plateConfigs and plateConfigs.castbar_offset or 0
if castBarOffSetY > healthBarHeight then
icon:SetPoint("topleft", castBar, "topright", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomleft", unitFrame.healthBar, "bottomright", profile.castbar_icon_x_offset, 0)
else
icon:SetPoint("topleft", unitFrame.healthBar, "topright", profile.castbar_icon_x_offset, 0)
icon:SetPoint("bottomleft", castBar, "bottomright", profile.castbar_icon_x_offset, 0)
end
PixelUtil.SetPoint (borderShield, "center", castBar, "right", 0, 0)
end
end
icon:SetWidth(icon:GetHeight())
else
icon:Hide()
borderShield:Hide()
end
else
icon:ClearAllPoints()
PixelUtil.SetPoint (icon, "left", castBar, "left", 0, 0)
PixelUtil.SetSize (icon, castBarHeight, castBarHeight)
--setup non interruptible cast shield
borderShield:SetTexture ([[Interface\ACHIEVEMENTFRAME\UI-Achievement-Progressive-IconBorder]])
borderShield:SetTexCoord (5/64, 37/64, 1/64, 36/64)
borderShield:ClearAllPoints()
borderShield:SetPoint ("center", castBar.Icon, "center")
PixelUtil.SetSize (borderShield, castBarHeight * 1.4, castBarHeight * 1.4)
borderShield:SetDesaturated (false)
end
if castBar.Icon.Masqued then
Plater.Masque.CastIcon:ReSkin(castBar.Icon)
end
end
--~cast
--hook for all castbar events
function Plater.CastBarOnEvent_Hook (self, event, unit, ...) --private
if (event == "PLAYER_ENTERING_WORLD") then
if (not self.isNamePlate) then
return
end
unit = self.unit
if (self.casting) then
event = "UNIT_SPELLCAST_START"
elseif (self.channeling) then
event = "UNIT_SPELLCAST_CHANNEL_START"
else
return
end
end
if (self.isNamePlate) then
local unitFrame = self.unitFrame
local shouldRunCastStartHook = false
if (event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START") then
local unitCast = unit
if (unitCast ~= self.unit) then
return
end
-- if we are starting a cast but it is an immediate chained cast, then needs to trigger OnHide and OnShow again afterwards
local globalScriptObject = SCRIPT_CASTBAR_TRIGGER_CACHE[self.SpellName]
--if (globalScriptObject and self.SpellEndTime and GetTime() <= self.SpellEndTime and (self.casting or self.channeling) and not self.IsInterrupted) then
if (globalScriptObject and (self.casting or self.channeling) and not self.IsInterrupted) then
self:OnHideWidget()
end
--local name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo (unitCast)
self.SpellName = self.spellName
self.SpellID = self.spellID
self.SpellTexture = self.spellTexture
self.SpellStartTime = self.spellStartTime or GetTime()
self.SpellEndTime = self.spellEndTime or GetTime()
local notInterruptible = not self.canInterrupt
self.IsInterrupted = false
self.InterruptSourceName = nil
self.InterruptSourceGUID = nil
self.ReUpdateNextTick = true
self.ThrottleUpdate = -1
if (notInterruptible) then
self.BorderShield:Show()
else
self.BorderShield:Hide()
end
if (notInterruptible) then
self.CanInterrupt = false
else
self.CanInterrupt = true
end
self.FrameOverlay:SetBackdropBorderColor (0, 0, 0, 0)
local profile = Plater.db.profile
local isInCombat = profile.use_player_combat_state and PLAYER_IN_COMBAT or unitFrame.InCombat
--cut the spell name text to fit within the castbar
Plater.UpdateSpellNameSize (self.Text, unitFrame.ActorType, nil, isInCombat)
Plater.UpdateCastbarTargetText (self)
--castbar icon
Plater.UpdateCastbarIcon(self)
shouldRunCastStartHook = true
--spell color
self.castColorTexture:Hide()
--cast color (from options tab Cast Colors)
local castColors = profile.cast_colors
local customColor = castColors[self.spellID]
if (customColor) then
local isEnabled, color, customSpellName = customColor[1], customColor[2], customColor[3]
if (color and isEnabled) then
local originalCastColor = profile.cast_color_settings.enabled
--set the new cast color
if (color == "white") then
--the color white is used as a default disabled color
originalCastColor = false
else
self:SetColor(color)
end
if (customSpellName and customSpellName ~= "") then
self.Text:SetText(customSpellName)
end
--check if the original cast color is enabled
if (originalCastColor) then
--get the original cast color
local castColor = self:GetCastColor()
self.castColorTexture:Show()
local r, g, b = Plater:ParseColors(castColor)
self.castColorTexture:SetColorTexture(r, g, b)
self.castColorTexture:SetHeight(self:GetHeight() + profile.cast_color_settings.height_offset)
end
end
end
elseif (event == "UNIT_SPELLCAST_INTERRUPTED") then
local unitCast = unit
if (unitCast ~= self.unit) then
return
end
-- this is called in SPELL_INTERRUPT event
--self:OnHideWidget()
--self.IsInterrupted = true
elseif (event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP") then
local unitCast = unit
if (unitCast ~= self.unit) then
return
end
self:OnHideWidget()
--self.IsInterrupted = true
end
--hooks
if (shouldRunCastStartHook) then
if (HOOK_CAST_START.ScriptAmount > 0) then
for i = 1, HOOK_CAST_START.ScriptAmount do
local globalScriptObject = HOOK_CAST_START [i]
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Cast Start")
--update envTable
local scriptEnv = scriptInfo.Env
scriptEnv._SpellID = self.SpellID
scriptEnv._UnitID = self.unit
scriptEnv._SpellName = self.SpellName
scriptEnv._Texture = self.SpellTexture
scriptEnv._Caster = self.unit
scriptEnv._Duration = self.SpellEndTime - self.SpellStartTime
scriptEnv._StartTime = self.SpellStartTime
scriptEnv._CanInterrupt = self.CanInterrupt
scriptEnv._EndTime = self.SpellEndTime
scriptEnv._RemainingTime = max (self.SpellEndTime - GetTime(), 0)
scriptEnv._CanStealOrPurge = self.CanStealOrPurge
scriptEnv._AuraType = self.AuraType
scriptEnv._CastBarHeight = unitFrame.castBar:GetHeight()
--run
unitFrame:ScriptRunHook (scriptInfo, "Cast Start", self)
end
end
end
end
end
Plater.CastBarOnTick_Hook = function (self, deltaTime) --private
if (self.percentText) then --check if is a plater cast bar
self.ThrottleUpdate = self.ThrottleUpdate - deltaTime
if (self.ThrottleUpdate < 0) then
self.SpellStartTime = self.spellStartTime or GetTime()
self.SpellEndTime = self.spellEndTime or GetTime()
if (self.ReUpdateNextTick) then
self.ReUpdateNextTick = nil
end
if (self.unit and Plater.db.profile.castbar_target_show and not UnitIsUnit (self.unit, "player")) then
local targetName = UnitName (self.unit .. "target")
if (targetName) then
local canShowTargetName = true
local notInTank = Plater.db.profile.castbar_target_notank
if (notInTank) then
if (Plater.PlayerIsTank and targetName == UnitName("player")) then
canShowTargetName = false
end
end
if (canShowTargetName) then
if DB_USE_NAME_TRANSLIT then
targetName = LibTranslit:Transliterate(targetName, TRANSLIT_MARK)
end
local _, class = UnitClass (self.unit .. "target")
if (class) then
self.FrameOverlay.TargetName:SetText (targetName)
self.FrameOverlay.TargetName:SetTextColor (DF:ParseColors (class))
else
self.FrameOverlay.TargetName:SetText (targetName)
DF:SetFontColor (self.FrameOverlay.TargetName, Plater.db.profile.castbar_target_color)
end
else
self.FrameOverlay.TargetName:SetText ("")
end
else
self.FrameOverlay.TargetName:SetText ("")
end
else
self.FrameOverlay.TargetName:SetText ("")
end
self.ThrottleUpdate = DB_TICK_THROTTLE
--get the script object of the aura which will be showing in this icon frame
local globalScriptObject = SCRIPT_CASTBAR_TRIGGER_CACHE[self.SpellName]
--check if this aura has a custom script
if (globalScriptObject and self.SpellEndTime and GetTime() < self.SpellEndTime and (self.casting or self.channeling) and not self.IsInterrupted) then
--stored information about scripts
local scriptContainer = self:ScriptGetContainer()
--get the info about this particularly script
local scriptInfo = self:ScriptGetInfo (globalScriptObject, scriptContainer)
local scriptEnv = scriptInfo.Env
scriptEnv._SpellID = self.SpellID
scriptEnv._UnitID = self.unit
scriptEnv._SpellName = self.SpellName
scriptEnv._Texture = self.SpellTexture
scriptEnv._Caster = self.unit
scriptEnv._Duration = self.SpellEndTime - self.SpellStartTime
scriptEnv._StartTime = self.SpellStartTime
scriptEnv._CanInterrupt = self.CanInterrupt
scriptEnv._EndTime = self.SpellEndTime
scriptEnv._RemainingTime = max (self.SpellEndTime - GetTime(), 0)
scriptEnv._CanStealOrPurge = self.CanStealOrPurge
scriptEnv._AuraType = self.AuraType
if (self.casting) then
scriptEnv._CastPercent = self.value / self.maxValue * 100
elseif (self.channeling) then
scriptEnv._CastPercent = abs (self.value - self.maxValue) / self.maxValue * 100
end
--run onupdate script
self:ScriptRunOnUpdate (scriptInfo)
end
--hooks
if (HOOK_CAST_UPDATE.ScriptAmount > 0) then
for i = 1, HOOK_CAST_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_CAST_UPDATE [i]
local unitFrame = self.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Cast Update")
--update envTable
local scriptEnv = scriptInfo.Env
scriptEnv._SpellID = self.SpellID
scriptEnv._UnitID = self.unit
scriptEnv._SpellName = self.SpellName
scriptEnv._Texture = self.SpellTexture
scriptEnv._Caster = self.unit
scriptEnv._Duration = self.SpellEndTime - self.SpellStartTime
scriptEnv._StartTime = self.SpellStartTime
scriptEnv._CanInterrupt = self.CanInterrupt
scriptEnv._EndTime = self.SpellEndTime
scriptEnv._RemainingTime = max (self.SpellEndTime - GetTime(), 0)
scriptEnv._CanStealOrPurge = self.CanStealOrPurge
scriptEnv._AuraType = self.AuraType
--run
unitFrame:ScriptRunHook (scriptInfo, "Cast Update", self)
end
end
end
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> health frame
function Plater.QuickHealthUpdate (unitFrame)
local unitHealth = UnitHealth (unitFrame.unit)
local unitHealthMax = UnitHealthMax (unitFrame.unit)
unitFrame.healthBar:SetMinMaxValues (0, unitHealthMax)
unitFrame.healthBar:SetValue (unitHealth)
unitFrame.healthBar.CurrentHealth = unitHealth
unitFrame.healthBar.CurrentHealthMax = unitHealthMax
unitFrame.healthBar.currentHealth = unitHealth
unitFrame.healthBar.currentHealthMax = unitHealthMax
end
local run_on_health_change_hook = function (unitFrame)
if unitFrame.isPerformanceUnit then return end -- don't run health update hooks on performance units
for i = 1, HOOK_HEALTH_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_HEALTH_UPDATE [i]
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Health Update")
--run
unitFrame:ScriptRunHook (scriptInfo, "Health Update")
end
end
function Plater.OnUpdateHealth (self) --self is unitFrame.healthBar
if (not self.isNamePlate) then
--this is not a nameplate, perhaps another frame from the framework
return
end
Plater.StartLogPerformanceCore("Plater-Core", "Health", "OnUpdateHealth")
-- update - for whatever weird reason max health event does not give proper values sometimes...
if self.displayedUnit then --failsafe?!
local maxHealth = UnitHealthMax (self.displayedUnit)
self:SetMinMaxValues (0, maxHealth)
self.currentHealthMax = maxHealth
end
local plateFrame = self.PlateFrame
local currentHealth = self.currentHealth
local currentHealthMax = self.currentHealthMax
local unitFrame = self.unitFrame
local oldHealth = self.CurrentHealth
--> exposed values to scripts
self.CurrentHealth = currentHealth
self.CurrentHealthMax = currentHealthMax
if (plateFrame.IsSelf) then
self.CurrentHealth = currentHealth
self.CurrentHealthMax = currentHealthMax
--> flash if low health
if (currentHealth / currentHealthMax < 0.27) then
if (not self.PlayHealthFlash) then
Plater.CreateHealthFlashFrame (plateFrame)
end
self.PlayHealthFlash()
else
if (self.PlayHealthFlash) then
if (currentHealth / currentHealthMax > 0.5) then
self.canHealthFlash = true
end
end
end
if (plateFrame.PlateConfig.healthbar_color_by_hp) then
local originalColor = plateFrame.PlateConfig.healthbar_color
local r, g, b = DF:LerpLinearColor (abs (currentHealth / currentHealthMax - 1), 1, originalColor[1], originalColor[2], originalColor[3], 1, .4, 0)
Plater.ChangeHealthBarColor_Internal (self, r, g, b, (originalColor[4] or 1), true)
--else
--Plater.ChangeHealthBarColor_Internal (self, unpack (plateFrame.PlateConfig.healthbar_color))
end
Plater.CheckLifePercentText (unitFrame)
else
--quick hide the nameplate if the unit doesn't exists or if the unit died
if (DB_USE_QUICK_HIDE and (IS_WOW_PROJECT_MAINLINE)) then
if (not UnitExists (unitFrame.unit) or self.CurrentHealth < 1) then
--the unit died!
unitFrame:Hide()
Plater.EndLogPerformanceCore("Plater-Core", "Health", "OnUpdateHealth")
return
end
end
if (DB_DO_ANIMATIONS) then
--do healthbar animation ~animation ~healthbar
oldHealth = oldHealth or self.CurrentHealth
self.CurrentHealthMax = currentHealthMax
self.AnimationStart = oldHealth
self.AnimationEnd = currentHealth
self:SetValue (oldHealth)
self.IsAnimating = true
if (self.AnimationEnd > self.AnimationStart) then
self.AnimateFunc = Plater.AnimateRightWithAccel
else
self.AnimateFunc = Plater.AnimateLeftWithAccel
end
else
self.CurrentHealth = currentHealth
self.CurrentHealthMax = currentHealthMax
end
if (plateFrame.actorType == ACTORTYPE_FRIENDLY_PLAYER) then
local isWithoutHealthbar = plateFrame.IsFriendlyPlayerWithoutHealthBar
plateFrame.IsNpcWithoutHealthBar = false --ensure this.
Plater.ParseHealthSettingForPlayer (plateFrame)
self.ScheduleNameUpdate = plateFrame.IsFriendlyPlayerWithoutHealthBar ~= isWithoutHealthbar
--Plater.UpdatePlateText (plateFrame, DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_PLAYER], false)
end
Plater.CheckLifePercentText (unitFrame)
end
Plater.EndLogPerformanceCore("Plater-Core", "Health", "OnUpdateHealth")
end
--self is the healthBar (it's parent is the unitFrame)
function Plater.OnUpdateHealthMax (self)
Plater.StartLogPerformanceCore("Plater-Core", "Health", "OnUpdateHealthMax")
--the framework already set the min max values
self.CurrentHealthMax = self.currentHealthMax
Plater.CheckLifePercentText (self.unitFrame)
Plater.EndLogPerformanceCore("Plater-Core", "Health", "OnUpdateHealthMax")
end
function Plater.OnHealthChange (self, unitId) --~health
Plater.OnUpdateHealth (self)
--> run on health changed hook
if (HOOK_HEALTH_UPDATE.ScriptAmount > 0) then
return run_on_health_change_hook (self.unitFrame)
end
end
function Plater.OnHealthMaxChange (self, unitId)
Plater.OnUpdateHealthMax (self)
--> run on health changed hook
if (HOOK_HEALTH_UPDATE.ScriptAmount > 0) then
return run_on_health_change_hook (self.unitFrame)
end
end
--> profile changes and refreshes ~db
Plater.db.RegisterCallback (Plater, "OnProfileChanged", "RefreshConfigProfileChanged")
Plater.db.RegisterCallback (Plater, "OnProfileCopied", "RefreshConfig")
Plater.db.RegisterCallback (Plater, "OnProfileReset", "RefreshConfig")
--Plater.db.RegisterCallback (Plater, "OnDatabaseShutdown", "SaveConsoleVariables")
function Plater.OnProfileCreated()
C_Timer.After (.5, function()
Plater:Msg ("new profile created, applying patches and adding default scripts.")
Plater.ImportScriptsFromLibrary()
Plater.ApplyPatches()
Plater.CompileAllScripts ("script")
Plater.CompileAllScripts ("hook")
--enable UIParent nameplates for new installs of Plater
--this setting is disabled by default and will be enabled for new users and new profiles
Plater.db.profile.use_ui_parent = true
--adjust the fine tune to player's screen scale
Plater.db.profile.ui_parent_scale_tune = 1 / UIParent:GetEffectiveScale()
--call major refresh
Plater:RefreshConfig()
Plater.UpdatePlateClickSpace()
--call the user to /reload UI
DF:ShowPromptPanel ("Plater profile created, do you want /reload now (recommended)?", function() ReloadUI() end, function() end, true, 500)
end)
end
Plater.db.RegisterCallback (Plater, "OnNewProfile", "OnProfileCreated")
Plater.UpdateSelfPlate()
--update quest log after the addon initialization
C_Timer.After (4.1, Plater.QuestLogUpdated)
--update all nameplate after the addon initialized
C_Timer.After (5.1, function()
Plater.IncreaseRefreshID()
Plater.FullRefreshAllPlates()
end)
for i = 1, 3 do
C_Timer.After (i, Plater.RefreshDBUpvalues)
end
if CastingBarFrame then
CastingBarFrame:HookScript ("OnShow", function (self)
if (Plater.db.profile.hide_blizzard_castbar) then
self:Hide()
end
end)
elseif PlayerCastingBarFrame then
PlayerCastingBarFrame:HookScript ("OnShow", function (self)
if (Plater.db.profile.hide_blizzard_castbar) then
self:Hide()
end
end)
end
-- fill class-info cache data
if IS_WOW_PROJECT_MAINLINE then
for classID = 1, MAX_CLASSES do
local _, classFile = GetClassInfo(classID)
CLASS_INFO_CACHE[classFile] = {}
for i = 1, GetNumSpecializationsForClassID(classID) do
local specID, maleName, _, iconID, role = GetSpecializationInfoForClassID(classID, i, 2) -- male
local _, femaleName, _, iconID, role = GetSpecializationInfoForClassID(classID, i, 3) -- female
CLASS_INFO_CACHE[classFile][maleName] = {role = role, specID = specID, iconID = iconID}
CLASS_INFO_CACHE[classFile][femaleName] = CLASS_INFO_CACHE[classFile][maleName]
end
end
end
-- hook to the InterfaceOptionsFrame and VideoOptionsFrame to update the nameplate sizes, as blizzard somehow messes things up there on hide...
if InterfaceOptionsFrame then
InterfaceOptionsFrame:HookScript('OnHide',Plater.UpdatePlateClickSpace)
VideoOptionsFrame:HookScript('OnHide',Plater.UpdatePlateClickSpace)
elseif SettingsPanel then
SettingsPanel:HookScript('OnHide',Plater.UpdatePlateClickSpace)
end
end
function Plater.FormatTime (time)
if (time >= 3600) then
return floor (time / 3600) .. "h"
elseif (time >= 60) then
return floor (time / 60) .. "m"
else
return floor (time)
end
end
function Plater.FormatTimeDecimal (time)
if time < 10 then
return ("%.1f"):format(time)
elseif time < 60 then
return ("%d"):format(time)
elseif time < 3600 then
return ("%d:%02d"):format(time/60%60, time%60)
elseif time < 86400 then
return ("%dh %02dm"):format(time/(3600), time/60%60)
else
return ("%dd %02dh"):format(time/86400, (time/3600) - (floor(time/86400) * 24))
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> color stuff ~color
function Plater.SetQuestColorByReaction (unitFrame)
--unit is a quest mob, reset the color to quest color
if (unitFrame.ActorType and DB_PLATE_CONFIG [unitFrame.ActorType].quest_color_enabled) then
if (unitFrame [MEMBER_REACTION] == Plater.UnitReaction.UNITREACTION_NEUTRAL) then
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, unpack (DB_PLATE_CONFIG [unitFrame.ActorType].quest_color_neutral))
elseif (unitFrame [MEMBER_REACTION] < Plater.UnitReaction.UNITREACTION_NEUTRAL) then
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, unpack (DB_PLATE_CONFIG [unitFrame.ActorType].quest_color_enemy))
else
--there's a bug here where quest_color is nil for a friendly npc
--this is happening when an enemy quest npc turns friendly and (probably) the actorType doesn't change
--so in the enemy npc settings table does not have 'quest_color' input
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, unpack (DB_PLATE_CONFIG [unitFrame.ActorType].quest_color or {.5, 1, 0, 1}))
end
end
end
--override colors
--this function will set the color of the nameplate by the reaction of the unit shown
--it can only run if color override is enabled and when not in combat or when in combat but color by aggro is disabled
function Plater.ColorOverrider (unitFrame, forceRefresh)
--not in combat or aggro isn't changing the healthbar color
if (forceRefresh or not InCombatLockdown() or not DB_AGGRO_CHANGE_HEALTHBAR_COLOR) then
--isn't a quest
if (not unitFrame [MEMBER_QUEST] or not DB_PLATE_CONFIG [unitFrame.ActorType].quest_color_enabled) then
local reaction = unitFrame [MEMBER_REACTION]
--has a valid reaction
if (reaction) then
local r, g, b, a = unpack (Plater.db.profile.color_override_colors [reaction])
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, r, g, b, a, true)
end
else
--unit is a quest mob, reset the color to quest color
Plater.SetQuestColorByReaction (unitFrame)
end
end
end
--refresh the use of the color overrider
--called from the OnInit and from the options panel when the override color settings is changed
function Plater.RefreshColorOverride() --private
if (Plater.db.profile.color_override) then
Plater.CanOverrideColor = true
else
Plater.CanOverrideColor = false
end
Plater.UpdateAllNameplateColors()
end
--internal function to change the health bar color
function Plater.ChangeHealthBarColor_Internal (healthBar, r, g, b, a, forceNoLerp) --private
a = a or 1
if (r ~= healthBar.R or g ~= healthBar.G or b ~= healthBar.B or a ~= healthBar.A) then
healthBar.R, healthBar.G, healthBar.B, healthBar.A = r, g, b, a
if (not DB_LERP_COLOR or forceNoLerp) then -- ~lerpcolor
healthBar.barTexture:SetVertexColor (r, g, b, a)
end
end
end
--do several checkes to determine which are the color of this nameplate
--if force refresh is true, it'll ignore aggro and incombat checks in the ColorOverrider function
function Plater.FindAndSetNameplateColor (unitFrame, forceRefresh)
local r, g, b, a = 1, 1, 1, 1
local unitID = unitFrame.unit
if (unitFrame.IsSelf or not unitFrame.PlaterOnScreen) then
return
else
--check if is a player
if UnitIsPlayer (unitID) then
if (unitFrame.ActorType == ACTORTYPE_FRIENDLY_PLAYER) then
if (Plater.db.profile.use_playerclass_color) then
local _, class = UnitClass (unitID)
local classColor = DB_CLASS_COLORS [class]
if (classColor) then -- and unitFrame.optionTable.useClassColors
r, g, b, a = classColor.r, classColor.g, classColor.b, classColor.a
end
else
r, g, b, a = unpack(Plater.db.profile.plate_config.friendlyplayer.fixed_class_color)
end
elseif (unitFrame.ActorType == ACTORTYPE_ENEMY_PLAYER) then
if (Plater.db.profile.plate_config.enemyplayer.use_playerclass_color) then
local _, class = UnitClass (unitID)
local classColor = DB_CLASS_COLORS [class]
if (classColor) then -- and unitFrame.optionTable.useClassColors
r, g, b, a = classColor.r, classColor.g, classColor.b, classColor.a
end
else
r, g, b, a = unpack(Plater.db.profile.plate_config.enemyplayer.fixed_class_color)
end
end
--check if is tapped
elseif (Plater.IsUnitTapDenied (unitID)) then
r, g, b, a = unpack (Plater.db.profile.tap_denied_color)
else
if (Plater.CanOverrideColor) then
Plater.ColorOverrider (unitFrame, forceRefresh)
return
end
--check if the mob is a quest mob
if (unitFrame [MEMBER_QUEST] and DB_PLATE_CONFIG [unitFrame.ActorType].quest_color_enabled) then
Plater.SetQuestColorByReaction (unitFrame)
return
end
--get the color from the client
r, g, b, a = UnitSelectionColor (unitID)
end
end
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, r, g, b, a, true)
end
--force an update on all nameplates showin in the screen
--called after a refresh color override (on init and option settings changes)
--called after leaving the combat
function Plater.UpdateAllNameplateColors() --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (not plateFrame.IsSelf) then
--reset the nameplate color
Plater.FindAndSetNameplateColor (plateFrame.unitFrame)
end
end
end
--get a unit and a text and color the text with the class color of the unit (accepts player GUID as well)
function Plater.SetTextColorByClass (unit, text)
--checking if the unit exists because this can be called from the cleu parser
if (unit) then
local _, class = nil, nil
if (unit:sub(1, #"Player-") == "Player-") then
_, class = GetPlayerInfoByGUID (unit)
else
_, class = UnitClass (unit)
end
if (class) then
local color = DB_CLASS_COLORS [class]
if (color) then
text = "|c" .. color.colorStr .. DF:RemoveRealName (text) .. "|r"
end
else
text = DF:RemoveRealName (text)
end
return text
else
return text
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> update functions ~update
--run the hook "Nameplate Updated", this is called from inside the Tick and UpdateAllPlates()
function Plater.TriggerNameplateUpdatedEvent(unitFrame)
if unitFrame.PlaterOnScreen and (HOOK_NAMEPLATE_UPDATED.ScriptAmount > 0) then
for i = 1, HOOK_NAMEPLATE_UPDATED.ScriptAmount do
local globalScriptObject = HOOK_NAMEPLATE_UPDATED [i]
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Nameplate Updated")
local scriptEnv = scriptInfo.Env
scriptEnv._HealthPercent = unitFrame.healthBar.CurrentHealth / unitFrame.healthBar.CurrentHealthMax * 100
--run
unitFrame:ScriptRunHook (scriptInfo, "Nameplate Updated")
end
end
end
--full refresh calls
function Plater.UpdateAllPlates (forceUpdate, justAdded, regenDisabled) --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame and plateFrame.unitFrame.PlaterOnScreen then
if not plateFrame.unitFrame.isPerformanceUnit then
Plater.AddToAuraUpdate(plateFrame.unitFrame.unit) -- force aura update
end
Plater.UpdatePlateFrame (plateFrame, nil, forceUpdate, justAdded, regenDisabled)
--trigger a nameplate updated event
Plater.TriggerNameplateUpdatedEvent(plateFrame.unitFrame)
end
end
end
--called from the options panel | this is the same as calling Name_Plate_Unit_Added for each nameplate
function Plater.FullRefreshAllPlates() --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
--hack to call the update without overriding user settings from scripts
Plater.RunScheduledUpdate ({plateFrame = plateFrame, GUID = plateFrame [MEMBER_GUID]})
end
end
--update the player bar (personal nameplate)
local re_update_self_plate = function()
Plater.UpdateSelfPlate()
end
function Plater.UpdateSelfPlate() --private
if (InCombatLockdown()) then
return C_Timer.After (.3, re_update_self_plate)
end
C_NamePlate.SetNamePlateSelfClickThrough (DB_PLATE_CONFIG.player.click_through)
--disabled due to modifying the player personal nameplate makes it be a little offset in the Y anchor making it to be in front of the player
-- C_NamePlate.SetNamePlateSelfSize (unpack (DB_PLATE_CONFIG.player.health))
end
-- ~size ~updatesize
--update thee nameplate size including healthbar, castbar, etc
function Plater.UpdatePlateSize (plateFrame)
if (not plateFrame.actorType) then
return
end
Plater.StartLogPerformanceCore("Plater-Core", "Update", "UpdatePlateSize")
local profile = Plater.db.profile
local unitFrame = plateFrame.unitFrame
local healthBar = unitFrame.healthBar
local castBar = unitFrame.castBar
local powerBar = unitFrame.powerBar
local buffFrame1 = unitFrame.BuffFrame
local buffFrame2 = unitFrame.BuffFrame2
local isInCombat = profile.use_player_combat_state and PLAYER_IN_COMBAT or unitFrame.InCombat
--use in combat bars when in pvp
if (plateFrame.actorType == ACTORTYPE_ENEMY_PLAYER) then
if ((Plater.ZoneInstanceType == "pvp" or Plater.ZoneInstanceType == "arena") and DB_PLATE_CONFIG.player.pvp_always_incombat) then
isInCombat = true
end
end
local actorType = plateFrame.actorType
--get the config for this actor type
local plateConfigs = DB_PLATE_CONFIG [actorType]
--get the config key based if the player is in combat
local castBarConfigKey, healthBarConfigKey, manaConfigKey = Plater.GetHashKey (isInCombat)
local healthBarWidth, healthBarHeight = unitFrame.customHealthBarWidth or plateConfigs [healthBarConfigKey][1], unitFrame.customHealthBarHeight or plateConfigs [healthBarConfigKey][2]
local castBarWidth, castBarHeight = unitFrame.customCastBarWidth or plateConfigs [castBarConfigKey][1], unitFrame.customCastBarHeight or plateConfigs [castBarConfigKey][2]
local powerBarWidth, powerBarHeight = unitFrame.customPowerBarHeight or plateConfigs [manaConfigKey][1], unitFrame.customPowerBarHeight or plateConfigs [manaConfigKey][2]
local castBarOffSetX = plateConfigs.castbar_offset_x
local castBarOffSetXRel = (healthBarWidth - castBarWidth) / 2
local castBarOffSetY = plateConfigs.castbar_offset
local powerBarOffSetX = (healthBarWidth - powerBarWidth) / 2
local powerBarOffSetY = 0
--calculate the size deviation for pets
local unitType = Plater.GetUnitType (plateFrame)
if (unitType == "pet") then
healthBarHeight = healthBarHeight * Plater.db.profile.pet_height_scale
healthBarWidth = healthBarWidth * Plater.db.profile.pet_width_scale
elseif (unitType == "minus") then
healthBarHeight = healthBarHeight * Plater.db.profile.minor_height_scale
healthBarWidth = healthBarWidth * Plater.db.profile.minor_width_scale
end
--community patch by Ariani#0960 (discord)
--make the unitFrame be parented to UIParent allowing frames to be moved between strata levels
--March 3rd, 2019
if (DB_USE_UIPARENT) then
--unit frame - is set to be the same size as the plateFrame
unitFrame:ClearAllPoints()
unitFrame:SetPoint ("topleft", unitFrame.PlateFrame, "topleft", 0, 0)
unitFrame:SetPoint ("bottomright", unitFrame.PlateFrame, "bottomright", 0, 0)
--health bar
-- ensure that we are using the configured size, as it will be automatically scaled
healthBar:ClearAllPoints()
PixelUtil.SetPoint (healthBar, "center", unitFrame, "center", profile.global_offset_x, profile.global_offset_y)
PixelUtil.SetSize (healthBar, healthBarWidth, healthBarHeight)
--end of patch
--update scale
Plater.UpdateUIParentScale (plateFrame)
else
--unit frame - is set to be the same size as the plateFrame
unitFrame:ClearAllPoints()
--unitFrame:SetAllPoints()
--using the same setpoint pattern on both nameplate parent types to make easy the frameshake to handle the points
unitFrame:SetPoint ("topleft", unitFrame.PlateFrame, "topleft", 0, 0)
unitFrame:SetPoint ("bottomright", unitFrame.PlateFrame, "bottomright", 0, 0)
--health bar
--this calculates the health bar anchor points
--it will always be placed in the center of the nameplate main frame attached with two anchor points
local xOffSet = (plateFrame:GetWidth() - (healthBarWidth * unitFrame.nameplateScaleAdjust)) / 2
local yOffSet = (plateFrame:GetHeight() - (healthBarHeight * unitFrame.nameplateScaleAdjust)) / 2
healthBar:SetScale(1/unitFrame.nameplateScaleAdjust)
healthBar:ClearAllPoints()
PixelUtil.SetPoint (healthBar, "topleft", unitFrame, "topleft", xOffSet + profile.global_offset_x, -yOffSet + profile.global_offset_y)
PixelUtil.SetPoint (healthBar, "bottomright", unitFrame, "bottomright", -xOffSet + profile.global_offset_x, yOffSet + profile.global_offset_y)
end
--execute indicator
healthBar.healthCutOff:SetSize (healthBarHeight, healthBarHeight)
healthBar.executeRange:SetHeight (healthBarHeight)
--cast bar - is set by default below the healthbar
castBar:ClearAllPoints()
PixelUtil.SetPoint (castBar, "topleft", healthBar, "bottomleft", castBarOffSetXRel + castBarOffSetX, castBarOffSetY)
PixelUtil.SetPoint (castBar, "topright", healthBar, "bottomright", -castBarOffSetXRel + castBarOffSetX, castBarOffSetY)
PixelUtil.SetWidth (castBar, castBarWidth)
PixelUtil.SetHeight (castBar, castBarHeight)
--PixelUtil.SetSize (castBar.BorderShield, castBarHeight * 1.4, castBarHeight * 1.4)
PixelUtil.SetSize (castBar.Spark, profile.cast_statusbar_spark_width, castBarHeight)
Plater.UpdateCastbarIcon(castBar)
castBar._points = {{"topleft", healthBar, "bottomleft", castBarOffSetXRel + castBarOffSetX, castBarOffSetY},
{"topright", healthBar, "bottomright", -castBarOffSetXRel + castBarOffSetX, castBarOffSetY}}
--power bar
powerBar:ClearAllPoints()
PixelUtil.SetPoint (powerBar, "topleft", healthBar, "bottomleft", powerBarOffSetX, powerBarOffSetY)
PixelUtil.SetPoint (powerBar, "topright", healthBar, "bottomright", -powerBarOffSetX, powerBarOffSetY)
PixelUtil.SetSize (powerBar, powerBarWidth, powerBarHeight)
--power bar are hidden by default, show it if there's a custom size for it
if (unitFrame.customPowerBarWidth and unitFrame.customPowerBarHeight) then
powerBar:SetUnit (unitFrame.unit)
end
--aura frame
--plateConfigs.buff_frame_y_offset is the offset from the actor type, e.g. enemy npc
local bf1Anchor = Plater.db.profile.aura_frame1_anchor
Plater.SetAnchor (buffFrame1, {side = bf1Anchor.side, x = bf1Anchor.x, y = bf1Anchor.y + plateConfigs.buff_frame_y_offset}, unitFrame.healthBar, (Plater.db.profile.aura_grow_direction or 2) == 2)
local bf2Anchor = Plater.db.profile.aura_frame2_anchor
Plater.SetAnchor (buffFrame2, {side = bf2Anchor.side, x = bf2Anchor.x, y = bf2Anchor.y + plateConfigs.buff_frame_y_offset}, unitFrame.healthBar, (Plater.db.profile.aura2_grow_direction or 2) == 2)
if (Plater.db.profile.show_health_prediction or Plater.db.profile.show_shield_prediction) and healthBar.displayedUnit then
healthBar:UpdateHealPrediction() -- ensure health prediction is updated properly
end
Plater.UpdateUnitName (plateFrame)
Plater.EndLogPerformanceCore("Plater-Core", "Update", "UpdatePlateSize")
end
--debug function to print the size of the anchor for each aura container
function Plater.DebugAuraAnchor()
local profile = Plater.db.profile
--get the config for this actor type
local plateConfigs = DB_PLATE_CONFIG ["enemynpc"]
print ("DB_PLATE_CONFIG [enemynpc].buff_frame_y_offset:", plateConfigs.buff_frame_y_offset)
end
--show the background of the clickable aura, this is also shown when changing the clickable area
function Plater.SetPlateBackground (plateFrame)
plateFrame.unitFrame:SetBackdrop ({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
plateFrame.unitFrame:SetBackdropColor (0, 0, 0, 0.5)
plateFrame.unitFrame:SetBackdropBorderColor (0, 0, 0, 1)
end
local shutdown_platesize_debug = function (timer)
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
Plater.HideClickSpace (plateFrame)
if (Plater.db.profile.click_space_always_show) then
Plater.SetPlateBackground (plateFrame)
else
plateFrame.unitFrame:SetBackdrop (nil)
end
end
Plater.PlateSizeDebugTimer = nil
end
local re_UpdatePlateClickSpace = function()
Plater.UpdatePlateClickSpace()
end
--debug to show the clickable area when adjusting the click space
function Plater.ShowClickSpace (plateFrame)
plateFrame.debugAreaText:Show()
plateFrame.debugAreaTexture:Show()
end
function Plater.HideClickSpace (plateFrame)
plateFrame.debugAreaText:Hide()
plateFrame.debugAreaTexture:Hide()
end
-- ~platesize
function Plater.UpdatePlateClickSpace (needReorder, isDebug) --private
if (not Plater.CanChangePlateSize()) then
return C_Timer.After (1, re_UpdatePlateClickSpace)
end
local width, height = Plater.db.profile.click_space_friendly[1], Plater.db.profile.click_space_friendly[2]
C_NamePlate.SetNamePlateFriendlySize (width, height)
local width, height = Plater.db.profile.click_space[1], Plater.db.profile.click_space[2]
C_NamePlate.SetNamePlateEnemySize (width, height)
C_NamePlate.SetNamePlateFriendlyClickThrough (Plater.db.profile.plate_config.friendlyplayer.click_through)
if (isDebug and not Plater.db.profile.click_space_always_show) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if not plateFrame.IsSelf and plateFrame.unitFrame.PlaterOnScreen then
Plater.ShowClickSpace (plateFrame)
if (Plater.PlateSizeDebugTimer and not Plater.PlateSizeDebugTimer._cancelled) then
Plater.PlateSizeDebugTimer:Cancel()
end
end
end
if (not Plater.PlateSizeDebugTimer) then
Plater:Msg ("showing the clickable area for test purposes.")
end
Plater.PlateSizeDebugTimer = C_Timer.NewTimer (3, shutdown_platesize_debug)
end
if (needReorder) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
Plater.UpdatePlateFrame (plateFrame, plateFrame.actorType)
end
end
end
function Plater.ForceTickOnAllNameplates() --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
Plater.NameplateTick (plateFrame.OnTickFrame, 10) --GetWorldDeltaSeconds()
end
end
end
--FPS meter to spread NameplateTick evenly
Plater.FPSData = {
startTime = GetTime(),
platesUpdatedThisFrame = 0,
platesToUpdatePerFrame = 40,
frames = 1,
curFPS = 1,
}
function Plater.EveryFrameFPSCheck()
-- calculate every .25sec
local curTime = GetTime()
local curFPSData = Plater.FPSData
if (curFPSData.startTime + 0.25) < curTime then
curFPSData.curFPS = math.max(curFPSData.frames / (curTime - curFPSData.startTime), 1)
curFPSData.platesToUpdatePerFrame = math.ceil(NUM_NAMEPLATES_ON_SCREEN / DB_TICK_THROTTLE / curFPSData.curFPS)
--ViragDevTool_AddData({curFPSData=curFPSData, NUM_NAMEPLATES_ON_SCREEN = NUM_NAMEPLATES_ON_SCREEN}, "Plater_FPS")
curFPSData.frames = 0
curFPSData.startTime = curTime
else
curFPSData.frames = curFPSData.frames + 1
end
--ViragDevTool_AddData(curFPSData.platesUpdatedThisFrame, "platesUpdatedThisFrame")
curFPSData.platesUpdatedThisFrame = 0
C_Timer.After( 0, Plater.EveryFrameFPSCheck )
end
C_Timer.After( 0, Plater.EveryFrameFPSCheck )
-- ~ontick ~onupdate ~tick
function Plater.NameplateTick (tickFrame, deltaTime) --private
Plater.StartLogPerformanceCore("Plater-Core", "Update", "NameplateTick")
tickFrame.ThrottleUpdate = (tickFrame.ThrottleUpdate or 0) - deltaTime
local unitFrame = tickFrame.unitFrame
local healthBar = unitFrame.healthBar
local profile = Plater.db.profile
--throttle updates, things on this block update with the interval set in the advanced tab
local shouldUpdate = tickFrame.ThrottleUpdate < 0
local curFPSData = Plater.FPSData
if shouldUpdate and not ((1.5 * DB_TICK_THROTTLE + tickFrame.ThrottleUpdate) < 0) then --ensure updates are not posponed indefinetely
if curFPSData.platesUpdatedThisFrame >= curFPSData.platesToUpdatePerFrame then
shouldUpdate = false
end
end
if (shouldUpdate) then
curFPSData.platesUpdatedThisFrame = curFPSData.platesUpdatedThisFrame + 1
--make the db path smaller for performance
local actorTypeDBConfig = DB_PLATE_CONFIG [tickFrame.actorType]
--health cutoff (execute range) - don't show if the nameplate is the personal bar
if (DB_USE_HEALTHCUTOFF and not unitFrame.IsSelf and not unitFrame.PlayerCannotAttack) then
local healthPercent = (healthBar.currentHealth or 1) / (healthBar.currentHealthMax or 1)
if (healthPercent < DB_HEALTHCUTOFF_AT) then
if (not healthBar.healthCutOff:IsShown() or healthBar.healthCutOff.isUpper) then
healthBar.healthCutOff.isUpper = false
healthBar.healthCutOff.isLower = true
healthBar.healthCutOff:ClearAllPoints()
healthBar.healthCutOff:SetSize (healthBar:GetHeight(), healthBar:GetHeight())
healthBar.healthCutOff:SetPoint ("center", healthBar, "left", healthBar:GetWidth() * DB_HEALTHCUTOFF_AT, 0)
if (not profile.health_cutoff_hide_divisor) then
healthBar.healthCutOff:Show()
healthBar.healthCutOff.ShowAnimation:Play()
else
healthBar.healthCutOff:Show()
healthBar.healthCutOff:SetAlpha (0)
end
healthBar.executeRange:Show()
healthBar.executeRange:SetTexCoord (0, DB_HEALTHCUTOFF_AT, 0, 1)
healthBar.executeRange:SetAlpha (0.2)
healthBar.executeRange:SetVertexColor (.3, .3, .3)
healthBar.executeRange:SetHeight (healthBar:GetHeight())
healthBar.executeRange:SetPoint ("right", healthBar.healthCutOff, "center")
healthBar.executeRange:SetPoint ("left", healthBar, "left")
if (profile.health_cutoff_extra_glow) then
healthBar.ExecuteGlowUp.ShowAnimation:Play()
healthBar.ExecuteGlowDown.ShowAnimation:Play()
end
end
unitFrame.InExecuteRange = true
elseif (healthPercent > DB_HEALTHCUTOFF_AT_UPPER and healthPercent < 0.999) then
if (not healthBar.healthCutOff:IsShown() or healthBar.healthCutOff.isLower) then
healthBar.healthCutOff.isUpper = true
healthBar.healthCutOff.isLower = false
healthBar.healthCutOff:ClearAllPoints()
healthBar.healthCutOff:SetSize (healthBar:GetHeight(), healthBar:GetHeight())
healthBar.healthCutOff:SetPoint ("center", healthBar, "right", - (healthBar:GetWidth() * (1-DB_HEALTHCUTOFF_AT_UPPER)), 0)
if (not profile.health_cutoff_hide_divisor) then
healthBar.healthCutOff:Show()
healthBar.healthCutOff.ShowAnimation:Play()
else
healthBar.healthCutOff:Show()
healthBar.healthCutOff:SetAlpha (0)
end
healthBar.executeRange:Show()
healthBar.executeRange:SetTexCoord (0, 1-DB_HEALTHCUTOFF_AT_UPPER, 0, 1)
healthBar.executeRange:SetAlpha (0.2)
healthBar.executeRange:SetVertexColor (.3, .3, .3)
healthBar.executeRange:SetHeight (healthBar:GetHeight())
healthBar.executeRange:SetPoint ("left", healthBar.healthCutOff, "center")
healthBar.executeRange:SetPoint ("right", healthBar, "right")
if (profile.health_cutoff_extra_glow) then
healthBar.ExecuteGlowUp.ShowAnimation:Play()
healthBar.ExecuteGlowDown.ShowAnimation:Play()
end
end
unitFrame.InExecuteRange = true
else
healthBar.healthCutOff:Hide()
healthBar.executeRange:Hide()
healthBar.ExecuteGlowUp:Hide()
healthBar.ExecuteGlowDown:Hide()
unitFrame.InExecuteRange = false
end
end
local wasCombat = unitFrame.InCombat
unitFrame.InCombat = UnitAffectingCombat (tickFrame.unit) or (Plater.ForceInCombatUnits[unitFrame [MEMBER_NPCID]] and PLAYER_IN_COMBAT) or false
if wasCombat ~= unitFrame.InCombat then
Plater.UpdatePlateSize (tickFrame.PlateFrame)
end
--check aggro if is in combat
if (PLAYER_IN_COMBAT) then
if (unitFrame.CanCheckAggro) then
Plater.UpdateNameplateThread (unitFrame)
end
end
--perform a range check
Plater.CheckRange (tickFrame.PlateFrame, (deltaTime == 999))
--if not in combat, check if can show the percent health out of combat
if (actorTypeDBConfig.percent_text_enabled and (((profile.use_player_combat_state and PLAYER_IN_COMBAT or unitFrame.InCombat)) or actorTypeDBConfig.percent_text_ooc)) then
Plater.UpdateLifePercentText (healthBar, unitFrame.unit, actorTypeDBConfig.percent_show_health, actorTypeDBConfig.percent_show_percent, actorTypeDBConfig.percent_text_show_decimals)
healthBar.lifePercent:Show()
else
healthBar.lifePercent:Hide()
end
--if the unit tapped? (gray color)
if (Plater.IsUnitTapDenied (tickFrame.unit)) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (profile.tap_denied_color))
end
--the color overrider for unitIDs goes after the threat check and before the aura, since auras can run scripts and scripts have priority on setting colors
if (DB_UNITCOLOR_CACHE [unitFrame [MEMBER_NPCID]]) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_UNITCOLOR_CACHE [unitFrame [MEMBER_NPCID]]))
unitFrame.UsingCustomColor = true --exposed to scripts
end
--update buffs and debuffs
if (DB_AURA_ENABLED) then --should update only when the heathbar is shown?
--Plater.StartLogPerformanceCore("Plater-Core", "Update", "UpdateAuras")
if (DB_TRACK_METHOD == 0x1) then --automatic
if (tickFrame.actorType == ACTORTYPE_PLAYER) then
--update auras on the personal bar
Plater.UpdateAuras_Self_Automatic (tickFrame.BuffFrame, tickFrame.unit)
else
Plater.UpdateAuras_Automatic (tickFrame.BuffFrame, tickFrame.unit)
end
else
--manual aura track
Plater.UpdateAuras_Manual (tickFrame.BuffFrame, tickFrame.unit, tickFrame.actorType == ACTORTYPE_PLAYER)
end
--update the buff layout and alpha
tickFrame.BuffFrame.unit = tickFrame.unit
--check for ghost auras
Plater.ShowGhostAuras(tickFrame.BuffFrame) --ghost auras only show in the debuff frame
--align icons in the aura frame
Plater.AlignAuraFrames (tickFrame.BuffFrame)
--update the alignment on the second aura frame as well if enabled
if (DB_AURA_SEPARATE_BUFFS) then
Plater.AlignAuraFrames (tickFrame.BuffFrame.BuffFrame2)
end
Plater.RunScriptTriggersForAuraIcons (unitFrame)
--tickFrame.BuffFrame:SetAlpha (DB_AURA_ALPHA)
--tickFrame.BuffFrame2:SetAlpha (DB_AURA_ALPHA)
--Plater.EndLogPerformanceCore("Plater-Core", "Update", "UpdateAuras")
end
-- update DBM and BigWigs nameplate auras
Plater.UpdateBossModAuras(unitFrame)
--set the delay to perform another update
tickFrame.ThrottleUpdate = DB_TICK_THROTTLE * (unitFrame.isPerformanceUnit and 5 or 1)
--check if the unit name or unit npcID has a script
local globalScriptObject = SCRIPT_UNIT_TRIGGER_CACHE[tickFrame.PlateFrame [MEMBER_NAMELOWER]] or SCRIPT_UNIT_TRIGGER_CACHE[unitFrame [MEMBER_NPCID]]
--check if this aura has a custom script
if (globalScriptObject) then
--stored information about scripts
local scriptContainer = unitFrame:ScriptGetContainer()
--get the info about this particularly script
local scriptInfo = unitFrame:ScriptGetInfo(globalScriptObject, scriptContainer)
local scriptEnv = scriptInfo.Env
scriptEnv._UnitID = tickFrame.PlateFrame [MEMBER_UNITID]
scriptEnv._NpcID = tickFrame.PlateFrame [MEMBER_NPCID]
scriptEnv._UnitName = tickFrame.PlateFrame [MEMBER_NAME]
scriptEnv._UnitGUID = tickFrame.PlateFrame [MEMBER_GUID]
scriptEnv._HealthPercent = healthBar.CurrentHealth / healthBar.CurrentHealthMax * 100
--run onupdate script
unitFrame:ScriptRunOnUpdate(scriptInfo)
end
--scheduled name update
if (unitFrame.ScheduleNameUpdate) then
if (unitFrame.ActorType == ACTORTYPE_FRIENDLY_PLAYER) then
tickFrame.PlateFrame.playerGuildName = GetGuildInfo (tickFrame.unit)
Plater.UpdatePlateText (tickFrame.PlateFrame, DB_PLATE_CONFIG [unitFrame.ActorType], false)
end
Plater.UpdateUnitName (tickFrame.PlateFrame)
unitFrame.ScheduleNameUpdate = nil
--run hook
if (HOOK_UNITNAME_UPDATE.ScriptAmount > 0) then
for i = 1, HOOK_UNITNAME_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_UNITNAME_UPDATE [i]
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Name Updated")
--run
unitFrame:ScriptRunHook (scriptInfo, "Name Updated")
end
end
end
--hooks
Plater.TriggerNameplateUpdatedEvent(unitFrame)
--details! integration
if (IS_USING_DETAILS_INTEGRATION and not tickFrame.PlateFrame.IsSelf and PLAYER_IN_COMBAT and unitFrame.InCombat) then
local detailsPlaterConfig = Details.plater
--> current damage taken from all sources
if (detailsPlaterConfig.realtime_dps_enabled) then
local unitDamageTable = DetailsPlaterFrame.DamageTaken [tickFrame.PlateFrame [MEMBER_GUID]]
if (unitDamageTable) then
local damage = unitDamageTable.CurrentDamage or 0
local textString = healthBar.DetailsRealTime
textString:SetText (Plater.FormatNumber (damage / PLATER_DPS_SAMPLE_SIZE))
else
local textString = healthBar.DetailsRealTime
textString:SetText ("")
end
end
if (detailsPlaterConfig.realtime_dps_player_enabled) then
local unitDamageTable = DetailsPlaterFrame.DamageTaken [tickFrame.PlateFrame [MEMBER_GUID]]
if (unitDamageTable) then
local damage = unitDamageTable.CurrentDamageFromPlayer or 0
local textString = healthBar.DetailsRealTimeFromPlayer
textString:SetText (Plater.FormatNumber (damage / PLATER_DPS_SAMPLE_SIZE))
else
local textString = healthBar.DetailsRealTimeFromPlayer
textString:SetText ("")
end
end
if (detailsPlaterConfig.damage_taken_enabled) then
local unitDamageTable = DetailsPlaterFrame.DamageTaken [tickFrame.PlateFrame [MEMBER_GUID]]
if (unitDamageTable) then
local damage = unitDamageTable.TotalDamageTaken or 0
local textString = healthBar.DetailsDamageTaken
textString:SetText (Plater.FormatNumber (damage))
else
local textString = healthBar.DetailsDamageTaken
textString:SetText ("")
end
end
end
--check shield ~shield
if (IS_WOW_PROJECT_MAINLINE) then
if (profile.indicator_shield) then
local amountAbsorb = UnitGetTotalAbsorbs(tickFrame.PlateFrame[MEMBER_UNITID])
if (amountAbsorb and amountAbsorb > 0) then
--update the total amount on the shield indicator
if (not healthBar.shieldIndicator.shieldTotal) then
healthBar.shieldIndicator.shieldTotal = amountAbsorb
else
if (amountAbsorb > healthBar.shieldIndicator.shieldTotal) then
healthBar.shieldIndicator.shieldTotal = amountAbsorb
end
end
healthBar.shieldIndicator:Show()
local percent = amountAbsorb / healthBar.shieldIndicator.shieldTotal
local width = healthBar:GetWidth() * percent
healthBar.shieldIndicator:SetWidth(width)
else
--hide the shield bar is currently shown
if (healthBar.shieldIndicator:IsShown()) then
healthBar.shieldIndicator:Hide()
healthBar.shieldIndicator.shieldTotal = nil
end
end
end
end
--end of throttled updates
end
--OnTick updates
--smooth color transition ~lerpcolor
if (DB_LERP_COLOR and not unitFrame.isPerformanceUnit) then
local currentR, currentG, currentB = healthBar.barTexture:GetVertexColor()
local r, g, b = DF:LerpLinearColor (deltaTime, DB_LERP_COLOR_SPEED, currentR, currentG, currentB, healthBar.R or currentR, healthBar.G or currentG, healthBar.B or currentB)
healthBar.barTexture:SetVertexColor (r, g, b)
end
--animate health bar ~animation
if (DB_DO_ANIMATIONS and not unitFrame.isPerformanceUnit) then
if (healthBar.IsAnimating) then
healthBar.AnimateFunc (healthBar, deltaTime)
end
end
Plater.EndLogPerformanceCore("Plater-Core", "Update", "NameplateTick")
end
local set_aggro_color = function (self, r, g, b, a) --self = unitName
if (DB_AGGRO_CHANGE_HEALTHBAR_COLOR) then
Plater.ChangeHealthBarColor_Internal (self.healthBar, r, g, b, a)
end
if (DB_AGGRO_CHANGE_BORDER_COLOR) then
Plater.ForceChangeBorderColor (self, r, g, b)
end
if (DB_AGGRO_CHANGE_NAME_COLOR) then
self.unitName:SetTextColor (r, g, b)
end
end
--aggro threat ~aggro ~threat
function Plater.UpdateNameplateThread (self) --self = unitFrame
--make sure there's a unitID in the unit frame
if (not self.displayedUnit or not self.CanCheckAggro) then
return
end
Plater.StartLogPerformanceCore("Plater-Core", "Update", "UpdateNameplateThreat")
local profile = Plater.db.profile
local isTanking, threatStatus, threatpct, threatrawpct, threatValue = UnitDetailedThreatSituation ("player", self.displayedUnit)
--expose all threat situation to scripts
self.namePlateThreatIsTanking = isTanking
self.namePlateThreatStatus = threatStatus
self.namePlateThreatPercent = threatpct or 0
self.namePlateThreatRawPercent = threatrawpct or 0
self.namePlateThreatValue = threatValue or 0
-- (3 = securely tanking, 2 = insecurely tanking, 1 = not tanking but higher threat than tank, 0 = not tanking and lower threat than tank)
self.namePlateThreatOffTankIsTanking = false
self.namePlateThreatOffTankName = nil
self.aggroGlowUpper:Hide()
self.aggroGlowLower:Hide()
--player is a tank
if (Plater.PlayerIsTank) then
--and isn't tanking the unit
if (not isTanking) then
--is the player in combat?
if (self.InCombat) then
--is the player in a raid group?
if (IsInRaid()) then
--check if another tank is effectively tanking
--as the other tank may not be targeted due to spell-casts, we need to check the threat situation for tanks
local unitOffTank = nil
local otherIsTanking, otherThreatStatus, otherThreatpct
--loop on all tanks in the group (tank_cache is updated on entering combat or when group roster is updated)
for tank, _ in pairs(TANK_CACHE) do
if UnitExists(tank) and not UnitIsUnit("player", tank) then
otherIsTanking, otherThreatStatus, otherThreatpct = UnitDetailedThreatSituation (tank, self.displayedUnit)
if otherIsTanking then
unitOffTank = tank
break
end
end
end
--another tank is tanking the unit
if (unitOffTank) then
self.namePlateThreatOffTankIsTanking = true
self.namePlateThreatOffTankName = unitOffTank
--as the unit is being tanked by the off-tank, check if the player it self which is the other tank is about to accidently pull aggro just by hitting the mob
if (threatpct and otherThreatpct) then
--threatpct = player threat on the mob
--otherThreatpct = the aggro on the tank tanking the unit
if ((threatpct + 10) - otherThreatpct > 0) then
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.pulling_from_tank))
else
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.anothertank))
end
else
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.anothertank))
end
else
--no tank is tanking this unit
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.noaggro))
end
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
else
--player isn't tanking this unit
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.noaggro))
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
end
else
--if isn't a quest mob
if (not self.PlateFrame [MEMBER_QUEST]) then
--there's no aggro, isn't in combat, isn't a quest mob
if (self [MEMBER_REACTION] == 4) then
--do nothing if the mob is neutral
--set_aggro_color (self, 1, 1, 0) --ticket #185
else
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.nocombat))
end
if (DB_NOT_COMBAT_ALPHA_ENABLED) then
self.PlateFrame [MEMBER_NOCOMBAT] = true
self:SetAlpha (profile.not_affecting_combat_alpha)
end
end
end
else
--The player is tanking and:
if (threatStatus == 3) then --is tanking safely
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.aggro))
elseif (threatStatus == 2) then --is tanking with risk of aggro loss
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.pulling))
if profile.show_aggro_glow then
self.aggroGlowUpper:Show()
self.aggroGlowLower:Show()
end
else --not tanking
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.noaggro))
end
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
end
else
--dps
if (isTanking) then
--the player is tanking as dps
if profile.dps.use_aggro_solo and not IsInGroup() then
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.solo))
else
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.aggro))
end
if (not self.PlateFrame.playerHasAggro and IS_IN_INSTANCE) then
if profile.show_aggro_flash then
self.PlateFrame.PlayBodyFlash ("-AGGRO-")
end
end
self.PlateFrame.playerHasAggro = true
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
else
if (threatStatus == nil) then
self.PlateFrame.playerHasAggro = false
--> unit is in combat?
if (self.InCombat) then
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.noaggro))
self.PlateFrame.playerHasAggro = false
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
else
--if isn't a quest mob
if (not self.PlateFrame [MEMBER_QUEST]) then
--there's no aggro, isn't in combat, isn't a quest mob
if (self [MEMBER_REACTION] == 4) then --ticket #185
--do nothing if the mob is neutral
--set_aggro_color (self, 1, 1, 0)
else
set_aggro_color (self, unpack (DB_AGGRO_TANK_COLORS.nocombat))
end
if (DB_NOT_COMBAT_ALPHA_ENABLED) then --not self.PlateFrame [MEMBER_NOCOMBAT] and
self.PlateFrame [MEMBER_NOCOMBAT] = true
self:SetAlpha (profile.not_affecting_combat_alpha)
end
end
end
else
if (threatStatus == 3) then --player is tanking the mob as dps
if profile.dps.use_aggro_solo and not IsInGroup() then
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.solo))
else
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.aggro))
end
if (not self.PlateFrame.playerHasAggro and IS_IN_INSTANCE) then
if profile.show_aggro_flash then
self.PlateFrame.PlayBodyFlash ("-AGGRO-")
end
end
self.PlateFrame.playerHasAggro = true
elseif (threatStatus == 2) then --player is tanking the mob with low aggro
if profile.dps.use_aggro_solo and not IsInGroup() then
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.solo))
else
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.aggro))
end
self.PlateFrame.playerHasAggro = true
else --the unit isn't attacking the player based on the threat situation
--which color the use in the nameplate based on the threat status
--this color can be overritten by the 'no tank aggro' check
local colorToUse
if (threatStatus == 1) then --player is almost aggroing the mob
--show aggro warning indicators
if profile.show_aggro_glow then
self.aggroGlowUpper:Show()
self.aggroGlowLower:Show()
end
if profile.dps.use_aggro_solo and not IsInGroup() then
colorToUse = DB_AGGRO_DPS_COLORS.solo
else
colorToUse = DB_AGGRO_DPS_COLORS.pulling
end
elseif (threatStatus == 0) then
colorToUse = DB_AGGRO_DPS_COLORS.noaggro
end
if (Plater.ZoneInstanceType == "party" or Plater.ZoneInstanceType == "raid") then
--check if can check for no tank aggro
if (DB_AGGRO_CAN_CHECK_NOTANKAGGRO) then
local unitTarget = UnitName (self.targetUnitID)
--check if the unit isn't attacking a tank comparing the target name with tank names
if (not TANK_CACHE [unitTarget]) then
--check if this isn't a false positive where the mob target another unit to cast a spell
local hasTankAggro = false
for tankName, _ in pairs (TANK_CACHE) do
if UnitExists(tankName) then
local threatStatus = UnitThreatSituation (tankName, self.displayedUnit)
if (threatStatus and threatStatus >= 2) then
--a tank has aggro on this unit, it is a false positive
hasTankAggro = true
break
end
end
end
if (not hasTankAggro) then
--the unit isn't targeting a tank and no tank in the group has threat status of 2 or more, the unit might be attacking a dps or healer
set_aggro_color (self, unpack (DB_AGGRO_DPS_COLORS.notontank))
else
--the unit isn't targeting a tank but a tank in the group has aggro on this unit
set_aggro_color (self, unpack (colorToUse))
end
else
--the unit is targeting a tank
set_aggro_color (self, unpack (colorToUse))
end
else
--isn't checking for 'no tank aggro'
set_aggro_color (self, unpack (colorToUse))
end
else
--player isn't inside a dungeon or raid
set_aggro_color (self, unpack (colorToUse))
end
self.PlateFrame.playerHasAggro = false
end
if (self.PlateFrame [MEMBER_NOCOMBAT]) then
self.PlateFrame [MEMBER_NOCOMBAT] = nil
Plater.CheckRange (self.PlateFrame, true)
end
end
end
end
Plater.EndLogPerformanceCore("Plater-Core", "Update", "UpdateNameplateThreat")
end
-- ~target ~selection
function Plater.UpdateTarget (plateFrame) --private
local profile = Plater.db.profile
local unitFrame = plateFrame.unitFrame
if UnitIsUnit (unitFrame [MEMBER_UNITID], "focus") then
if profile.focus_indicator_enabled then
--this is a rare call, no need to cache these values
local texture = LibSharedMedia:Fetch ("statusbar", Plater.db.profile.focus_texture)
plateFrame.FocusIndicator:SetTexture (texture)
plateFrame.FocusIndicator:SetVertexColor (unpack (Plater.db.profile.focus_color))
plateFrame.FocusIndicator:Show()
end
unitFrame.IsFocus = true
else
unitFrame.IsFocus = false
plateFrame.FocusIndicator:Hide()
end
if (UnitIsUnit (unitFrame [MEMBER_UNITID], "target")) then
plateFrame [MEMBER_TARGET] = true
unitFrame [MEMBER_TARGET] = true
--hide obscured texture
plateFrame.Obscured:Hide()
--target indicator
Plater.UpdateTargetIndicator (plateFrame)
--target highlight
if (profile.target_highlight) then
if (plateFrame.actorType ~= ACTORTYPE_FRIENDLY_PLAYER and plateFrame.actorType ~= ACTORTYPE_FRIENDLY_NPC and not plateFrame.PlayerCannotAttack and unitFrame.healthBar:IsShown()) then
plateFrame.TargetNeonUp:Show()
plateFrame.TargetNeonDown:Show()
else
plateFrame.TargetNeonUp:Hide()
plateFrame.TargetNeonDown:Hide()
end
Plater.UpdateTargetHighlight (plateFrame) --neon
else
plateFrame.TargetNeonUp:Hide()
plateFrame.TargetNeonDown:Hide()
end
if (not unitFrame.healthBar:IsShown()) then
unitFrame.targetOverlayTexture:Hide()
else
unitFrame.targetOverlayTexture:Show()
end
if (DB_USE_UIPARENT) then
Plater.UpdateUIParentTargetLevels (unitFrame)
end
Plater.UpdateResourceFrame()
else
plateFrame.TargetNeonUp:Hide()
plateFrame.TargetNeonDown:Hide()
unitFrame.targetOverlayTexture:Hide()
plateFrame [MEMBER_TARGET] = nil
unitFrame [MEMBER_TARGET] = nil
if (unitFrame.IsTarget or unitFrame.TargetTextures2Sides [1]:IsShown() or unitFrame.TargetTextures4Sides [1]:IsShown()) then
for i = 1, 2 do
unitFrame.TargetTextures2Sides [i]:Hide()
end
for i = 1, 4 do
unitFrame.TargetTextures4Sides [i]:Hide()
end
unitFrame.IsTarget = false
end
if (DB_TARGET_SHADY_ENABLED and (not DB_TARGET_SHADY_COMBATONLY or (profile.use_player_combat_state and PLAYER_IN_COMBAT or unitFrame.InCombat)) and not plateFrame.IsSelf) then
plateFrame.Obscured:Show()
plateFrame.Obscured:SetAlpha (DB_TARGET_SHADY_ALPHA)
else
plateFrame.Obscured:Hide()
end
if (DB_USE_UIPARENT) then
Plater.UpdateUIParentLevels (unitFrame)
end
end
--[[
plateFrame.unitFrame.WidgetContainer:UnregisterForWidgetSet()
local widgetSetId = UnitWidgetSet(plateFrame.unitFrame [MEMBER_UNITID])
local playerControlled = UnitPlayerControlled(plateFrame.unitFrame [MEMBER_UNITID])
if widgetSetId and ((playerControlled and UnitIsOwnerOrControllerOfUnit('player', plateFrame.unitFrame [MEMBER_UNITID])) or not playerControlled) then
--plateFrame.unitFrame.WidgetContainer:RegisterForWidgetSet(widgetSetId)
plateFrame.unitFrame.WidgetContainer:RegisterForWidgetSet(widgetSetId, Plater.PlaterDefaultWidgetLayout, nil, plateFrame.unitFrame [MEMBER_UNITID]);
plateFrame.unitFrame.WidgetContainer:ProcessAllWidgets()
end
]]--
Plater.CheckRange (plateFrame, true) --disabled on 2018-10-09 | enabled back on 2020-1-16
end
--called when the player targets a new unit, when focus changed or when a unit isn't in the screen any more
function Plater.OnPlayerTargetChanged() --private
Plater.PlayerCurrentTargetGUID = UnitGUID ("target")
Plater.PlayerHasTarget = Plater.PlayerCurrentTargetGUID and true
Plater.PlayerHasTargetNonSelf = Plater.PlayerHasTarget and Plater.PlayerCurrentTargetGUID ~= Plater.PlayerGUID and true
Plater.PlayerCurrentFocusTargetGUID = UnitGUID ("focus")
Plater.PlayerHasFocusTarget = Plater.PlayerCurrentFocusTargetGUID and true
Plater.PlayerHasFocusTargetNonSelf = Plater.PlayerHasFocusTarget and Plater.PlayerCurrentFocusTargetGUID ~= Plater.PlayerGUID and true
for index, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
Plater.UpdateTarget (plateFrame)
--hooks
if (HOOK_TARGET_CHANGED.ScriptAmount > 0) then
for i = 1, HOOK_TARGET_CHANGED.ScriptAmount do
local globalScriptObject = HOOK_TARGET_CHANGED [i]
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Target Changed")
--run
unitFrame:ScriptRunHook (scriptInfo, "Target Changed")
end
end
end
end
Plater.Resources.UpdateResourceFramePosition() --~resource
end
function Plater.UpdateTargetHighlight (plateFrame)
local healthBar = plateFrame.unitFrame.healthBar
local profile = Plater.db.profile
local alpha = profile.target_highlight_alpha
local height = profile.target_highlight_height
local color = profile.target_highlight_color
local texture = profile.target_highlight_texture
plateFrame.TargetNeonUp:SetVertexColor (unpack (color))
plateFrame.TargetNeonUp:SetAlpha (alpha)
plateFrame.TargetNeonUp:SetTexture (texture)
plateFrame.TargetNeonUp:SetHeight (height)
PixelUtil.SetPoint (plateFrame.TargetNeonUp, "bottomleft", healthBar, "topleft", 0, 0)
PixelUtil.SetPoint (plateFrame.TargetNeonUp, "bottomright", healthBar, "topright", 0, 0)
plateFrame.TargetNeonDown:SetVertexColor (unpack (color))
plateFrame.TargetNeonDown:SetAlpha (alpha)
plateFrame.TargetNeonDown:SetTexture (texture)
plateFrame.TargetNeonDown:SetHeight (height)
PixelUtil.SetPoint (plateFrame.TargetNeonDown, "topleft", healthBar, "bottomleft", 0, 0)
PixelUtil.SetPoint (plateFrame.TargetNeonDown, "topright", healthBar, "bottomright", 0, 0)
end
function Plater.UpdateTargetIndicator (plateFrame)
local healthBarHeight = plateFrame.unitFrame.healthBar:GetHeight()
--if the height is lower than 4, just hide all indicators
if (healthBarHeight < 4) then
for i = 1, 2 do
plateFrame.unitFrame.TargetTextures2Sides [i]:Hide()
end
for i = 1, 4 do
plateFrame.unitFrame.TargetTextures4Sides [i]:Hide()
end
return
end
local preset = Plater.TargetIndicators [Plater.db.profile.target_indicator]
if (not preset) then
--use default indicator is the indicator isn't found
preset = Plater.TargetIndicators ["Silver"]
end
local width, height = preset.width, preset.height
local wscale, hscale = preset.wscale or 1, preset.hscale or 1
local x, y = preset.x or 0, preset.y or 0
local desaturated = preset.desaturated
local coords = preset.coords
local path = preset.path
local blend = preset.blend or "BLEND"
local alpha = preset.alpha or 1
local doScale = preset.autoScale
local custScale = preset.scale
local overlayColorR, overlayColorG, overlayColorB = DF:ParseColors (preset.color or "white")
local scale = (not doScale and custScale) or (healthBarHeight / (doScale and height or 10))
--four parts (textures)
if (#coords == 4) then
for i = 1, 4 do
local texture = plateFrame.unitFrame.TargetTextures4Sides [i]
texture:Show()
texture:SetTexture (path)
texture:SetTexCoord (unpack (coords [i]))
texture:SetSize (width * scale * wscale, height * scale * hscale)
texture:SetAlpha (alpha)
texture:SetVertexColor (overlayColorR, overlayColorG, overlayColorB)
texture:SetDesaturated (desaturated)
if (i == 1) then
--PixelUtil.SetPoint (texture, "topleft", plateFrame.unitFrame.healthBar, "topleft", -x * scale, y * scale)
texture:SetPoint ("topleft", plateFrame.unitFrame.healthBar, "topleft", -x * scale, y * scale)
elseif (i == 2) then
--PixelUtil.SetPoint (texture, "bottomleft", plateFrame.unitFrame.healthBar, "bottomleft", -x * scale, -y * scale)
texture:SetPoint ("bottomleft", plateFrame.unitFrame.healthBar, "bottomleft", -x * scale, -y * scale)
elseif (i == 3) then
--PixelUtil.SetPoint (texture, "bottomright", plateFrame.unitFrame.healthBar, "bottomright", x * scale, -y * scale)
texture:SetPoint ("bottomright", plateFrame.unitFrame.healthBar, "bottomright", x * scale, -y * scale)
elseif (i == 4) then
--PixelUtil.SetPoint (texture, "topright", plateFrame.unitFrame.healthBar, "topright", x * scale, y * scale)
texture:SetPoint ("topright", plateFrame.unitFrame.healthBar, "topright", x * scale, y * scale)
end
end
for i = 1, 2 do
plateFrame.unitFrame.TargetTextures2Sides [i]:Hide()
end
--two parts
else
for i = 1, 2 do
local texture = plateFrame.unitFrame.TargetTextures2Sides [i]
texture:Show()
texture:SetTexture (path)
texture:SetBlendMode (blend)
texture:SetTexCoord (unpack (coords [i]))
--PixelUtil.SetSize (texture, width * scale, height * scale)
--PixelUtil.SetSize (texture, width * scale * wscale, height * scale * hscale)
texture:SetSize (width * scale * wscale, height * scale * hscale)
texture:SetDesaturated (desaturated)
texture:SetAlpha (alpha)
texture:SetVertexColor (overlayColorR, overlayColorG, overlayColorB)
if (i == 1) then
--PixelUtil.SetPoint (texture, "left", plateFrame.unitFrame.healthBar, "left", -x * scale, y * scale)
texture:SetPoint ("left", plateFrame.unitFrame.healthBar, "left", -x * scale, y * scale)
elseif (i == 2) then
--PixelUtil.SetPoint (texture, "right", plateFrame.unitFrame.healthBar, "right", x * scale, -y * scale)
texture:SetPoint ("right", plateFrame.unitFrame.healthBar, "right", x * scale, -y * scale)
end
end
for i = 1, 4 do
plateFrame.unitFrame.TargetTextures4Sides [i]:Hide()
end
end
plateFrame.unitFrame.IsTarget = true
end
-- ~updatetext ~update - called only from UpdatePlateFrame()
-- update all texts in the nameplate, settings can variate from different unit types
-- needReset is true when the previous unit type shown on this place is different from the current unit
function Plater.UpdatePlateText (plateFrame, plateConfigs, needReset) --private
if plateFrame.unitFrame.isWidgetOnlyMode then
plateFrame.ActorNameSpecial:Hide()
plateFrame.ActorTitleSpecial:Hide()
return
end
-- ensure castBar updates are done, as this needs to be done for all types of plates...
local spellnameString = plateFrame.unitFrame.castBar.Text
local spellPercentString = plateFrame.unitFrame.castBar.percentText
--update spell name text
if (needReset) then
DF:SetFontColor (spellnameString, plateConfigs.spellname_text_color)
--DF:SetFontOutline (spellnameString, plateConfigs.spellname_text_shadow)
Plater.SetFontOutlineAndShadow (spellnameString, plateConfigs.spellname_text_outline, plateConfigs.spellname_text_shadow_color, plateConfigs.spellname_text_shadow_color_offset[1], plateConfigs.spellname_text_shadow_color_offset[2])
DF:SetFontFace (spellnameString, plateConfigs.spellname_text_font)
DF:SetFontSize (spellnameString, plateConfigs.spellname_text_size)
Plater.SetAnchor (spellnameString, plateConfigs.spellname_text_anchor)
end
--update spell cast time
if (plateConfigs.spellpercent_text_enabled) then
spellPercentString:Show()
plateFrame.unitFrame.castBar.Settings.ShowCastTime = true
if (needReset) then
DF:SetFontColor (spellPercentString, plateConfigs.spellpercent_text_color)
DF:SetFontSize (spellPercentString, plateConfigs.spellpercent_text_size)
--DF:SetFontOutline (spellPercentString, plateConfigs.spellpercent_text_shadow)
Plater.SetFontOutlineAndShadow (spellPercentString, plateConfigs.spellpercent_text_outline, plateConfigs.spellpercent_text_shadow_color, plateConfigs.spellpercent_text_shadow_color_offset[1], plateConfigs.spellpercent_text_shadow_color_offset[2])
DF:SetFontFace (spellPercentString, plateConfigs.spellpercent_text_font)
Plater.SetAnchor (spellPercentString, plateConfigs.spellpercent_text_anchor)
end
else
plateFrame.unitFrame.castBar.Settings.ShowCastTime = false
spellPercentString:Hide()
end
-- updates for special frames
if (plateFrame.IsSelf) then
--return
--needReset = true
elseif (plateFrame.IsFriendlyPlayerWithoutHealthBar) then --not critical code
--when the option to show only the player name is enabled
--special string to show the player name
local nameFontString = plateFrame.ActorNameSpecial
nameFontString:Show()
--set the name in the string
plateFrame.CurrentUnitNameString = nameFontString
Plater.UpdateUnitName (plateFrame)
DF:SetFontSize (nameFontString, plateConfigs.actorname_text_size)
DF:SetFontFace (nameFontString, plateConfigs.actorname_text_font)
--DF:SetFontOutline (nameFontString, plateConfigs.actorname_text_shadow)
Plater.SetFontOutlineAndShadow (nameFontString, plateConfigs.actorname_text_outline, plateConfigs.actorname_text_shadow_color, plateConfigs.actorname_text_shadow_color_offset[1], plateConfigs.actorname_text_shadow_color_offset[2])
--check if the player has a guild, this check is done when the nameplate is added
if (plateFrame.playerGuildName) then
if (plateConfigs.show_guild_name) then
Plater.AddGuildNameToPlayerName (plateFrame)
end
end
--set the point of the name and guild texts
nameFontString:ClearAllPoints()
PixelUtil.SetPoint (plateFrame.ActorNameSpecial, "center", plateFrame.unitFrame, "center", 0, 10)
--format the color if is the same guild, a friend from friends list or color by player class
if (Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_use_guild_color and plateFrame.playerGuildName == Plater.PlayerGuildName) then
--is a guild friend?
DF:SetFontColor (nameFontString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_guild_color))
plateFrame.isFriend = true
elseif (Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_use_friends_color and Plater.FriendsCache [plateFrame [MEMBER_NAME]]) then
--is regular friend
DF:SetFontColor (nameFontString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_friend_color))
--DF:SetFontOutline (nameFontString, plateConfigs.actorname_text_shadow)
Plater.SetFontOutlineAndShadow (nameFontString, plateConfigs.actorname_text_outline, plateConfigs.actorname_text_shadow_color, plateConfigs.actorname_text_shadow_color_offset[1], plateConfigs.actorname_text_shadow_color_offset[2])
plateFrame.isFriend = true
else
--isn't friend, check if is showing only the name and if is showing class colors
if (plateConfigs.actorname_use_class_color) then
local _, unitClass = UnitClass (plateFrame.unitFrame [MEMBER_UNITID])
if (unitClass) then
local color = DB_CLASS_COLORS [unitClass]
DF:SetFontColor (nameFontString, color.r, color.g, color.b)
else
DF:SetFontColor (nameFontString, plateConfigs.actorname_text_color)
end
else
DF:SetFontColor (nameFontString, plateConfigs.actorname_text_color)
end
plateFrame.isFriend = nil
end
return
elseif (plateFrame.IsNpcWithoutHealthBar) then --not critical code
--reset points for special units
plateFrame.ActorNameSpecial:ClearAllPoints()
plateFrame.ActorTitleSpecial:ClearAllPoints()
PixelUtil.SetPoint (plateFrame.ActorNameSpecial, "center", plateFrame.unitFrame, "center", 0, 10)
PixelUtil.SetPoint (plateFrame.ActorTitleSpecial, "top", plateFrame.ActorNameSpecial, "bottom", 0, -2)
--there's two ways of showing this for friendly npcs (selected from the options panel): show all names or only npcs with profession names
--enemy npcs always show all
if (plateConfigs.all_names) then
plateFrame.ActorNameSpecial:Show()
plateFrame.CurrentUnitNameString = plateFrame.ActorNameSpecial
Plater.UpdateUnitName (plateFrame)
--if this is an enemy or neutral npc
if (plateFrame [MEMBER_REACTION] <= 4) then
local r, g, b, a
--get the quest color if this npcs is a quest npc
if (plateFrame [MEMBER_QUEST] and DB_PLATE_CONFIG [plateFrame.unitFrame.ActorType].quest_color_enabled) then
if (plateFrame [MEMBER_REACTION] == Plater.UnitReaction.UNITREACTION_NEUTRAL) then
r, g, b, a = unpack (plateConfigs.quest_color_neutral)
else
r, g, b, a = unpack (plateConfigs.quest_color_enemy)
g = g + 0.1
b = b + 0.1
end
else
r, g, b, a = 1, 1, 0, 1 --neutral
if (plateFrame [MEMBER_REACTION] <= 3) then
r, g, b, a = 1, .05, .05, 1
end
end
plateFrame.ActorNameSpecial:SetTextColor (r, g, b, a)
DF:SetFontSize (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_size)
DF:SetFontFace (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_font)
--DF:SetFontOutline (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_outline, plateConfigs.big_actorname_text_shadow_color, plateConfigs.big_actorname_text_shadow_color_offset[1], plateConfigs.big_actorname_text_shadow_color_offset[2])
--npc title
local subTitle = Plater.GetActorSubName (plateFrame)
if (subTitle and subTitle ~= "" and not subTitle:match (string.gsub(UNIT_LEVEL_TEMPLATE, "%%d", "(%.*)"))) then
plateFrame.ActorTitleSpecial:Show()
--subTitle = DF:RemoveRealmName (subTitle) -- why are removing real names on npc titles? e.g. <T-Shirt Scalper> Skin-Me-Own-Coat-Dibblefur gets broken to <T>.
plateFrame.ActorTitleSpecial:SetText ("<" .. subTitle .. ">")
plateFrame.ActorTitleSpecial:ClearAllPoints()
PixelUtil.SetPoint (plateFrame.ActorTitleSpecial, "top", plateFrame.ActorNameSpecial, "bottom", 0, -2)
plateFrame.ActorTitleSpecial:SetTextColor (r, g, b, a)
DF:SetFontSize (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_size)
DF:SetFontFace (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_font)
--DF:SetFontOutline (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_outline, plateConfigs.big_actortitle_text_shadow_color, plateConfigs.big_actortitle_text_shadow_color_offset[1], plateConfigs.big_actortitle_text_shadow_color_offset[2])
else
plateFrame.ActorTitleSpecial:Hide()
end
else
--it's a friendly npc
plateFrame.ActorNameSpecial:SetTextColor (unpack (plateConfigs.big_actorname_text_color))
DF:SetFontSize (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_size)
DF:SetFontFace (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_font)
--DF:SetFontOutline (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_outline, plateConfigs.big_actorname_text_shadow_color, plateConfigs.big_actorname_text_shadow_color_offset[1], plateConfigs.big_actorname_text_shadow_color_offset[2])
--profession (title)
local subTitle = Plater.GetActorSubName (plateFrame)
if (subTitle and subTitle ~= "" and not subTitle:match (string.gsub(UNIT_LEVEL_TEMPLATE, "%%d", "(%.*)"))) then
plateFrame.ActorTitleSpecial:Show()
--subTitle = DF:RemoveRealmName (subTitle)
plateFrame.ActorTitleSpecial:SetText ("<" .. subTitle .. ">")
plateFrame.ActorTitleSpecial:ClearAllPoints()
PixelUtil.SetPoint (plateFrame.ActorTitleSpecial, "top", plateFrame.ActorNameSpecial, "bottom", 0, -2)
plateFrame.ActorTitleSpecial:SetTextColor (unpack (plateConfigs.big_actortitle_text_color))
DF:SetFontSize (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_size)
DF:SetFontFace (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_font)
--DF:SetFontOutline (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_outline, plateConfigs.big_actortitle_text_shadow_color, plateConfigs.big_actortitle_text_shadow_color_offset[1], plateConfigs.big_actortitle_text_shadow_color_offset[2])
end
end
else
--scan tooltip to check if there's an title for this npc
local subTitle = Plater.GetActorSubName (plateFrame)
if (subTitle and subTitle ~= "" and not Plater.IsNpcInIgnoreList (plateFrame, true)) then
if (not subTitle:match (string.gsub(UNIT_LEVEL_TEMPLATE, "%%d", "(%.*)"))) then --isn't level
plateFrame.ActorTitleSpecial:Show()
--subTitle = DF:RemoveRealmName (subTitle)
plateFrame.ActorTitleSpecial:SetText ("<" .. subTitle .. ">")
plateFrame.ActorTitleSpecial:ClearAllPoints()
PixelUtil.SetPoint (plateFrame.ActorTitleSpecial, "top", plateFrame.ActorNameSpecial, "bottom", 0, -2)
plateFrame.ActorTitleSpecial:SetTextColor (unpack (plateConfigs.big_actortitle_text_color))
plateFrame.ActorNameSpecial:SetTextColor (unpack (plateConfigs.big_actorname_text_color))
DF:SetFontSize (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_size)
DF:SetFontFace (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_font)
--DF:SetFontOutline (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorTitleSpecial, plateConfigs.big_actortitle_text_outline, plateConfigs.big_actortitle_text_shadow_color, plateConfigs.big_actortitle_text_shadow_color_offset[1], plateConfigs.big_actortitle_text_shadow_color_offset[2])
--npc name
plateFrame.ActorNameSpecial:Show()
plateFrame.CurrentUnitNameString = plateFrame.ActorNameSpecial
Plater.UpdateUnitName (plateFrame)
DF:SetFontSize (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_size)
DF:SetFontFace (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_font)
--DF:SetFontOutline (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_shadow)
Plater.SetFontOutlineAndShadow (plateFrame.ActorNameSpecial, plateConfigs.big_actorname_text_outline, plateConfigs.big_actorname_text_shadow_color, plateConfigs.big_actorname_text_shadow_color_offset[1], plateConfigs.big_actorname_text_shadow_color_offset[2])
end
end
end
return
end
--get the unitId shown on this nameplate
local unitId = plateFrame.unitFrame.unit
--critical code
--the nameplate is showing the health bar
--cache the strings for performance
local nameString = plateFrame.unitFrame.healthBar.unitName
local guildString = plateFrame.ActorTitleSpecial
local levelString = plateFrame.unitFrame.healthBar.actorLevel
local lifeString = plateFrame.unitFrame.healthBar.lifePercent
--update the unit name
plateFrame.CurrentUnitNameString = nameString
Plater.UpdateUnitName (plateFrame)
--update unit name text
if (needReset) then
DF:SetFontSize (nameString, plateConfigs.actorname_text_size)
DF:SetFontFace (nameString, plateConfigs.actorname_text_font)
Plater.SetFontOutlineAndShadow (nameString, plateConfigs.actorname_text_outline, plateConfigs.actorname_text_shadow_color, plateConfigs.actorname_text_shadow_color_offset[1], plateConfigs.actorname_text_shadow_color_offset[2])
Plater.SetAnchor (nameString, plateConfigs.actorname_text_anchor)
--PixelUtil.SetHeight (nameString, nameString:GetLineHeight())
end
if (plateFrame.playerGuildName) then
if (plateConfigs.show_guild_name) then
Plater.AddGuildNameToPlayerName (plateFrame)
end
end
if (Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_use_guild_color and plateFrame.playerGuildName == Plater.PlayerGuildName) then
--is a guild friend?
DF:SetFontColor (nameString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_guild_color))
DF:SetFontColor (guildString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_guild_color))
plateFrame.isFriend = true
elseif (Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_use_friends_color and Plater.FriendsCache [plateFrame [MEMBER_NAME]]) then
--is regular friend
DF:SetFontColor (nameString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_friend_color))
DF:SetFontColor (guildString, unpack(Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_friend_color))
plateFrame.isFriend = true
elseif (plateFrame.actorType == ACTORTYPE_FRIENDLY_PLAYER and Plater.db.profile.plate_config [ACTORTYPE_FRIENDLY_PLAYER].actorname_use_class_color) then
--class colors should be used, if possible, because this is enabled
plateFrame.isFriend = nil
local _, unitClass = UnitClass (plateFrame.unitFrame [MEMBER_UNITID])
if (unitClass) then
local color = DB_CLASS_COLORS [unitClass]
DF:SetFontColor (nameString, color.r, color.g, color.b)
DF:SetFontColor (guildString, color.r, color.g, color.b)
else
DF:SetFontColor (nameString, plateConfigs.actorname_text_color)
DF:SetFontColor (guildString, plateConfigs.actorname_text_color)
end
elseif (plateFrame.actorType == ACTORTYPE_ENEMY_PLAYER and Plater.db.profile.plate_config [ACTORTYPE_ENEMY_PLAYER].actorname_use_class_color) then
--class colors should be used, if possible, because this is enabled
plateFrame.isFriend = nil
local _, unitClass = UnitClass (plateFrame.unitFrame [MEMBER_UNITID])
if (unitClass) then
local color = DB_CLASS_COLORS [unitClass]
DF:SetFontColor (nameString, color.r, color.g, color.b)
DF:SetFontColor (guildString, color.r, color.g, color.b)
else
DF:SetFontColor (nameString, plateConfigs.actorname_text_color)
DF:SetFontColor (guildString, plateConfigs.actorname_text_color)
end
else
DF:SetFontColor (nameString, plateConfigs.actorname_text_color)
DF:SetFontColor (guildString, plateConfigs.actorname_text_color)
plateFrame.isFriend = nil
end
--update unit level text
if (plateConfigs.level_text_enabled) then
levelString:Show()
if (needReset) then
DF:SetFontSize (levelString, plateConfigs.level_text_size)
DF:SetFontFace (levelString, plateConfigs.level_text_font)
Plater.SetFontOutlineAndShadow (levelString, plateConfigs.level_text_outline, plateConfigs.level_text_shadow_color, plateConfigs.level_text_shadow_color_offset[1], plateConfigs.level_text_shadow_color_offset[2])
Plater.SetAnchor (levelString, plateConfigs.level_text_anchor)
Plater.UpdateLevelTextAndColor (levelString, unitId)
levelString:SetAlpha (plateConfigs.level_text_alpha)
else
Plater.UpdateLevelTextAndColor (levelString, unitId)
levelString:SetAlpha (plateConfigs.level_text_alpha)
end
else
levelString:Hide()
end
--update health amount text
if (plateConfigs.percent_text_enabled) then
if (needReset) then
DF:SetFontSize (lifeString, plateConfigs.percent_text_size)
DF:SetFontFace (lifeString, plateConfigs.percent_text_font)
Plater.SetFontOutlineAndShadow (lifeString, plateConfigs.percent_text_outline, plateConfigs.percent_text_shadow_color, plateConfigs.percent_text_shadow_color_offset[1], plateConfigs.percent_text_shadow_color_offset[2])
DF:SetFontColor (lifeString, plateConfigs.percent_text_color)
Plater.SetAnchor (lifeString, plateConfigs.percent_text_anchor)
PixelUtil.SetHeight (lifeString, lifeString:GetLineHeight())
lifeString:SetAlpha (plateConfigs.percent_text_alpha)
end
Plater.UpdateLifePercentText (plateFrame.unitFrame.healthBar, unitId, plateConfigs.percent_show_health, plateConfigs.percent_show_percent, plateConfigs.percent_text_show_decimals)
else
lifeString:Hide()
end
--name isn't shown in the personal bar
if (plateFrame.IsSelf) then
plateFrame.unitFrame.healthBar.unitName:SetText ("")
end
return true
end
--check if the life percent should be showing for this nameplate
--self is plateFrame
function Plater.UpdateLifePercentVisibility (self)
local plateConfigs = Plater.GetSettings (self)
if (plateConfigs.percent_text_enabled) then
--can show out of combat? or if the player is in combat
if ((Plater.db.profile.use_player_combat_state and PLAYER_IN_COMBAT or self.unitFrame.InCombat) or plateConfigs.percent_text_ooc) then
self.unitFrame.healthBar.lifePercent:Show()
else
self.unitFrame.healthBar.lifePercent:Hide()
end
else
self.unitFrame.healthBar.lifePercent:Hide()
end
end
--return the nameplate config directly from the profile
--this is the actual table from the db, any changes will affect the profile
--self is plateFrame
function Plater.GetSettings (self) --private
return self.PlateConfig
end
function Plater.UpdateLifePercentText (healthBar, unitId, showHealthAmount, showPercentAmount, showDecimals) -- ~health
--get the cached health amount for performance
local currentHealth, maxHealth = healthBar.CurrentHealth, healthBar.CurrentHealthMax
if (showHealthAmount and showPercentAmount) then
local percent = currentHealth / maxHealth * 100
if (showDecimals) then
if (percent < 10) then
healthBar.lifePercent:SetText (Plater.FormatNumber (currentHealth) .. " (" .. format ("%.2f", percent) .. "%)")
elseif (percent < 99.9) then
healthBar.lifePercent:SetText (Plater.FormatNumber (currentHealth) .. " (" .. format ("%.1f", percent) .. "%)")
else
healthBar.lifePercent:SetText (Plater.FormatNumber (currentHealth) .. " (100%)")
end
else
healthBar.lifePercent:SetText (Plater.FormatNumber (currentHealth) .. " (" .. floor (percent) .. "%)")
end
elseif (showHealthAmount) then
healthBar.lifePercent:SetText (Plater.FormatNumber (currentHealth))
elseif (showPercentAmount) then
local percent = currentHealth / maxHealth * 100
if (showDecimals) then
if (percent < 10) then
healthBar.lifePercent:SetText (format ("%.2f", percent) .. "%")
elseif (percent < 99.9) then
healthBar.lifePercent:SetText (format ("%.1f", percent) .. "%")
else
healthBar.lifePercent:SetText ("100%")
end
else
healthBar.lifePercent:SetText (floor (percent) .. "%")
end
else
healthBar.lifePercent:SetText ("")
end
end
-- this test if the percent life text can updated
function Plater.CheckLifePercentText (unitFrame) --private
if (not unitFrame.actorType) then
return
end
local actorTypeDBConfig = DB_PLATE_CONFIG [unitFrame.actorType]
if (Plater.db.profile.use_player_combat_state and PLAYER_IN_COMBAT or unitFrame.InCombat) then
if (actorTypeDBConfig.percent_text_enabled) then
Plater.UpdateLifePercentText (unitFrame.healthBar, unitFrame.unit, actorTypeDBConfig.percent_show_health, actorTypeDBConfig.percent_show_percent, actorTypeDBConfig.percent_text_show_decimals)
else
unitFrame.healthBar.lifePercent:Hide()
end
else
--if not in combat, check if can show the percent health out of combat
if (actorTypeDBConfig.percent_text_enabled and actorTypeDBConfig.percent_text_ooc) then
Plater.UpdateLifePercentText (unitFrame.healthBar, unitFrame.unit, actorTypeDBConfig.percent_show_health, actorTypeDBConfig.percent_show_percent, actorTypeDBConfig.percent_text_show_decimals)
else
unitFrame.healthBar.lifePercent:Hide()
end
end
end
function Plater.UpdateAllNames() --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame.actorType == ACTORTYPE_PLAYER) then
plateFrame.NameAnchor = 0
elseif (plateFrame.actorType == Plater.UnitReaction.UNITREACTION_FRIENDLY) then
plateFrame.NameAnchor = DB_NAME_PLAYERFRIENDLY_ANCHOR
elseif (plateFrame.actorType == ACTORTYPE_ENEMY_PLAYER) then
plateFrame.NameAnchor = DB_NAME_PLAYERENEMY_ANCHOR
elseif (plateFrame.actorType == ACTORTYPE_FRIENDLY_NPC) then
plateFrame.NameAnchor = DB_NAME_NPCFRIENDLY_ANCHOR
elseif (plateFrame.actorType == ACTORTYPE_ENEMY_NPC) then
plateFrame.NameAnchor = DB_NAME_NPCENEMY_ANCHOR
end
Plater.UpdateUnitName (plateFrame)
end
end
function Plater.UpdateSpellNameSize (nameString, actorType, cutOff, inCombat)
local spellName = nameString:GetText()
if not spellName or spellName == "" then
return
end
local maxLength = Plater.MaxCastBarTextLength or 500
cutOff = cutOff or 40
actorType = actorType or "enemynpc"
if (not Plater.db.profile.no_spellname_length_limit) then
local castKey = Plater.GetHashKey(inCombat)
if Plater.db.profile.plate_config[actorType][castKey] then
maxLength = Plater.db.profile.plate_config[actorType][castKey][1] - cutOff
end
end
while (nameString:GetStringWidth() > maxLength) do
spellName = strsub (spellName, 1, #spellName - 1)
nameString:SetText (spellName)
if (string.len (spellName) <= 1) then
break
end
end
-- cleanup utf8...
spellName = DF:CleanTruncateUTF8String(spellName)
nameString:SetText (spellName)
end
function Plater.AddGuildNameToPlayerName (plateFrame)
local currentText = plateFrame.CurrentUnitNameString:GetText()
if (not currentText:find ("<")) then
plateFrame.CurrentUnitNameString:SetText (currentText .. "\n" .. "<" .. plateFrame.playerGuildName .. ">")
end
end
function Plater.UpdateUnitName (plateFrame)
local nameString = plateFrame.CurrentUnitNameString
if ( not (plateFrame.IsFriendlyPlayerWithoutHealthBar or plateFrame.IsNpcWithoutHealthBar) and plateFrame.NameAnchor >= 9) then
--remove some character from the unit name if the name is placed inside the nameplate
Plater.UpdateUnitNameTextSize (plateFrame, nameString)
else
nameString:SetText (plateFrame [MEMBER_NAME] or plateFrame.unitFrame [MEMBER_NAME] or "")
end
--check if the player has a guild, this check is done when the nameplate is added
if (plateFrame.playerGuildName) then
if (plateFrame.PlateConfig.show_guild_name) then
Plater.AddGuildNameToPlayerName (plateFrame)
end
end
end
function Plater.UpdateUnitNameTextSize (plateFrame, nameString, maxWidth)
local stringSize = maxWidth or max (plateFrame.unitFrame.healthBar:GetWidth() - 6, 44)
local name = plateFrame [MEMBER_NAME] or plateFrame.unitFrame [MEMBER_NAME] or ""
nameString:SetText (name)
if not name or name == "" then
return
end
while (nameString:GetStringWidth() > stringSize) do
name = strsub (name, 1, #name-1)
nameString:SetText (name)
if (string.len (name) <= 1) then
break
end
end
-- cleanup utf8...
name = DF:CleanTruncateUTF8String(name)
nameString:SetText (name)
end
--updates the level text and the color
function Plater.UpdateLevelTextAndColor (levelString, unitId)
--level text
local level = UnitLevel (unitId)
if (not level) then
levelString:SetText ("")
elseif (level == -1) then
levelString:SetText ("??")
else
levelString:SetText (level)
end
--level color
local color = GetRelativeDifficultyColor (UnitLevel ("player") or 120, UnitLevel (unitId) or 120) or Plater.DefaultLevelColor
levelString:SetTextColor (color.r, color.g, color.b, Plater.db.profile.level_text_alpha)
end
--units can be rename on the Npc Colors tab, this function run from nameplate_added and UpdatePlateFrame() (usually from UpdateAllPlates() are called)
function Plater.UpdateNameOnRenamedUnit(plateFrame)
--set the npc name if the unit has a custom name
local newNpcName = Plater.db.profile.npcs_renamed[plateFrame[MEMBER_NPCID]]
local unitFrame = plateFrame.unitFrame
if (newNpcName) then
plateFrame [MEMBER_NAME] = newNpcName
plateFrame [MEMBER_NAMELOWER] = lower (newNpcName)
unitFrame [MEMBER_NAME] = newNpcName
unitFrame [MEMBER_NAMELOWER] = plateFrame [MEMBER_NAMELOWER]
unitFrame.unitName:SetText(newNpcName)
unitFrame.unitName.isRenamed = true
else
if (unitFrame.unitName.isRenamed) then
newNpcName = UnitName(plateFrame[MEMBER_UNITID])
plateFrame [MEMBER_NAME] = newNpcName
plateFrame [MEMBER_NAMELOWER] = lower (newNpcName)
unitFrame [MEMBER_NAME] = newNpcName
unitFrame [MEMBER_NAMELOWER] = plateFrame [MEMBER_NAMELOWER]
unitFrame.unitName:SetText(newNpcName)
unitFrame.unitName.isRenamed = nil
end
end
end
-- ~updateplate ~update ~updatenameplate
function Plater.UpdatePlateFrame (plateFrame, actorType, forceUpdate, justAdded, regenDisabled)
Plater.StartLogPerformanceCore("Plater-Core", "Update", "UpdatePlateFrame")
actorType = actorType or plateFrame.actorType
if (not actorType or not plateFrame.unitFrame.PlaterOnScreen) then
return
end
local unitFrame = plateFrame.unitFrame
local healthBar = unitFrame.healthBar
local castBar = unitFrame.castBar
local buffFrame = unitFrame.BuffFrame
local buffFrame2 = unitFrame.BuffFrame2
local nameFrame = unitFrame.healthBar.unitName
plateFrame.actorType = actorType
unitFrame.actorType = actorType
unitFrame.ActorType = actorType --exposed to scripts
local shouldForceRefresh = justAdded or forceUpdate
if (plateFrame.IsNpcWithoutHealthBar or plateFrame.IsFriendlyPlayerWithoutHealthBar) then
shouldForceRefresh = true
end
healthBar.BorderIsAggroIndicator = nil
local wasQuestPlate = plateFrame [MEMBER_QUEST]
plateFrame [MEMBER_QUEST] = false
unitFrame [MEMBER_QUEST] = false
plateFrame.QuestInfo = {}
unitFrame.QuestInfo = {}
plateFrame.ActorNameSpecial:Hide()
plateFrame.ActorTitleSpecial:Hide()
plateFrame.Top3DFrame:Hide()
plateFrame.RaidTarget:Hide()
--clear aggro glow
unitFrame.aggroGlowUpper:Hide()
unitFrame.aggroGlowLower:Hide()
--check for quest color
if (IS_IN_OPEN_WORLD and actorType == ACTORTYPE_ENEMY_NPC and DB_PLATE_CONFIG [actorType].quest_enabled) then --actorType == ACTORTYPE_FRIENDLY_NPC or
local isQuestMob = Plater.IsQuestObjective (plateFrame)
if (isQuestMob and DB_PLATE_CONFIG [actorType].quest_color_enabled and not Plater.IsUnitTapDenied (plateFrame.unitFrame.unit)) then
if (plateFrame [MEMBER_REACTION] == Plater.UnitReaction.UNITREACTION_NEUTRAL) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].quest_color_neutral))
else
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].quest_color_enemy))
end
else
if (wasQuestPlate) then
Plater.FindAndSetNameplateColor (unitFrame)
end
end
else
if (wasQuestPlate) then
Plater.FindAndSetNameplateColor (unitFrame)
end
end
--if the nameplate is for a friendly npc
if (actorType == ACTORTYPE_FRIENDLY_NPC) then
plateFrame.IsFriendlyPlayerWithoutHealthBar = false
local subTitleExists = false
local subTitle = Plater.GetActorSubName (plateFrame)
if (subTitle and subTitle ~= "" and not Plater.IsNpcInIgnoreList (plateFrame, true)) then
if (not subTitle:match (string.gsub(UNIT_LEVEL_TEMPLATE, "%%d", "(%.*)"))) then --isn't level
subTitleExists = true
end
end
Plater.ForceFindPetOwner (plateFrame [MEMBER_GUID])
-- handle own pets separately, including nazjatar guardians
if (Plater.PlayerPetCache [unitFrame [MEMBER_GUID]] and not plateFrame.isBattlePet) then
if (DB_PLATE_CONFIG [actorType].only_names) then
healthBar:Hide()
buffFrame:Hide()
buffFrame2:Hide()
nameFrame:Hide()
plateFrame.IsNpcWithoutHealthBar = true
else
healthBar:Show()
buffFrame:Show()
buffFrame2:Show()
nameFrame:Show()
plateFrame.IsNpcWithoutHealthBar = false
end
elseif (IS_IN_OPEN_WORLD and DB_PLATE_CONFIG [actorType].quest_enabled and Plater.IsQuestObjective (plateFrame)) then
if (DB_PLATE_CONFIG [actorType].quest_color_enabled) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].quest_color))
end
healthBar:Show()
buffFrame:Show()
buffFrame2:Show()
nameFrame:Show()
plateFrame.IsNpcWithoutHealthBar = false
--these twoseettings make the healthing dummy show the healthbar
-- Plater.db.profile.plate_config.friendlynpc.only_names = false
-- Plater.db.profile.plate_config.friendlynpc.all_names = false
elseif (DB_PLATE_CONFIG [actorType].only_names) then
--show only the npc name without the health bar
healthBar:Hide()
buffFrame:Hide()
buffFrame2:Hide()
nameFrame:Hide()
plateFrame.IsNpcWithoutHealthBar = true
elseif (not subTitleExists and not DB_PLATE_CONFIG [actorType].all_names) then
-- show only if a title is present
healthBar:Hide()
buffFrame:Hide()
buffFrame:Hide()
nameFrame:Hide()
plateFrame.IsNpcWithoutHealthBar = true
else
healthBar:Show()
buffFrame:Show()
buffFrame2:Show()
nameFrame:Show()
plateFrame.IsNpcWithoutHealthBar = false
end
elseif (actorType == ACTORTYPE_FRIENDLY_PLAYER) then
plateFrame.IsNpcWithoutHealthBar = false
Plater.ParseHealthSettingForPlayer (plateFrame, justAdded)
--change the player health bar color to either class color or users choice
if (not Plater.db.profile.use_playerclass_color) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack(DB_PLATE_CONFIG [actorType].fixed_class_color))
else
local _, class = UnitClass (unitFrame [MEMBER_UNITID])
if (class) then
local color = DB_CLASS_COLORS [class]
Plater.ChangeHealthBarColor_Internal (healthBar, color.r, color.g, color.b, color.a)
else
Plater.ChangeHealthBarColor_Internal (healthBar, 1, 1, 1, 1)
end
end
elseif (actorType == ACTORTYPE_ENEMY_PLAYER) then
plateFrame.IsNpcWithoutHealthBar = false
if (plateFrame.PlayerCannotAttack and not DB_SHOW_HEALTHBARS_FOR_NOT_ATTACKABLE) then
healthBar:Hide()
buffFrame:Hide()
buffFrame2:Hide()
nameFrame:Hide()
plateFrame.IsFriendlyPlayerWithoutHealthBar = true
else
healthBar:Show()
buffFrame:Show()
buffFrame2:Show()
nameFrame:Show()
plateFrame.IsFriendlyPlayerWithoutHealthBar = false
if (DB_PLATE_CONFIG [actorType].use_playerclass_color) then
local _, class = UnitClass (unitFrame [MEMBER_UNITID])
if (class) then
local color = DB_CLASS_COLORS [class]
Plater.ChangeHealthBarColor_Internal (healthBar, color.r, color.g, color.b, color.a)
else
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].fixed_class_color))
end
else
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].fixed_class_color))
end
end
else --> ENEMY NPC pass throught here
plateFrame.IsFriendlyPlayerWithoutHealthBar = false
--check if this is an enemy npc but the player cannot attack it
if (plateFrame.PlayerCannotAttack and not DB_SHOW_HEALTHBARS_FOR_NOT_ATTACKABLE) then
healthBar:Hide()
buffFrame:Hide()
buffFrame2:Hide()
nameFrame:Hide()
plateFrame.IsNpcWithoutHealthBar = true
else
healthBar:Show()
buffFrame:Show()
buffFrame2:Show()
plateFrame.IsNpcWithoutHealthBar = false
if unitFrame.IsSelf then
--refresh color
if (plateFrame.PlateConfig.healthbar_color_by_hp) then
local currentHealth = healthBar.currentHealth
local currentHealthMax = healthBar.currentHealthMax
local originalColor = plateFrame.PlateConfig.healthbar_color
local r, g, b = DF:LerpLinearColor (abs (currentHealth / currentHealthMax - 1), 1, originalColor[1], originalColor[2], originalColor[3], 1, .4, 0)
Plater.ChangeHealthBarColor_Internal (healthBar, r, g, b, (originalColor[4] or 1), true)
else
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].healthbar_color))
end
else
nameFrame:Show()
-- could be a pet
Plater.ForceFindPetOwner (plateFrame [MEMBER_GUID])
end
end
end
castBar:SetStatusBarTexture (DB_TEXTURE_CASTBAR)
--update all texts in the nameplate
Plater.UpdatePlateText (plateFrame, DB_PLATE_CONFIG [actorType], shouldForceRefresh or plateFrame.PreviousUnitType ~= actorType or unitFrame.RefreshID < PLATER_REFRESH_ID)
if (unitFrame.RefreshID < PLATER_REFRESH_ID or shouldForceRefresh) then
unitFrame.RefreshID = PLATER_REFRESH_ID
local profile = Plater.db.profile
--update highlight texture
unitFrame.HighlightFrame.HighlightTexture:SetTexture (DB_TEXTURE_HEALTHBAR)
unitFrame.HighlightFrame.HighlightTexture:SetBlendMode ("ADD")
unitFrame.HighlightFrame.HighlightTexture:SetAlpha (profile.hover_highlight_alpha)
--click area is shown?
if (profile.click_space_always_show) then
Plater.SetPlateBackground (plateFrame)
else
plateFrame.unitFrame:SetBackdrop (nil)
end
--setup cast bar
castBar.background:SetTexture (DB_TEXTURE_CASTBAR_BG)
castBar.extraBackground:SetTexture (DB_TEXTURE_CASTBAR_BG)
castBar.background:SetVertexColor (unpack (profile.cast_statusbar_bgcolor))
castBar.extraBackground:SetVertexColor (unpack (profile.cast_statusbar_bgcolor))
castBar.flashTexture:SetTexture (DB_TEXTURE_CASTBAR)
castBar.Icon:SetTexCoord (0.078125, 0.921875, 0.078125, 0.921875)
local colors = castBar.Settings.Colors
colors.Casting:SetColor (profile.cast_statusbar_color)
colors.Channeling:SetColor (profile.cast_statusbar_color_channeling)
colors.NonInterruptible:SetColor (profile.cast_statusbar_color_nointerrupt)
colors.Interrupted:SetColor (profile.cast_statusbar_color_interrupted)
colors.Finished:SetColor (profile.cast_statusbar_color_finished)
castBar.Settings.FadeInTime = profile.cast_statusbar_fadein_time
castBar.Settings.FadeOutTime = profile.cast_statusbar_fadeout_time
castBar.fadeOutAnimation.alpha1:SetDuration (castBar.Settings.FadeOutTime)
castBar.fadeInAnimation.alpha1:SetDuration (castBar.Settings.FadeInTime)
castBar.Settings.NoFadeEffects = not profile.cast_statusbar_use_fade_effects
castBar.Settings.SparkTexture = profile.cast_statusbar_spark_texture
castBar.Spark:SetTexture (castBar.Settings.SparkTexture)
castBar.Spark:SetVertexColor (unpack (profile.cast_statusbar_spark_color))
castBar.Spark:SetAlpha (profile.cast_statusbar_spark_alpha)
if (profile.cast_statusbar_spark_half) then
castBar.Spark:SetTexCoord (0, 0.5, 0, 1)
else
castBar.Spark:SetTexCoord (0, 1, 0, 1)
end
castBar.castColorTexture:Hide()
if (profile.cast_color_settings.enabled) then
castBar.castColorTexture:SetWidth(profile.cast_color_settings.width)
castBar.castColorTexture:SetAlpha(profile.cast_color_settings.alpha)
castBar.castColorTexture:SetDrawLayer(profile.cast_color_settings.layer, -6)
Plater.SetAnchor(castBar.castColorTexture, profile.cast_color_settings.anchor)
end
castBar.Settings.SparkOffset = profile.cast_statusbar_spark_offset
--setup power bar
unitFrame.powerBar:SetTexture (DB_TEXTURE_HEALTHBAR)
--setup health bar~
healthBar:SetTexture (DB_TEXTURE_HEALTHBAR)
healthBar.background:SetTexture (DB_TEXTURE_HEALTHBAR_BG)
healthBar.background:SetVertexColor (unpack (profile.health_statusbar_bgcolor))
--update border
Plater.UpdatePlateBorders (plateFrame)
--target overlay texture
local targetedOverlayTexture = LibSharedMedia:Fetch ("statusbar", profile.health_selection_overlay)
unitFrame.targetOverlayTexture:SetTexture (targetedOverlayTexture)
unitFrame.targetOverlayTexture:SetAlpha (profile.health_selection_overlay_alpha)
--heal prediction
unitFrame.healthBar.Settings.ShowHealingPrediction = Plater.db.profile.show_health_prediction
unitFrame.healthBar.Settings.ShowShields = Plater.db.profile.show_shield_prediction
if (unitFrame.healthBar.unit) then
unitFrame.healthBar:UNIT_HEALTH()
end
if IS_WOW_PROJECT_MAINLINE then
Plater.SetAnchor (unitFrame.WidgetContainer, profile.widget_bar_anchor, unitFrame)
plateFrame.unitFrame.WidgetContainer:SetScale(Plater.db.profile.widget_bar_scale)
end
end
--update the plate size for this unit
Plater.UpdatePlateSize (plateFrame)
--raid marker
Plater.UpdatePlateRaidMarker (plateFrame)
--indicators for the unit
Plater.UpdateIndicators (plateFrame, actorType, regenDisabled)
--update the visibility of the health text
Plater.UpdateLifePercentVisibility (plateFrame)
--update the health text
Plater.CheckLifePercentText (unitFrame)
--target indicator
Plater.UpdateTarget (plateFrame)
--personal player bar
if (plateFrame.IsSelf) then
Plater.UpdatePersonalBar (NamePlateDriverFrame)
if (not DB_PLATE_CONFIG [actorType].healthbar_color_by_hp) then
Plater.ChangeHealthBarColor_Internal (healthBar, unpack (DB_PLATE_CONFIG [actorType].healthbar_color))
end
end
Plater.UpdateCustomDesign (unitFrame)
Plater.UpdateNameOnRenamedUnit(plateFrame)
--update options in the extra icons row frame
if (unitFrame.ExtraIconFrame.RefreshID < PLATER_REFRESH_ID) then
Plater.SetAnchor (unitFrame.ExtraIconFrame, Plater.db.profile.extra_icon_anchor)
unitFrame.ExtraIconFrame:SetOption ("show_text", Plater.db.profile.extra_icon_show_timer)
unitFrame.ExtraIconFrame:SetOption ("text_font", Plater.db.profile.extra_icon_timer_font)
unitFrame.ExtraIconFrame:SetOption ("text_size", Plater.db.profile.extra_icon_timer_size)
unitFrame.ExtraIconFrame:SetOption ("text_outline", Plater.db.profile.extra_icon_timer_outline)
unitFrame.ExtraIconFrame:SetOption ("grow_direction", unitFrame.ExtraIconFrame:GetIconGrowDirection())
unitFrame.ExtraIconFrame:SetOption ("icon_width", Plater.db.profile.extra_icon_width)
unitFrame.ExtraIconFrame:SetOption ("icon_height", Plater.db.profile.extra_icon_height)
unitFrame.ExtraIconFrame:SetOption ("texcoord", Plater.db.profile.extra_icon_wide_icon and Plater.WideIconCoords or Plater.BorderLessIconCoords)
unitFrame.ExtraIconFrame:SetOption ("desc_text", Plater.db.profile.extra_icon_caster_name)
unitFrame.ExtraIconFrame:SetOption ("desc_text_font", Plater.db.profile.extra_icon_caster_font)
unitFrame.ExtraIconFrame:SetOption ("desc_text_size", Plater.db.profile.extra_icon_caster_size)
unitFrame.ExtraIconFrame:SetOption ("desc_text_outline", Plater.db.profile.extra_icon_caster_outline)
unitFrame.ExtraIconFrame:SetOption ("stack_text", Plater.db.profile.extra_icon_show_stacks)
unitFrame.ExtraIconFrame:SetOption ("stack_text_font", Plater.db.profile.extra_icon_stack_font)
unitFrame.ExtraIconFrame:SetOption ("stack_text_size", Plater.db.profile.extra_icon_stack_size)
unitFrame.ExtraIconFrame:SetOption ("stack_text_outline", Plater.db.profile.extra_icon_stack_outline)
unitFrame.ExtraIconFrame:SetOption ("surpress_tulla_omni_cc", Plater.db.profile.disable_omnicc_on_auras)
unitFrame.ExtraIconFrame:SetOption ("surpress_blizzard_cd_timer", true)
unitFrame.ExtraIconFrame:SetOption ("decimal_timer", Plater.db.profile.extra_icon_timer_decimals)
unitFrame.ExtraIconFrame:SetOption ("cooldown_reverse", Plater.db.profile.extra_icon_cooldown_reverse)
unitFrame.ExtraIconFrame:SetOption ("cooldown_swipe_enabled", Plater.db.profile.extra_icon_show_swipe)
unitFrame.ExtraIconFrame:SetOption ("cooldown_edge_texture", Plater.db.profile.extra_icon_cooldown_edge_texture)
--> update refresh ID
unitFrame.ExtraIconFrame.RefreshID = PLATER_REFRESH_ID
end
--update options in the boss mods icons frame
Plater.UpdateBossModAuraFrameSettings(unitFrame, PLATER_REFRESH_ID)
--> details! integration
if (IS_USING_DETAILS_INTEGRATION) then
local detailsPlaterConfig = Details.plater
if (detailsPlaterConfig.realtime_dps_enabled) then
local textString = healthBar.DetailsRealTime
Plater.SetAnchor (textString, detailsPlaterConfig.realtime_dps_anchor)
DF:SetFontSize (textString, detailsPlaterConfig.realtime_dps_size)
DF:SetFontOutline (textString, detailsPlaterConfig.realtime_dps_shadow)
DF:SetFontColor (textString, detailsPlaterConfig.realtime_dps_color)
end
if (detailsPlaterConfig.realtime_dps_player_enabled) then
local textString = healthBar.DetailsRealTimeFromPlayer
Plater.SetAnchor (textString, detailsPlaterConfig.realtime_dps_player_anchor)
DF:SetFontSize (textString, detailsPlaterConfig.realtime_dps_player_size)
DF:SetFontOutline (textString, detailsPlaterConfig.realtime_dps_player_shadow)
DF:SetFontColor (textString, detailsPlaterConfig.realtime_dps_player_color)
end
if (detailsPlaterConfig.damage_taken_enabled) then
local textString = healthBar.DetailsDamageTaken
Plater.SetAnchor (textString, detailsPlaterConfig.damage_taken_anchor)
DF:SetFontSize (textString, detailsPlaterConfig.damage_taken_size)
DF:SetFontOutline (textString, detailsPlaterConfig.damage_taken_shadow)
DF:SetFontColor (textString, detailsPlaterConfig.damage_taken_color)
end
--reset all labels used by details!
healthBar.DetailsRealTime:SetText ("")
healthBar.DetailsRealTimeFromPlayer:SetText ("")
healthBar.DetailsDamageTaken:SetText ("")
end
if (plateFrame.OnTickFrame.actorType == actorType and plateFrame.OnTickFrame.unit == unitFrame [MEMBER_UNITID]) then
Plater.NameplateTick (plateFrame.OnTickFrame, 10)
end
Plater.EndLogPerformanceCore("Plater-Core", "Update", "UpdatePlateFrame")
end
-- ~border
--changes the border color, this call is used internally on Plater
--see Plater.SetBorderColor for scripting calls
--currently this is called for threat color changes (if enabled at the options panel)
function Plater.ForceChangeBorderColor (self, r, g, b) --private --self = unitFrame
--this call is from the retail game, file: blizzard_nameplates.lua
if (not self.customBorderColor) then
self.healthBar.border:SetVertexColor (r, g, b)
self.BorderIsAggroIndicator = true
end
end
--> update the border color respecting custom colors set by scripts
function Plater.UpdateBorderColor (self) --self is unitFrame
--set the border color
if (not self.customBorderColor) then
self.healthBar.border:SetVertexColor (DB_BORDER_COLOR_R, DB_BORDER_COLOR_G, DB_BORDER_COLOR_B, DB_BORDER_COLOR_A)
self.powerBar.border:SetVertexColor (DB_BORDER_COLOR_R, DB_BORDER_COLOR_G, DB_BORDER_COLOR_B, DB_BORDER_COLOR_A)
else
self.healthBar.border:SetVertexColor (unpack (self.customBorderColor))
self.powerBar.border:SetVertexColor (unpack (self.customBorderColor))
end
end
function Plater.UpdatePlateBorders (plateFrame) --private
--if didn't pass a plate to update, update all frames
if (not plateFrame) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
Plater.UpdatePlateBorders (plateFrame)
end
return
end
Plater.UpdatePlateBorderThickness (plateFrame)
--ignore if the border is being used internally as threat indicator
if (plateFrame.unitFrame.healthBar.BorderIsAggroIndicator) then
return
end
Plater.UpdateBorderColor (plateFrame.unitFrame)
end
function Plater.UpdatePlateBorderThickness (plateFrame)
if (not plateFrame) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
Plater.UpdatePlateBorderThickness (plateFrame)
end
return
end
plateFrame.unitFrame.healthBar.border:SetBorderSizes (DB_BORDER_THICKNESS, DB_BORDER_THICKNESS, DB_BORDER_THICKNESS, DB_BORDER_THICKNESS)
plateFrame.unitFrame.healthBar.border:UpdateSizes()
plateFrame.unitFrame.powerBar.border:SetBorderSizes (DB_BORDER_THICKNESS, DB_BORDER_THICKNESS, DB_BORDER_THICKNESS, DB_BORDER_THICKNESS)
plateFrame.unitFrame.powerBar.border:UpdateSizes()
end
-- ~raidmarker ~raidtarget
function Plater.UpdatePlateRaidMarker (plateFrame)
local index = GetRaidTargetIndex (plateFrame.unitFrame [MEMBER_UNITID])
if (index and not plateFrame.IsSelf) then
local icon = plateFrame.unitFrame.PlaterRaidTargetFrame.RaidTargetIcon
SetRaidTargetIconTexture (icon, index)
icon:Show()
if (not icon.IsShowning) then
--play animations
icon.IsShowning = true
icon.ShowAnimation:Play()
end
--adjust scale and anchor
plateFrame.unitFrame.PlaterRaidTargetFrame:SetScale (Plater.db.profile.indicator_raidmark_scale)
Plater.SetAnchor (plateFrame.unitFrame.PlaterRaidTargetFrame, Plater.db.profile.indicator_raidmark_anchor)
--adjust frame level:
plateFrame.unitFrame.PlaterRaidTargetFrame:SetFrameStrata(plateFrame.unitFrame.healthBar:GetFrameStrata())
plateFrame.unitFrame.PlaterRaidTargetFrame:SetFrameLevel(plateFrame.unitFrame.healthBar:GetFrameLevel() + 25)
--mini mark inside the nameplate
if (Plater.db.profile.indicator_extra_raidmark) then
plateFrame.RaidTarget:Show()
plateFrame.RaidTarget:SetTexture (icon:GetTexture())
plateFrame.RaidTarget:SetTexCoord (icon:GetTexCoord())
local height = plateFrame.unitFrame.healthBar:GetHeight() - 2
plateFrame.RaidTarget:SetSize (height, height)
plateFrame.RaidTarget:SetAlpha (.4)
end
else
plateFrame.unitFrame.PlaterRaidTargetFrame.RaidTargetIcon.IsShowning = nil
plateFrame.unitFrame.PlaterRaidTargetFrame.RaidTargetIcon:Hide()
--hide the extra raid target inside the nameplate
plateFrame.RaidTarget:Hide()
end
end
--iterate among all nameplates and update the raid target icon
function Plater.UpdateRaidMarkersOnAllNameplates() --private
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if plateFrame.unitFrame.PlaterOnScreen then
Plater.UpdatePlateRaidMarker (plateFrame)
--hooks
if (HOOK_RAID_TARGET.ScriptAmount > 0) then
for i = 1, HOOK_RAID_TARGET.ScriptAmount do
local globalScriptObject = HOOK_RAID_TARGET [i]
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Raid Target")
--run
unitFrame:ScriptRunHook (scriptInfo, "Raid Target")
end
end
end
end
end
-- ~indicators
function Plater.UpdateIndicators (plateFrame, actorType, regenDisabled)
--limpa os indicadores
Plater.ClearIndicators (plateFrame)
local config = Plater.db.profile
if (actorType == ACTORTYPE_ENEMY_PLAYER) then
if (config.indicator_faction) then
--don't show faction icon on arena of battleground, it's kinda useless (terciob july 2022)
if (Plater.ZoneInstanceType ~= "pvp" and Plater.ZoneInstanceType ~= "arena") then
Plater.AddIndicator (plateFrame, UnitFactionGroup (plateFrame.unitFrame [MEMBER_UNITID]))
end
end
if (config.indicator_enemyclass) then
Plater.AddIndicator (plateFrame, "classicon")
end
--don't show spec icon during combat, it occupies a valuable space (terciob july 2022)
if (config.indicator_spec and not InCombatLockdown() and not regenDisabled) then
-- use BG info if available
local texture, L, R, T, B = Plater.GetSpecIconForUnitFromBG(plateFrame.unitFrame [MEMBER_UNITID])
if texture then
Plater.AddIndicator (plateFrame, "specicon", texture, L, R, T, B)
else
--> check if the user is using details
if (Details and Details.realversion >= 134) then
local spec = Details:GetSpecByGUID (plateFrame [MEMBER_GUID])
if (spec) then
local texture, L, R, T, B = Details:GetSpecIcon (spec)
Plater.AddIndicator (plateFrame, "specicon", texture, L, R, T, B)
end
end
end
end
elseif (actorType == ACTORTYPE_FRIENDLY_PLAYER) then
if (config.indicator_friendlyfaction) then
Plater.AddIndicator (plateFrame, UnitFactionGroup (plateFrame.unitFrame [MEMBER_UNITID]))
end
if (config.indicator_friendlyclass) then
Plater.AddIndicator (plateFrame, "classicon")
end
if (config.indicator_friendlyspec) then
-- use BG info if available
local texture, L, R, T, B = Plater.GetSpecIconForUnitFromBG(plateFrame [MEMBER_UNITID])
if texture then
Plater.AddIndicator (plateFrame, "specicon", texture, L, R, T, B)
else
--> check if the user is using details
if (Details and Details.realversion >= 134) then
local spec = Details:GetSpecByGUID (plateFrame [MEMBER_GUID])
if (spec) then
local texture, L, R, T, B = Details:GetSpecIcon (spec)
Plater.AddIndicator (plateFrame, "specicon", texture, L, R, T, B)
end
end
end
end
elseif (actorType == ACTORTYPE_ENEMY_NPC) then
--is a pet
if (PET_CACHE [plateFrame [MEMBER_GUID]]) then
if (config.indicator_pet) then
Plater.AddIndicator (plateFrame, "pet")
end
end
--classification
local unitClassification = UnitClassification (plateFrame.unitFrame [MEMBER_UNITID]) --elite minus normal rare rareelite worldboss
if (unitClassification == "worldboss" and config.indicator_worldboss) then
Plater.AddIndicator (plateFrame, "worldboss")
elseif (unitClassification == "rareelite" and (config.indicator_rare or config.indicator_elite)) then
Plater.AddIndicator (plateFrame, "elite")
Plater.AddIndicator (plateFrame, "rare")
else
if (unitClassification == "elite" and config.indicator_elite) then
Plater.AddIndicator (plateFrame, "elite")
end
if (unitClassification == "rare" and config.indicator_rare) then
Plater.AddIndicator (plateFrame, "rare")
end
end
--quest boss
local isQuestBoss = (IS_WOW_PROJECT_MAINLINE) and UnitIsQuestBoss (plateFrame.unitFrame [MEMBER_UNITID]) or false --true false
if (isQuestBoss and config.indicator_quest) then
Plater.AddIndicator (plateFrame, "quest")
end
elseif (actorType == ACTORTYPE_FRIENDLY_NPC) then
if (plateFrame [MEMBER_QUEST]) then
Plater.AddIndicator (plateFrame, "quest")
end
end
--custom indicators from scripts
for i = 1, #plateFrame.unitFrame.CustomIndicators do
Plater.AddIndicator (plateFrame, "custom", unpack (plateFrame.unitFrame.CustomIndicators [i]))
end
end
function Plater.AddIndicator (plateFrame, indicator, ...)
local thisIndicator = plateFrame.IconIndicators [plateFrame.IconIndicators.Next]
if (not thisIndicator) then
local newIndicator = plateFrame.unitFrame.healthBar:CreateTexture (nil, "overlay")
newIndicator:SetDrawLayer("OVERLAY", 7)
newIndicator:SetSize (10, 10)
tinsert (plateFrame.IconIndicators, newIndicator)
thisIndicator = newIndicator
end
thisIndicator:Show()
thisIndicator:SetTexCoord (0, 1, 0, 1)
thisIndicator:SetVertexColor (1, 1, 1)
thisIndicator:SetDesaturated (false)
thisIndicator:SetSize (10, 10)
thisIndicator:SetScale (Plater.db.profile.indicator_scale)
-- ~icons
if (indicator == "pet") then
thisIndicator:SetTexture ([[Interface\AddOns\Plater\images\peticon]])
elseif (indicator == "Horde") then
thisIndicator:SetTexture ([[Interface\PVPFrame\PVP-Currency-Horde]])
thisIndicator:SetSize (12, 12)
elseif (indicator == "Alliance") then
thisIndicator:SetTexture ([[Interface\PVPFrame\PVP-Currency-Alliance]])
thisIndicator:SetTexCoord (4/32, 29/32, 2/32, 30/32)
thisIndicator:SetSize (12, 12)
elseif (indicator == "elite") then
thisIndicator:SetTexture ([[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]])
thisIndicator:SetTexCoord (0.75, 1, 0, 1)
thisIndicator:SetVertexColor (1, .8, 0)
thisIndicator:SetSize (12, 12)
elseif (indicator == "rare") then
thisIndicator:SetTexture ([[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]])
thisIndicator:SetTexCoord (0.75, 1, 0, 1)
thisIndicator:SetSize (12, 12)
thisIndicator:SetDesaturated (true)
elseif (indicator == "quest") then
thisIndicator:SetTexture ([[Interface\TARGETINGFRAME\PortraitQuestBadge]])
thisIndicator:SetTexCoord (2/32, 26/32, 1/32, 31/32)
elseif (indicator == "classicon") then
local _, class = UnitClass (plateFrame.unitFrame [MEMBER_UNITID])
if (class) then
thisIndicator:SetTexture ([[Interface\GLUES\CHARACTERCREATE\UI-CharacterCreate-Classes]])
thisIndicator:SetTexCoord (unpack (CLASS_ICON_TCOORDS [class]))
end
elseif (indicator == "specicon") then
local texture, L, R, T, B = ...
thisIndicator:SetTexture (texture)
thisIndicator:SetTexCoord (L, R, T, B)
elseif (indicator == "worldboss") then
thisIndicator:SetTexture ([[Interface\Scenarios\ScenarioIcon-Boss]])
elseif (indicator == "custom") then
local texture, width, height, color, L, R, T, B = ...
thisIndicator:SetTexture (texture)
thisIndicator:SetSize (width, height)
thisIndicator:SetTexCoord (L, R, T, B)
local r, g, b = DF:ParseColors (color)
thisIndicator:SetVertexColor (r, g, b)
end
if (plateFrame.IconIndicators.Next == 1) then
Plater.SetAnchor (thisIndicator, Plater.db.profile.indicator_anchor)
else
local attachTo = plateFrame.IconIndicators [plateFrame.IconIndicators.Next - 1]
--se for menor que 4 ele deve crescer para o lado da esquerda, nos outros casos vai para a direita
if (Plater.db.profile.indicator_anchor.side < 4) then
PixelUtil.SetPoint (thisIndicator, "right", attachTo, "left", -2, 0)
else
PixelUtil.SetPoint (thisIndicator, "left", attachTo, "right", 1, 0)
end
end
plateFrame.IconIndicators.Next = plateFrame.IconIndicators.Next + 1
end
function Plater.ClearIndicators (plateFrame)
for _, indicator in ipairs (plateFrame.IconIndicators) do
indicator:Hide()
indicator:ClearAllPoints()
end
plateFrame.IconIndicators.Next = 1
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> misc stuff - general functions ~misc
--auto toggle the show friendly players, and other stuff.
function Plater.RefreshAutoToggle() --private
if (InCombatLockdown()) then
C_Timer.After (0.5, re_RefreshAutoToggle)
return
end
local zoneName, zoneType = GetInstanceInfo()
local profile = Plater.db.profile
if (profile.auto_inside_raid_dungeon.hide_enemy_player_pets) then
if (zoneType == "party" or zoneType == "raid") then
SetCVar("nameplateShowEnemyPets", CVAR_DISABLED)
else
SetCVar("nameplateShowEnemyPets", CVAR_ENABLED)
end
end
if (profile.auto_inside_raid_dungeon.hide_enemy_player_totems) then
if (zoneType == "party" or zoneType == "raid") then
SetCVar("nameplateShowEnemyTotems", CVAR_DISABLED)
else
SetCVar("nameplateShowEnemyTotems", CVAR_ENABLED)
end
end
--friendly nameplate toggle
if (profile.auto_toggle_friendly_enabled) then
--discover which is the map type the player is in
if (zoneType == "party") then
SetCVar ("nameplateShowFriends", profile.auto_toggle_friendly ["party"] and CVAR_ENABLED or CVAR_DISABLED)
elseif (zoneType == "raid") then
SetCVar ("nameplateShowFriends", profile.auto_toggle_friendly ["raid"] and CVAR_ENABLED or CVAR_DISABLED)
elseif (zoneType == "arena" or zoneType == "pvp") then
SetCVar ("nameplateShowFriends", profile.auto_toggle_friendly ["arena"] and CVAR_ENABLED or CVAR_DISABLED)
else
--if the player is resting, consider inside a major city
if (IsResting()) then
SetCVar ("nameplateShowFriends", profile.auto_toggle_friendly ["cities"] and CVAR_ENABLED or CVAR_DISABLED)
else
SetCVar ("nameplateShowFriends", profile.auto_toggle_friendly ["world"] and CVAR_ENABLED or CVAR_DISABLED)
end
end
end
--stacking toggle
if (profile.auto_toggle_stacking_enabled and profile.stacking_nameplates_enabled) then
--discover which is the map type the player is in
if (zoneType == "party") then
SetCVar ("nameplateMotion", profile.auto_toggle_stacking ["party"] and CVAR_ENABLED or CVAR_DISABLED)
elseif (zoneType == "raid") then
SetCVar ("nameplateMotion", profile.auto_toggle_stacking ["raid"] and CVAR_ENABLED or CVAR_DISABLED)
elseif (zoneType == "arena" or zoneType == "pvp") then
SetCVar ("nameplateMotion", profile.auto_toggle_stacking ["arena"] and CVAR_ENABLED or CVAR_DISABLED)
else
--if the player is resting, consider inside a major city
if (IsResting()) then
SetCVar ("nameplateMotion", profile.auto_toggle_stacking ["cities"] and CVAR_ENABLED or CVAR_DISABLED)
else
SetCVar ("nameplateMotion", profile.auto_toggle_stacking ["world"] and CVAR_ENABLED or CVAR_DISABLED)
end
end
end
end
local anchor_functions = {
function (widget, config, attachTo, centered)--1 topleft
widget:ClearAllPoints()
local widgetRelative = centered and "bottom" or "bottomleft"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "topleft", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--2 left
widget:ClearAllPoints()
local widgetRelative = centered and "center" or "right"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "left", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--3 bottomleft
widget:ClearAllPoints()
local widgetRelative = centered and "top" or "topleft"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "bottomleft", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--4 bottom
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "top", attachTo, "bottom", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--5 bottomright
widget:ClearAllPoints()
local widgetRelative = centered and "top" or "topright"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "bottomright", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--6 right
widget:ClearAllPoints()
local widgetRelative = centered and "center" or "left"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "right", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--7 topright
widget:ClearAllPoints()
local widgetRelative = centered and "bottom" or "bottomright"
PixelUtil.SetPoint (widget, widgetRelative, attachTo, "topright", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--8 top
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "bottom", attachTo, "top", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--9 center
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "center", attachTo, "center", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--10 inner left
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "left", attachTo, "left", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--11 inner right
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "right", attachTo, "right", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--12 inner top
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "top", attachTo, "top", config.x, config.y, 0, 0)
end,
function (widget, config, attachTo, centered)--13 inner bottom
widget:ClearAllPoints()
PixelUtil.SetPoint (widget, "bottom", attachTo, "bottom", config.x, config.y, 0, 0)
end
}
--auto set the point based on the table from the config, if attachTo isn't received, it'll use its parent
function Plater.SetAnchor (widget, config, attachTo, centered) --private
attachTo = attachTo or widget:GetParent()
anchor_functions [config.side] (widget, config, attachTo, centered)
end
-- anchor sides as comprehensive table.
Plater.AnchorSides = {
TOP_LEFT = 1,
LEFT = 2,
BOTTOM_LEFT = 3,
BOTTOM = 4,
BOTTOM_RIGHT = 5,
RIGHT = 6,
TOP_RIGHT = 7,
TOP = 8,
CENTER = 9,
INNER_LEFT = 10,
INNER_RIGHT = 11,
INNER_TOP = 12,
INNER_BOTTOM = 13,
}
--check the setting 'only_damaged' and 'only_thename' for player characters. not critical code, can run slow
function Plater.ParseHealthSettingForPlayer (plateFrame, force) --private
local isFriendlyPlayerWithoutHealthBar = plateFrame.IsFriendlyPlayerWithoutHealthBar
if (DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_PLAYER].only_thename and not DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_PLAYER].only_damaged) then
if (not isFriendlyPlayerWithoutHealthBar) or force then
Plater.HideHealthBar (plateFrame.unitFrame, true)
end
elseif (DB_PLATE_CONFIG [ACTORTYPE_FRIENDLY_PLAYER].only_damaged) then
local healthBar = plateFrame.unitFrame.healthBar
if ((healthBar.currentHealth or 1) < (healthBar.currentHealthMax or 1)) then
if isFriendlyPlayerWithoutHealthBar or force then
Plater.ShowHealthBar (plateFrame.unitFrame)
end
elseif (not isFriendlyPlayerWithoutHealthBar) or force then
Plater.HideHealthBar (plateFrame.unitFrame, true)
end
elseif isFriendlyPlayerWithoutHealthBar or force then
Plater.ShowHealthBar (plateFrame.unitFrame)
end
end
function Plater.GetPlateAlpha (plateFrame)
if (UnitIsUnit (plateFrame.unitFrame [MEMBER_UNITID], "target")) then
return 1
else
return AlphaBlending
end
end
local widget_set_alpha = function (widget, value)
if (widget.FadeAnimation:IsPlaying()) then
widget.FadeAnimation:Stop()
end
widget.FadeAnimation.Animation:SetFromAlpha (widget:GetAlpha())
widget.FadeAnimation.Animation:SetToAlpha (value)
widget.FadeAnimation:Play()
end
local on_finished_fade_animation = function (fadeAnimation)
local widget = fadeAnimation:GetParent()
widget:SetAlpha(fadeAnimation.Animation:GetToAlpha())
end
Plater.CreateAlphaAnimation = function (plateFrame)
local unitFrame = plateFrame.unitFrame
local healthBar = plateFrame.unitFrame.healthBar
local castBar = plateFrame.unitFrame.castBar
local powerBar = plateFrame.unitFrame.powerBar
local buffFrame = plateFrame.unitFrame.BuffFrame
local buffFrame2 = plateFrame.unitFrame.BuffFrame2
local allWidgets = {
unitFrame, healthBar, castBar, buffFrame, buffFrame2, powerBar
}
for i = 1, #allWidgets do
local widget = allWidgets[i]
widget.FadeAnimation = widget:CreateAnimationGroup()
--widget.FadeAnimation:SetScript ("OnPlay", on_play_fade_animation)
widget.FadeAnimation:SetScript ("OnFinished", on_finished_fade_animation)
widget.FadeAnimation.Animation = widget.FadeAnimation:CreateAnimation ("Alpha")
widget.FadeAnimation.Animation:SetOrder (1)
widget.FadeAnimation.Animation:SetDuration (0.15)
widget.SetAlphaTo = widget_set_alpha
end
end
function Plater.CheckHighlight (self)
if (UnitIsUnit ("mouseover", self.unit)) then
self.HighlightTexture:Show()
else
self.HighlightTexture:Hide()
end
end
--create a new frame for the highlight (when the mouse passes over the nameplate)
function Plater.CreateHighlightNameplate (plateFrame) --private
local highlightOverlay = CreateFrame ("frame", "$parentHighlightOverlay", plateFrame.unitFrame.healthBar, BackdropTemplateMixin and "BackdropTemplate") --why this was parented to UIParent (question mark)
highlightOverlay:EnableMouse (false)
highlightOverlay:SetAllPoints()
highlightOverlay:SetScript ("OnUpdate", Plater.CheckHighlight)
highlightOverlay:Hide()
--highlightOverlay:SetFrameStrata ("TOOLTIP") --it'll use the same strata as the health bar now
highlightOverlay.HighlightTexture = plateFrame.unitFrame.healthBar:CreateTexture (nil, "artwork")
highlightOverlay.HighlightTexture:SetAllPoints()
highlightOverlay.HighlightTexture:SetColorTexture (1, 1, 1, 1)
highlightOverlay.HighlightTexture:SetAlpha (1)
highlightOverlay:Hide()
plateFrame.unitFrame.HighlightFrame = highlightOverlay
end
function Plater.EnableHighlight (unitFrame)
unitFrame.HighlightFrame:Show()
unitFrame.HighlightFrame.HighlightTexture:Show()
unitFrame.HighlightFrame.unit = unitFrame [MEMBER_UNITID]
unitFrame.HighlightFrame:SetScript ("OnUpdate", Plater.CheckHighlight)
end
function Plater.DisableHighlight (unitFrame)
unitFrame.HighlightFrame:SetScript ("OnUpdate", nil)
unitFrame.HighlightFrame:Hide()
unitFrame.HighlightFrame.HighlightTexture:Hide()
end
function Plater.CreateHealthFlashFrame (plateFrame) --private
local f_anim = CreateFrame ("frame", nil, plateFrame.unitFrame.healthBar, BackdropTemplateMixin and "BackdropTemplate")
f_anim:SetFrameLevel (plateFrame.unitFrame.healthBar:GetFrameLevel()-1)
f_anim:SetPoint ("topleft", plateFrame.unitFrame.healthBar, "topleft", -2, 2)
f_anim:SetPoint ("bottomright", plateFrame.unitFrame.healthBar, "bottomright", 2, -2)
plateFrame.unitFrame.healthBar.canHealthFlash = true
local t = f_anim:CreateTexture (nil, "artwork")
t:SetColorTexture (1, 1, 1, 1)
t:SetAllPoints()
t:SetBlendMode ("ADD")
f_anim.texture = t
local animation = t:CreateAnimationGroup()
local anim1 = animation:CreateAnimation ("Alpha")
local anim2 = animation:CreateAnimation ("Alpha")
local anim3 = animation:CreateAnimation ("Alpha")
anim1:SetOrder (1)
anim1:SetFromAlpha (0)
anim1:SetToAlpha (1)
anim1:SetDuration (0.1)
anim2:SetOrder (2)
anim2:SetFromAlpha (1)
anim2:SetToAlpha (0)
anim2:SetDuration (0.1)
anim3:SetOrder (3)
anim3:SetFromAlpha (0)
anim3:SetToAlpha (1)
anim3:SetDuration (0.1)
f_anim.animation = animation
animation:SetScript ("OnFinished", function (self)
f_anim:Hide()
end)
animation:SetScript ("OnPlay", function (self)
f_anim:Show()
end)
local do_flash_anim = function (duration)
if (not plateFrame.unitFrame.healthBar.canHealthFlash) then
return
end
plateFrame.unitFrame.healthBar.canHealthFlash = false
duration = duration or 0.1
anim1:SetDuration (duration)
anim2:SetDuration (duration)
anim3:SetDuration (duration)
f_anim:Show()
animation:Play()
end
f_anim:Hide()
plateFrame.unitFrame.healthBar.HealthFlashFrame = f_anim
plateFrame.unitFrame.healthBar.PlayHealthFlash = do_flash_anim
end
function Plater.CreateAggroFlashFrame (plateFrame) --private
local f_anim = CreateFrame ("frame", nil, plateFrame.unitFrame.healthBar, BackdropTemplateMixin and "BackdropTemplate")
--local f_anim = CreateFrame ("frame", nil, plateFrame, BackdropTemplateMixin and "BackdropTemplate")
f_anim:SetFrameLevel (plateFrame.unitFrame.healthBar:GetFrameLevel()+3)
f_anim:SetPoint ("topleft", plateFrame.unitFrame.healthBar, "topleft")
f_anim:SetPoint ("bottomright", plateFrame.unitFrame.healthBar, "bottomright")
local t = f_anim:CreateTexture (nil, "artwork")
--t:SetTexCoord (0, 0.78125, 0, 0.66796875)
--t:SetTexture ([[Interface\AchievementFrame\UI-Achievement-Alert-Glow]])
t:SetColorTexture (1, 1, 1, 1)
t:SetAllPoints()
t:SetBlendMode ("ADD")
f_anim.texture = t
local s = f_anim:CreateFontString (nil, "overlay", "GameFontNormal")
s:SetText ("-AGGRO-")
s:SetTextColor (.70, .70, .70)
s:SetPoint ("center", t, "center")
f_anim.text = s
local animation = t:CreateAnimationGroup()
local anim1 = animation:CreateAnimation ("Alpha")
local anim2 = animation:CreateAnimation ("Alpha")
anim1:SetOrder (1)
anim1:SetFromAlpha (0)
anim1:SetToAlpha (1)
anim1:SetDuration (0.2)
anim2:SetOrder (2)
anim2:SetFromAlpha (1)
anim2:SetToAlpha (0)
anim2:SetDuration (0.2)
f_anim.animation = animation
animation:SetScript ("OnFinished", function (self)
f_anim:Hide()
end)
animation:SetScript ("OnPlay", function (self)
f_anim:Show()
end)
local do_flash_anim = function (text, duration, ignoreCooldown)
if (not ignoreCooldown and Plater.CombatTime+5 > GetTime()) then
return
end
text = text or ""
duration = duration or 0.2
anim1:SetDuration (duration)
anim2:SetDuration (duration)
s:SetText (text)
f_anim:Show()
animation:Play()
end
f_anim:Hide()
plateFrame.unitFrame.BodyFlashFrame = f_anim
plateFrame.PlayBodyFlash = do_flash_anim
end
--> animation with acceleration ~animation ~healthbaranimation
function Plater.AnimateLeftWithAccel (self, deltaTime)
local distance = (self.AnimationStart - self.AnimationEnd) / self.CurrentHealthMax * 100 --scale 1 - 100
local minTravel = min (distance / 10, 3) -- 10 = trigger distance to max speed 3 = speed scale on max travel
local maxTravel = max (minTravel, 0.45) -- 0.45 = min scale speed on low travel speed
local calcAnimationSpeed = (self.CurrentHealthMax * (deltaTime * DB_ANIMATION_TIME_DILATATION)) * maxTravel --re-scale back to unit health, scale with delta time and scale with the travel speed
self.AnimationStart = self.AnimationStart - (calcAnimationSpeed)
self:SetValue (self.AnimationStart)
self.CurrentHealth = self.AnimationStart
if (self.Spark) then
self.Spark:SetPoint ("center", self, "left", self.AnimationStart / self.CurrentHealthMax * self:GetWidth(), 0)
self.Spark:Show()
end
if (self.AnimationStart-1 <= self.AnimationEnd) then
self:SetValue (self.AnimationEnd)
self.CurrentHealth = self.AnimationEnd
self.IsAnimating = false
if (self.Spark) then
self.Spark:Hide()
end
end
end
function Plater.AnimateRightWithAccel (self, deltaTime)
local distance = (self.AnimationEnd - self.AnimationStart) / self.CurrentHealthMax * 100 --scale 1 - 100 basis
local minTravel = math.min (distance / 10, 3) -- 10 = trigger distance to max speed 3 = speed scale on max travel
local maxTravel = math.max (minTravel, 0.45) -- 0.45 = min scale speed on low travel speed
local calcAnimationSpeed = (self.CurrentHealthMax * (deltaTime * DB_ANIMATION_TIME_DILATATION)) * maxTravel --re-scale back to unit health, scale with delta time and scale with the travel speed
self.AnimationStart = self.AnimationStart + (calcAnimationSpeed)
self:SetValue (self.AnimationStart)
self.CurrentHealth = self.AnimationStart
if (self.AnimationStart+1 >= self.AnimationEnd) then
self:SetValue (self.AnimationEnd)
self.CurrentHealth = self.AnimationEnd
self.IsAnimating = false
end
end
function Plater.CreateScaleAnimation (plateFrame) --private
--animation table
plateFrame.SpellAnimations = {}
--scale animation
local duration = 0.05
local animationHub = DF:CreateAnimationHub (plateFrame.unitFrame)
animationHub.ScaleUp = DF:CreateAnimation (animationHub, "scale", 1, duration, 1, 1, 1.2, 1.2)
animationHub.ScaleDown = DF:CreateAnimation (animationHub, "scale", 2, duration, 1, 1, 0.8, 0.8)
plateFrame.SpellAnimations ["scale"] = animationHub
end
function Plater.DoNameplateAnimation (plateFrame, frameAnimations, spellName, isCritical) --private
for animationIndex, animationTable in ipairs (frameAnimations) do
if ((animationTable.animationCooldown [plateFrame] or 0) < GetTime()) then
--animation "scale" is pre constructed when the nameplate frame is created
if (animationTable.animation_type == "scale") then
--get the animation
local animationHub = plateFrame.SpellAnimations ["scale"]
--duration
animationHub.ScaleUp:SetDuration (animationTable.duration)
animationHub.ScaleDown:SetDuration (animationTable.duration)
local scaleUpX, scaleUpY = animationTable.scale_upX, animationTable.scale_upY
local scaleDownX, scaleDownY = animationTable.scale_downX, animationTable.scale_downY;
(animationHub.ScaleUp.SetFromScale or animationHub.ScaleUp.SetScaleFrom) (animationHub.ScaleUp, 1, 1);
(animationHub.ScaleUp.SetToScale or animationHub.ScaleUp.SetScaleTo) (animationHub.ScaleUp, scaleUpX, scaleUpY);
(animationHub.ScaleDown.SetFromScale or animationHub.ScaleDown.SetScaleFrom) (animationHub.ScaleDown, 1, 1);
(animationHub.ScaleDown.SetToScale or animationHub.ScaleDown.SetScaleTo) (animationHub.ScaleDown, scaleDownX, scaleDownY)
--play it
animationHub:Play()
animationTable.animationCooldown [plateFrame] = GetTime() + animationTable.cooldown
elseif (animationTable.animation_type == "frameshake") then
--get the animation
local frameShake = plateFrame.SpellAnimations ["frameshake" .. spellName]
local shakeTargetFrame = plateFrame.unitFrame
if (not frameShake) then
--[=[ 8.2 GetPoint isn't more possible in nameplate childs
for i = 1, shakeTargetFrame:GetNumPoints() do --shakeTargetFrame = unitFrame from Plater
local p1, p2, p3, p4, p5 = shakeTargetFrame:GetPoint (i)
points [#points+1] = {p1, p2, p3, p4, p5}
end
--]=]
local points = Plater.GetPoints (plateFrame.unitFrame)
frameShake = DF:CreateFrameShake (shakeTargetFrame, animationTable.duration, animationTable.amplitude, animationTable.frequency, animationTable.absolute_sineX, animationTable.absolute_sineY, animationTable.scaleX, animationTable.scaleY, animationTable.fade_in, animationTable.fade_out, points)
plateFrame.SpellAnimations ["frameshake" .. spellName] = frameShake
end
local animationScale = Plater.db.profile.spell_animations_scale
if (IS_EDITING_SPELL_ANIMATIONS) then
shakeTargetFrame:SetFrameShakeSettings (frameShake, animationTable.duration, animationTable.amplitude, animationTable.frequency, animationTable.absolute_sineX, animationTable.absolute_sineY, animationTable.scaleX, animationTable.scaleY, animationTable.fade_in, animationTable.fade_out)
end
if (isCritical and animationTable.critical_scale) then
animationScale = animationScale * animationTable.critical_scale
shakeTargetFrame:PlayFrameShake (frameShake, animationScale, animationScale, animationScale, DF:Clamp (0.75, 1.75, animationScale)) --, animationScale
else
--scaleDirection, scaleAmplitude, scaleFrequency, scaleDuration
shakeTargetFrame:PlayFrameShake (frameShake, animationScale, animationScale, animationScale, DF:Clamp (0.75, 1.75, animationScale)) --, animationScale
end
animationTable.animationCooldown [plateFrame] = GetTime() + animationTable.cooldown
end
end
end
end
function Plater.RefreshIsEditingAnimations (state) --private
IS_EDITING_SPELL_ANIMATIONS = state
end
--black list npcs to not show when showing friendly npcs
local ignored_npcs_when_profession = {
[32751] = true, --warp huntress pet - Dalaran
[110571] = 1, --delas mooonfang - Dalaran
[113199] = true, --delas's pet - Dalaran
[110018] = 1, --gazrix gearlock - Dalaran
[107622] = true, --glutonia - Dalaran
[106263] = 1, --earthen ring shaman - Dalaran
[106262] = 1, --earthen ring shaman - Dalaran
[97141] = true, --koraud - Dalaran
}
function Plater.IsNpcInIgnoreList (plateFrame, onlyProfession) --private
if (onlyProfession) then
local npcId = plateFrame [MEMBER_NPCID]
if (not npcId) then
return
end
if (ignored_npcs_when_profession [npcId]) then
return true
end
end
end
function Plater.UpdateMaxCastbarTextLength(newGlobalSize)
Plater.MaxCastBarTextLength = newGlobalSize
end
function Plater.GetNpcIDFromGUID (guid) --private
local npcID = select (6, strsplit ("-", guid))
return tonumber (npcID or "0") or 0
end
function Plater.GetNpcID (plateFrame) --private
local npcId = plateFrame [MEMBER_GUID]
if (npcId and npcId ~= "") then
npcId = select (6, strsplit ("-", npcId))
if (npcId) then
npcId = tonumber (npcId)
else
return
end
else
return
end
if (not npcId) then
return
end
plateFrame [MEMBER_NPCID] = npcId
plateFrame.unitFrame [MEMBER_NPCID] = npcId
return npcId
end
function Plater.GetUnitType (plateFrame)
if (plateFrame ["namePlateClassification"] == "minus") then
return "minus"
elseif (PET_CACHE [plateFrame [MEMBER_GUID]]) then
return "pet"
end
return "normal"
end
--returns isPet, isPlayerPet, PET_CACHE-entry (if existing)
function Plater.IsUnitPet (unitFrame)
if not unitFrame then return false, false, nil end
local entry = PET_CACHE [unitFrame.PlateFrame [MEMBER_GUID]]
if (entry) then
return true, Plater.PlayerPetCache [unitFrame.PlateFrame [MEMBER_GUID]] and true or false, entry
end
return false, false, nil
end
function Plater.CanChangePlateSize() --private
return not InCombatLockdown()
end
function Plater.RefreshOmniCCGroup (fromInit) --private
if (OmniCC) then
local platerThemeName = "Plater Nameplates Theme"
local platerRuleName = "Plater Nameplates Rule"
--cleanup old data...
OmniCC:RemoveRule("PlaterNameplates Blacklist")
OmniCC:RemoveTheme("PlaterNameplates Blacklist")
--attempt to get the plater theme
local platerTheme = OmniCC:GetTheme(platerThemeName)
--check if the plater theme exists, if it doesn't but the call is from Initialization or Profile Refresh, just quit
if (not platerTheme and fromInit) then
return
end
--if doesn't exists and isn't from init (the call came from the options panel by the user clicking in the checkbox)
if (not platerTheme) then
platerTheme = OmniCC:AddTheme(platerThemeName)
platerTheme.enableText = false
end
local platerRules = OmniCC:AddRule(platerRuleName, platerThemeName)
if not platerRules then
-- rule already exists, get it properly...
for _, rule in OmniCC:GetRulesets() do
if rule.id == platerRuleName then
platerRules = rule
break
end
end
end
DF.table.addunique (platerRules.patterns, "PlaterMainAuraIcon")
DF.table.addunique (platerRules.patterns, "PlaterSecondaryAuraIcon")
DF.table.addunique (platerRules.patterns, "ExtraIconRowIcon")
if (Plater.db.profile.disable_omnicc_on_auras) then
platerTheme.enableText = false
platerRules.enabled = true
else
platerTheme.enableText = true
end
OmniCC:OnProfileChanged()
OmniCC.Cooldown:ForAll("Refresh", true)
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> combat log reader ~combatlog ~cleu
local PlaterCLEUParser = CreateFrame ("frame", "PlaterCLEUParserFrame", UIParent, BackdropTemplateMixin and "BackdropTemplate")
local parserFunctions = {
SPELL_DAMAGE = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (SPELL_WITH_ANIMATIONS [spellName] and sourceGUID == Plater.PlayerGUID) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame [MEMBER_GUID] == targetGUID and plateFrame.unitFrame.PlaterOnScreen) then
Plater.DoNameplateAnimation (plateFrame, SPELL_WITH_ANIMATIONS [spellName], spellName, isCritical)
end
end
end
end,
SPELL_SUMMON = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
--[=[ --some actors are not having the pet flag 0x3000, so we are directly adding all target summons into the cache
print ("Summon", targetFlag, bit.band (targetFlag, 0x00003000) ~= 0)
if (sourceFlag and bit.band (sourceFlag, 0x00003000) ~= 0) then
print ("new pet", sourceName, targetName)
PET_CACHE [sourceGUID] = time
elseif (targetFlag and bit.band (targetFlag, 0x00003000) ~= 0) then
print ("new pet", sourceName, targetName)
PET_CACHE [targetGUID] = time
end
--]=]
local entry = {ownerGUID = sourceGUID, ownerName = sourceName, petName = targetName, time = time}
PET_CACHE [targetGUID] = entry
if (sourceGUID == Plater.PlayerGUID) then
Plater.PlayerPetCache [targetGUID] = entry
end
end,
SPELL_INTERRUPT = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (not Plater.db.profile.show_interrupt_author) then
return
end
local name = sourceName
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
local unitFrame = plateFrame.unitFrame
local castBar = unitFrame.castBar
if (unitFrame.PlaterOnScreen and castBar:IsShown()) then
if (plateFrame [MEMBER_GUID] == targetGUID) then
--get owner name if a pet interrupted
local petOwnerTable = PET_CACHE[sourceGUID]
if (petOwnerTable) then
name = petOwnerTable.ownerName or name
sourceGUID = petOwnerTable.ownerGUID or sourceGUID
end
if DB_USE_NAME_TRANSLIT then
name = LibTranslit:Transliterate(name, TRANSLIT_MARK)
end
castBar.Text:SetText (INTERRUPTED .. " [" .. Plater.SetTextColorByClass (sourceGUID, name) .. "]")
castBar.IsInterrupted = true
castBar.InterruptSourceName = sourceName
castBar.InterruptSourceGUID = sourceGUID
--interrupt animation
if (Plater.db.profile.cast_statusbar_interrupt_anim) then
local interruptAnim = castBar._interruptAnim
if (not interruptAnim) then
--scale animation
local duration = 0.05
local animationHub = DF:CreateAnimationHub(castBar)
animationHub.ScaleUp = DF:CreateAnimation(animationHub, "scale", 1, duration, 1, 1, 1, 1.05)
animationHub.ScaleDown = DF:CreateAnimation(animationHub, "scale", 2, duration, 1, 1.05, 1, 0.95)
--shake animattion
local duration = 0.36
local amplitude = 0.58
local frequency = 37.39
local absolute_sineX = false
local absolute_sineY = false
local scaleX = 0
local scaleY = 1.2
local fade_out = 0.33
local fade_in = 0.001
local cooldown = 0.5
local points = castBar._points
local frameShakeObject = DF:CreateFrameShake(castBar, duration, amplitude, frequency, absolute_sineX, absolute_sineY, scaleX, scaleY, fade_in, fade_out, points)
castBar._interruptAnim = {
Scale = animationHub,
Shake = frameShakeObject
}
interruptAnim = castBar._interruptAnim
end
interruptAnim.Scale:Play()
castBar:PlayFrameShake(interruptAnim.Shake)
end
castBar.FrameOverlay.TargetName:Hide() -- hide the target immediately
--> check and stop the casting script if any
castBar:OnHideWidget()
end
end
end
end,
SPELL_CAST_SUCCESS = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (not DB_CAPTURED_SPELLS[spellID]) then
if (not sourceFlag or bit.band(sourceFlag, 0x00000400) == 0) then --not a player
local npcId = Plater:GetNpcIdFromGuid(sourceGUID or "")
if (npcId and npcId ~= 0) then
DB_CAPTURED_SPELLS[spellID] = {event = token, source = sourceName, npcID = npcId, encounterID = Plater.CurrentEncounterID, encounterName = Plater.CurrentEncounterName}
end
end
end
end,
SPELL_CAST_START = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (not DB_CAPTURED_CASTS[spellID]) then
if (not sourceFlag or bit.band(sourceFlag, 0x00000400) == 0) then --not a player
local npcId = Plater:GetNpcIdFromGuid(sourceGUID or "")
if (npcId and npcId ~= 0) then
DB_CAPTURED_CASTS[spellID] = {npcID = npcId, encounterID = Plater.CurrentEncounterID, encounterName = Plater.CurrentEncounterName}
end
end
end
if (spellName) then
Plater.LastCombat.spellNames[spellName] = true
end
end,
SPELL_AURA_APPLIED = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (not DB_CAPTURED_SPELLS[spellID]) then
if (not sourceFlag or bit.band(sourceFlag, 0x00000400) == 0) then --not a player
local npcId = Plater:GetNpcIdFromGuid(sourceGUID or "")
if (npcId and npcId ~= 0) then
local auraType = amount
DB_CAPTURED_SPELLS [spellID] = {event = token, source = sourceName, type = auraType, npcID = npcId, encounterID = Plater.CurrentEncounterID, encounterName = Plater.CurrentEncounterName}
end
end
end
if IS_WOW_PROJECT_NOT_MAINLINE then
-- paladin tank buff tracking
local playerGUID = Plater.PlayerGUID
if sourceGUID == playerGUID and targetGUID == playerGUID then
spellId = select(7, GetSpellInfo(spellName))
if spellId == 25780 then
UpdatePlayerTankState(true)
--Plater.RefreshTankCache()
end
end
end
end,
}
if IS_WOW_PROJECT_NOT_MAINLINE then
tinsert(parserFunctions, {
SPELL_AURA_REMOVED = function (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
-- paladin tank buff tracking
local playerGUID = Plater.PlayerGUID
if sourceGUID == playerGUID and targetGUID == playerGUID then
spellId = select(7, GetSpellInfo(spellName))
if spellId == 25780 then
UpdatePlayerTankState(false)
--Plater.RefreshTankCache()
end
end
end,
})
end
PlaterCLEUParser.Parser = function (self)
local time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical = CombatLogGetCurrentEventInfo()
local func = parserFunctions [token]
if (func) then
Plater.StartLogPerformanceCore("Plater-Core", "Events", token)
func (time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical)
if (targetName) then
Plater.LastCombat.npcNames[targetName] = true
end
Plater.EndLogPerformanceCore("Plater-Core", "Events", token)
end
end
PlaterCLEUParser:SetScript ("OnEvent", PlaterCLEUParser.Parser)
PlaterCLEUParser:RegisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")
C_Timer.NewTicker (600, function()
local now = time()
for guid, entry in pairs (PET_CACHE) do
local time = entry.time
if (time+600 < now) then
PET_CACHE [guid] = nil
end
end
for guid, entry in pairs (Plater.PlayerPetCache) do
local time = entry.time
if (time + 3600 < now) then
Plater.PlayerPetCache [guid] = nil
end
end
end)
Plater.NpcBlackList = {}
function Plater.ForceFindPetOwner (serial) --private
Plater.StartLogPerformanceCore("Plater-Core", "Update", "ForceFindPetOwner")
local tooltipFrame = PlaterPetOwnerFinder or CreateFrame ("GameTooltip", "PlaterPetOwnerFinder", nil, "GameTooltipTemplate")
tooltipFrame:SetOwner (WorldFrame, "ANCHOR_NONE")
tooltipFrame:SetHyperlink ("unit:" .. serial or "")
local isPlayerPet = false
local isOtherPet = false
local ownerName = ""
local line1 = _G ["PlaterPetOwnerFinderTextLeft2"]
local text1 = line1 and line1:GetText()
if (text1 and text1 ~= "") then
local pName = GetUnitName ("player", true)
local playerName = pName:gsub ("%-.*", "") --remove realm name
if (text1:find (playerName)) then
isPlayerPet = true
ownerName = playerName
else
ownerName = (string.match(text1, string.gsub(UNITNAME_TITLE_PET, "%%s", "(%.*)")) or string.match(text1, string.gsub(UNITNAME_TITLE_MINION, "%%s", "(%.*)")) or string.match(text1, string.gsub(UNITNAME_TITLE_GUARDIAN, "%%s", "(%.*)")))
if ownerName then
isOtherPet = true
end
end
end
if (not isPlayerPet and not isOtherPet) then
local line2 = _G ["PlaterPetOwnerFinderTextLeft3"]
local text2 = line2 and line2:GetText()
if (text2 and text2 ~= "") then
local pName = GetUnitName ("player", true)
local playerName = pName:gsub ("%-.*", "") --remove realm name
if (text2:find (playerName)) then
isPlayerPet = true
ownerName = playerName
else
ownerName = (string.match(text2, string.gsub(UNITNAME_TITLE_PET, "%%s", "(%.*)")) or string.match(text2, string.gsub(UNITNAME_TITLE_MINION, "%%s", "(%.*)")) or string.match(text2, string.gsub(UNITNAME_TITLE_GUARDIAN, "%%s", "(%.*)")))
if ownerName then
isOtherPet = true
end
end
end
end
if (isPlayerPet or isOtherPet) then
local petNameLine = _G ["PlaterPetOwnerFinderTextLeft1"]
local petName = petNameLine and petNameLine:GetText()
local entry = {ownerGUID = UnitGUID(ownerName), ownerName = ownerName, petName = petName, time = time()}
if (isPlayerPet) then
PET_CACHE [serial] = entry
Plater.PlayerPetCache [serial] = entry
elseif (isOtherPet) then
--ViragDevTool_AddData({serial = serial, entry = entry, tooltipFrame = tooltipFrame}, "pet")
PET_CACHE [serial] = entry
end
else
Plater.NpcBlackList [serial] = true
end
Plater.EndLogPerformanceCore("Plater-Core", "Update", "ForceFindPetOwner")
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> cvars - ~cvars
function Plater.CreatePlaterButtonAtInterfaceOptions()
if not InterfaceOptionsFrame then return end --DF does not has this anymore TODO
local f = CreateFrame ("frame", nil, InterfaceOptionsNamesPanel, BackdropTemplateMixin and "BackdropTemplate")
f:SetSize (300, 200)
f:SetPoint ("topleft", InterfaceOptionsNamesPanel, "topleft", 10, -440)
local open_options = function()
InterfaceOptionsFrame:Hide()
HideUIPanel(GameMenuFrame)
Plater.OpenOptionsPanel()
end
local Button = DF:CreateButton (f, open_options, 100, 22, "", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"))
Button:SetPoint ("topleft", f, "topleft", 10, 0)
Button:SetText ("Advanced Nameplate Options")
Button:SetIcon ([[Interface\BUTTONS\UI-OptionsButton]], 18, 18, "overlay", {0, 1, 0, 1})
end
--elseof
function Plater.SetCVarsOnFirstRun()
if (InCombatLockdown()) then
C_Timer.After (1, function() Plater.SetCVarsOnFirstRun() end)
return
end
canSaveCVars = false -- ensure to not overwrite profile
--> these are the cvars set for each character when they logon
--disabled:
--SetCVar ("nameplateShowSelf", CVAR_DISABLED)
--SetCVar ("nameplateShowFriends", CVAR_ENABLED)
--> location of the personal bar
-- SetCVar ("nameplateSelfBottomInset", 20 / 100)
-- SetCVar ("nameplateSelfTopInset", abs (20 - 99) / 100)
--> set the stacking to true
--SetCVar ("nameplateMotion", CVAR_ENABLED) --March 08, 2019 don't change the stacking type when installing plater
--> distance between each nameplate when using stacking
--SetCVar ("nameplateOverlapV", 1.25)
--> make nameplates always shown and down't show minions
SetCVar ("nameplateShowAll", CVAR_ENABLED)
if IS_WOW_PROJECT_MAINLINE then
SetCVar ("ShowNamePlateLoseAggroFlash", CVAR_ENABLED) --blizzard flash
end
--scale when it is too far away from the camera
SetCVar ("nameplateMinScale", 1)
--scale of the nameplate for important units, default is 1.2 which makes the nameplate be too big with the 1.15 target scale
SetCVar ("nameplateLargerScale", 1.10)
--enable enemy minus nameplates
SetCVar ("nameplateShowEnemyMinions", CVAR_ENABLED)
SetCVar ("nameplateShowEnemyMinus", CVAR_ENABLED)
--don't show friendly npcs
SetCVar ("nameplateShowFriendlyNPCs", 0)
--disable friendly minius nameplates
SetCVar ("nameplateShowFriendlyGuardians", CVAR_DISABLED)
SetCVar ("nameplateShowFriendlyPets", CVAR_DISABLED)
SetCVar ("nameplateShowFriendlyTotems", CVAR_DISABLED)
SetCVar ("nameplateShowFriendlyMinions", CVAR_DISABLED)
--> make it show the class color of players
SetCVar ("ShowClassColorInNameplate", CVAR_ENABLED)
--> lock nameplates to screen
SetCVar ("nameplateOtherTopInset", "0.085")
SetCVar ("nameplateLargeTopInset", "0.085")
SetCVar ("clampTargetNameplateToScreen", "1")
SetCVar ("nameplateTargetRadialPosition", "1")
SetCVar ("nameplateTargetBehindMaxDistance", "30")
--> reset the horizontal and vertical scale
SetCVar ("NamePlateHorizontalScale", CVAR_ENABLED)
SetCVar ("NamePlateVerticalScale", CVAR_ENABLED)
if IS_WOW_PROJECT_MAINLINE then
SetCVar ("NamePlateClassificationScale", CVAR_ENABLED)
end
--> make the selection be a little bigger
SetCVar ("nameplateSelectedScale", "1.15")
--> movement speed of nameplates when using stacking, going above this isn't recommended
SetCVar ("nameplateMotionSpeed", "0.05")
--> make the personal bar hide very fast
SetCVar ("nameplatePersonalHideDelaySeconds", 0.2)
--> don't show debuffs on blizzard healthbars
SetCVar ("nameplateShowDebuffsOnFriendly", CVAR_DISABLED)
--> view distance
if IS_WOW_PROJECT_MAINLINE then
SetCVar ("nameplateMaxDistance", 60)
else
SetCVar ("nameplateMaxDistance", 41)
end
--> ensure resource on target consistency:
if IS_WOW_PROJECT_MAINLINE then
PlaterDBChr.resources_on_target = GetCVar ("nameplateResourceOnTarget") == CVAR_ENABLED
SetCVar ("nameplateResourceOnTarget", CVAR_DISABLED)
end
PlaterDBChr.first_run3 [UnitGUID ("player")] = true
Plater.db.profile.first_run3 = true
Plater.RunFunctionForEvent ("ZONE_CHANGED_NEW_AREA")
--Plater:Msg ("Plater has been successfully installed on this character.")
Plater.RestoreProfileCVars() -- restore profile, if existing
canSaveCVars = true -- save cvars again
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> quest log stuff ~quest
--PlaterScanTooltip:SetOwner (WorldFrame, "ANCHOR_NONE")
local GameTooltipFrame = CreateFrame ("GameTooltip", "PlaterScanTooltip", nil, "GameTooltipTemplate")
local GameTooltipFrameTextLeft2 = _G ["PlaterScanTooltipTextLeft2"]
function Plater.GetActorSubName (plateFrame) --private
local cbMode = GetCVar("colorblindMode") == "1"
GameTooltipFrame:SetOwner (WorldFrame, "ANCHOR_NONE")
GameTooltipFrame:SetHyperlink ("unit:" .. (plateFrame [MEMBER_GUID] or ''))
if cbMode then
local GameTooltipFrameTextLeft3 = GameTooltipFrameTextLeft3 or _G ["PlaterScanTooltipTextLeft3"]
return GameTooltipFrameTextLeft3 and GameTooltipFrameTextLeft3:GetText() or GameTooltipFrameTextLeft2:GetText()
else
return GameTooltipFrameTextLeft2:GetText()
end
end
local GameTooltipScanQuest = CreateFrame ("GameTooltip", "PlaterScanQuestTooltip", nil, "GameTooltipTemplate")
local ScanQuestTextCache = {}
--for i = 1, 8 do
-- ScanQuestTextCache [i] = _G ["PlaterScanQuestTooltipTextLeft" .. i]
--end
function Plater.IsQuestObjective (plateFrame)
if (not plateFrame [MEMBER_GUID]) then --platerFrame.actorType == "friendlynpc"
return
end
Plater.StartLogPerformanceCore("Plater-Core", "Update", "IsQuestObjective")
-- reset quest amount
plateFrame.QuestAmountCurrent = nil
plateFrame.QuestAmountTotal = nil
plateFrame.QuestText = nil
plateFrame.QuestName = nil
plateFrame.QuestIsCampaign = nil
plateFrame.unitFrame.QuestAmountCurrent = nil
plateFrame.unitFrame.QuestAmountTotal = nil
plateFrame.unitFrame.QuestText = nil
plateFrame.unitFrame.QuestName = nil
plateFrame.unitFrame.QuestIsCampaign = nil
local useQuestie = false
local QuestieTooltips = QuestieLoader and QuestieLoader._modules["QuestieTooltips"]
if QuestieTooltips then
ScanQuestTextCache = QuestieTooltips:GetTooltip("m_"..plateFrame [MEMBER_NPCID])
if not ScanQuestTextCache then
ScanQuestTextCache = {}
end
useQuestie = true
else
GameTooltipScanQuest:SetOwner (WorldFrame, "ANCHOR_NONE")
GameTooltipScanQuest:SetHyperlink ("unit:" .. plateFrame [MEMBER_GUID])
--8.2 tooltip changes fix by GentMerc#9560 on Discord
for i = 1, GameTooltipScanQuest:NumLines() do
ScanQuestTextCache [i] = _G ["PlaterScanQuestTooltipTextLeft" .. i]
end
end
local playerName = UnitName("player")
local isInGroup = IsInGroup()
local unitQuestData = {}
local isQuestUnit = false
local atLeastOneQuestUnfinished = false
for i = 1, #ScanQuestTextCache do
local text = nil
if useQuestie then
text = ScanQuestTextCache [i]
text = gsub(text,"|c........","") -- remove coloring begin
text = gsub(text,"|r","") -- remove color end
text = gsub(text,"%[.*%] ","") -- remove level text
text = gsub(text," %(%d+%)","") -- remove quest-id
else
text = ScanQuestTextCache [i]:GetText()
end
if (Plater.QuestCache [text]) then
--unit belongs to a quest
isQuestUnit = true
local isCampaignQuest = Plater.QuestCacheCampaign[text]
local isGroupQuest, yourQuest = nil, nil
local questData = {
questName = text,
questText = "",
finished = true,
groupQuest = false,
groupFinished = true,
amount = 0,
groupAmount = 0,
total = 0,
yourQuest = false,
isCampaignQuest = isCampaignQuest,
}
local amount1, amount2, questText = nil, nil, nil
local amountSet = false
local j = i
while (ScanQuestTextCache [j+1]) do
--check if the unit objective isn't already done
local nextLineText = nil
if useQuestie then
nextLineText = ScanQuestTextCache [j+1]
if nextLineText then
nextLineText = gsub(nextLineText,"|c........","") -- remove coloring begin
nextLineText = gsub(nextLineText,"|r","") -- remove color end
end
else
nextLineText = ScanQuestTextCache [j+1]:GetText()
end
if (nextLineText) then
if useQuestie then
local isQuestieOwn = nextLineText:match ("%(("..playerName..")%)%s*$") and true or false
local isQuestieGroup = nextLineText:match ("%((%w+)%)%s*$") and isInGroup and true or false
yourQuest = isQuestieOwn or not isQuestieGroup
isGroupQuest = isQuestieGroup
questData.yourQuest = yourQuest
questData.groupQuest = isGroupQuest
end
if not useQuestie and isInGroup and nextLineText == playerName then
yourQuest = true
isGroupQuest = true
questData.yourQuest = true
questData.groupQuest = true
elseif not nextLineText:match(THREAT_TOOLTIP) then
local p1, p2 = nextLineText:match ("(%d+)/(%d+)")
if (not p1) then
-- check for % based quests
p1 = nextLineText:match ("(%d+%%)")
if p1 then
-- remove the % sign for consistency
p1 = string.gsub(p1,"%%", '')
end
end
if (p1 and p2 and not (p1 == p2)) or (p1 and not p2 and not (p1 == "100")) then
-- quest not completed
atLeastOneQuestUnfinished = true
amount1, amount2 = p1, p2
if not amountSet or ((tonumber(p1) or 0) < (tonumber(questData.groupAmount) or 0)) then
questData.groupAmount = amount1
end
questData.total = amount2
if yourQuest ~= false then
yourQuest = false -- already set on data
questData.finished = false
questData.amount = amount1
end
questData.groupFinished = false
questData.questText = nextLineText
questText = nextLineText
amountSet = true
elseif yourQuest and (p1 and p2 and (p1 == p2)) or (p1 and not p2 and (p1 == "100")) then
yourQuest = false -- already set on data
questData.finished = true
questData.amount = p1
end
else
j = 99 --safely break here, as we saw threat% -> quest text is done
end
end
j = j + 1
end
if (amount1 and atLeastOneQuestUnfinished) then
plateFrame.QuestAmountCurrent = questData.groupAmount
plateFrame.QuestAmountTotal = amount2
plateFrame.QuestText = questText
plateFrame.QuestName = text
plateFrame.QuestIsCampaign = isCampaignQuest
--expose to scripts
plateFrame.unitFrame.QuestAmountCurrent = questData.groupAmount
plateFrame.unitFrame.QuestAmountTotal = amount2
plateFrame.unitFrame.QuestText = questText
plateFrame.unitFrame.QuestName = text
plateFrame.unitFrame.QuestIsCampaign = isCampaignQuest
end
if not isGroupQuest then
questData.yourQuest = true
end
tinsert(unitQuestData, questData)
end
end
plateFrame.QuestInfo = unitQuestData
plateFrame.unitFrame.QuestInfo = unitQuestData
local namePlateIsQuestObjective = isQuestUnit and atLeastOneQuestUnfinished
plateFrame [MEMBER_QUEST] = namePlateIsQuestObjective
plateFrame.unitFrame [MEMBER_QUEST] = namePlateIsQuestObjective
Plater.EndLogPerformanceCore("Plater-Core", "Update", "IsQuestObjective")
return namePlateIsQuestObjective
end
local update_quest_cache = function()
--clear the quest cache
wipe (Plater.QuestCache)
wipe (Plater.QuestCacheCampaign)
--do not update if is inside an instance
local isInInstance = IsInInstance()
if (isInInstance) then
return
end
--update the quest cache
local numEntries, numQuests = C_QuestLog.GetNumQuestLogEntries and C_QuestLog.GetNumQuestLogEntries() or GetNumQuestLogEntries()
for questLogId = 1, numEntries do
if IS_WOW_PROJECT_MAINLINE then
local questDetails = C_QuestLog.GetInfo(questLogId)
--any chance to track via quest objective? no unit IDs given there...
--ViragDevTool_AddData({questDetails = questDetails, QuestObjectives = C_QuestLog.GetQuestObjectives(questDetails.questID), Title = C_QuestLog.GetTitleForLogIndex(questLogId)}, "QuestUpdate - " .. questLogId)
if (questDetails and not questDetails.isHeader and questDetails.title and type (questDetails.questID) == "number" and questDetails.questID > 0) then
Plater.QuestCache [questDetails.title] = true
if (questDetails.campaignID) then
Plater.QuestCacheCampaign[questDetails.title] = true
end
end
else
local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questId, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle (questLogId)
if (type (questId) == "number" and questId > 0) then -- and not isComplete
Plater.QuestCache [title] = true
end
end
end
if IS_WOW_PROJECT_MAINLINE then
local mapId = C_Map.GetBestMapForUnit ("player")
if (mapId) then
local worldQuests = C_TaskQuest.GetQuestsForPlayerByMapID (mapId)
if (type (worldQuests) == "table") then
for i, questTable in ipairs (worldQuests) do
local x, y, floor, numObjectives, questId, inProgress = questTable.x, questTable.y, questTable.floor, questTable.numObjectives, questTable.questId, questTable.inProgress
if (type (questId) == "number" and questId > 0) then
local questName = C_TaskQuest.GetQuestInfoByQuestID (questId)
if (questName) then
Plater.QuestCache [questName] = true
end
end
end
end
end
end
Plater.UpdateAllPlates()
end
function Plater.QuestLogUpdated() --private
if (Plater.UpdateQuestCacheThrottle and not Plater.UpdateQuestCacheThrottle._cancelled) then
Plater.UpdateQuestCacheThrottle:Cancel()
end
Plater.UpdateQuestCacheThrottle = C_Timer.NewTimer(2, update_quest_cache)
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> API ~API
--attempt to get the role of the unit shown in the nameplate
function Plater.GetUnitRole (unitFrame)
if IS_WOW_PROJECT_MAINLINE then
local assignedRole = UnitGroupRolesAssigned (unitFrame.unit)
if (assignedRole and assignedRole ~= "NONE") then
return assignedRole
end
if (Plater.ZoneInstanceType == "arena") then
local oponentes = GetNumArenaOpponentSpecs()
for i = 1, oponentes do
local unitGUID = UnitGUID ("arena" .. i)
if (unitGUID == unitFrame [MEMBER_GUID]) then
local spec = GetArenaOpponentSpec (i)
if (spec) then
local id, name, description, icon, role, class = GetSpecializationInfoByID (spec)
if (role and role ~= "NONE") then
return role
end
end
end
end
elseif (Plater.ZoneInstanceType == "pvp") then
if (Details) then
local actor = Details:GetActor ("current", DETAILS_ATTRIBUTE_DAMAGE, GetUnitName (unitFrame.unit, true))
if (actor) then
local spec = actor.spec
if (spec) then
local id, name, description, icon, role, class = GetSpecializationInfoByID (spec)
if (role and role ~= "NONE") then
return role
end
end
end
end
end
return assignedRole
else
if IS_WOW_PROJECT_CLASSIC_WRATH then
local assignedRole = UnitGroupRolesAssigned (unitFrame.unit)
if (assignedRole and assignedRole ~= "NONE") then
return assignedRole
end
end
if GetPartyAssignment("MAINTANK", unit) then
return "MAINTANK"
elseif GetPartyAssignment("MAINASSIST", unit) then
return "MAINASSIST"
end
end
end
local BG_PLAYER_CACHE = {}
function Plater.UpdateBgPlayerRoleCache()
wipe(BG_PLAYER_CACHE)
if IS_WOW_PROJECT_MAINLINE then
if Plater.ZoneInstanceType == "pvp" then
local curNumScores = GetNumBattlefieldScores()
for i = 1, curNumScores do
local info = C_PvP.GetScoreInfo(i)
if info then
local name, faction, race, class, classToken, talentSpec = info.name, info.faction, info.raceName, info.className, info.classToken, info.talentSpec
if name then
BG_PLAYER_CACHE[name] = {faction = faction, race = race, class = class, classToken = classToken, talentSpec = talentSpec, specID = (CLASS_INFO_CACHE[classToken] and CLASS_INFO_CACHE[classToken][talentSpec] and CLASS_INFO_CACHE[classToken][talentSpec].specID), name = name}
end
end
end
elseif Plater.ZoneInstanceType == "arena" then
local numOpps = GetNumArenaOpponentSpecs();
for i=1, numOpps do
local specID, gender = GetArenaOpponentSpec(i);
if (specID > 0) then
local name = GetUnitName ("arena"..i, true)
if name then
local id, talentSpec, _, _, _, class = GetSpecializationInfoByID(specID, gender);
local class, classToken = UnitClass("arena"..i);
local race = UnitRace("arena"..i);
BG_PLAYER_CACHE[name] = {faction = nil, race = race, class = class, classToken = classToken, talentSpec = talentSpec, specID = specID, name = name}
end
end
end
end
else
--TODO: Does this really work in BG/Arena or is it just score screen?
if Plater.ZoneInstanceType == "pvp" or Plater.ZoneInstanceType == "arena" then
local curNumScores = GetNumBattlefieldScores()
for i = 1, curNumScores do
local name, _, _, _, _, faction, _, race, class, classToken = GetBattlefieldScore(i);
if name then
BG_PLAYER_CACHE[name] = {faction = faction, race = race, class = class, classToken = classToken, talentSpec = "UNKNOWN", specID = nil, name = name}
end
end
end
end
end
function Plater.GetUnitBGInfo(unit)
if (not UnitIsPlayer(unit)) then
return nil
end
if (not Plater.ZoneInstanceType == "pvp" and not Plater.ZoneInstanceType == "arena") then
return nil
end
local name = GetUnitName(unit, true)
if not BG_PLAYER_CACHE[name] then
Plater.UpdateBgPlayerRoleCache()
end
return BG_PLAYER_CACHE[name]
end
function Plater.GetSpecIconForUnitFromBG(unit)
local cache = Plater.GetUnitBGInfo(unit)
if cache and cache.specID then
return Plater.GetSpecIcon(cache.specID)
end
return nil
end
function Plater.GetSpecIcon(spec)
if (spec) then
if (spec > 600) then --hack to new spec ids on new leveling zones from level 1-10
spec = 65
end
if (useAlpha) then
return [[Interface\AddOns\Plater\images\spec_icons_normal_alpha]], unpack (class_specs_coords [spec])
else
return [[Interface\AddOns\Plater\images\spec_icons_normal]], unpack (class_specs_coords [spec])
end
end
end
--similar to Plater.GetSettings, but can be called from scripts
--is is also safe because it passes a read-only table with copied values
function Plater.GetConfig (unitFrame)
return Plater.ActorTypeSettingsCache [unitFrame.ActorType]
end
--return true if the player is in open world (not inside dungeons, etc)
function Plater.IsInOpenWorld()
return IS_IN_OPEN_WORLD
end
--refresh the frame strata and frame level when using UIParent as the parent
function Plater.RefreshNameplateStrata (unitFrame)
return Plater.UpdateUIParentLevels (unitFrame)
end
--add an extra indicator
function Plater.ShowIndicator (unitFrame, texture, width, height, color, L, R, T, B)
tinsert (unitFrame.CustomIndicators, {texture or "", width or 12, height or 12, color or "white", L or 0, R or 1, T or 0, B or 1})
Plater.UpdateIndicators (unitFrame.PlateFrame, unitFrame.ActorType)
end
--allow scripts to perform safe cvars changes with backup of default values
--PostponeCVarChange stores cvars scheduled to be changed after the combat lockdown drops
Plater.PostponeSetCVar = {}
local postpone_set_cvar = function (timerObject)
local variableName, value = timerObject.variableName, timerObject.value
Plater.PostponeSetCVar [variableName] = nil
Plater.SafeSetCVar (variableName, value)
end
function Plater.SafeSetCVar (variableName, value)
--check if is a valid cvar
if (GetCVar (variableName) == nil) then
Plater:Msg ("invalid cvar for Plater.SafeSetCVar()")
return
end
--check if there's a scheduled change for this cvar and cancel it
if (Plater.PostponeSetCVar [variableName]) then
Plater.PostponeSetCVar [variableName]:Cancel()
Plater.PostponeSetCVar [variableName] = nil
end
--check if is in combat, if is, schedule to change this cvar after the lockdown drop
if (InCombatLockdown()) then
local timerObject = C_Timer.NewTimer (0.5, postpone_set_cvar)
timerObject.variableName = variableName
timerObject.value = value
Plater.PostponeSetCVar [variableName] = timerObject
return true
end
--store the default value if there's no default value set yet
local cvarCache = Plater.db.profile.cvar_default_cache
if (cvarCache [variableName] == nil) then
cvarCache [variableName] = GetCVar (variableName)
end
SetCVar (variableName, value)
return true
end
Plater.PostponeRestoreCVar = {}
function Plater.PostponeCVarRestauration (timerObject)
local variableName = timerObject.variableName
Plater.PostponeRestoreCVar [variableName] = nil
Plater.RestoreCVar (variableName)
end
function Plater.RestoreCVar (variableName)
--check if is a valid cvar
if (GetCVar (variableName) == nil) then
Plater:Msg ("invalid cvar for Plater.SafeSetCVar()")
return
end
--check if there's a scheduled change for this cvar and cancel it
if (Plater.PostponeRestoreCVar [variableName]) then
Plater.PostponeRestoreCVar [variableName]:Cancel()
Plater.PostponeRestoreCVar [variableName] = nil
end
--check if is in combat, if is, schedule to change this cvar after the lockdown drop
if (InCombatLockdown()) then
local timerObject = C_Timer.NewTimer (0.5, Plater.PostponeCVarRestauration)
timerObject.variableName = variableName
Plater.PostponeRestoreCVar [variableName] = timerObject
return true
end
--restore the value
local cvarCache = Plater.db.profile.cvar_default_cache
if (cvarCache [variableName]) then
SetCVar (variableName, cvarCache [variableName])
cvarCache [variableName] = nil
return true
end
end
--return if the unit is in the friends list
function Plater.IsUnitInFriendsList (unitFrame)
return Plater.FriendsCache [unitFrame [MEMBER_NAME]] or Plater.FriendsCache [unitFrame [MEMBER_NAMELOWER]]
end
--> api version of the tap denied function
function Plater.IsUnitTapped (unitFrame)
return Plater.IsUnitTapDenied (unitFrame.unit)
end
--set if Plater will check for the execute range and what percent of life is require to enter in the execute range
--healthAmount is a floor com zero to one, example: 25% is 0.25
function Plater.SetExecuteRange (isExecuteEnabled, healthAmountLower, healthAmountUpper)
DB_USE_HEALTHCUTOFF = isExecuteEnabled
DB_HEALTHCUTOFF_AT = tonumber (healthAmountLower) or -0.1
DB_HEALTHCUTOFF_AT_UPPER = tonumber (healthAmountUpper) or 1.1
end
--return the name of the unit guild
function Plater.GetUnitGuildName (unitFrame)
return unitFrame.PlateFrame.playerGuildName
end
--return if the nameplate is showing an aura
function Plater.NameplateHasAura (unitFrame, aura)
return unitFrame.BuffFrame.AuraCache [aura] or unitFrame.BuffFrame2.AuraCache [aura] or unitFrame.ExtraIconFrame.AuraCache [aura]
end
--return if the unit has a specific aura
function Plater.UnitHasAura (unitFrame, aura)
return unitFrame and unitFrame.AuraCache and aura and unitFrame.AuraCache [aura] and true or false
end
--return if the unit has an enrage effect
function Plater.UnitHasEnrage (unitFrame)
return unitFrame and unitFrame.AuraCache and unitFrame.AuraCache.hasEnrage
end
--return if the unit has a dispellable effect
function Plater.UnitHasDispellable (unitFrame)
return unitFrame and unitFrame.AuraCache and unitFrame.AuraCache.canStealOrPurge
end
--get npc color set in the colors tab
function Plater.GetNpcColor (unitFrame)
return DB_UNITCOLOR_SCRIPT_CACHE [unitFrame [MEMBER_NPCID]]
end
--return which raid mark the namepalte has
function Plater.GetRaidMark (unitFrame)
if (unitFrame.IsSelf) then
return false
end
return GetRaidTargetIndex (unitFrame.unit)
end
--limit the text size of a font string
function Plater.LimitTextSize (fontString, maxWidth)
if (not fontString) then
Plater:Msg ("Plater.LimitTextSize() with not fontString")
return
end
maxWidth = max (maxWidth or 0, 10)
local text = fontString:GetText()
if not text or text == "" then
return
end
while (fontString:GetStringWidth() > maxWidth) do
text = strsub (text, 1, #text - 1)
fontString:SetText (text)
if (string.len (text) <= 1) then
break
end
end
-- cleanup utf8...
text = DF:CleanTruncateUTF8String(text)
fontString:SetText (text)
end
--create a custom aura checking, this reset the currently shown auras and only check for auras the script passed
--@buffList: a table with aura names as keys and true as the value, example: ["aura name"] = true
--@debuffList: same as above
--@noSpecialAuras: won't check special auras
function Plater.CheckAuras (self, buffList, debuffList, noSpecialAuras)
local buffFrame = self.BuffFrame
local buffFrame2 = self.BuffFrame2
Plater.ResetAuraContainer (buffFrame)
Plater.TrackSpecificAuras (buffFrame, self.unit, true, buffList, self.IsSelf, noSpecialAuras)
Plater.TrackSpecificAuras (buffFrame, self.unit, false, debuffList, self.IsSelf, noSpecialAuras)
Plater.HideNonUsedAuraIcons (buffFrame)
--update the buff layout and alpha
buffFrame.unit = self.unit
Plater.AlignAuraFrames (buffFrame)
--buffFrame:SetAlpha (DB_AURA_ALPHA)
if (DB_AURA_SEPARATE_BUFFS) then
buffFrame2.unit = self.unit
Plater.AlignAuraFrames (buffFrame2)
--buffFrame2:SetAlpha (DB_AURA_ALPHA)
end
Plater.RunScriptTriggersForAuraIcons (unitFrame)
end
--return the health bar and the unitname text
function Plater.GetHealthBar (unitFrame)
--check if the plateFrame has been passed instead
if (unitFrame.unitFrame) then
unitFrame = unitFrame.unitFrame
end
return unitFrame.healthBar, unitFrame.healthBar.unitName
end
--return the cast bar and the spellname text
function Plater.GetCastBar (unitFrame)
--check if the plateFrame has been passed instead
if (unitFrame.unitFrame) then
unitFrame = unitFrame.unitFrame
end
return unitFrame.castBar, unitFrame.castBar.Text
end
--create a glow around the frame using LibCustomGlow - defaults to "button" glow
--[[ options can be used to create different glow types, see https://www.curseforge.com/wow/addons/libcustomglow
--type "pixel"
options = {
glowType = "pixel",
color = "white", -- all plater color types accepted, from lib: {r,g,b,a}, color of lines and opacity, from 0 to 1. Defaul value is {0.95, 0.95, 0.32, 1}
N = 8, -- number of lines. Defaul value is 8;
frequency = 0.25, -- frequency, set to negative to inverse direction of rotation. Default value is 0.25;
length = 4, -- length of lines. Default value depends on region size and number of lines;
th = 2, -- thickness of lines. Default value is 2;
xOffset = 0,
yOffset = 0, -- offset of glow relative to region border;
border = false, -- set to true to create border under lines;
key = "", -- key of glow, allows for multiple glows on one frame;
}
-- type "ants"
options = {
glowType = "ants",
color = "white", -- all plater color types accepted, from lib: {r,g,b,a}, color of lines and opacity, from 0 to 1. Defaul value is {0.95, 0.95, 0.32, 1}
N = 4, -- number of particle groups. Each group contains 4 particles. Defaul value is 4;
frequency = 0.125, -- frequency, set to negative to inverse direction of rotation. Default value is 0.125;
scale = 1, -- scale of particles
xOffset = 0,
yOffset = 0, -- offset of glow relative to region border;
key = "", -- key of glow, allows for multiple glows on one frame;
}
-- type "button"
options = {
glowType = "button",
color = "white", -- all plater color types accepted, from lib: {r,g,b,a}, color of lines and opacity, from 0 to 1. Defaul value is {0.95, 0.95, 0.32, 1}
frequency = 0.125, -- frequency, set to negative to inverse direction of rotation. Default value is 0.125;
}
--]]
function Plater.StartGlow(frame, color, options, key)
if not frame then return end
if not color and (options and options.color) then
color = options.color
end
if color then
local r, g, b, a = DF:ParseColors (color)
color = {r, g, b, a}
options.color = color
end
if not options then
options = {
glowType = "button",
color = color,
key = key or "",
}
end
if not options.glowType then
options.glowType = "button"
end
if key then
options.key = key
end
if (not frame.__PlaterGlowFrame) then
frame.__PlaterGlowFrame = CreateFrame("Frame", nil, frame, BackdropTemplateMixin and "BackdropTemplate");
frame.__PlaterGlowFrame:SetAllPoints(frame);
frame.__PlaterGlowFrame:SetSize(frame:GetSize());
end
if options.glowType == "button" then
LCG.ButtonGlow_Start(frame.__PlaterGlowFrame, options.color, options.frequency)
elseif options.glowType == "pixel" then
if not options.border then options.border = false end
LCG.PixelGlow_Start(frame.__PlaterGlowFrame, options.color, options.N, options.frequency, options.length, options.th, options.xOffset, options.yOffset, options.border, options.key or "")
elseif options.glowType == "ants" then
LCG.AutoCastGlow_Start(frame.__PlaterGlowFrame, options.color, options.N, options.frequency, options.scale, options.xOffset, options.yOffset, options.key or "")
end
end
-- creates a button glow effect
function Plater.StartButtonGlow(frame, color, options, key)
-- type "button"
if not options then
options = {
glowType = "button",
color = color, -- all plater color types accepted, from lib: {r,g,b,a}, color of lines and opacity, from 0 to 1. Defaul value is {0.95, 0.95, 0.32, 1}
frequency = 0.125, -- frequency, set to negative to inverse direction of rotation. Default value is 0.125;
key = key or "", -- key of glow, allows for multiple glows on one frame;
}
else
options.glowType = "button"
end
Plater.StartGlow(frame, options.color, options, options.key)
end
-- creates an ants glow effect
function Plater.StartAntsGlow(frame, color, options, key)
-- type "ants"
if not options then
options = {
glowType = "ants",
color = color,
N = 4, -- number of particle groups. Each group contains 4 particles. Defaul value is 4;
frequency = 0.125, -- frequency, set to negative to inverse direction of rotation. Default value is 0.125;
scale = 1, -- scale of particles
xOffset = 0,
yOffset = 0, -- offset of glow relative to region border;
key = key or "", -- key of glow, allows for multiple glows on one frame;
}
else
options.glowType = "ants"
end
Plater.StartGlow(frame, options.color, options, options.key)
end
-- creates a pixel glow effect
function Plater.StartPixelGlow(frame, color, options, key)
-- type "pixel"
if not options then
options = {
glowType = "pixel",
color = color, -- all plater color types accepted, from lib: {r,g,b,a}, color of lines and opacity, from 0 to 1. Defaul value is {0.95, 0.95, 0.32, 1}
N = 8, -- number of lines. Defaul value is 8;
frequency = 0.25, -- frequency, set to negative to inverse direction of rotation. Default value is 0.25;
--length = 4, -- length of lines. Default value depends on region size and number of lines;
th = 2, -- thickness of lines. Default value is 2;
xOffset = 0,
yOffset = 0, -- offset of glow relative to region border;
border = false, -- set to true to create border under lines;
key = key or "", -- key of glow, allows for multiple glows on one frame;
}
else
options.glowType = "pixel"
end
Plater.StartGlow(frame, options.color, options, options.key)
end
-- stop LibCustomGlow effects on the frame, if existing
-- if glowType (and key) are given, stop one glow. if not, stop all.
function Plater.StopGlow(frame, glowType, key)
if not frame then return end
if not frame.__PlaterGlowFrame then return end
if glowType then
if glowType == "button" then
LCG.ButtonGlow_Stop(frame.__PlaterGlowFrame, key or "")
elseif glowType == "pixel" then
LCG.PixelGlow_Stop(frame.__PlaterGlowFrame, key or "")
elseif glowType == "ants" then
LCG.AutoCastGlow_Stop(frame.__PlaterGlowFrame, key or "")
end
else
LCG.ButtonGlow_Stop(frame.__PlaterGlowFrame, key or "")
LCG.PixelGlow_Stop(frame.__PlaterGlowFrame, key or "")
LCG.AutoCastGlow_Stop(frame.__PlaterGlowFrame, key or "")
end
end
-- stop a button glow
function Plater.StopButtonGlow(frame, key)
Plater.StopGlow(frame, "button", key)
end
-- stop a button glow
function Plater.StopPixelGlow(frame, key)
Plater.StopGlow(frame, "pixel", key)
end
-- stop an ants glow
function Plater.StopAntsGlow(frame, key)
Plater.StopGlow(frame, "ants", key)
end
--create a glow around an icon
function Plater.CreateIconGlow (frame, color)
local f = Plater:CreateGlowOverlay (frame, color, color)
return f
end
--create a glow around the healthbar or castbar frame
function Plater.CreateNameplateGlow (frame, color, left, right, top, bottom)
local antTable = {
Throttle = 0.025,
AmountParts = 15,
TexturePartsWidth = 167.4,
TexturePartsHeight = 83.6,
TextureWidth = 512,
TextureHeight = 512,
BlendMode = "ADD",
Color = color,
Texture = [[Interface\AddOns\Plater\images\ants_rectangle]],
}
--> ants
local f = DF:CreateAnts (frame, antTable, -27 + (left or 0), 25 + (right or 0), 5 + (top or 0), -7 + (bottom or 0))
f:SetFrameLevel (frame:GetFrameLevel() + 1)
f:SetAlpha (ALPHA_BLEND_AMOUNT - 0.249845)
--> glow
local glow = f:CreateTexture (nil, "background")
glow:SetTexture ([[Interface\AddOns\Plater\images\nameplate_glow]])
PixelUtil.SetPoint (glow, "center", frame, "center", 0, 0)
glow:SetSize (frame:GetWidth() + frame:GetWidth()/2.3, 36)
glow:SetBlendMode ("ADD")
glow:SetVertexColor (DF:ParseColors (color or "white"))
glow:SetAlpha (ALPHA_BLEND_AMOUNT)
glow.GlowTexture = glow
return f
end
function Plater.OnPlayCustomFlashAnimation (animationHub)
animationHub:GetParent():Show()
animationHub.Texture:Show()
--animationHub.Texture:Show()
end
function Plater.OnStopCustomFlashAnimation (animationHub)
animationHub:GetParent():Hide()
animationHub.Texture:Hide()
end
function Plater.UpdateCustomFlashAnimation (animationHub, duration, r, g, b)
for i = 1, #animationHub.AllAnimations do
if (duration) then
animationHub.AllAnimations [i]:SetDuration (duration)
end
if (r) then
r, g, b = DF:ParseColors (r, g, b)
animationHub.Texture:SetColorTexture (r, g, b)
end
end
end
--creates a flash, call returnedValue:Play() to flash
function Plater.CreateFlash (frame, duration, amount, r, g, b, a)
--defaults
duration = duration or 0.25
amount = amount or 1
if (not r) then
r, g, b, a = 1, 1, 1, 1
else
r, g, b, a = DF:ParseColors (r, g, b, a)
end
--create the flash frame
local f = CreateFrame ("frame", "PlaterFlashAnimationFrame".. math.random (1, 100000000), frame, BackdropTemplateMixin and "BackdropTemplate")
f:SetFrameLevel (frame:GetFrameLevel()+1)
f:SetAllPoints()
f:Hide()
--create the flash texture
local t = f:CreateTexture ("PlaterFlashAnimationTexture".. math.random (1, 100000000), "artwork")
t:SetColorTexture (r, g, b, a)
t:SetAllPoints()
t:SetBlendMode ("ADD")
t:Hide()
--create the flash animation
local animationHub = DF:CreateAnimationHub (f, Plater.OnPlayCustomFlashAnimation, Plater.OnStopCustomFlashAnimation)
animationHub.AllAnimations = {}
animationHub.Parent = f
animationHub.Texture = t
animationHub.Amount = amount
animationHub.UpdateDurationAndColor = Plater.UpdateCustomFlashAnimation
for i = 1, amount * 2, 2 do
local fadeIn = DF:CreateAnimation (animationHub, "ALPHA", i, duration, 0, 1)
local fadeOut = DF:CreateAnimation (animationHub, "ALPHA", i + 1, duration, 1, 0)
tinsert (animationHub.AllAnimations, fadeIn)
tinsert (animationHub.AllAnimations, fadeOut)
end
return animationHub
end
--called to undo a color modification
function Plater.RefreshNameplateColor (unitFrame)
if (unitFrame.unit) then
if (Plater.IsUnitTapDenied (unitFrame.unit)) then
Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, unpack (Plater.db.profile.tap_denied_color))
else
if (InCombatLockdown()) then
local unitReaction = unitFrame.PlateFrame [MEMBER_REACTION]
if (unitReaction == 4 and not unitFrame.InCombat) then
Plater.FindAndSetNameplateColor (unitFrame, true)
elseif (DB_AGGRO_CHANGE_HEALTHBAR_COLOR and unitFrame.CanCheckAggro and unitReaction <= 4) then
Plater.UpdateNameplateThread (unitFrame)
else
Plater.FindAndSetNameplateColor (unitFrame)
end
else
Plater.FindAndSetNameplateColor (unitFrame)
end
end
end
end
--modify the color of the health bar
function Plater.SetNameplateColor (unitFrame, r, g, b, a)
if (unitFrame.unit) then
if (not r) then
Plater.RefreshNameplateColor (unitFrame)
else
r, g, b, a = DF:ParseColors (r, g, b, a)
return Plater.ChangeHealthBarColor_Internal (unitFrame.healthBar, r, g, b, a)
end
end
end
--set a temporarly size for the healthbar
--this value is reset when the nameplate is added to the screen
function Plater.SetNameplateSize (unitFrame, width, height)
unitFrame.customHealthBarWidth = width
unitFrame.customHealthBarHeight = height
Plater.UpdatePlateSize (unitFrame.PlateFrame)
end
--modify the color of the cast bar
function Plater.SetCastBarColor (unitFrame, r, g, b)
if (unitFrame.unit) then
if (not r) then
--refresh the castbar color (the framework adjust the cast bar color)
unitFrame.castBar:UpdateCastColor()
else
--framework accepts SetColor, it does parse the color within the call
return unitFrame.castBar:SetColor (r, g, b)
end
end
end
--set a temporarly size for the castbar
--this value is reset when the nameplate is added to the screen
function Plater.SetCastBarSize (unitFrame, width, height)
unitFrame.customCastBarWidth = width
unitFrame.customCastBarHeight = height
Plater.UpdatePlateSize (unitFrame.PlateFrame)
end
--same thing as the two above but for the power bar
function Plater.SetPowerBarSize (unitFrame, width, height)
unitFrame.customPowerBarWidth = width
unitFrame.customPowerBarHeight = height
Plater.UpdatePlateSize (unitFrame.PlateFrame)
end
--changes the border color, this call is for the API, can be called from external sources
function Plater.SetBorderColor (self, r, g, b, a) --self = unitFrame
if (not r) then
self.customBorderColor = nil
Plater.UpdateBorderColor (self)
return
end
r, g, b, a = DF:ParseColors (r, g, b, a)
--UpdateBorderColor will use the value set on customBorderColor member if any
self.customBorderColor = {r, g, b, a}
Plater.UpdateBorderColor (self)
end
--flashes on the health bar border
function Plater.FlashNameplateBorder (unitFrame, duration)
if (not unitFrame.healthBar.PlayHealthFlash) then
Plater.CreateHealthFlashFrame (unitFrame.PlateFrame)
end
unitFrame.healthBar.canHealthFlash = true
unitFrame.healthBar.PlayHealthFlash (duration)
end
--flashes the unitFrame body
function Plater.FlashNameplateBody (unitFrame, text, duration)
--> sending true to ignore cooldown
unitFrame.PlateFrame.PlayBodyFlash (text, duration, true)
end
--return if the player is in combat
function Plater.IsInCombat()
return InCombatLockdown() or PLAYER_IN_COMBAT
end
--return true if the unit is in the tank role
function Plater.IsUnitTank (unitFrame)
return TANK_CACHE [unitFrame [MEMBER_NAME]] or TANK_CACHE [unitFrame [MEMBER_NAMELOWER]]
end
--check the role and the role of the specialization to return if the player is in a tank role
function Plater.IsPlayerTank()
return IsPlayerEffectivelyTank()
end
--return the table where tanks is stored
--has the unit name as the key and true as value
function Plater.GetTanks()
return TANK_CACHE
end
--change the color of the cast bar
function Plater.SetCastBarBorderColor (castBar, r, g, b, a)
--check if the frame passed was the unitFrame instead of the castbar it self
if (castBar.castBar) then
castBar = castBar.castBar
end
if (not r) then
castBar.FrameOverlay:SetBackdropBorderColor (0, 0, 0, 0)
return
end
r, g, b, a = DF:ParseColors (r, g, b, a)
castBar.FrameOverlay:SetBackdropBorderColor (r, g, b, a)
end
--show the health bar, the health bar is shown by default, use to undo HideHealthBar() call
function Plater.ShowHealthBar (unitFrame)
unitFrame.healthBar:Show()
unitFrame.BuffFrame:Show()
unitFrame.BuffFrame2:Show()
unitFrame.ExtraIconFrame:Show()
unitFrame.healthBar.unitName:Show()
unitFrame.PlateFrame.IsFriendlyPlayerWithoutHealthBar = false
unitFrame.PlateFrame.IsNpcWithoutHealthBar = false
unitFrame.ActorNameSpecial:Hide()
unitFrame.ActorTitleSpecial:Hide()
Plater.UpdatePlateText (unitFrame.PlateFrame, DB_PLATE_CONFIG [unitFrame.ActorType], true)
end
--hide the health bar and show the secondary unit name and title text strings
function Plater.HideHealthBar (unitFrame, showPlayerName, showNameNpc)
unitFrame.healthBar:Hide()
unitFrame.BuffFrame:Hide()
unitFrame.BuffFrame2:Hide()
unitFrame.ExtraIconFrame:Hide()
unitFrame.healthBar.unitName:Hide()
showPlayerName = showPlayerName and (unitFrame.ActorType == ACTORTYPE_FRIENDLY_PLAYER or unitFrame.ActorType == ACTORTYPE_ENEMY_PLAYER)
showNameNpc = showNameNpc and (unitFrame.ActorType == ACTORTYPE_FRIENDLY_NPC or unitFrame.ActorType == ACTORTYPE_ENEMY_NPC)
unitFrame.PlateFrame.IsFriendlyPlayerWithoutHealthBar = showPlayerName
unitFrame.PlateFrame.IsNpcWithoutHealthBar = showNameNpc
if (showPlayerName) then
Plater.UpdatePlateText (unitFrame.PlateFrame, DB_PLATE_CONFIG [unitFrame.ActorType], true)
elseif (showNameNpc) then
Plater.UpdatePlateText (unitFrame.PlateFrame, DB_PLATE_CONFIG [unitFrame.ActorType], true)
end
end
--forces a range check regardless of the user options and only changes the member_range flag, no alpha changes
--if the spell name is passed, it just return the result without modifying the nameplate attributes
function Plater.NameplateInRange (unitFrame, spellName)
if (spellName) then
return IsSpellInRange (spellName, unitFrame [MEMBER_UNITID]) == 1
else
local rangeChecker
if unitFrame [MEMBER_REACTION] < 5 then
rangeChecker = Plater.RangeCheckFunctionEnemy
else
rangeChecker = Plater.RangeCheckFunctionFriendly
end
if (rangeChecker and rangeChecker (unitFrame [MEMBER_UNITID])) then
unitFrame [MEMBER_RANGE] = true
return true
else
unitFrame [MEMBER_RANGE] = false
return false
end
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> scripting ~scripting
function Plater.ExportProfileToString()
local profile = Plater.db.profile
--store current profile name
profile.profile_name = Plater.db:GetCurrentProfile()
--temp store the animations on another table
local spellAnimations = profile.spell_animation_list
--remove the animation list from the profile
profile.spell_animation_list = nil
--temp store trashcans
local trashcanScripts = profile.script_data_trash
local trashcanHooks = profile.hook_data_trash
--clear the trash can
profile.script_data_trash = {}
profile.hook_data_trash = {}
--cleanup mods HooksTemp (for good)
for i = #Plater.db.profile.hook_data, 1, -1 do
local scriptObject = Plater.db.profile.hook_data [i]
scriptObject.HooksTemp = {}
end
--convert the profile to string
local data = Plater.CompressData (profile, "print")
if (not data) then
Plater:Msg ("failed to compress the profile")
end
--restore the profile animations and trashcan
profile.spell_animation_list = spellAnimations
profile.script_data_trash = trashcanScripts
profile.hook_data_trash = trashcanHooks
--reset profile_name
profile.profile_name = nil
return data
end
--scripts mixin - these functions are mixed in with castbar, unitframe and aura icons
Plater.ScriptMetaFunctions = {
--get the table which stores all script information for the widget
--self is the affected widget, e.g. icon frame, unitframe, castbar progressbar
ScriptGetContainer = function(self)
local infoTable = self.ScriptInfoTable
if (not infoTable) then
self.ScriptInfoTable = {}
return self.ScriptInfoTable
else
return infoTable
end
end,
--get the table which stores the information for a single script
--run for hooks only
HookGetInfo = function (self, globalScriptObject, scriptContainer)
scriptContainer = scriptContainer or self:ScriptGetContainer()
--using the memory address of the original scriptObject from db.profile as the map key
local scriptInfo = scriptContainer[globalScriptObject.DBScriptObject.scriptId]
if (
(not scriptInfo) or
(scriptInfo.GlobalScriptObject.NeedHotReload) or
(scriptInfo.GlobalScriptObject.Build and scriptInfo.GlobalScriptObject.Build < PLATER_HOOK_BUILD)
) then
local forceHotReload = scriptInfo and scriptInfo.GlobalScriptObject.NeedHotReload
--keep script info and update as needed
scriptInfo = scriptInfo or {
GlobalScriptObject = globalScriptObject,
HotReload = -1,
Env = {},
IsActive = false
}
scriptInfo.GlobalScriptObject = globalScriptObject
scriptInfo.GlobalScriptObject.Build = PLATER_HOOK_BUILD
scriptInfo.GlobalScriptObject.NeedHotReload = false
if (globalScriptObject.HasConstructor and (not scriptInfo.Initialized or forceHotReload)) then
local modName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Mod-RunHooks", modName, "Constructor")
local okay, errortext = pcall (globalScriptObject.Constructor, self, self.displayedUnit or self.unit or self:GetParent()[MEMBER_UNITID], self, scriptInfo.Env, PLATER_GLOBAL_MOD_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Mod-RunHooks", modName, "Constructor")
if (not okay) then
Plater:Msg ("Mod |cFFAAAA22" .. modName .. "|r Constructor error: " .. errortext)
end
scriptInfo.Initialized = true
end
scriptContainer [globalScriptObject.DBScriptObject.scriptId] = scriptInfo
end
--always overwriting the globalScriptObject fixes the issue for not updating the script after saving it but only for OnShow OnUpdate and OnHide
scriptInfo.GlobalScriptObject = globalScriptObject
return scriptInfo
end,
--get the table which stores the information for a single script
--run for scripts only
ScriptGetInfo = function (self, globalScriptObject, scriptContainer)
scriptContainer = scriptContainer or self:ScriptGetContainer()
--using the memory address of the original scriptObject from db.profile as the map key
local scriptInfo = scriptContainer[globalScriptObject.DBScriptObject.scriptId]
local lastUpdateTime = globalScriptObject.LastUpdateTime or 0
if (not scriptInfo or scriptInfo.LastUpdateTime <= lastUpdateTime) then
--create script info
if (not scriptInfo) then
scriptInfo = {
--GlobalScriptObject = globalScriptObject, --is set below
HotReload = -1, --deprecated
Env = {},
IsActive = false
}
end
scriptInfo.LastUpdateTime = GetTime()
--scriptInfo.GlobalScriptObject = globalScriptObject
scriptContainer [globalScriptObject.DBScriptObject.scriptId] = scriptInfo
end
--always overwriting the globalScriptObject fixes the issue for not updating the script after saving it but only for OnShow OnUpdate and OnHide
scriptInfo.GlobalScriptObject = globalScriptObject
return scriptInfo
end,
--if the global script had an update or if the first time running this script on this widget, run the constructor
ScriptHotReload = function (self, scriptInfo)
--dispatch constructor if necessary
if (scriptInfo.HotReload < scriptInfo.GlobalScriptObject.HotReload) then
--update the hotreload state
scriptInfo.HotReload = scriptInfo.GlobalScriptObject.HotReload
--there's some bug with the global env becoming nil after saving a script
--print(scriptInfo.GlobalScriptObject.DBScriptObject.Name, PLATER_GLOBAL_SCRIPT_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
--dispatch the constructor
local unitFrame = self.unitFrame or self
local scriptName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Scripts", scriptName, "Constructor")
local okay, errortext = pcall (scriptInfo.GlobalScriptObject ["ConstructorCode"], self, unitFrame.displayedUnit or unitFrame.unit or unitFrame.PlateFrame[MEMBER_UNITID], unitFrame, scriptInfo.Env, PLATER_GLOBAL_SCRIPT_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Scripts", scriptName, "Constructor")
if (not okay) then
Plater:Msg ("Script |cFFAAAA22" .. scriptName .. "|r Constructor error: " .. errortext)
end
end
end,
--run the update script, called when the castbar updates, from within the tick and from the aura file on the AddAura()
ScriptRunOnUpdate = function (self, scriptInfo)
if (not scriptInfo.IsActive) then
--run constructor
self:ScriptHotReload (scriptInfo)
--run on show
self:ScriptRunOnShow (scriptInfo)
end
--dispatch the runtime script
local unitFrame = self.unitFrame or self
local scriptName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Scripts", scriptName, "OnUpdate")
local okay, errortext = pcall (scriptInfo.GlobalScriptObject ["UpdateCode"], self, unitFrame.displayedUnit or unitFrame.unit or unitFrame.PlateFrame[MEMBER_UNITID], unitFrame, scriptInfo.Env, PLATER_GLOBAL_SCRIPT_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Scripts", scriptName, "OnUpdate")
if (not okay) then
Plater:Msg ("Script |cFFAAAA22" .. scriptName .. "|r OnUpdate error: " .. errortext)
end
end,
--run the OnShow script
ScriptRunOnShow = function(self, scriptInfo)
--dispatch the on show script
local unitFrame = self.unitFrame or self
scriptInfo.Env._DefaultWidth = self:GetWidth()
scriptInfo.Env._DefaultHeight = self:GetHeight()
local scriptName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Scripts", scriptName, "OnShow")
local func = scriptInfo.GlobalScriptObject["OnShowCode"]
local okay, errortext = pcall(func, self, unitFrame.displayedUnit or unitFrame.unit or unitFrame.PlateFrame[MEMBER_UNITID], unitFrame, scriptInfo.Env, PLATER_GLOBAL_SCRIPT_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Scripts", scriptName, "OnShow")
if (not okay) then
Plater:Msg ("Script |cFFAAAA22" .. scriptName .. "|r OnShow error: " .. errortext)
end
scriptInfo.IsActive = true
self.ScriptKey = scriptInfo.GlobalScriptObject.ScriptKey
end,
--run the OnHide script
ScriptRunOnHide = function (self, scriptInfo)
--dispatch the on hide script
local unitFrame = self.unitFrame or self
local scriptName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Scripts", scriptName, "OnHide")
local okay, errortext = pcall (scriptInfo.GlobalScriptObject ["OnHideCode"], self, unitFrame.displayedUnit or unitFrame.unit or unitFrame.PlateFrame[MEMBER_UNITID], unitFrame, scriptInfo.Env, PLATER_GLOBAL_SCRIPT_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Scripts", scriptName, "OnHide")
if (not okay) then
Plater:Msg ("Script |cFFAAAA22" .. scriptName .. "|r OnHide error: " .. errortext)
end
scriptInfo.IsActive = false
self.ScriptKey = nil
end,
--run the Initialization script, called during compile time
ScriptRunInitialization = function (globalScriptObject)
--dispatch the init script
local scriptName = globalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Scripts", scriptName, "Initialization")
local okay, errortext = pcall (globalScriptObject ["Initialization"], PLATER_GLOBAL_SCRIPT_ENV [globalScriptObject.DBScriptObject.scriptId])
Plater.EndLogPerformance("Scripts", scriptName, "Initialization")
if (not okay) then
Plater:Msg ("Script |cFFAAAA22" .. scriptName .. "|r Initialization error: " .. errortext)
end
end,
ScriptRunCommMessageHook = function(globalScriptObject, hookName, source, ...)
local modName = globalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Mod-RunHooks", modName, hook)
local okay, errortext = pcall (globalScriptObject [hookName], PLATER_GLOBAL_MOD_ENV [globalScriptObject.DBScriptObject.scriptId], source, ...)
Plater.EndLogPerformance("Mod-RunHooks", modName, hookName)
if (not okay) then
Plater:Msg ("Mod |cFFAAAA22" .. modName .. "|r code for |cFFBB8800" .. hookName .. "|r error: " .. errortext)
end
end,
ScriptRunHook = function (self, scriptInfo, hookName, frame, ...)
--dispatch a hook for the script
--at the moment, self is always the unit frame
local modName = scriptInfo.GlobalScriptObject.DBScriptObject.Name
Plater.StartLogPerformance("Mod-RunHooks", modName, hookName)
local okay, errortext = pcall (scriptInfo.GlobalScriptObject [hookName], frame or self, self.displayedUnit, self, scriptInfo.Env, PLATER_GLOBAL_MOD_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId], ...)
Plater.EndLogPerformance("Mod-RunHooks", modName, hookName)
if (not okay) then
Plater:Msg ("Mod |cFFAAAA22" .. modName .. "|r code for |cFFBB8800" .. hookName .. "|r error: " .. errortext)
end
end,
--run only once without attach to the script or hook
ScriptRunNoAttach = function (hookInfo, hookName)
local func = hookInfo [hookName]
local modName = hookInfo.DBScriptObject.Name
Plater.StartLogPerformance("Mod-RunHooks", modName, " -NoAttach- " .. hookName)
local okay, errortext = pcall (func, PLATER_GLOBAL_MOD_ENV [hookInfo.DBScriptObject.scriptId])
Plater.EndLogPerformance("Mod-RunHooks", modName, " -NoAttach- " .. hookName)
if (not okay) then
Plater:Msg ("Mod |cFFAAAA22" .. modName .. "|r code for |cFFBB8800" .. hookName .. "|r error: " .. errortext)
end
end,
--run when the widget hides
OnHideWidget = function(self)
--check if can quickly quit (if there's no script container for the nameplate)
if (self.ScriptInfoTable) then
local triggerCacheTable
if (self.IsAuraIcon) then
triggerCacheTable = SCRIPT_AURA_TRIGGER_CACHE
elseif (self.IsCastBar) then
triggerCacheTable = SCRIPT_CASTBAR_TRIGGER_CACHE
elseif (self.IsUnitNameplate) then
triggerCacheTable = SCRIPT_UNIT_TRIGGER_CACHE
end
--ScriptKey holds the trigger of the script currently running
local globalScriptObject = triggerCacheTable[self.ScriptKey]
--does the aura has a custom script?
if (globalScriptObject) then
--does the aura icon has a table with script information?
local scriptContainer = self:ScriptGetContainer() --return self.ScriptInfoTable
if (scriptContainer) then
local scriptInfo = self:ScriptGetInfo(globalScriptObject, scriptContainer)
if (scriptInfo and scriptInfo.IsActive) then
self:ScriptRunOnHide(scriptInfo)
end
end
end
end
--> hooks, check which kind of widget this is and then run the appropriate hook
if (self.IsCastBar) then
if (HOOK_CAST_STOP.ScriptAmount > 0) then
for i = 1, HOOK_CAST_STOP.ScriptAmount do
local globalScriptObject = HOOK_CAST_STOP [i]
local unitFrame = self.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Cast Stop")
--run
unitFrame:ScriptRunHook (scriptInfo, "Cast Stop", self)
end
end
end
end,
--stop a running script by the trigger ID
--this is used when deleting a script or disabling it
KillScript = function(self, triggerID)
local triggerCacheTable
if (self.IsAuraIcon) then
triggerCacheTable = SCRIPT_AURA_TRIGGER_CACHE
triggerID = GetSpellInfo(triggerID)
elseif (self.IsCastBar) then
triggerCacheTable = SCRIPT_CASTBAR_TRIGGER_CACHE
triggerID = GetSpellInfo(triggerID)
elseif (self.IsUnitNameplate) then
triggerCacheTable = SCRIPT_UNIT_TRIGGER_CACHE
end
if (self.ScriptKey and self.ScriptKey == triggerID) then
local globalScriptObject = triggerCacheTable[triggerID]
if (globalScriptObject) then
local scriptContainer = self:ScriptGetContainer()
if (scriptContainer) then
local scriptInfo = self:ScriptGetInfo (globalScriptObject, scriptContainer)
if (scriptInfo and scriptInfo.IsActive) then
self:ScriptRunOnHide (scriptInfo)
end
end
end
end
end,
IsProtected = function (self)
-- assume that nameplates are always protected since 8.2
if self then
if self.PlateFrame then
return self.PlateFrame:IsProtected()
end
end
return false
end,
}
function Plater.GetAllScripts (scriptType)
if (scriptType == "script") then
return Plater.db.profile.script_data
elseif (scriptType == "hook") then
return Plater.db.profile.hook_data
end
end
function Plater.GetAllScriptsAsPrioSortedCopy (scriptType)
local scripts
local seeds = {}
local function copyHookTables (t1, t2)
for key, value in pairs (t2) do
if (key ~= "__index") then
if (type (value) == "table") then
t1 [key] = t1 [key] or {}
-- add hashID to the hook-data
t1 [key].scriptId = tostring(value) -- keep this internal hashed
--create UID if it does not exist --TODO maybe not needed in the future
local uID = value.UID
if not uID then
local seed = tonumber(value.Time) or time()
while seeds[seed] do
seed = math.random(value.Time)
end
seeds[seed] = true
uID = Plater.CreateUniqueIdentifier(seed)
--value.UID = uID -- TODO permanently set UID
t1 [key].UID = uID -- TODO temporary volatile for now
end
DF.table.copy (t1 [key], t2 [key])
else
t1 [key] = value
end
end
end
return t1
end
if (scriptType == "script") then
--cleanup first
for scriptId, scriptObject in ipairs (Plater.db.profile.script_data) do
scriptObject.scriptId = nil
end
--copy
scripts = copyHookTables({}, Plater.db.profile.script_data)
elseif (scriptType == "hook") then
--cleanup first
for scriptId, scriptObject in ipairs (Plater.db.profile.hook_data) do
scriptObject.scriptId = nil
end
--copy
scripts = copyHookTables({}, Plater.db.profile.hook_data)
end
local function round(x)
if not x then return nil end
return (x + 0.5 - (x + 0.5) % 1)
end
if scripts then
table.sort(scripts, function(a,b)
if a and not b then
return false
elseif not a and b then
return true
else
return round(a.Prio or 99) > round(b.Prio or 99)
end
return false
end)
end
--table.foreach(scripts, function(index, self) if self then print(self.Prio, self.Name) else print("not self") end end)
return scripts
end
--compile all scripts
function Plater.CompileAllScripts (scriptType, noHotReload)
if (scriptType == "script") then
for scriptId, scriptObject in ipairs (Plater.GetAllScriptsAsPrioSortedCopy ("script")) do
if (scriptObject.Enabled) then
Plater.CompileScript (scriptObject, noHotReload)
end
end
elseif (scriptType == "hook") then
--get all hook scripts from the profile database
for scriptId, scriptObject in ipairs (Plater.GetAllScriptsAsPrioSortedCopy ("hook")) do
Plater.CompileHook (scriptObject, noHotReload)
end
end
end
--recompile a single scriptObject deleting the global environment
function Plater.RecompileScript(scriptObject)
if not scriptObject.scriptId then
scriptObject.scriptId = tostring(scriptObject)
end
local scriptType = Plater.GetScriptType(scriptObject)
if (scriptType == "script") then
Plater.CompileScript(scriptObject)
elseif (scriptType == "hook") then
Plater.CompileHook(scriptObject)
end
end
--when a script object get disabled, need to clear all compiled scripts in the cache and recompile than again
--this other scripts that uses the same trigger name get activated
-- ~scripts
Plater.CoreVersion = 1
--internal Plater functions
--in the list/false: can't be overwritten; true->can't be read at all
local privateFunctions = {
["Plater"] = {
["CompileAllScripts"] = true,
["GetAllScripts"] = true,
["GetAllScriptsAsPrioSortedCopy"] = true,
["ScriptMetaFunctions"] = true,
["DecompressData"] = true,
["CompressData"] = true,
["ExportProfileToString"] = true,
["WipeAndRecompileAllScripts"] = true,
["AllHookGlobalContainers"] = true,
["WipeHookContainers"] = true,
["GetContainerForHook"] = true,
["CurrentlyLoadedHooks"] = true,
["RunDestructorForHook"] = true,
["CompileHook"] = true,
["CompileScript"] = true,
["CheckScriptTriggerOverlap"] = true,
["GetScriptObject"] = true,
["GetScriptDB"] = true,
["GetScriptType"] = true,
["GetDecodedScriptType"] = true,
["ImportScriptsFromLibrary"] = true,
["ImportScriptString"] = true,
["AddScript"] = true,
["BuildScriptObjectFromIndexTable"] = true,
["DecodeImportedString"] = true,
["PrepareTableToExport"] = true,
["ScriptReceivedFromGroup"] = true,
["ExportScriptToGroup"] = true,
["ShowImportScriptConfirmation"] = true,
["DispatchTalentUpdateHookEvent "] = true,
["ScheduleHookForCombat"] = true,
["ScheduleRunFunctionForEvent"] = true,
["RunFunctionForEvent"] = true,
["EventHandler"] = true,
["RegisterRefreshDBCallback"] = true,
["FireRefreshDBCallback"] = true,
["RefreshDBUpvalues"] = false,
["RefreshDBLists"] = false,
["UpdateAuraCache"] = false,
["ApplyPatches"] = true,
["RefreshConfig"] = true,
["RefreshConfigProfileChanged"] = true,
["SaveConsoleVariables"] = true,
["GetSettings"] = true,
["CodeTypeNames"] = true,
["HookScripts"] = true,
["HookScriptsDesc"] = true,
["IncreaseHookBuildID"] = true,
["IncreaseRefreshID"] = true,
["SpecList"] = true,
["UpdateSettingsCache"] = true,
["ActorTypeSettingsCache"] = true,
["RunScheduledUpdate"] = true,
["ScheduleUpdateForNameplate"] = true,
["EventHandlerFrame"] = true,
["OnInit"] = true,
["HookLoadCallback"] = true,
["CheckFirstRun"] = true,
["CommHandler"] = true,
["CommReceived"] = true,
["GetAllShownPlates"] = false,
["GetHashKey"] = false,
["IsShowingResourcesOnTarget"] = false,
["OnRetailNamePlateShow"] = true,
["UpdateSelfPlate"] = true,
["CastBarOnShow_Hook"] = true,
["CastBarOnEvent_Hook"] = true,
["CastBarOnTick_Hook"] = true,
["RefreshAuras"] = true,
["CreateAuraIcon"] = true,
["RefreshColorOverride"] = true,
["ChangeHealthBarColor_Internal"] = true,
["UpdateAllPlates"] = true,
["FullRefreshAllPlates"] = true,
["UpdatePlateClickSpace"] = true,
["EveryFrameFPSCheck"] = true,
["NameplateTick"] = true,
["OnPlayerTargetChanged"] = true,
["UpdateTarget"] = true,
["UpdatePlateText"] = true,
["CheckLifePercentText"] = true,
["UpdateAllNames"] = true,
--["UpdateLevelTextAndColor"] = true,
["UpdatePlateFrame"] = true,
["ForceChangeBorderColor"] = true,
["UpdatePlateBorders"] = true,
["UpdateRaidMarkersOnAllNameplates"] = true,
["RefreshAutoToggle"] = true,
["ParseHealthSettingForPlayer"] = true,
["CreateAlphaAnimation"] = true,
["CreateHighlightNameplate"] = true,
["CreateHealthFlashFrame"] = true,
["CreateAggroFlashFrame"] = true,
["CreateScaleAnimation"] = true,
["DoNameplateAnimation"] = true,
["RefreshIsEditingAnimations"] = true,
["IsNpcInIgnoreList"] = true,
["CanChangePlateSize"] = true,
["RefreshOmniCCGroup"] = true,
["CreatePlaterButtonAtInterfaceOptions"] = true,
["SetCVarsOnFirstRun"] = true,
["GetActorSubName"] = false,
["QuestLogUpdated"] = true,
["GetNpcIDFromGUID"] = false,
["GetNpcID"] = false,
["ForceTickOnAllNameplates"] = true,
["UpdateUIParentScale"] = true,
["SetNameplateScale"] = false,
["UpdateUIParentLevels"] = true,
["UpdateUIParentTargetLevels"] = true,
["RefreshTankCache"] = true,
["ToggleThreatColorMode"] = false,
["ForceFindPetOwner"] = true,
["UpdateBgPlayerRoleCache"] = false,
["GetSpecIconForUnitFromBG"] = false,
["GetUnitBGInfo"] = false,
["GetSpecIcon"] = false,
["InitLDB"] = true,
["APIList"] = true,
["FrameworkList"] = true,
["UnitFrameMembers"] = true,
["NameplateComponents"] = true,
["UpdateOptionsTabUpdateState"] = true,
["EnableProfiling"] = false,
["DisableProfiling"] = false,
["StartLogPerformance"] = false,
["EndLogPerformance"] = false,
["StartLogPerformanceCore"] = false,
["StartLogPerformanceCore"] = false,
["EndLogPerformanceCore"] = false,
["DumpPerformance"] = true,
["ShowPerfData"] = true,
["StoreEventLogData"] = true,
["CheckOptionsTab"] = true,
["OpenOptionsPanel"] = true,
["TriggerDefaultMembers"] = true,
["OpenCopyUrlDialog"] = true,
["CreateOptionTableForScriptObject"] = true,
["HasWagoUpdate"] = true,
["GetWagoUpdateDataFromCompanion"] = true,
["CheckWagoUpdates"] = true,
["AddCompanionData"] = true,
["CompanionDataSlugs"] = true,
["GetVersionInfo"] = false,
["versionString"] = false,
["fullVersionInfo"] = false,
["DispatchCommReceivedMessageHookEvent"] = true,
["DispatchCommSendMessageHookEvents"] = true,
["VerifyScriptIdForComm"] = true,
["MessageReceivedFromScript"] = true,
["CreateUniqueIdentifier"] = false,
["GetScriptFromUID"] = true,
["SendCommMessage"] = true,
["CreateCommHeader"] = true,
["SendComm"] = false,
["FPSData"] = {
["startTime"] = true,
["frames"] = true,
["platesUpdatedThisFrame"] = true,
["platesToUpdatePerFrame"] = true,
["curFPS"] = false,
},
["UnitReaction"] = {
["UNITREACTION_HOSTILE"] = false,
["UNITREACTION_NEUTRAL"] = false,
["UNITREACTION_FRIENDLY"] = false,
},
["Export_NpcColors"] = true,
["Export_CastColors"] = true,
["ScriptAura"] = true,
["ScriptCastBar"] = true,
["ScriptUnit"] = true,
["RemoveFromAuraUpdate"] = true,
["AddToAuraUpdate"] = true,
["AnchorSides"] = false,
["SetAnchor"] = false,
["RunScriptTriggersForAuraIcons"] = true,
["AddAura"] = true,
["GetAuraIcon"] = true,
["HideNonUsedAuraIcons"] = true,
["AddExtraIcon"] = true,
["ResetAuraContainer"] = true,
["TrackSpecificAuras"] = true,
["UpdateAuras_Manual"] = true,
["UpdateAuras_Automatic"] = true,
["UpdateAuras_Self_Automatic"] = true,
["CreateAuraIcon"] = true,
["PerformanceUnits"] = true,
["ForceBlizzardNameplateUnits"] = true,
["COMM_PLATER_PREFIX"] = true,
["COMM_SCRIPT_GROUP_EXPORTED"] = true,
["COMM_SCRIPT_MSG"] = true,
},
["DetailsFramework"] = {
["SetEnvironment"] = true,
},
["WeakAuras"] = {
["Add"] = true,
["AddMany"] = true,
["Delete"] = true,
["NewAura"] = true,
},
["C_GuildInfo"] = {
["RemoveFromGuild"] = true,
},
--block mail, trades, action house, banks
["C_AuctionHouse"] = true,
["C_Bank"] = true,
["C_GuildBank"] = true,
["SetSendMailMoney"] = true,
["SendMail"] = true,
["SetTradeMoney"] = true,
["AddTradeMoney"] = true,
["PickupTradeMoney"] = true,
["PickupPlayerMoney"] = true,
["AcceptTrade"] = true,
--frames
["BankFrame"] = true,
["TradeFrame"] = true,
["GuildBankFrame"] = true,
["MailFrame"] = true,
["EnumerateFrames"] = true,
--block run code inside code
["RunScript"] = true,
["securecall"] = true,
["getfenv"] = true,
["getfenv"] = true,
["loadstring"] = true,
["pcall"] = true,
["xpcall"] = true,
["getglobal"] = true,
["setmetatable"] = true,
["DevTools_DumpCommand"] = true,
--avoid creating/running macros
["SetBindingMacro"] = true,
["CreateMacro"] = true,
["EditMacro"] = true,
["hash_SlashCmdList"] = true,
["SlashCmdList"] = true,
["MacroEditBox"] = true,
["ChatEdit_SendText"] = true,
["AreDangerousScriptsAllowed"] = true,
--block guild commands
["GuildDisband"] = true,
["GuildUninvite"] = true,
--other things
["C_GMTicketInfo"] = true,
--deny messing addons with script support
["PlaterDB"] = true,
["PlaterDBChr"] = true,
["_detalhes_global"] = true,
["WeakAurasSaved"] = true,
}
local overrideFunctions = {
["CreateFrame"] = function(frameType, name, parent, template, id)
if template then
template = string.gsub(template, "SecureActionButtonTemplate", "")
template = string.gsub(template, "SecureHandlerClickTemplate", "")
end
return CreateFrame(frameType, name, parent, template, id)
end,
}
--this allows full shadowing on 'Plater' global with the filter above
local function buildShadowTable(privateFunctionsTable, tableKey, shadowTable)
if not privateFunctionsTable then return end
shadowTable = shadowTable or {}
--ViragDevTool_AddData({privateFunctionsTable, tableKey, shadowTable}, "buildShadowTable")
local shadowValuesTable = {}
if tableKey then
shadowTable[tableKey] = {}
shadowTable = shadowTable[tableKey]
end
--ViragDevTool_AddData({tableKey, shadowValuesTable}, "buildShadowTable_tables")
for key, value in pairs(privateFunctionsTable) do
--ViragDevTool_AddData({key, value}, "buildShadowTable_ITER")
if type(value) == "table" then
buildShadowTable(value, key, shadowTable)
else
--ViragDevTool_AddData({key, value}, "buildShadowTable_ADD")
shadowValuesTable [key] = value
end
end
--ViragDevTool_AddData({shadowValuesTable, tableKey}, "buildShadowTable_SET")
setmetatable(shadowTable, {
__index = function (env, key)
--ViragDevTool_AddData({env, key, tableKey, tableKey and _G[tableKey] or _G}, "GET")
if key == "_G" then
return env
elseif overrideFunctions [key] then
return overrideFunctions [key]
elseif shadowValuesTable [key] then -- if true, don't return value
return nil
else
return rawget(tableKey and _G[tableKey] or _G, key)
end
end,
__newindex = function (t, k, v)
--ViragDevTool_AddData({t, k, v, tableKey, tableKey and _G[tableKey] or _G}, "SET")
if shadowValuesTable [k] ~= nil then -- if in the list: don't overwrite
error ("'" .. tableKey .. "." .. k .. "' is protected and may not be overwritten.")
else
rawset(tableKey and _G[tableKey] or _G, k, v)
end
end,
})
--ViragDevTool_AddData({shadowTable}, "buildShadowTable_return")
return shadowTable
end
local ShadowTable = nil
local getShadowTable = function()
if not ShadowTable then
ShadowTable = buildShadowTable(privateFunctions)
end
return ShadowTable
end
local platerModEnvironment = {} -- needed for DF:SetEnvironment to have a common mod/script environment in Plater
local platerModEnvironment2 = getShadowTable()
local function SetPlaterEnvironment(func)
setfenv(func, platerModEnvironment2)
end
function Plater.WipeAndRecompileAllScripts (scriptType, noHotReload)
if (scriptType == "script") then
table.wipe(SCRIPT_AURA_TRIGGER_CACHE)
table.wipe(SCRIPT_CASTBAR_TRIGGER_CACHE)
table.wipe(SCRIPT_UNIT_TRIGGER_CACHE)
Plater.CompileAllScripts (scriptType, noHotReload)
elseif (scriptType == "hook") then
Plater.WipeHookContainers (noHotReload)
Plater.CompileAllScripts (scriptType, noHotReload)
end
end
Plater.AllHookGlobalContainers = {
HOOK_NAMEPLATE_CREATED,
HOOK_NAMEPLATE_ADDED,
HOOK_NAMEPLATE_REMOVED,
HOOK_NAMEPLATE_UPDATED,
HOOK_TARGET_CHANGED,
HOOK_CAST_START,
HOOK_CAST_UPDATE,
HOOK_CAST_STOP,
HOOK_RAID_TARGET,
HOOK_COMBAT_ENTER,
HOOK_COMBAT_LEAVE,
HOOK_NAMEPLATE_CONSTRUCTOR,
HOOK_PLAYER_POWER_UPDATE,
HOOK_PLAYER_TALENT_UPDATE,
HOOK_HEALTH_UPDATE,
HOOK_ZONE_CHANGED,
HOOK_UNITNAME_UPDATE,
HOOK_LOAD_SCREEN,
HOOK_PLAYER_LOGON,
HOOK_MOD_INITIALIZATION,
HOOK_COMM_RECEIVED_MESSAGE,
HOOK_COMM_SEND_MESSAGE,
HOOK_NAMEPLATE_DESTRUCTOR,
}
function Plater.WipeHookContainers (noHotReload)
Plater.IncreaseHookBuildID()
for _, container in ipairs (Plater.AllHookGlobalContainers) do
if (not noHotReload) then
for _, globalScriptObject in ipairs (container) do
globalScriptObject.NeedHotReload = true
end
end
table.wipe (container)
container.ScriptAmount = 0
end
end
function Plater.GetContainerForHook (hookName)
if (hookName == "Initialization") then
return HOOK_MOD_INITIALIZATION
elseif (hookName == "Deinitialization") then
return HOOK_MOD_DEINITIALIZATION
elseif (hookName == "Constructor") then
return HOOK_NAMEPLATE_CONSTRUCTOR
elseif (hookName == "Nameplate Created") then
return HOOK_NAMEPLATE_CREATED
elseif (hookName == "Nameplate Added") then
return HOOK_NAMEPLATE_ADDED
elseif (hookName == "Nameplate Removed") then
return HOOK_NAMEPLATE_REMOVED
elseif (hookName == "Nameplate Updated") then
return HOOK_NAMEPLATE_UPDATED
elseif (hookName == "Target Changed") then
return HOOK_TARGET_CHANGED
elseif (hookName == "Cast Start") then
return HOOK_CAST_START
elseif (hookName == "Cast Update") then
return HOOK_CAST_UPDATE
elseif (hookName == "Cast Stop") then
return HOOK_CAST_STOP
elseif (hookName == "Raid Target") then
return HOOK_RAID_TARGET
elseif (hookName == "Enter Combat") then
return HOOK_COMBAT_ENTER
elseif (hookName == "Leave Combat") then
return HOOK_COMBAT_LEAVE
elseif (hookName == "Player Power Update") then
return HOOK_PLAYER_POWER_UPDATE
elseif (hookName == "Player Talent Update") then
return HOOK_PLAYER_TALENT_UPDATE
elseif (hookName == "Health Update") then
return HOOK_HEALTH_UPDATE
elseif (hookName == "Zone Changed") then
return HOOK_ZONE_CHANGED
elseif (hookName == "Name Updated") then
return HOOK_UNITNAME_UPDATE
elseif (hookName == "Load Screen") then
return HOOK_LOAD_SCREEN
elseif (hookName == "Player Logon") then
return HOOK_PLAYER_LOGON
elseif (hookName == "Receive Comm Message") then
return HOOK_COMM_RECEIVED_MESSAGE
elseif (hookName == "Send Comm Message") then
return HOOK_COMM_SEND_MESSAGE
elseif (hookName == "Destructor") then
return HOOK_NAMEPLATE_DESTRUCTOR
else
Plater:Msg ("Unknown hook: " .. (hookName or "Invalid Hook Name"))
end
end
--store the names of hooks that passed the filters
Plater.CurrentlyLoadedHooks = {}
function Plater.RunDestructorForHook (scriptObject)
--check if the script has a destructor script
if (scriptObject.Hooks ["Destructor"]) then
--load and compile the destructor code
local code = "return " .. scriptObject.Hooks ["Destructor"]
if IS_WOW_PROJECT_NOT_MAINLINE then
code = string.gsub(code, "\"NamePlateFullBorderTemplate\"", "\"PlaterNamePlateFullBorderTemplate\"")
end
local compiledScript, errortext = loadstring (code, "Destructor for " .. scriptObject.Name)
if (not compiledScript) then
Plater:Msg ("failed to compile destructor for script " .. scriptObject.Name .. ": " .. errortext)
else
--store the function to execute
--setfenv (compiledScript, functionFilter)
if (Plater.db.profile.shadowMode and Plater.db.profile.shadowMode == 0) then -- legacy mode
DF:SetEnvironment(compiledScript, nil, platerModEnvironment)
elseif (not Plater.db.profile.shadowMode or Plater.db.profile.shadowMode == 1) then
SetPlaterEnvironment(compiledScript)
end
local func = compiledScript()
--iterate among all nameplates
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame) then
--local globalScriptObject = HOOK_NAMEPLATE_DESTRUCTOR [scriptObject.scriptId]
--does not exist when mod is not loaded through load conditions or similar
local globalScriptObject = HOOK_NAMEPLATE_DESTRUCTOR [scriptObject.scriptId] or {
HotReload = -1,
DBScriptObject = scriptObject,
Build = PLATER_HOOK_BUILD,
}
local unitFrame = plateFrame.unitFrame
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Destructor")
local okay, errortext = pcall (func, unitFrame, unitFrame.displayedUnit, unitFrame, scriptInfo.Env, PLATER_GLOBAL_MOD_ENV [scriptInfo.GlobalScriptObject.DBScriptObject.scriptId])
if (not okay) then
Plater:Msg ("Mod: |cFFAAAA22" .. scriptInfo.GlobalScriptObject.DBScriptObject.Name .. "|r " .. scriptObject.Name .. " error: " .. errortext)
end
end
end
end
end
end
function Plater.RunDeinitializationForHook (scriptObject)
--check if the script has a destructor script
if (scriptObject.Hooks ["Deinitialization"]) then
--load and compile the destructor code
local code = "return " .. scriptObject.Hooks ["Deinitialization"]
if IS_WOW_PROJECT_NOT_MAINLINE then
code = string.gsub(code, "\"NamePlateFullBorderTemplate\"", "\"PlaterNamePlateFullBorderTemplate\"")
end
local compiledScript, errortext = loadstring (code, "Deinitialization for " .. scriptObject.Name)
if (not compiledScript) then
Plater:Msg ("failed to compile Deinitialization for script " .. scriptObject.Name .. ": " .. errortext)
else
--store the function to execute
--setfenv (compiledScript, functionFilter)
if (Plater.db.profile.shadowMode and Plater.db.profile.shadowMode == 0) then -- legacy mode
DF:SetEnvironment(compiledScript, nil, platerModEnvironment)
elseif (not Plater.db.profile.shadowMode or Plater.db.profile.shadowMode == 1) then
SetPlaterEnvironment(compiledScript)
end
--does not exist when mod is not loaded through load conditions or similar
local globalScriptObject = HOOK_NAMEPLATE_DESTRUCTOR [scriptObject.scriptId] or {
HotReload = -1,
DBScriptObject = scriptObject,
Build = PLATER_HOOK_BUILD,
}
globalScriptObject ["Deinitialization"] = compiledScript()
Plater.ScriptMetaFunctions.ScriptRunNoAttach (globalScriptObject, "Deinitialization")
end
end
end
-- which option types should be copied to modTable.config?
local options_for_config_table = {
[1] = true, -- Color
[2] = true, -- Number
[3] = true, -- Text
[4] = true, -- Toggle
[5] = false, -- Label
[6] = false, -- Blank Line
[7] = true -- Texture
}
--compile scripts from the Hooking tab
function Plater.CompileHook (scriptObject, noHotReload)
--check if the script is valid and if is enabled
if (not scriptObject) then
return
end
if not scriptObject.scriptId then
scriptObject.scriptId = tostring(scriptObject)
end
--check if this hook is currently loaded
if (not scriptObject.Enabled) then
if (Plater.CurrentlyLoadedHooks [scriptObject.scriptId]) then
Plater.CurrentlyLoadedHooks [scriptObject.scriptId] = false
Plater.RunDestructorForHook (scriptObject)
Plater.RunDeinitializationForHook (scriptObject)
end
--clear env when disabling/disabled
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId] = nil
return
end
do --check integrity
if (not scriptObject.Name) then
Plater:Msg ("fail to load mod: " .. (scriptObject.Name or "") .. ".")
return
end
if (not scriptObject.LoadConditions) then
Plater:Msg ("fail to load mod: " .. (scriptObject.Name or "") .. ".")
return
end
if (
not scriptObject.LoadConditions.class or
not scriptObject.LoadConditions.spec or
not scriptObject.LoadConditions.race or
not scriptObject.LoadConditions.talent or
not scriptObject.LoadConditions.pvptalent or
not scriptObject.LoadConditions.group or
not scriptObject.LoadConditions.role or
not scriptObject.LoadConditions.affix or
not scriptObject.LoadConditions.encounter_ids or
not scriptObject.LoadConditions.map_ids
) then
Plater:Msg ("fail to load mod: " .. (scriptObject.Name or "") .. ".")
return
end
if (not scriptObject.Hooks) then
Plater:Msg ("fail to load mod: " .. (scriptObject.Name or "") .. ".")
return
end
end
--check if can load this hook
if (not DF:PassLoadFilters (scriptObject.LoadConditions, Plater.EncounterID)) then
--check if this hook is currently loaded
if (Plater.CurrentlyLoadedHooks [scriptObject.scriptId]) then
Plater.CurrentlyLoadedHooks [scriptObject.scriptId] = false
Plater.RunDestructorForHook (scriptObject)
Plater.RunDeinitializationForHook (scriptObject)
end
if not noHotReload then
--clear env if needed
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId] = nil
end
return
else
Plater.CurrentlyLoadedHooks [scriptObject.scriptId] = true
end
if not noHotReload then
--clear env if needed
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId] = nil
end
--store the scripts to be compiled
local scriptCode = {}
--get scripts from the object
for hookName, code in pairs (scriptObject.Hooks) do
scriptCode [hookName] = "return " .. code
end
--get or create the global script object
local globalScriptObject = {
HotReload = -1,
DBScriptObject = scriptObject,
Build = PLATER_HOOK_BUILD,
scriptId = scriptObject.scriptId,
}
--init modEnv if necessary
local needsInitCall = false
if (not PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId]) then
needsInitCall = true
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId] = {
config = {}
}
end
--copy options to global env
-- ensure options are valid:
Plater.CreateOptionTableForScriptObject(scriptObject)
local scriptOptions = scriptObject.Options
local scriptOptionsValues = scriptObject.OptionsValues
for i = 1, #scriptOptions do
local thisOption = scriptOptions[i]
if (options_for_config_table[thisOption.Type]) then
if (type(scriptOptionsValues[thisOption.Key]) == "boolean") then
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId].config[thisOption.Key] = scriptOptionsValues[thisOption.Key]
elseif (thisOption.Type == 7) then
--check if the options is a list
--build default values if needed
if not scriptOptionsValues[thisOption.Key] then
scriptOptionsValues[thisOption.Key] = DF.table.copy({}, thisOption.Value)
end
--build a hash table with the entries in the list
local hashTable = {}
for index, entryTable in ipairs(scriptOptionsValues[thisOption.Key]) do
local key = entryTable[1]
local value = entryTable[2]
hashTable[key] = value
end
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId].config[thisOption.Key] = hashTable
else
PLATER_GLOBAL_MOD_ENV [scriptObject.scriptId].config[thisOption.Key] = scriptOptionsValues[thisOption.Key] or thisOption.Value
end
end
end
--compile
for hookName, code in pairs (scriptCode) do
local globalScriptContainer = Plater.GetContainerForHook (hookName)
if (type (code) ~= "string") then
Plater:Msg ("fail to load mod: " .. (scriptObject.Name or "") .. ".")
return
end
if IS_WOW_PROJECT_NOT_MAINLINE then
code = string.gsub(code, "\"NamePlateFullBorderTemplate\"", "\"PlaterNamePlateFullBorderTemplate\"")
end
--find occurences of Plater.SendComm(arg1, arg2, arg3, ...) and replace with Plater.SendComm_Internal(uniqueIdentifier, arg1, arg2, arg3, ...) or fail to compile for all than "Send Comm Message" and don't replace (use empty dummy)
if hookName == "Send Comm Message" then
code = string.gsub(code, "Plater.SendComm%s*%(", "Plater.SendComm(" .. globalScriptContainer.ScriptAmount + 1 .. ", \"" .. scriptObject.scriptId .. "\", \"" .. scriptObject.UID .. "\", ")
else
local foundSendComm = string.find(code, "Plater.SendComm")
if foundSendComm then
Plater:Msg ("failed to compile " .. hookName .. " for script " .. scriptObject.Name .. ": " .. "Usage of 'Plater.SendComm' is only allowed in 'Send Comm Message' hook.")
end
end
local compiledScript, errortext = loadstring (code, "" .. hookName .. " for " .. scriptObject.Name)
if (not compiledScript) then
Plater:Msg ("failed to compile " .. hookName .. " for script " .. scriptObject.Name .. ": " .. errortext)
else
--setfenv (compiledScript, functionFilter)
if (Plater.db.profile.shadowMode and Plater.db.profile.shadowMode == 0) then -- legacy mode
DF:SetEnvironment(compiledScript, nil, platerModEnvironment)
elseif (not Plater.db.profile.shadowMode or Plater.db.profile.shadowMode == 1) then
SetPlaterEnvironment(compiledScript)
end
--store the function to execute inside the global script object
globalScriptObject [hookName] = compiledScript()
--insert the script in the global script container, remove existing, as option changes re-compile only single mod without wipe
local isReplace = false
for i, curScriptObject in ipairs(globalScriptContainer) do
if scriptObject.scriptId == curScriptObject.scriptId then
tremove(globalScriptContainer, i)
isReplace = true
end
end
tinsert (globalScriptContainer, globalScriptObject)
globalScriptContainer.ScriptAmount = globalScriptContainer.ScriptAmount + (isReplace and 0 or 1)
if (hookName == "Constructor") then
globalScriptObject.HasConstructor = true
elseif (hookName == "Initialization") and needsInitCall then
Plater.ScriptMetaFunctions.ScriptRunNoAttach (globalScriptObject, "Initialization")
end
end
end
end
--compile scripts from the Scripting tab
function Plater.CompileScript(scriptObject, noHotReload, ...)
--check if the script is valid and if is enabled
if (not scriptObject) then
return
elseif (not scriptObject.Enabled) then
return
end
if (not scriptObject.scriptId) then
scriptObject.scriptId = tostring(scriptObject)
end
--clear env on re-compilation if necessary
if (not noHotReload) then
PLATER_GLOBAL_SCRIPT_ENV[scriptObject.scriptId] = nil
end
--store the scripts to be compiled
local scriptCode, scriptFunctions = {}, {}
--get scripts passed
for i = 1, select ("#",...) do
scriptCode[Plater.CodeTypeNames [i]] = "return " .. select(i, ...)
end
--get scripts which wasn't passed
for i = 1, #Plater.CodeTypeNames do
local scriptType = Plater.CodeTypeNames[i]
-- ensure init is filled always, 5 is the index where the init code is
if (not scriptObject[scriptType] and i == 5) then
scriptObject[scriptType] = [=[
function (scriptTable)
--insert code here
end
]=]
end
if (not scriptCode[scriptType]) then
scriptCode[scriptType] = "return " .. scriptObject[scriptType]
end
end
--init modEnv if necessary
local needsInitCall = false
if (not PLATER_GLOBAL_SCRIPT_ENV[scriptObject.scriptId]) then
needsInitCall = true
PLATER_GLOBAL_SCRIPT_ENV[scriptObject.scriptId] = {
config = {}
}
end
--copy options to global env and ensure options are valid
Plater.CreateOptionTableForScriptObject(scriptObject)
local scriptOptions = scriptObject.Options
local scriptOptionsValues = scriptObject.OptionsValues
for i = 1, #scriptOptions do
local thisOption = scriptOptions[i]
if (options_for_config_table[thisOption.Type]) then
if (type(scriptOptionsValues[thisOption.Key]) == "boolean") then
PLATER_GLOBAL_SCRIPT_ENV [scriptObject.scriptId].config[thisOption.Key] = scriptOptionsValues[thisOption.Key]
elseif (thisOption.Type == 7) then --check if the options is a list
--build default values if needed
if not scriptOptionsValues[thisOption.Key] then
scriptOptionsValues[thisOption.Key] = DF.table.copy({}, thisOption.Value)
end
--build a hash table with the entries in the list
local hashTable = {}
for index, entryTable in ipairs(scriptOptionsValues[thisOption.Key]) do
local key = entryTable[1]
local value = entryTable[2]
hashTable[key] = value
end
PLATER_GLOBAL_SCRIPT_ENV [scriptObject.scriptId].config[thisOption.Key] = hashTable
else
PLATER_GLOBAL_SCRIPT_ENV [scriptObject.scriptId].config[thisOption.Key] = scriptOptionsValues[thisOption.Key] or thisOption.Value
end
end
end
--compile
for scriptType, code in pairs(scriptCode) do
if (IS_WOW_PROJECT_NOT_MAINLINE) then
code = string.gsub(code, "\"NamePlateFullBorderTemplate\"", "\"PlaterNamePlateFullBorderTemplate\"")
end
local compiledScript, errortext = loadstring(code, "" .. scriptType .. " for " .. scriptObject.Name)
if (not compiledScript) then
Plater:Msg ("failed to compile " .. scriptType .. " for script " .. scriptObject.Name .. ": " .. errortext)
else
--get the function to execute
--setfenv(compiledScript, functionFilter) deprecated
if (Plater.db.profile.shadowMode and Plater.db.profile.shadowMode == 0) then --legacy mode
DF:SetEnvironment(compiledScript, nil, platerModEnvironment)
elseif (not Plater.db.profile.shadowMode or Plater.db.profile.shadowMode == 1) then
SetPlaterEnvironment(compiledScript)
end
--extract the function
scriptFunctions[scriptType] = compiledScript()
end
end
--trigger container is the table with spellIds for auras and/or spellcast
--triggerId is the spellId converted to spellName or the unitName in case of a Unit name
local triggerContainer, triggerId
if (scriptObject.ScriptType == 1 or scriptObject.ScriptType == 2) then --aura or castbar
triggerContainer = "SpellIds"
elseif (scriptObject.ScriptType == 3) then --unit name
triggerContainer = "NpcNames"
end
for i = 1, #scriptObject[triggerContainer] do
local triggerId = scriptObject[triggerContainer][i]
--if the trigger is using spellId, check if the spell exists
if (scriptObject.ScriptType == 1 or scriptObject.ScriptType == 2) then
if (type(triggerId) == "number") then
triggerId = GetSpellInfo(triggerId)
if (not triggerId) then
if IS_WOW_PROJECT_MAINLINE then -- disable this in classic for now... too spammy
Plater:Msg ("failed to get the spell name for spellId: " .. (scriptObject [triggerContainer] [i] or "invalid spellId") .. "for script '" .. scriptObject.Name .. "'")
end
end
end
elseif (scriptObject.ScriptType == 3) then --unit names
--cast the string to number to see if it's a npcId
triggerId = tonumber(triggerId) or triggerId
--if is a unit name, make it be in lower case
if (type(triggerId) == "string") then
triggerId = lower(triggerId)
end
end
if (triggerId) then
--get the global script object table
local triggerCacheTable
if (scriptObject.ScriptType == 1) then
triggerCacheTable = SCRIPT_AURA_TRIGGER_CACHE
elseif (scriptObject.ScriptType == 2) then
triggerCacheTable = SCRIPT_CASTBAR_TRIGGER_CACHE
elseif (scriptObject.ScriptType == 3) then
triggerCacheTable = SCRIPT_UNIT_TRIGGER_CACHE
end
local globalScriptObject = triggerCacheTable[triggerId]
if (not globalScriptObject) then
--first time compiled, create the global script object
--this table controls the hot reload state, holds the original object from the database and has the compiled functions
globalScriptObject = {
DBScriptObject = scriptObject,
--whenever the script is applied or saved the hot reload increases making it run again when the script is triggered
HotReload = 1,
--script key is set in the widget so it can lookup for a script using the key when the widget is hidding
ScriptKey = triggerId,
}
--insert the table just created inthe the triggerCacheTable
triggerCacheTable[triggerId] = globalScriptObject
else --hot reload and update
globalScriptObject.HotReload = globalScriptObject.HotReload + 1
globalScriptObject.DBScriptObject = scriptObject
end
globalScriptObject.LastUpdateTime = GetTime()-0.05
--add the script functions to the global object table
for scriptType, func in pairs(scriptFunctions) do
globalScriptObject[scriptType] = func
end
--run initialization (once)
if (needsInitCall) then
Plater.ScriptMetaFunctions.ScriptRunInitialization(globalScriptObject)
needsInitCall = false
end
end
end
end
--check all triggers of all scripts for overlaps
--where a same spellId, npcName or npcId is being used by two or more scripts
--return a table with the triggerId with a index table of all scripts using that trigger
function Plater.CheckScriptTriggerOverlap()
--store all triggers of all scripts in the format [triggerId] = {scripts using this trigger}
local allTriggers = {
Auras = {},
Casts = {},
Npcs = {},
}
--build the table containinf all scripts and what scripts they trigger
for index, scriptObject in ipairs (Plater.GetAllScripts ("script")) do
if (scriptObject.Enabled) then
for _, spellId in ipairs (scriptObject.SpellIds) do
if (scriptObject.ScriptType == 1) then
--> triggers auras
local triggerTable = allTriggers.Auras [spellId]
if (not triggerTable) then
allTriggers.Auras [spellId] = {scriptObject}
else
tinsert (triggerTable, scriptObject)
end
elseif (scriptObject.ScriptType == 2) then
--> triggers cast
local triggerTable = allTriggers.Casts [spellId]
if (not triggerTable) then
allTriggers.Casts [spellId] = {scriptObject}
else
tinsert (triggerTable, scriptObject)
end
end
end
for _, NpcId in ipairs (scriptObject.NpcNames) do
local triggerTable = allTriggers.Npcs [NpcId]
if (not triggerTable) then
allTriggers.Npcs [NpcId] = {scriptObject}
else
tinsert (triggerTable, scriptObject)
end
end
end
end
--> store scripts with overlap
local scriptsWithOverlap = {
Auras = {},
Casts = {},
Npcs = {},
}
local amount = 0
--> check if there's more than 1 script for each trigger
for triggerId, scriptsTable in pairs (allTriggers.Auras) do
if (#scriptsTable > 1) then
--overlap found
scriptsWithOverlap.Auras [triggerId] = scriptsTable
amount = amount + 1
end
end
for triggerId, scriptsTable in pairs (allTriggers.Casts) do
if (#scriptsTable > 1) then
--overlap found
scriptsWithOverlap.Casts [triggerId] = scriptsTable
amount = amount + 1
end
end
for triggerId, scriptsTable in pairs (allTriggers.Npcs) do
if (#scriptsTable > 1) then
--overlap found
scriptsWithOverlap.Npcs [triggerId] = scriptsTable
amount = amount + 1
end
end
return scriptsWithOverlap, amount
end
--retrive the script object for a selected scriptId
function Plater.GetScriptObject (scriptID, scriptType)
if (scriptType == "script") then
local script = Plater.db.profile.script_data [scriptID]
if (script) then
return script
end
elseif (scriptType == "hook") then
local script = Plater.db.profile.hook_data [scriptID]
if (script) then
return script
end
end
end
--return the main db table for the script type
function Plater.GetScriptDB (scriptType)
if (scriptType == "script") then
return Plater.db.profile.script_data
elseif (scriptType == "hook") then
return Plater.db.profile.hook_data
end
end
--if the type of a scriptObject is unknown
function Plater.GetScriptType (scriptObject)
if (scriptObject.Hooks) then
return "hook"
elseif (scriptObject.SpellIds) then
return "script"
end
end
--an indexScriptTable is a table decoded from an imported string, Plater uses this table to build an scriptObject
--check the type of indexes in the indexScriptTable to determine which type of script is this
--this is done to avoid sending an extra index just to tell which type of script is the string
function Plater.GetDecodedScriptType (indexScriptTable)
-- newer versions
if indexScriptTable.type == "hook" then
return "hook"
elseif indexScriptTable.type == "script" then
return "script"
elseif indexScriptTable.type == "npc_colors" then
return "npc_colors"
end
-- fallback for old versions
indexScriptTable = Plater.MigrateScriptModImport (indexScriptTable) -- just to make sure this works as intended...
if (indexScriptTable.NpcColor) then
return "npc_colors"
elseif (type (indexScriptTable ["9"]) == "table") then --hook
return "hook"
elseif (type (indexScriptTable ["9"]) == "number") then --script
return "script"
end
end
--import scripts from the library
--autoImportScript is a table holding the revision number, the string to import and the type of script
function Plater.ImportScriptsFromLibrary()
if (PlaterScriptLibrary) then
for name, autoImportScript in pairs (PlaterScriptLibrary) do
local importedDB
if (autoImportScript.ScriptType == "script") then
importedDB = Plater.db.profile.script_auto_imported
elseif (autoImportScript.ScriptType == "hook") then
importedDB = Plater.db.profile.hook_auto_imported
end
if ((importedDB [name] or 0) < autoImportScript.Revision) then
importedDB [name] = autoImportScript.Revision
local encodedString = autoImportScript.String
if (encodedString) then
local success, scriptAdded, wasEnabled = Plater.ImportScriptString (encodedString, true, autoImportScript.OverrideTriggers, false, false)
if (success) then
if (autoImportScript.Revision == 1) then
Plater:Msg ("New Script Installed: " .. name)
else
Plater:Msg ("Applied Update to Script: " .. name)
end
--all scripts imported are enabled by default, if the import object has a enabled member, probably its value is false
if (type (autoImportScript.Enabled) == "boolean") then
scriptAdded.Enabled = wasEnabled == nil and autoImportScript.Enabled or wasEnabled or false
end
end
end
end
end
--can't wipe because it need to be reused when a new profile is created
--table.wipe (PlaterScriptLibrary)
end
end
-- migrate imports to string-based indexes
function Plater.MigrateScriptModImport (indexScriptTable)
local newindexScriptTable = {}
if not indexScriptTable or type(indexScriptTable) ~= "table" then
return newindexScriptTable
end
-- generate a keys list and a tmpTable with all string keys
for k,v in pairs(indexScriptTable) do
newindexScriptTable[k .. ""] = v
end
-- if index 2 or 5 are empty, fill them (icons for mods/scripts)
if not newindexScriptTable["2"] then
--newindexScriptTable["2"] = 134400
end
if not newindexScriptTable["5"] then
--newindexScriptTable["5"] = 134400
end
--print(DF.table.dump(newindexScriptTable))
return newindexScriptTable
end
--merge/clean up user options
function Plater.UpdateOptionsForModScriptImport(scriptObjectNew, scriptObjectOld)
if not scriptObjectNew or not scriptObjectOld then return end
--consistency/init:
scriptObjectNew.OptionsValues = scriptObjectNew.OptionsValues or {}
scriptObjectNew.Options = scriptObjectNew.Options or {}
scriptObjectOld.OptionsValues = scriptObjectOld.OptionsValues or {}
local newUserOptions = scriptObjectNew.OptionsValues
local newOptions = scriptObjectNew.Options
local oldUserOptions = scriptObjectOld.OptionsValues
for i=1, #newOptions do
local newOption = newOptions[i]
if newOption.Key and oldUserOptions[newOption.Key] then
newUserOptions[newOption.Key] = oldUserOptions[newOption.Key]
end
end
end
--import a string from any source with more options than the convencional importer
--this is used when importing scripts from the library and when the user inserted the wrong script type in the import box at hook or script, e.g. imported a hook in the script import box
--guarantee to always receive a 'print' type of encode
function Plater.ImportScriptString (text, ignoreRevision, overrideTriggers, showDebug, keepExisting)
if (not text or type (text) ~= "string") then
return
end
local errortext, objectAdded, wasEnabled
local indexScriptTable = Plater.DecompressData (text, "print")
if (indexScriptTable and type (indexScriptTable) == "table") then
indexScriptTable = Plater.MigrateScriptModImport (indexScriptTable)
--get the script type, if is a hook or regular script
local scriptType = Plater.GetDecodedScriptType (indexScriptTable)
local newScript = Plater.BuildScriptObjectFromIndexTable (indexScriptTable, scriptType)
if (newScript) then
if (scriptType == "script") then
local scriptName = newScript.Name
local alreadyExists = false
local scriptDB = Plater.GetScriptDB (scriptType)
if not keepExisting then
for i = 1, #scriptDB do
local scriptObject = scriptDB [i]
if (scriptObject.Name == scriptName) then
--the script already exists
if (not ignoreRevision) then
if (scriptObject.Revision >= newScript.Revision) then
if (showDebug) then
Plater:Msg ("Your version of this script is newer or is the same version.")
return false
end
end
end
--copy triggers that the current script has to the new script object since the user might have modified the list
if (not overrideTriggers) then
if (newScript.ScriptType == 0x1 or newScript.ScriptType == 0x2) then
--aura or cast trigger
newScript.SpellIds = {}
for index, trigger in ipairs (scriptObject.SpellIds) do
DF.table.addunique (newScript.SpellIds, trigger)
end
else
--npc trigger
newScript.NpcNames = {}
for index, trigger in ipairs (scriptObject.NpcNames) do
DF.table.addunique (newScript.NpcNames, trigger)
end
end
end
--keep the enabled state
wasEnabled = scriptObject.Enabled
newScript.Enabled = scriptObject.Enabled
Plater.UpdateOptionsForModScriptImport(newScript, scriptObject)
--replace the old script with the new one
local oldScript = scriptDB[i]
if (oldScript) then
--move it to trash
oldScript.__TrashAt = time()
tinsert(Plater.db.profile.script_data_trash, oldScript)
end
tremove (scriptDB, i)
tinsert (scriptDB, i, newScript)
objectAdded = newScript
if (showDebug) then
Plater:Msg ("Script replaced by a newer version.")
end
alreadyExists = true
break
end
end
end
if (not alreadyExists) then
tinsert (scriptDB, newScript)
objectAdded = newScript
if (showDebug) then
Plater:Msg ("Script added.")
end
end
elseif (scriptType == "hook") then
local scriptName = newScript.Name
local alreadyExists = false
local scriptDB = Plater.GetScriptDB (scriptType)
if not keepExisting then
for i = 1, #scriptDB do
local scriptObject = scriptDB [i]
if (scriptObject.Name == scriptName) then
--the script already exists
if (not ignoreRevision) then
if (scriptObject.Revision >= newScript.Revision) then
if (showDebug) then
Plater:Msg ("Your version of this script is newer or is the same version.")
return false
end
end
end
--keep the enabled state
wasEnabled = scriptObject.Enabled
newScript.Enabled = scriptObject.Enabled
Plater.UpdateOptionsForModScriptImport(newScript, scriptObject)
--replace the old script with the new one
local oldScript = scriptDB[i]
if (oldScript) then
--move it to trash
oldScript.__TrashAt = time()
tinsert(Plater.db.profile.hook_data_trash, oldScript)
end
--replace the old script with the new one
tremove (scriptDB, i)
tinsert (scriptDB, i, newScript)
objectAdded = newScript
if (showDebug) then
Plater:Msg ("Mod replaced by a newer version.")
end
alreadyExists = true
break
end
end
end
if (not alreadyExists) then
tinsert (scriptDB, newScript)
objectAdded = newScript
if (showDebug) then
Plater:Msg ("Script added.")
end
end
end
else
--check if the user in importing a profile in the scripting tab
if (indexScriptTable.plate_config) then
DF:ShowErrorMessage ("Invalid Script or Mod.\n\nImport profiles at the Profiles tab.")
elseif (indexScriptTable.NpcColor) then
DF:ShowErrorMessage ("Invalid Script or Mod.\n\nImport NpcColors at the Npc Colors tab.")
end
errortext = "Cannot import: data imported is invalid"
end
else
errortext = "Cannot import: data imported is invalid"
end
if (errortext and showDebug) then
Plater:Msg (errortext)
return false
end
if objectAdded then
return true, objectAdded, wasEnabled
else
return false
end
end
--add a scriptObject to the script db
--if noOverwrite is passed, it won't replace if a script with the same name already exists
function Plater.AddScript (scriptObjectToAdd, noOverwrite)
if (scriptObjectToAdd) then
local indexToReplace
local existingScriptObject
local scriptType = Plater.GetScriptType (scriptObjectToAdd)
local scriptDB = Plater.GetScriptDB (scriptType)
--check if already exists
for i = 1, #scriptDB do
local scriptObject = scriptDB [i]
if (scriptObject.Name == scriptObjectToAdd.Name) then
--the script already exists
if (noOverwrite) then
return
else
indexToReplace = i
existingScriptObject = scriptObject
break
end
end
end
if (indexToReplace) then
--remove the old script and add the new one
Plater.UpdateOptionsForModScriptImport(scriptObjectToAdd, existingScriptObject)
tremove (scriptDB, indexToReplace)
tinsert (scriptDB, indexToReplace, scriptObjectToAdd)
else
--add the new script to the end of the table
tinsert (scriptDB, scriptObjectToAdd)
end
end
end
--get a index table from an imported string and build a scriptObject from it
function Plater.BuildScriptObjectFromIndexTable (indexTable, scriptType)
if (scriptType == "hook") then
-- check integrity: name and hooks
if not indexTable ["1"] or not indexTable ["9"] then
return nil
end
local scriptObject = {}
scriptObject.Enabled = true --imported scripts are always enabled
scriptObject.Name = indexTable ["1"]
scriptObject.Icon = indexTable ["2"]
scriptObject.Desc = indexTable ["3"]
scriptObject.Author = indexTable ["4"]
scriptObject.Time = indexTable ["5"]
scriptObject.Revision = indexTable ["6"]
scriptObject.PlaterCore = indexTable ["7"]
scriptObject.LoadConditions = indexTable ["8"]
scriptObject.Hooks = {}
scriptObject.HooksTemp = {}
scriptObject.LastHookEdited = ""
for hookName, hookCode in pairs (indexTable ["9"]) do
scriptObject.Hooks [hookName] = hookCode
end
scriptObject.Options = indexTable.options
scriptObject.url = indexTable.url or ""
scriptObject.version = indexTable.version or -1
scriptObject.semver = indexTable.semver or ""
scriptObject.UID = indexTable.UID
return scriptObject
elseif (scriptType == "script") then
-- check integrity: type, name, triggers and hooks
if not indexTable ["1"] or not indexTable ["2"] or not indexTable ["3"] or not indexTable ["4"]
or not indexTable ["11"] or not indexTable ["12"] or not indexTable ["13"] or not indexTable ["14"] then
return nil
end
local scriptObject = {}
scriptObject.Enabled = true --imported scripts are always enabled
scriptObject.ScriptType = indexTable ["1"]
scriptObject.Name = indexTable ["2"]
scriptObject.SpellIds = indexTable ["3"]
scriptObject.NpcNames = indexTable ["4"]
scriptObject.Icon = indexTable ["5"]
scriptObject.Desc = indexTable ["6"]
scriptObject.Author = indexTable ["7"]
scriptObject.Time = indexTable ["8"]
scriptObject.Revision = indexTable ["9"]
scriptObject.PlaterCore = indexTable ["10"]
scriptObject.Options = indexTable.options
scriptObject.url = indexTable.url or ""
scriptObject.version = indexTable.version or -1
scriptObject.semver = indexTable.semver or ""
for i = 1, #Plater.CodeTypeNames do
local memberName = Plater.CodeTypeNames [i]
scriptObject [memberName] = indexTable [(10 + i)..""]
end
return scriptObject
end
end
--transform the string into a indexScriptTable and then transform it into a scriptObject
function Plater.DecodeImportedString (str)
local LibAceSerializer = LibStub:GetLibrary ("AceSerializer-3.0")
if (LibAceSerializer) then
-- ~zip
local decoded = DF.DecodeString (str)
if (decoded) then
local unSerializedOkay, indexScriptTable = LibAceSerializer:Deserialize (decoded)
if (unSerializedOkay and type (indexScriptTable) == "table") then
local scriptObject = Plater.BuildScriptObjectFromIndexTable (indexScriptTable, Plater.GetDecodedScriptType (indexScriptTable))
if (scriptObject) then
return scriptObject
end
end
end
end
end
--function Plater.PrepareTableToExportStringIndexes (scriptObject)
function Plater.PrepareTableToExport (scriptObject)
if (scriptObject.Hooks) then
--script for hooks
local t = {}
t ["1"] = scriptObject.Name
t ["2"] = scriptObject.Icon
t ["3"] = scriptObject.Desc
t ["4"] = scriptObject.Author
t ["5"] = scriptObject.Time
t ["6"] = scriptObject.Revision
t ["7"] = scriptObject.PlaterCore
t ["8"] = scriptObject.LoadConditions
t ["9"] = {}
for hookName, hookCode in pairs (scriptObject.Hooks) do
t ["9"] [hookName] = hookCode
end
t ["options"] = scriptObject.Options or {}
t ["addon"] = "Plater"
t ["tocversion"] = select(4, GetBuildInfo()) -- provide export toc
t ["type"] = "hook"
t ["UID"] = scriptObject.UID
return t
else
--regular script for aura cast or unitID
local t = {}
t ["1"] = scriptObject.ScriptType
t ["2"] = scriptObject.Name
t ["3"] = scriptObject.SpellIds
t ["4"] = scriptObject.NpcNames
t ["5"] = scriptObject.Icon
t ["6"] = scriptObject.Desc
t ["7"] = scriptObject.Author
t ["8"] = scriptObject.Time
t ["9"] = scriptObject.Revision
t ["10"] = scriptObject.PlaterCore
for i = 1, #Plater.CodeTypeNames do
local memberName = Plater.CodeTypeNames [i]
t [(10 + i)..""] = scriptObject [memberName]
end
t ["options"] = scriptObject.Options or {}
t ["addon"] = "Plater"
t ["tocversion"] = select(4, GetBuildInfo()) -- provide export toc
t ["type"] = "script"
return t
end
end
function Plater.ScriptReceivedFromGroup (prefix, playerName, playerRealm, playerGUID, importedString)
if (not Plater.db.profile.script_banned_user [playerGUID]) then
local indexScriptTable = Plater.DecompressData (importedString, "comm")
if (indexScriptTable and type (indexScriptTable) == "table") then
local importedScriptObject = Plater.BuildScriptObjectFromIndexTable (indexScriptTable, Plater.GetDecodedScriptType (indexScriptTable))
if (not importedScriptObject) then
return
end
local scriptName = importedScriptObject.Name
local alreadyExists = false
local alreadyExistsVersion = 0
local scriptType = Plater.GetScriptType (importedScriptObject)
local scriptDB = Plater.GetScriptDB (scriptType)
for i = 1, #scriptDB do
local scriptObject = scriptDB [i]
if (scriptObject.Name == scriptName) then
alreadyExists = true
alreadyExistsVersion = scriptObject.Revision
break
end
end
--add the script to the queue
Plater.ScriptsWaitingApproval = Plater.ScriptsWaitingApproval or {}
tinsert (Plater.ScriptsWaitingApproval, {importedScriptObject, playerName, playerRealm, playerGUID, alreadyExists, alreadyExistsVersion})
Plater.ShowImportScriptConfirmation()
end
end
end
function Plater.ExportScriptToGroup (scriptId, scriptType)
local scriptToSend = Plater.GetScriptObject (scriptId, scriptType)
if (not scriptToSend) then
Plater:Msg ("script not found", scriptId)
return
end
--convert hash table to index table for smaller size
local indexedScriptTable = Plater.PrepareTableToExport (scriptToSend)
--compress the indexed table for WoWAddonChannel
local encodedString = Plater.CompressData (indexedScriptTable, "comm")
if (encodedString) then
local LibAceSerializer = LibStub:GetLibrary ("AceSerializer-3.0")
if (IsInRaid (LE_PARTY_CATEGORY_HOME)) then
Plater:SendCommMessage (Plater.COMM_PLATER_PREFIX, LibAceSerializer:Serialize (Plater.COMM_SCRIPT_GROUP_EXPORTED, UnitName ("player"), GetRealmName(), UnitGUID ("player"), encodedString), "RAID")
elseif (IsInGroup (LE_PARTY_CATEGORY_HOME)) then
Plater:SendCommMessage (Plater.COMM_PLATER_PREFIX, LibAceSerializer:Serialize (Plater.COMM_SCRIPT_GROUP_EXPORTED, UnitName ("player"), GetRealmName(), UnitGUID ("player"), encodedString), "PARTY")
else
Plater:Msg ("Failed to send the script: your group isn't home group.")
end
else
Plater:Msg ("Fail to encode scriptId", scriptId)
end
end
function Plater.ShowImportScriptConfirmation()
if (not Plater.ImportConfirm) then
Plater.ImportConfirm = DF:CreateSimplePanel (UIParent, 380, 130, "Plater Nameplates: Script Importer", "PlaterImportScriptConfirmation")
Plater.ImportConfirm:Hide()
DF:ApplyStandardBackdrop (Plater.ImportConfirm)
Plater.ImportConfirm.AcceptText = Plater:CreateLabel (Plater.ImportConfirm, "", Plater:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE"))
Plater.ImportConfirm.AcceptText:SetPoint (16, -26)
Plater.ImportConfirm.ScriptName = Plater:CreateLabel (Plater.ImportConfirm, "", Plater:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE"))
Plater.ImportConfirm.ScriptName:SetPoint (16, -41)
Plater.ImportConfirm.ScriptVersion = Plater:CreateLabel (Plater.ImportConfirm, "", Plater:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE"))
Plater.ImportConfirm.ScriptVersion:SetPoint (16, -56)
local accept_aura = function (self, button, scriptObject)
Plater.AddScript (scriptObject)
Plater.ImportConfirm:Hide()
Plater.ShowImportScriptConfirmation()
end
local decline_aura = function (self, button, scriptObject, senderGUID)
if (Plater.ImportConfirm.AlwaysIgnoreCheckBox.value) then
Plater.db.profile.script_banned_user [senderGUID] = true
Plater:Msg ("the user won't send more scripts to you.")
end
Plater.ImportConfirm:Hide()
Plater.ShowImportScriptConfirmation()
end
Plater.ImportConfirm.AcceptButton = Plater:CreateButton (Plater.ImportConfirm, accept_aura, 125, 20, "Accept", -1, nil, nil, nil, nil, nil, Plater:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"))
Plater.ImportConfirm.DeclineButton = Plater:CreateButton (Plater.ImportConfirm, decline_aura, 125, 20, "Decline", -1, nil, nil, nil, nil, nil, Plater:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"))
Plater.ImportConfirm.AcceptButton:SetPoint ("bottomright", Plater.ImportConfirm, "bottomright", -14, 31)
Plater.ImportConfirm.DeclineButton:SetPoint ("bottomleft", Plater.ImportConfirm, "bottomleft", 14, 31)
Plater.ImportConfirm.AlwaysIgnoreCheckBox = DF:CreateSwitch (Plater.ImportConfirm, function()end, false, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, DF:GetTemplate ("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"))
Plater.ImportConfirm.AlwaysIgnoreCheckBox:SetAsCheckBox()
Plater.ImportConfirm.AlwaysIgnoreLabel = Plater:CreateLabel (Plater.ImportConfirm, "Always decline this user", Plater:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE"))
Plater.ImportConfirm.AlwaysIgnoreCheckBox:SetPoint ("topleft", Plater.ImportConfirm.DeclineButton, "bottomleft", 0, -4)
Plater.ImportConfirm.AlwaysIgnoreLabel:SetPoint ("left", Plater.ImportConfirm.AlwaysIgnoreCheckBox, "right", 2, 0)
Plater.ImportConfirm.Flash = Plater.CreateFlash (Plater.ImportConfirm)
end
if (Plater.ImportConfirm:IsShown()) then
Plater.ImportConfirm.Title:SetText ("Plater Nameplates: Script Importer (" .. #Plater.ScriptsWaitingApproval + 1 .. ")")
return
else
Plater.ImportConfirm.Title:SetText ("Plater Nameplates: Script Importer (" .. #Plater.ScriptsWaitingApproval .. ")")
end
local nextScriptToApprove = tremove (Plater.ScriptsWaitingApproval)
if (nextScriptToApprove) then
local scriptObject = nextScriptToApprove [1]
local senderGUID = nextScriptToApprove [4]
rawset (Plater.ImportConfirm.AcceptButton, "param1", scriptObject)
rawset (Plater.ImportConfirm.AcceptButton, "param2", senderGUID)
rawset (Plater.ImportConfirm.DeclineButton, "param1", scriptObject)
rawset (Plater.ImportConfirm.DeclineButton, "param2", senderGUID)
Plater.ImportConfirm.AcceptText.text = "The user |cFFFFAA00" .. nextScriptToApprove [2] .. "|r sent the script: |cFFFFAA00" .. scriptObject.Name .. "|r"
Plater.ImportConfirm.ScriptName.text = "Script Version: |cFFFFAA00" .. scriptObject.Revision .. "|r"
Plater.ImportConfirm.ScriptVersion.text = nextScriptToApprove [5] and "|cFFFFAA33You already have this script on version:|r " .. nextScriptToApprove [6] or "|cFF33DD33You don't have this script yet!"
Plater.ImportConfirm:SetPoint ("center", UIParent, "center", 0, 150)
Plater.ImportConfirm.AlwaysIgnoreCheckBox:SetValue (false)
Plater.ImportConfirm.Flash:Play()
Plater.ImportConfirm:Show()
--play audio: IgPlayerInvite or igPlayerInviteDecline
else
Plater.ImportConfirm:Hide()
end
end
function Plater.DispatchCommReceivedMessageHookEvent(scriptUID, source, ...)
if (HOOK_COMM_RECEIVED_MESSAGE.ScriptAmount > 0) then
for i = 1, HOOK_COMM_RECEIVED_MESSAGE.ScriptAmount do
local globalScriptObject = HOOK_COMM_RECEIVED_MESSAGE[i]
if (globalScriptObject.DBScriptObject.UID == scriptUID) then
--run
Plater.ScriptMetaFunctions.ScriptRunCommMessageHook(globalScriptObject, "Receive Comm Message", source, ...)
end
end
end
end
function Plater.DispatchCommSendMessageHookEvents()
if (HOOK_COMM_SEND_MESSAGE.ScriptAmount > 0) then
for i = 1, HOOK_COMM_SEND_MESSAGE.ScriptAmount do
local globalScriptObject = HOOK_COMM_SEND_MESSAGE[i]
--run
Plater.ScriptMetaFunctions.ScriptRunCommMessageHook(globalScriptObject, "Send Comm Message")
end
end
end
function Plater.VerifyScriptIdForComm(scriptIndex, scriptId, uniqueId)
if not scriptIndex or not scriptId or not uniqueId then return end
local globalScriptObject = HOOK_COMM_SEND_MESSAGE[scriptIndex]
if globalScriptObject and globalScriptObject.DBScriptObject and globalScriptObject.DBScriptObject.scriptId and globalScriptObject.DBScriptObject.scriptId == scriptId and globalScriptObject.DBScriptObject.UID and globalScriptObject.DBScriptObject.UID == uniqueId then
return true
end
return false
end
function Plater.DispatchTalentUpdateHookEvent()
if (HOOK_PLAYER_TALENT_UPDATE.ScriptAmount > 0) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame and plateFrame.unitFrame.PlaterOnScreen) then
for i = 1, HOOK_PLAYER_TALENT_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_PLAYER_TALENT_UPDATE [i]
local unitFrame = plateFrame.unitFrame
if not plateFrame.unitFrame.PlaterOnScreen then
return
end
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Player Talent Update")
--run
unitFrame:ScriptRunHook (scriptInfo, "Player Talent Update")
end
end
end
end
end
function Plater.ScheduleHookForCombat (timerObject)
if (timerObject.Event == "Enter Combat") then
if (HOOK_COMBAT_ENTER.ScriptAmount > 0) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
for i = 1, HOOK_COMBAT_ENTER.ScriptAmount do
local globalScriptObject = HOOK_COMBAT_ENTER [i]
local unitFrame = plateFrame.unitFrame
if not plateFrame.unitFrame.PlaterOnScreen then
return
end
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Enter Combat")
--run
unitFrame:ScriptRunHook (scriptInfo, "Enter Combat")
end
end
end
elseif (timerObject.Event == "Leave Combat") then
if (HOOK_COMBAT_LEAVE.ScriptAmount > 0) then
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
for i = 1, HOOK_COMBAT_LEAVE.ScriptAmount do
local globalScriptObject = HOOK_COMBAT_LEAVE [i]
local unitFrame = plateFrame.unitFrame
if not plateFrame.unitFrame.PlaterOnScreen then
return
end
local scriptContainer = unitFrame:ScriptGetContainer()
local scriptInfo = unitFrame:HookGetInfo(globalScriptObject, scriptContainer, "Leave Combat")
--run
unitFrame:ScriptRunHook (scriptInfo, "Leave Combat")
end
end
end
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> slash commands ~slash
SLASH_PLATER1 = "/plater"
SLASH_PLATER2 = "/nameplate"
SLASH_PLATER3 = "/nameplates"
-- ~cvar
local cvarDiagList = {
"nameplateMaxDistance",
"nameplateOtherTopInset",
"nameplateOtherAtBase",
"nameplateMinAlpha",
"nameplateMinAlphaDistance",
"nameplateShowAll",
"nameplateShowEnemies",
"nameplateShowEnemyMinions",
"nameplateShowEnemyMinus",
"nameplateShowFriends",
"nameplateShowFriendlyGuardians",
"nameplateShowFriendlyPets",
"nameplateShowFriendlyTotems",
"nameplateShowFriendlyMinions",
"NamePlateHorizontalScale",
"NamePlateVerticalScale",
}
function SlashCmdList.PLATER (msg, editbox)
if (msg == "version") then
Plater.GetVersionInfo(true)
return
elseif (msg == "dignostico" or msg == "diag" or msg == "debug") then
print ("Plater Diagnostic:")
for i = 1, #cvarDiagList do
local cvar = cvarDiagList [i]
print ("|cFFC0C0C0" .. cvar, "|r->", GetCVar (cvar))
end
local alphaPlateFrame = "there's no nameplate in the screen"
local alphaUnitFrame = ""
local alphaHealthFrame = ""
local testPlate
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
if (plateFrame [MEMBER_REACTION] < 4) then
testPlate = plateFrame
alphaPlateFrame = plateFrame:GetAlpha()
alphaUnitFrame = plateFrame.unitFrame:GetAlpha()
alphaHealthFrame = plateFrame.unitFrame.healthBar:GetAlpha()
break
end
end
print ("|cFFC0C0C0Alpha|r", "->", alphaPlateFrame, "-", alphaUnitFrame, "-", alphaHealthFrame)
if (testPlate) then
local w, h = testPlate:GetSize()
print ("|cFFC0C0C0Size|r", "->", w, h, "-", testPlate.unitFrame.healthBar:GetSize())
local point1, anchorFrame, point2, x, y = testPlate:GetPoint (1)
print ("|cFFC0C0C0Point|r", "->", point1, anchorFrame:GetName(), point2, x, y)
local plateIsShown = testPlate:IsShown() and "yes" or "no"
local unitFrameIsShown = testPlate.unitFrame:IsShown() and "yes" or "no"
local healthBarIsShown = testPlate.unitFrame.healthBar:IsShown() and "yes" or "no"
print ("|cFFC0C0C0ShownStatus|r", "->", plateIsShown, "-", unitFrameIsShown, "-", healthBarIsShown)
else
print ("|cFFC0C0C0Size|r", "-> there's no nameplate in the screen")
print ("|cFFC0C0C0Point|r", "-> there's no nameplate in the screen")
print ("|cFFC0C0C0ShownStatus|r", "-> there's no nameplate in the screen")
end
return
elseif (msg == "color" or msg == "colors") then
Plater.OpenColorFrame()
return
elseif (msg == "npcs" or msg == "ids") then
elseif (msg == "add" or msg == "addnpc") then
local plateFrame = C_NamePlate.GetNamePlateForUnit ("target")
if (plateFrame) then
local npcId = plateFrame [MEMBER_NPCID]
if (npcId) then
local colorDB = Plater.db.profile.npc_cache
if (not colorDB [npcId]) then
Plater.db.profile.npc_cache [npcId] = {plateFrame [MEMBER_NAME] or "UNKNOWN", Plater.ZoneName or "UNKNOWN"}
Plater:Msg ("Unit added.")
if (PlaterOptionsPanelFrame and PlaterOptionsPanelFrame:IsShown()) then
PlaterOptionsPanelContainerColorManagementColorsScroll:Hide()
C_Timer.After (.2, function()
PlaterOptionsPanelContainerColorManagementColorsScroll:Show()
end)
end
else
Plater:Msg ("Unit already added.")
end
else
Plater:Msg ("Invalid npc nameplate.")
end
else
Plater:Msg ("you need to target a npc or the npc nameplate couldn't be found.")
end
return
elseif (msg == "rare") then
local waitTick = function(tickerObject)
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
local unitClassification = UnitClassification(plateFrame.unitFrame[MEMBER_UNITID])
if (unitClassification == "rareelite") then
FlashClientIcon()
Plater:Msg("(debug) rare spawned!")
end
end
end
if (not Plater.rare_ticker) then
Plater:Msg("Plater will flash the taskbar wow icon when a rare spawns.")
Plater.rare_ticker = _G.C_Timer.NewTicker(3, waitTick)
else
Plater.rare_ticker:Cancel()
Plater.rare_ticker = nil
Plater:Msg("Plater stopped looking for rares.")
end
return
elseif (msg == "profstart" or msg == "profstartcore" or msg == "profstartadvance") then
Plater.EnableProfiling(true, true)
return
elseif (msg == "profstartmods") then
Plater.EnableProfiling(false, true)
return
elseif (msg == "profstartold") then
Plater.EnableProfiling(true, false)
return
elseif (msg == "profstop") then
Plater.DisableProfiling()
return
elseif (msg == "profprint") then
Plater.ShowPerfData()
return
elseif (msg == "minimap") then
PlaterDBChr.minimap.hide = not PlaterDBChr.minimap.hide
if (PlaterDBChr.minimap.hide) then
LDBIcon:Hide ("Plater")
else
LDBIcon:Show ("Plater")
end
LDBIcon:Refresh ("Plater", PlaterDBChr.minimap)
return
elseif (msg and msg:find("^cvar[s]?")) then
Plater.DebugCVars(msg:gsub("^cvar[s]? ?", ""))
return
end
local usage = "Usage Info:"
usage = usage .. "\n|cffffaeae/plater|r : Open the Plater options window"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33version|r: print Plater version information"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33profstart|r: Start Plater profiling"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33profstop|r: Stop Plater profiling"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33profprint|r: Print gathered profiling information"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33add|r: Adds the targeted unit to the NPC Cache"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33colors|r: Opens the Plater color palette"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33minimap|r: Toggle the Plater minimap icon"
usage = usage .. "\n|cffffaeae/plater|r |cffffff33cvar <cvar name>|r: Print information about a cvar value stored in the profile."
usage = usage .. "\n|cffffaeaeVersion:|r |cffffff33" .. Plater.GetVersionInfo() .. "|r"
Plater:Msg(usage)
Plater.OpenOptionsPanel()
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> debuggers ~debug
function Plater.DebugColorAnimation()
if (Plater.DebugColorAnimation_Timer) then
return
end
Plater.DebugColorAnimation_Timer = C_Timer.NewTicker (0.5, function() --~animationtest
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
--make the bar jump from green to pink - pink to green
Plater.ChangeHealthBarColor_Internal (plateFrame.unitFrame.healthBar, math.abs (math.sin (GetTime())), math.abs (math.cos (GetTime())), math.abs (math.sin (GetTime())), 1)
end
end)
C_Timer.After (10, function()
if (Plater.DebugColorAnimation_Timer) then
Plater.DebugColorAnimation_Timer:Cancel()
Plater.DebugColorAnimation_Timer = nil
Plater:Msg ("stopped the animation test.")
Plater.UpdateAllPlates()
end
end)
Plater:Msg ("is now animating color nameplates in your screen for test purposes.")
end
function Plater.DebugHealthAnimation()
if (Plater.DebugHealthAnimation_Timer) then
return
end
Plater.DebugHealthAnimation_Timer = C_Timer.NewTicker (1.5, function() --~animationtest
for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do
local self = plateFrame.unitFrame
if (self.healthBar.CurrentHealth == 0) then
self.healthBar.AnimationStart = 0
self.healthBar.AnimationEnd = UnitHealthMax (self [MEMBER_UNITID])
else
self.healthBar.AnimationStart = UnitHealthMax (self [MEMBER_UNITID])
self.healthBar.AnimationEnd = 0
end
self.healthBar:SetValue (self.healthBar.CurrentHealth)
self.healthBar.CurrentHealthMax = UnitHealthMax (self [MEMBER_UNITID])
self.healthBar.IsAnimating = true
if (self.healthBar.AnimationEnd > self.healthBar.AnimationStart) then
self.healthBar.AnimateFunc = Plater.AnimateRightWithAccel
else
self.healthBar.AnimateFunc = Plater.AnimateLeftWithAccel
end
end
end)
C_Timer.After (10, function()
if (Plater.DebugHealthAnimation_Timer) then
Plater.DebugHealthAnimation_Timer:Cancel()
Plater.DebugHealthAnimation_Timer = nil
Plater:Msg ("stopped the animation test.")
Plater.UpdateAllPlates()
end
end)
Plater:Msg ("is now animating nameplates in your screen for test purposes.")
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> color frame
function Plater.OpenColorFrame()
if (PlaterColorPreview) then
PlaterColorPreview:Show()
return
end
local function hex (num)
local hexstr = '0123456789abcdef'
local s = ''
while num > 0 do
local mod = math.fmod(num, 16)
s = string.sub(hexstr, mod+1, mod+1) .. s
num = math.floor(num / 16)
end
if s == '' then s = '00' end
if (string.len (s) == 1) then
s = "0"..s
end
return s
end
local a = CreateFrame ("frame", "PlaterColorPreview", UIParent, BackdropTemplateMixin and "BackdropTemplate")
a:SetSize (1400, 910)
a:SetPoint ("topleft", UIParent, "topleft")
--close button
local closeButton = DF:CreateButton (a, function() a:Hide() end, 160, 20, "", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"))
closeButton:SetPoint ("topright", a, "topright", -1, 0)
closeButton:SetText ("Close Color Palette")
DF:ApplyStandardBackdrop (a)
local onFocusGained = function (self)
self:HighlightText (0)
end
local onFocusLost = function (self)
self:HighlightText (0, 0)
end
local allColors = {}
for colorName, colorTable in pairs (DF.alias_text_colors) do
tinsert (allColors, {colorTable, colorName, hex (colorTable[1]*255) .. hex (colorTable[2]*255) .. hex (colorTable[3]*255)})
end
table.sort (allColors, function (t1, t2)
return t1[1][3] > t2[1][3]
end)
local x = 5
local y = -20
local totalWidth = 105
--for colorname, colortable in pairs (DF.alias_text_colors) do
for index, colorTable in ipairs (allColors) do
local colortable = colorTable [1]
local colorname = colorTable [2]
local backgroundTexture = a:CreateTexture (nil, "overlay")
backgroundTexture:SetColorTexture (unpack (colortable))
backgroundTexture:SetSize (100, 20)
backgroundTexture:SetPoint ("topleft", a, "topleft", x, y)
local textEntry = DF:CreateTextEntry (a, function()end, 100, 20)
textEntry:SetBackdrop (nil)
textEntry:SetPoint ("topleft", backgroundTexture, "topleft", 0, 0)
textEntry:SetPoint ("bottomright", backgroundTexture, "bottomright", 0, 0)
textEntry:SetText (colorname)
textEntry:SetHook ("OnEditFocusGained", onFocusGained)
textEntry:SetHook ("OnEditFocusLost", onFocusLost)
y = y - 20
if (y < -880) then
y = -20
x = x + 105
totalWidth = totalWidth + 105
end
end
a:SetWidth (totalWidth)
end
--functiona enda