--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 pairs = pairs
local rawset = rawset
local rawget = rawget
local error = error
local setfenv = setfenv
local pcall = pcall
local InCombatLockdown = InCombatLockdown
local UnitIsPlayer = UnitIsPlayer
local UnitClassification = UnitClassification
local UnitDetailedThreatSituation = UnitDetailedThreatSituation
local AuraUtilForEachAura = AuraUtil.ForEachAura
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 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 , { --options table
name = " Plater Nameplates " ,
type = " group " ,
args = {
openOptions = {
name = " Open Plater Options " ,
desc = " Opens the Plater Options Menu. " ,
type = " execute " ,
func = function ( )
InterfaceOptionsFrame : Hide ( )
HideUIPanel ( GameMenuFrame )
Plater.OpenOptionsPanel ( )
end ,
} ,
}
} )
Plater.versionString = GetAddOnMetadata ( " Plater_dev " , " Version " ) or GetAddOnMetadata ( " Plater " , " Version " )
Plater.fullVersionInfo = Plater.versionString .. " - DetailsFramework v " .. select ( 2 , LibStub : GetLibrary ( " DetailsFramework-1.0 " ) ) .. " - WoW " .. GetBuildInfo ( )
function Plater . GetVersionInfo ( printOut )
-- update, just in case...
Plater.versionString = GetAddOnMetadata ( " Plater_dev " , " Version " ) or GetAddOnMetadata ( " Plater " , " Version " )
Plater.fullVersionInfo = Plater.versionString .. " - DetailsFramework v " .. select ( 2 , LibStub : GetLibrary ( " DetailsFramework-1.0 " ) ) .. " - WoW " .. 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
--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
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)
}
--> 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 " ,
" 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 when it is compiled. Used to initialize the global mod environment 'modTable'. " ,
[ " Constructor " ] = " Executed once when the nameplate run the hook for the first time. \n \n Use to initialize configs in the environment. \n \n Always receive unitFrame in 'self' parameter. " ,
[ " Destructor " ] = " Run when the hook is Disabled or unloaded due to Load Conditions. \n \n Use 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 \n Requires 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 \n Use 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 \n Use to register textures, indicators, etc. \n \n |cFF44FF44Do not run on nameplates, \n run only once after login \n or /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_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
local COMM_PLATER_PREFIX = " PLT "
local 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 ,
} ,
}
--> 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
--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 = Plater.ScriptAura
Plater.ScriptCastBar = { }
local SCRIPT_CASTBAR = Plater.ScriptCastBar
Plater.ScriptUnit = { }
local SCRIPT_UNIT = 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 = { }
--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 ] = { } ,
}
--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
-- TBC
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
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
--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 : SetAlpha ( nameplateAlpha )
unitFrame.healthBar : SetAlpha ( 1 )
if not castBarFade then
unitFrame.castBar : SetAlpha ( 1 )
end
unitFrame.powerBar : SetAlpha ( 1 )
unitFrame.BuffFrame : SetAlpha ( 1 )
unitFrame.BuffFrame2 : SetAlpha ( 1 )
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 ( 1 )
unitFrame.BuffFrame2 : SetAlpha ( 1 )
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 ( 1 )
unitFrame.BuffFrame2 : SetAlpha ( 1 )
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
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
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 ( inRangeAlpha )
buffFrame2 : SetAlpha ( inRangeAlpha )
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 ( 1 )
buffFrame2 : SetAlpha ( 1 )
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 ( 1 )
buffFrame2 : SetAlpha ( 1 )
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 "
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 "
else
return GetPartyAssignment ( " MAINTANK " , unit )
end
end
-- toggle Threat Color Mode between tank / dps (CLASSIC)
function Plater . ToggleThreatColorMode ( )
if IS_WOW_PROJECT_NOT_MAINLINE 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 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 ,
[ " 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 ,
[ " nameplateShowFriendlyGuardians " ] = true ,
[ " nameplateShowFriendlyMinions " ] = true ,
[ " nameplateShowFriendlyNPCs " ] = true ,
[ " nameplateShowFriendlyPets " ] = true ,
[ " nameplateShowFriendlyTotems " ] = true ,
[ " nameplateShowFriends " ] = true ,
[ " nameplateShowOnlyNames " ] = true ,
[ " nameplateShowSelf " ] = ( IS_WOW_PROJECT_MAINLINE ) ,
[ " nameplateTargetBehindMaxDistance " ] = true ,
[ " clampTargetNameplateToScreen " ] = true ,
[ " nameplateTargetRadialPosition " ] = true ,
--["showQuestTrackingTooltips"] = true, -- this seems to be gone as of 18.12.2020
[ " nameplateSelectedAlpha " ] = true ,
[ " nameplateNotSelectedAlpha " ] = ( IS_WOW_PROJECT_NOT_MAINLINE ) ,
[ " nameplateRemovalAnimation " ] = ( IS_WOW_PROJECT_NOT_MAINLINE ) ,
}
--on logout or on profile change, save some important cvars inside the profile
function Plater . SaveConsoleVariables ( cvar , value ) --private
--print("save cvars", cvar, value, debugstack())
local cvarTable = Plater.db . profile.saved_cvars
if ( not cvarTable ) then
--return
Plater.db . profile.saved_cvars = { }
cvarTable = Plater.db . profile.saved_cvars
end
if not cvar then
for CVarName , enabled in pairs ( cvars_to_store ) do
if enabled then
cvarTable [ CVarName ] = tostring ( GetCVar ( CVarName ) )
end
end
elseif cvars_to_store [ cvar ] then
cvarTable [ cvar ] = tostring ( value )
end
end
hooksecurefunc ( ' SetCVar ' , Plater.SaveConsoleVariables )
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 )
--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
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.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 )
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 : ScriptGetInfo ( 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 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 ,
PLAYER_SPECIALIZATION_CHANGED = function ( )
C_Timer.After ( 1.5 , Plater.CanUsePlaterResourceFrame ) --~resource
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 ,
PLAYER_REGEN_DISABLED = function ( )
PLAYER_IN_COMBAT = true
Plater.RefreshTankCache ( )
--Plater.UpdateAuraCache()
Plater.UpdateAllPlates ( )
--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 ( )
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.CreatePlaterResourceFrame ( ) --~resource
--run hooks on load screen
if ( HOOK_LOAD_SCREEN.ScriptAmount > 0 ) then
Plater.PlayerEnteringWorld = true
end
end ,
PLAYER_LOGOUT = function ( )
--Plater.SaveConsoleVariables()
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 = { }
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
--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
--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 " , - 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 " , - 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 " , nil , 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 : ScriptGetInfo ( globalScriptObject , scriptContainer , " Nameplate Created " )
plateFrame.unitFrame : ScriptRunHook ( scriptInfo , " Nameplate Created " )
end
end
end ,
-- ~added
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 " )
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 )
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
--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
unitFrame.Settings . ShowCastBar = true -- reset to default, clearing later.
unitFrame : SetUnit ( unitID )
--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
unitFrame.QuestAmountCurrent = nil
unitFrame.QuestAmountTotal = 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
plateFrame.PlayerCannotAttack = nil
plateFrame.playerGuildName = nil
plateFrame [ MEMBER_NOCOMBAT ] = nil
plateFrame [ MEMBER_TARGET ] = nil
plateFrame [ MEMBER_NPCID ] = nil
unitFrame [ MEMBER_TARGET ] = nil
unitFrame [ MEMBER_NPCID ] = 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
--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
plateFrame [ MEMBER_GUID ] = UnitGUID ( unitID ) or " "
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 )
--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 [ MEMBER_GUID ] = plateFrame [ MEMBER_GUID ]
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 )
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 )
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 )
end
end
else
--the unit is a npc
Plater.GetNpcID ( plateFrame )
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 )
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 )
end
else
--includes neutral npcs
--add the npc in the npcid cache
if ( not DB_NPCIDS_CACHE [ plateFrame [ MEMBER_NPCID ] ] and not IS_IN_OPEN_WORLD and not Plater.ZonePvpType 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 }
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 )
end
--get threat situation to expose it to scripts already in the nameplate added hook
local isTanking , threatStatus , threatpct = UnitDetailedThreatSituation ( " player " , unitID )
unitFrame.namePlateThreatIsTanking = isTanking
unitFrame.namePlateThreatStatus = threatStatus
unitFrame.namePlateThreatPercent = threatpct or 0
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
--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)
--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 : ScriptGetInfo ( 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 )
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 : ScriptGetInfo ( 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 ( )
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
PlaterDBChr.spellRangeCheckRangeEnemy [ specID ] = Plater.DefaultSpellRangeList [ specID ]
end
if ( PlaterDBChr.spellRangeCheckRangeFriendly [ specID ] == nil or not LibRangeCheck : GetFriendMaxChecker ( PlaterDBChr.spellRangeCheckRangeFriendly [ specID ] ) ) 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
PlaterDBChr.spellRangeCheckRangeEnemy [ playerClass ] = Plater.DefaultSpellRangeList [ playerClass ]
end
if ( PlaterDBChr.spellRangeCheckRangeFriendly [ playerClass ] == nil or not LibRangeCheck : GetFriendMaxChecker ( PlaterDBChr.spellRangeCheckRangeFriendly [ playerClass ] ) ) 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 " ) )
--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 " )
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 ( 0.1 , Plater.UpdatePlateClickSpace )
--C_Timer.After (1, Plater.GetSpellForRangeCheck)
C_Timer.After ( 4 , Plater.GetHealthCutoffValue )
C_Timer.After ( 4.2 , Plater.ForceCVars )
--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 ( " 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 " )
if IS_WOW_PROJECT_NOT_MAINLINE then -- tank spec detection
Plater.EventHandlerFrame : RegisterEvent ( " UNIT_INVENTORY_CHANGED " )
Plater.EventHandlerFrame : RegisterEvent ( " UPDATE_SHAPESHIFT_FORM " )
end
--many times at saved variables load the spell database isn't loaded yet
function Plater : PLAYER_LOGIN ( )
C_Timer.After ( 0.1 , Plater.RestoreProfileCVars )
C_Timer.After ( 0.2 , Plater.ForceCVars )
--C_Timer.After (0.3, Plater.GetSpellForRangeCheck)
C_Timer.After ( 0.4 , Plater.UpdatePlateClickSpace )
-- 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
Plater.PlayerPetCache [ petGUID ] = time ( )
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 ( 5 , 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 )
end
Plater : RegisterEvent ( " PLAYER_LOGIN " )
--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 : ScriptGetInfo ( 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 ( )
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 )
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
--> 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 = 1
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.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
icon : SetPoint ( " topright " , unitFrame.healthBar , " 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 )
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
icon : SetPoint ( " topleft " , unitFrame.healthBar , " 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 )
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
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
--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.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 ( )
if ( profile.cast_color_settings . enabled ) then
local castColors = Plater.db . profile.cast_colors
--check if this cast has a custom color
if ( castColors [ self.spellID ] ) then
self.castColorTexture : Show ( )
local r , g , b = Plater : ParseColors ( castColors [ self.spellID ] [ 2 ] )
self.castColorTexture : SetColorTexture ( r , g , b )
self.castColorTexture : SetHeight ( self : GetHeight ( ) + profile.cast_color_settings . height_offset )
end
end
elseif ( event == " UNIT_SPELLCAST_INTERRUPTED " ) then
local unitCast = unit
if ( unitCast ~= self.unit ) then
return
end
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 : ScriptGetInfo ( 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 [ 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 : ScriptGetInfo ( 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 )
for i = 1 , HOOK_HEALTH_UPDATE.ScriptAmount do
local globalScriptObject = HOOK_HEALTH_UPDATE [ i ]
local scriptContainer = unitFrame : ScriptGetContainer ( )
local scriptInfo = unitFrame : ScriptGetInfo ( globalScriptObject , scriptContainer , " Health Update " )
--run
unitFrame : ScriptRunHook ( scriptInfo , " Health Update " )
end
end
function Plater . OnUpdateHealth ( self )
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
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 )
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 ( )
C_Timer.After ( 4.1 , Plater.QuestLogUpdated )
C_Timer.After ( 5.1 , function ( ) Plater.IncreaseRefreshID ( ) ; Plater.UpdateAllPlates ( ) end )
for i = 1 , 3 do
C_Timer.After ( i , Plater.RefreshDBUpvalues )
end
CastingBarFrame : HookScript ( " OnShow " , function ( self )
if ( Plater.db . profile.hide_blizzard_castbar ) then
self : Hide ( )
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...
InterfaceOptionsFrame : HookScript ( ' OnHide ' , Plater.UpdatePlateClickSpace )
VideoOptionsFrame : HookScript ( ' OnHide ' , Plater.UpdatePlateClickSpace )
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
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> 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 ] ) 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 = RAID_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 = RAID_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
function Plater . SetTextColorByClass ( unit , text )
--checking if the unit exists because this can be called from the cleu parser
if ( unit ) then
local _ , class = UnitClass ( unit )
if ( class ) then
local color = RAID_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
--full refresh calls
function Plater . UpdateAllPlates ( forceUpdate , justAdded ) --private
for _ , plateFrame in ipairs ( Plater.GetAllShownPlates ( ) ) do
Plater.UpdatePlateFrame ( plateFrame , nil , forceUpdate , justAdded )
end
end
--called from the options panel
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
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 ) / 2
local yOffSet = ( plateFrame : GetHeight ( ) - healthBarHeight ) / 2
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 )
--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 )
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 = 0 ,
curFPS = 0 ,
}
function Plater . EveryFrameFPSCheck ( )
-- calculate every .25sec
local curTime = GetTime ( )
local curFPSData = Plater.FPSData
if ( curFPSData.startTime + 0.25 ) < curTime then
curFPSData.curFPS = curFPSData.frames / ( curTime - curFPSData.startTime )
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 - 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 ]
--perform a range check
Plater.CheckRange ( tickFrame.PlateFrame , ( deltaTime == 999 ) )
--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 )
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
--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
--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 )
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
--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
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
--check if the unit name or unit npcID has a script
local globalScriptObject = SCRIPT_UNIT [ tickFrame.PlateFrame [ MEMBER_NAMELOWER ] ] or SCRIPT_UNIT [ 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 : ScriptGetInfo ( globalScriptObject , scriptContainer , " Name Updated " )
--run
unitFrame : ScriptRunHook ( scriptInfo , " Name Updated " )
end
end
end
--hooks
if ( 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 : ScriptGetInfo ( globalScriptObject , scriptContainer , " Nameplate Updated " )
local scriptEnv = scriptInfo.Env
scriptEnv._HealthPercent = healthBar.CurrentHealth / healthBar.CurrentHealthMax * 100
--run
unitFrame : ScriptRunHook ( scriptInfo , " Nameplate Updated " )
end
end
--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
--end of throttled updates
end
--OnTick updates
--smooth color transition ~lerpcolor
if ( DB_LERP_COLOR ) 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 ) 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
local profile = Plater.db . profile
local isTanking , threatStatus , threatpct = UnitDetailedThreatSituation ( " player " , self.displayedUnit )
--expose all threat situation to scripts
self.namePlateThreatIsTanking = isTanking
self.namePlateThreatStatus = threatStatus
self.namePlateThreatPercent = threatpct 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
end
-- ~target
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 ) 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 : ScriptGetInfo ( globalScriptObject , scriptContainer , " Target Changed " )
--run
unitFrame : ScriptRunHook ( scriptInfo , " Target Changed " )
end
end
end
end
Plater.CanUsePlaterResourceFrame ( ) --~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 )
elseif ( i == 2 ) then
PixelUtil.SetPoint ( texture , " 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 )
elseif ( i == 4 ) then
PixelUtil.SetPoint ( texture , " 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 )
elseif ( i == 2 ) then
PixelUtil.SetPoint ( texture , " 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 = RAID_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 = RAID_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 = RAID_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
-- ~updateplate ~update ~updatenameplate
function Plater . UpdatePlateFrame ( plateFrame , actorType , forceUpdate , justAdded )
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
plateFrame.IsNpcWithoutHealthBar = false
plateFrame.IsFriendlyPlayerWithoutHealthBar = false
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
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 ( )
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 ( )
--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 ( )
end
elseif ( actorType == ACTORTYPE_FRIENDLY_PLAYER ) then
Plater.ParseHealthSettingForPlayer ( plateFrame )
--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 = RAID_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
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 ( )
if ( DB_PLATE_CONFIG [ actorType ] . use_playerclass_color ) then
local _ , class = UnitClass ( unitFrame [ MEMBER_UNITID ] )
if ( class ) then
local color = RAID_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 or enemy player pass throught here
--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 ( )
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 ) --for channeling color, use the same color as the regular cast
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 )
--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 )
--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 )
--> 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 : ScriptGetInfo ( globalScriptObject , scriptContainer , " Raid Target " )
--run
unitFrame : ScriptRunHook ( scriptInfo , " Raid Target " )
end
end
end
end
end
-- ~indicators
function Plater . UpdateIndicators ( plateFrame , actorType )
--limpa os indicadores
Plater.ClearIndicators ( plateFrame )
local config = Plater.db . profile
if ( actorType == ACTORTYPE_ENEMY_PLAYER ) then
if ( config.indicator_faction ) then
Plater.AddIndicator ( plateFrame , UnitFactionGroup ( plateFrame.unitFrame [ MEMBER_UNITID ] ) )
end
if ( config.indicator_enemyclass ) then
Plater.AddIndicator ( plateFrame , " classicon " )
end
if ( config.indicator_spec ) 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 ( )
--friendly nameplate toggle
if ( Plater.db . profile.auto_toggle_friendly_enabled ) then
--discover which is the map type the player is in
if ( zoneType == " party " ) then
SetCVar ( " nameplateShowFriends " , Plater.db . profile.auto_toggle_friendly [ " party " ] and CVAR_ENABLED or CVAR_DISABLED )
elseif ( zoneType == " raid " ) then
SetCVar ( " nameplateShowFriends " , Plater.db . profile.auto_toggle_friendly [ " raid " ] and CVAR_ENABLED or CVAR_DISABLED )
elseif ( zoneType == " arena " or zoneType == " pvp " ) then
SetCVar ( " nameplateShowFriends " , Plater.db . 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 " , Plater.db . profile.auto_toggle_friendly [ " cities " ] and CVAR_ENABLED or CVAR_DISABLED )
else
SetCVar ( " nameplateShowFriends " , Plater.db . profile.auto_toggle_friendly [ " world " ] and CVAR_ENABLED or CVAR_DISABLED )
end
end
end
--stacking toggle
if ( Plater.db . profile.auto_toggle_stacking_enabled and Plater.db . profile.stacking_nameplates_enabled ) then
--discover which is the map type the player is in
if ( zoneType == " party " ) then
SetCVar ( " nameplateMotion " , Plater.db . profile.auto_toggle_stacking [ " party " ] and CVAR_ENABLED or CVAR_DISABLED )
elseif ( zoneType == " raid " ) then
SetCVar ( " nameplateMotion " , Plater.db . profile.auto_toggle_stacking [ " raid " ] and CVAR_ENABLED or CVAR_DISABLED )
elseif ( zoneType == " arena " or zoneType == " pvp " ) then
SetCVar ( " nameplateMotion " , Plater.db . 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 " , Plater.db . profile.auto_toggle_stacking [ " cities " ] and CVAR_ENABLED or CVAR_DISABLED )
else
SetCVar ( " nameplateMotion " , Plater.db . 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
--check the setting 'only_damaged' and 'only_thename' for player characters. not critical code, can run slow
function Plater . ParseHealthSettingForPlayer ( plateFrame ) --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 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
Plater.ShowHealthBar ( plateFrame.unitFrame )
elseif not isFriendlyPlayerWithoutHealthBar then
Plater.HideHealthBar ( plateFrame.unitFrame , true )
end
else
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 ( 1 , 1 )
animationHub.ScaleUp : SetToScale ( scaleUpX , scaleUpY )
animationHub.ScaleDown : SetFromScale ( 1 , 1 )
animationHub.ScaleDown : SetToScale ( 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
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
--]=]
PET_CACHE [ targetGUID ] = time
if ( sourceGUID == Plater.PlayerGUID ) then
Plater.PlayerPetCache [ targetGUID ] = time
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
for _ , plateFrame in ipairs ( Plater.GetAllShownPlates ( ) ) do
if ( plateFrame.unitFrame . PlaterOnScreen and plateFrame.unitFrame . castBar : IsShown ( ) ) then
if ( plateFrame [ MEMBER_GUID ] == targetGUID ) then
if DB_USE_NAME_TRANSLIT then
sourceName = LibTranslit : Transliterate ( sourceName , TRANSLIT_MARK )
end
plateFrame.unitFrame . castBar.Text : SetText ( INTERRUPTED .. " [ " .. Plater.SetTextColorByClass ( sourceName , sourceName ) .. " ] " )
plateFrame.unitFrame . castBar.IsInterrupted = true
--> check and stop the casting script if any
plateFrame.unitFrame . 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 = Plater : GetNpcIdFromGuid ( sourceGUID or " " ) , encounterID = Plater.CurrentEncounterID , encounterName = Plater.CurrentEncounterName }
end
end
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 )
Plater.EndLogPerformanceCore ( " Plater-Core " , " Events " , token )
end
end
PlaterCLEUParser : SetScript ( " OnEvent " , PlaterCLEUParser.Parser )
PlaterCLEUParser : RegisterEvent ( " COMBAT_LOG_EVENT_UNFILTERED " )
C_Timer.NewTicker ( 180 , function ( )
local now = time ( )
for guid , time in pairs ( PET_CACHE ) do
if ( time + 180 < now ) then
PET_CACHE [ guid ] = nil
end
end
for guid , time in pairs ( Plater.PlayerPetCache ) do
if ( time + 3600 < now ) then
Plater.PlayerPetCache [ guid ] = nil
end
end
end )
Plater.NpcBlackList = { }
function Plater . ForceFindPetOwner ( serial ) --private
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 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
elseif ( string.match ( text1 , string.gsub ( UNITNAME_TITLE_PET , " %%s " , " (%.*) " ) ) or string.match ( text1 , string.gsub ( UNITNAME_TITLE_MINION , " %%s " , " (%.*) " ) ) ) then
isOtherPet = true
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
elseif ( string.match ( text2 , string.gsub ( UNITNAME_TITLE_PET , " %%s " , " (%.*) " ) ) or string.match ( text2 , string.gsub ( UNITNAME_TITLE_MINION , " %%s " , " (%.*) " ) ) ) then
isOtherPet = true
end
end
end
if ( isPlayerPet ) then
PET_CACHE [ serial ] = time ( )
Plater.PlayerPetCache [ serial ] = time ( )
elseif ( isOtherPet ) then
PET_CACHE [ serial ] = time ( )
else
Plater.NpcBlackList [ serial ] = true
end
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--> cvars - ~cvars
function Plater . CreatePlaterButtonAtInterfaceOptions ( )
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
--> 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 )
--> view distance
SetCVar ( " nameplateMaxDistance " , 100 )
--> 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 " )
--InterfaceOptionsNamesPanelUnitNameplatesMakeLarger:Click() --this isn't required anymore since we use our own unitframe now
--InterfaceOptionsNamesPanelUnitNameplatesPersonalResource:Click() --removing this since I don't have documentation on why this was added
--InterfaceOptionsNamesPanelUnitNameplatesPersonalResource:Click()
--[=[
Plater.RestoreProfileCVars ( )
--]=]
--Plater:Msg ("Plater has been successfully installed on this character.")
end
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
for CVarName , CVarValue in pairs ( savedCVars ) do
if cvars_to_store [ CVarName ] then --only restore what we want to store/restore!
SetCVar ( CVarName , CVarValue )
end
end
if ( PlaterOptionsPanelFrame ) then
--PlaterOptionsPanelFrame.RefreshOptionsFrame()
end
end
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.unitFrame . QuestAmountCurrent = nil
plateFrame.unitFrame . QuestAmountTotal = 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 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
else
text = ScanQuestTextCache [ i ] : GetText ( )
end
if ( Plater.QuestCache [ text ] ) then
--unit belongs to a quest
isQuestUnit = true
local isGroupQuest , yourQuest = nil , nil
local questData = {
questName = text ,
questText = " " ,
finished = true ,
groupQuest = false ,
groupFinished = true ,
amount = 0 ,
total = 0 ,
yourQuest = false ,
}
local amount1 , amount2 , questText = nil , nil , nil
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 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
questData.amount = amount1
questData.total = amount2
if yourQuest ~= false then
yourQuest = false
questData.finished = false
end
questData.groupFinished = false
questData.questText = nextLineText
questText = nextLineText
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 = amount1
plateFrame.QuestAmountTotal = amount2
plateFrame.QuestText = questText
--expose to scripts
plateFrame.unitFrame . QuestAmountCurrent = amount1
plateFrame.unitFrame . QuestAmountTotal = amount2
plateFrame.unitFrame . QuestText = questText
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 )
--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
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 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 ]
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
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 )
--defaults
duration = duration or 0.25
amount = amount or 1
if ( not r ) then
r , g , b = 1 , 1 , 1
else
r , g , b = DF : ParseColors ( r , g , b )
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 )
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 UnitAffectingCombat ( unitFrame.unit ) ) 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
--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
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
ScriptGetInfo = function ( self , globalScriptObject , widgetScriptContainer , isHookScript )
widgetScriptContainer = widgetScriptContainer or self : ScriptGetContainer ( )
--using the memory address of the original scriptObject from db.profile as the map key
local scriptInfo = widgetScriptContainer [ 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 ( isHookScript and 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
widgetScriptContainer [ globalScriptObject.DBScriptObject . scriptId ] = scriptInfo
end
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
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 okay , errortext = pcall ( scriptInfo.GlobalScriptObject [ " OnShowCode " ] , 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 mainScriptTable
if ( self.IsAuraIcon ) then
mainScriptTable = SCRIPT_AURA
elseif ( self.IsCastBar ) then
mainScriptTable = SCRIPT_CASTBAR
elseif ( self.IsUnitNameplate ) then
mainScriptTable = SCRIPT_UNIT
end
--> ScriptKey holds the trigger of the script currently running
local globalScriptObject = mainScriptTable [ 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 ( )
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 : ScriptGetInfo ( 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 mainScriptTable
if ( self.IsAuraIcon ) then
mainScriptTable = SCRIPT_AURA
triggerID = GetSpellInfo ( triggerID )
elseif ( self.IsCastBar ) then
mainScriptTable = SCRIPT_CASTBAR
triggerID = GetSpellInfo ( triggerID )
elseif ( self.IsUnitNameplate ) then
mainScriptTable = SCRIPT_UNIT
end
if ( self.ScriptKey and self.ScriptKey == triggerID ) then
local globalScriptObject = mainScriptTable [ 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
if not noHotReload then
PLATER_GLOBAL_SCRIPT_ENV [ scriptObject.scriptId ] = nil
end
Plater.CompileScript ( scriptObject )
end
end
elseif ( scriptType == " hook " ) then
--get all hook scripts from the profile database
for scriptId , scriptObject in ipairs ( Plater.GetAllScriptsAsPrioSortedCopy ( " hook " ) ) do
if not noHotReload then
PLATER_GLOBAL_MOD_ENV [ scriptObject.scriptId ] = nil
end
Plater.CompileHook ( scriptObject )
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_GLOBAL_SCRIPT_ENV [ scriptObject.scriptId ] = nil
Plater.CompileScript ( scriptObject )
elseif ( scriptType == " hook " ) then
PLATER_GLOBAL_MOD_ENV [ scriptObject.scriptId ] = nil
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 ,
[ " UpdateWagoStashData " ] = true ,
[ " CheckWagoUpdates " ] = 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 ,
} ,
[ " 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 )
table.wipe ( SCRIPT_CASTBAR )
table.wipe ( SCRIPT_UNIT )
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 == " 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 : ScriptGetInfo ( 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
-- 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 )
--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 )
end
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 )
end
return
else
Plater.CurrentlyLoadedHooks [ scriptObject.scriptId ] = true
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 ,
}
--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, no need to check if already exists, hook containers cache are cleaned before script compile
tinsert ( globalScriptContainer , globalScriptObject )
globalScriptContainer.ScriptAmount = globalScriptContainer.ScriptAmount + 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 , ... )
--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
--store the scripts to be compiled
local scriptCode , scriptFunctions = { } , { }
--get scripts passed to
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
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
-- 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)
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
scriptFunctions [ scriptType ] = compiledScript ( )
end
end
--trigger container is the table with spellIds for auras or spellcast
--triggerId is the spellId then converted to spellName or the unitName in case is a Unit script
local triggerContainer , triggerId
if ( scriptObject.ScriptType == 1 or scriptObject.ScriptType == 2 ) then --aura or castbar
triggerContainer = " SpellIds "
elseif ( scriptObject.ScriptType == 3 ) then --unit plate
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
--> if is a unit name, make it be in lower case
elseif ( scriptObject.ScriptType == 3 ) then
--> cast the string to number to see if it's a npcId
triggerId = tonumber ( triggerId ) or triggerId
--> the user may have inserted the npcId
if ( type ( triggerId ) == " string " ) then
triggerId = lower ( triggerId )
end
end
if ( triggerId ) then
--get the global script object table
local mainScriptTable
if ( scriptObject.ScriptType == 1 ) then
mainScriptTable = SCRIPT_AURA
elseif ( scriptObject.ScriptType == 2 ) then
mainScriptTable = SCRIPT_CASTBAR
elseif ( scriptObject.ScriptType == 3 ) then
mainScriptTable = SCRIPT_UNIT
end
local globalScriptObject = mainScriptTable [ 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 ,
}
mainScriptTable [ triggerId ] = globalScriptObject
else --hot reload and update
globalScriptObject.HotReload = globalScriptObject.HotReload + 1
globalScriptObject.DBScriptObject = scriptObject
end
--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 \n Import profiles at the Profiles tab. " )
elseif ( indexScriptTable.NpcColor ) then
DF : ShowErrorMessage ( " Invalid Script or Mod. \n \n Import 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 ( COMM_PLATER_PREFIX , LibAceSerializer : Serialize ( COMM_SCRIPT_GROUP_EXPORTED , UnitName ( " player " ) , GetRealmName ( ) , UnitGUID ( " player " ) , encodedString ) , " RAID " )
elseif ( IsInGroup ( LE_PARTY_CATEGORY_HOME ) ) then
Plater : SendCommMessage ( COMM_PLATER_PREFIX , LibAceSerializer : Serialize ( 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 : ScriptGetInfo ( 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 : ScriptGetInfo ( 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 : ScriptGetInfo ( 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 ] , Plater.ZoneName }
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 " ) then
Plater.EnableProfiling ( true )
return
elseif ( msg == " profstartmods " ) then
Plater.EnableProfiling ( 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
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 |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