Advertisement
Guest User

HolySonar addon

a guest
Sep 15th, 2014
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.53 KB | None | 0 0
  1. Radar = {}
  2. HolyNovaIcon = {};
  3. local currentMap = {}
  4. currentMap.height = 500
  5. currentMap.width = 500
  6.  
  7. -- Colors Initialization
  8. local Colors = {}
  9. Colors.green = {}
  10. Colors.green.r = 0.309803922
  11. Colors.green.g = 0.674509804
  12. Colors.green.b = 0.043137255
  13.  
  14. Colors.yellow = {}
  15. Colors.yellow.r = 0.674509804
  16. Colors.yellow.g = 0.592156863
  17. Colors.yellow.b = 0.043137255
  18.  
  19. Colors.orange = {}
  20. Colors.orange.r = 0.674509804
  21. Colors.orange.g = 0.325490196
  22. Colors.orange.b = 0.043137255
  23.  
  24. Colors.red = {}
  25. Colors.red.r = 0.674509804
  26. Colors.red.g = 0.145098039
  27. Colors.red.b = 0.043137255
  28.  
  29. Colors.BAD = {}
  30. Colors.BAD.r = 0.674509804
  31. Colors.BAD.g = 0.145098039
  32. Colors.BAD.b = 0.043137255
  33.  
  34. Colors.GOOD = {}
  35. Colors.GOOD.r = 0.309803922
  36. Colors.GOOD.g = 0.674509804
  37. Colors.GOOD.b = 0.043137255
  38.  
  39. -- Values that will be setted in a configuration file/menu
  40. RadarSize = 300       -- Square radar Height and Width
  41.  
  42. -- This Global will keep all dots frames, so change them to update the radar
  43. local dots = {}
  44. SLASH_HOLYSONAR1 = '/hn'
  45. function SlashCmdList.HOLYSONAR(msg, editbox) -- 4.
  46.     if msg == "radar" then
  47.         -- Toggles Radar Visibility on /hn radar
  48.         if Radar:IsVisible() then
  49.             Radar:Hide()
  50.         else
  51.             Radar:Show()
  52.         end
  53.     elseif msg == "icon" then
  54.         -- Toggles Icon Visibility on /hn icon
  55.         if HolyNovaIcon:IsVisible() then
  56.             HolyNovaIcon:Hide()
  57.         else
  58.             HolyNovaIcon:Show()
  59.         end
  60.     else
  61.         -- Toggles Icon Visibility on  both
  62.         if HolyNovaIcon:IsVisible() then
  63.             HolyNovaIcon:Hide()
  64.             Radar:Hide()
  65.         else
  66.             HolyNovaIcon:Show()
  67.             Radar:Show()
  68.         end
  69.     end
  70. end
  71.  
  72. -- Holy Nova Icon With text initialization!
  73. local function newHNIcon()
  74.     -- Create the main frame
  75.     local IconFrame = CreateFrame("Frame", "HolyNovaTargets", UIParent)
  76.     IconFrame:SetFrameStrata("DIALOG")
  77.     IconFrame:SetPoint("CENTER", -400, 0)
  78.     IconFrame:SetSize(64,64)
  79.     IconFrame:EnableMouse(false)
  80.  
  81.     -- Set Holy Nova Icon Texture
  82.     local iconTexture = IconFrame:CreateTexture(nil,"BACKGROUND")
  83.     iconTexture:SetAllPoints(IconFrame)
  84.     iconTexture:SetTexture("Interface\\Icons\\Spell_Holy_HolyNova.blp")
  85.  
  86.     -- Overlay on the icon to display a "Good/Bad" effect
  87.     local overlay = IconFrame:CreateTexture("ARTWORK")
  88.     overlay:SetAllPoints()
  89.     -- Start with BAD Color
  90.     overlay:SetTexture(Colors.BAD.r, Colors.BAD.g, Colors.BAD.b)
  91.     overlay:SetAlpha(0.2)
  92.     overlay:Show()
  93.     IconFrame.overlay = overlay
  94.  
  95.     -- Text to display amount if people around
  96.     local iconText = IconFrame:CreateFontString();
  97.     iconText:SetFont("Fonts\\FRIZQT__.TTF", 18, "OUTLINE, MONOCHROME")
  98.     iconText:SetText("0")
  99.     iconText:SetTextColor(1,1,1)
  100.     iconText:SetPoint("CENTER",IconFrame,"CENTER",0,0)
  101.     IconFrame.text = iconText
  102.     IconFrame:Show()
  103.  
  104.     return IconFrame
  105. end
  106.  
  107. -- Radar Frame initialization code!
  108. local function newRadar()
  109.     local radarFrame = CreateFrame("Frame", "LifeRadar", UIParent)
  110.     radarFrame:SetFrameStrata("DIALOG")
  111.     radarFrame:SetPoint("CENTER", 400, 0)
  112.  
  113.     radarFrame:SetHeight(RadarSize)
  114.     radarFrame:SetWidth(RadarSize)
  115.     radarFrame:EnableMouse(false)       -- Click through
  116.     radarFrame:SetToplevel(true)
  117.  
  118.     -- Transparent Black background
  119.     local bg = radarFrame:CreateTexture(nil, "BACKGROUND")
  120.     bg:SetAllPoints(radarFrame)
  121.     bg:SetBlendMode("BLEND")
  122.     bg:SetTexture(0, 0, 0, 0.3)
  123.     radarFrame.background = bg
  124.  
  125.  
  126.     -- I've used DBM circle, it looks pretty
  127.     -- You can create another one and import it
  128.     local circle = radarFrame:CreateTexture(nil, "ARTWORK")
  129.     circle:SetSize(RadarSize, RadarSize)
  130.     circle:SetPoint("CENTER")
  131.     circle:SetTexture("Interface\\AddOns\\DBM-Core\\textures\\radar_circle.blp")
  132.     circle:SetBlendMode("ADD")
  133.     circle:SetVertexColor(0, 1, 0)
  134.     -- Store the background circle on the variable, so we can change it's color
  135.     radarFrame.circle = circle
  136.  
  137.     -- Player arrow, not needed, but looks good for reference
  138.     local player = radarFrame:CreateTexture(nil, "OVERLAY")
  139.     player:SetSize(32, 32)
  140.     player:SetTexture("Interface\\Minimap\\MinimapArrow.blp")
  141.     player:SetBlendMode("ADD")
  142.     player:SetPoint("CENTER")
  143.  
  144.     -- Max Raid size is 40, so 40 frames (Dots) created should be enough
  145.     for i = 1, 40 do
  146.         local dot = radarFrame:CreateTexture(nil, "OVERLAY")
  147.         dot:SetSize(20, 20)
  148.         -- X,Y coords, You can start them on 0
  149.         -- TOPLEFT is the "Anchor", so x and y are 'how maby pixels of distance the frame is from the anchor'
  150.         dot:SetPoint("TOPLEFT", i*5, i*-5)
  151.  
  152.         -- PartyRaidBlips is a 'big' image containing a lot of textures, that include class icons, markeers, etc.
  153.         dot:SetTexture("Interface\\Minimap\\PartyRaidBlips")
  154.  
  155.         -- You have to remap the texture in order to "zoom" on a specific texture
  156.         -- Here I zoomed on the Priest one (just a white dot), just to get a nice looking circle without having to make a new texture
  157.         dot:SetTexCoord(0.5, 0.625, 0, 0.25)
  158.  
  159.         -- Here you can set the dot color using RGBA, so the icon original color is irrelevant
  160.         -- It'll desaturate it and colorize
  161.         -- Randomized for fun
  162.         dot:SetVertexColor(math.random(),math.random(),math.random(),1)
  163.  
  164.         -- All dots start hidden, so you can dot:Show() them after
  165.         dot:Hide()
  166.         dots[i] = dot
  167.     end
  168.  
  169.     -- Frame starts hidden
  170.     radarFrame:Show()
  171.     return radarFrame
  172. end
  173.  
  174. -- Map methods
  175. local function getUnitMapPosition(unit)
  176.     SetMapToCurrentZone()
  177.     local relative_x, relative_y = GetPlayerMapPosition(unit)
  178.  
  179.     return currentMap.width*relative_x, currentMap.height*relative_y
  180. end
  181.  
  182. local function updateCurrentMap()
  183.     -- Try custom map size first
  184.     SetMapToCurrentZone()
  185.     local mapName = GetMapInfo()
  186.     local floor, a1, b1, c1, d1 = GetCurrentMapDungeonLevel()
  187.      
  188.     -- failed, try Blizzard's map size
  189.     if not (a1 and b1 and c1 and d1) then
  190.         local zoneIndex, a2, b2, c2, d2 = GetCurrentMapZone()
  191.         a1, b1, c1, d1 = a2, b2, c2, d2
  192.     end
  193.  
  194.     if not (a1 and b1 and c1 and d1) then return end
  195.     currentMap.height = abs(d1-b1)
  196.     currentMap.width = abs(c1-a1)
  197. end
  198.  
  199. -- Straight line distance from 2 coordinates
  200. local function getDistance(x1, y1, x2, y2)
  201.     local xx = x2 - x1
  202.     local yy = y2 - y1
  203.  
  204.     return sqrt(xx*xx + yy*yy)
  205. end
  206.  
  207. -- Just to make things more readable
  208. local function getDistanceByUnits(unit1,unit2)
  209.     return getDistance(unit1.x,unit1.y,unit2.x,unit2.y)
  210. end
  211.  
  212. -- Health Percent and Health Deficit methods
  213. local function getHealthPct(unit)
  214.     local maxHp = UnitHealthMax(unit)
  215.     local currentHp = UnitHealth(unit)
  216.      
  217.     if maxHp == 0 then
  218.         maxHp = 1
  219.     end
  220.     if currentHp == 0 then
  221.         currentHp = 1
  222.     end
  223.  
  224.     local pctHp = currentHp/maxHp
  225.  
  226.     return pctHp
  227. end
  228. local function getHealthDeficit(unit)
  229.     local healthDeficit = UnitHealthMax(unit) - UnitHealth(unit)
  230.     return healthDeficit
  231. end
  232. local function getDeficitColor(HP)
  233.     if(HP >= 0.95) then
  234.         return Colors.green
  235.     elseif(HP < 0.95 and HP >= 0.75) then
  236.         return Colors.yellow
  237.     elseif(HP < 0.75 and HP >= 0.50) then
  238.         return Colors.orange
  239.     elseif(HP < 0.50) then
  240.         return Colors.red
  241.     end
  242. end
  243.  
  244. -- Generates a table containing all valid players for healing
  245. -- Dead and disconnected units are not taken in account, player is also not on the list
  246. local function getValidPlayerList()
  247.  
  248.     -- If not in a group, return an empty table
  249.     local groupSize = GetNumGroupMembers()
  250.     if groupSize == 0 then
  251.         return {}
  252.     end
  253.  
  254.     -- Resets our current playerList
  255.     local playerList = {}
  256.  
  257.     -- Check if we're on a party or raid
  258.     local prefix = "raid"
  259.     if not IsInRaid() then
  260.         prefix = "party"
  261.         -- Party unit ids does not include the player! (Only goes from 1 to 4)
  262.         groupSize = groupSize - 1
  263.     end
  264.  
  265.  
  266.     -- Player data:
  267.     local player = {}
  268.     player.x, player.y = getUnitMapPosition("player")
  269.  
  270.     -- Iterate through all players
  271.     local k = 1
  272.     for i = 1, groupSize do
  273.         -- Create a new Unit
  274.         local newUnit = {}
  275.         newUnit.unitId = prefix .. i
  276.         -- Check if Valid Unit - Not Dead, not the player and actually exists (UnitName doesn't return nil)
  277.         if not UnitIsDeadOrGhost(newUnit.unitId) and not UnitIsUnit(newUnit.unitId,"player") and UnitName(newUnit.unitId) then
  278.  
  279.             -- Name for debugging purpouses, not used
  280.             newUnit.name = UnitName(newUnit.unitId)
  281.  
  282.             -- Store Unit Health Deficit
  283.             newUnit.healthDeficit = getHealthDeficit(newUnit.unitId)
  284.             newUnit.healthPct = getHealthPct(newUnit.unitId)
  285.  
  286.             -- Store Unit Coordinates, to display on the radar
  287.             newUnit.x, newUnit.y = getUnitMapPosition(newUnit.unitId)
  288.  
  289.             -- Store Unit distance from player
  290.             newUnit.distance = getDistanceByUnits(player,newUnit)
  291.  
  292.             -- Store the Player itself on the table
  293.             -- Insert is not working on WoD beta, so doing normal k+1 thing - NOT GOOD
  294.             playerList[k] = newUnit
  295.             k = k + 1
  296.         end
  297.     end
  298.  
  299.     return playerList
  300. end
  301.  
  302.  
  303. local function updateData(playerList,radius)
  304.     local player = {}
  305.     player.x, player.y = getUnitMapPosition("player")
  306.  
  307.     -- Holy Nova Heal amount - TBD
  308.     local HolyNovaAmount = 5000
  309.  
  310.     -- 1 = No overheal is allowed, 0 = Full overheal is allowed
  311.     local HolyNovaOverhealCoheficient = 1
  312.  
  313.     --local string = ""
  314.     local last = 1
  315.     local playersInRange = 0
  316.     for i,unit in ipairs(playerList) do
  317.         --string = string .. unit.name.. "/"..unit.unitId..": "..unit.distance.."\n"
  318.         -- Check if player HP deficit is higher than the holy nova amount and overheal treshold for being considered in range
  319.         if unit.healthDeficit > HolyNovaAmount*HolyNovaOverhealCoheficient then
  320.             if unit.distance <= radius*1.1 then
  321.                 playersInRange = playersInRange + 1
  322.             end
  323.         end
  324.  
  325.         -- Get a dot
  326.         local dot = dots[i]
  327.        
  328.         -- Get its color based on player Health percent
  329.         local color = getDeficitColor(unit.healthPct)
  330.         dot:SetVertexColor(color.r,color.g,color.b,1)
  331.  
  332.         -- Now we have to calculate where the point will be in the radar
  333.         -- To make things easier, let's get the distance between the player x,y and the current unit x,y
  334.         -- This is considering the player is in the center of the radar
  335.         -- Calculate Distances in yards
  336.         local dist_x = unit.x - player.x
  337.         local dist_y = unit.y - player.y
  338.  
  339.         -- Normalize it to pixels
  340.         -- How much does 1 yard is in pixels for our radar size? RadarRadius/Measuring radius
  341.         -- Radius is doubled because we're considering the diameter here
  342.         local radarSize = tonumber(Radar:GetHeight())
  343.         local yardInPixel = (radarSize/(radius*2))
  344.  
  345.         -- Multiply it so we get the values in pixel
  346.         local radar_x = dist_x*yardInPixel
  347.         local radar_y = dist_y*yardInPixel
  348.        
  349.         -- Since we considered the player is in the center, we set the anchor to the center of the radar
  350.         -- and place our offsets for x and y as calculated
  351.         -- Need to clear point always
  352.         dot:ClearAllPoints();
  353.         dot:SetPoint("CENTER", radar_x, radar_y)
  354.  
  355.         -- Point should be visible only if it's inside the radar
  356.  
  357.         -- Remember, the anchor is the center point so it should go from "-150 to 150" if the Width/Height is 300
  358.         -- This considers a square only, should make one to collide with the actual circle
  359.         --local bound1, bound2 = Radar:GetWidth()/-2, Radar:GetWidth()/2
  360.         --if radar_x > bound1 and radar_x < bound2 and radar_y > bound1 and radar_y < bound2 then
  361.             --dot:Show()
  362.         --else
  363.             --dot:Hide()
  364.         --end
  365.  
  366.         -- Use this instead to show only inside radar CIRCLE
  367.         if unit.distance <= radius then
  368.             dot:Show()
  369.         else
  370.             dot:Hide()
  371.         end
  372.  
  373.         -- If this is the last, then everything beyond should be hidden (see below)
  374.         last = i + 1
  375.     end
  376.  
  377.  
  378.     HolyNovaIcon.text:SetText(playersInRange)
  379.     --HolyNovaIcon.text:SetText(string)
  380.  
  381.     local overlay = HolyNovaIcon.overlay
  382.     if playersInRange > 4 then
  383.         overlay:SetTexture(Colors.GOOD.r, Colors.GOOD.g, Colors.GOOD.b)
  384.     else
  385.         overlay:SetTexture(Colors.BAD.r, Colors.BAD.g, Colors.BAD.b)
  386.     end
  387.  
  388.     -- Hide all dots that are beyond our group size
  389.     for i = last, 40 do
  390.         local dot = dots[i]
  391.         dot:Hide()        
  392.     end
  393. end
  394.  
  395. local tickTime = 0.05 --call range checking function ever tickTime seconds
  396. local targetTime = 0
  397. local total = 0
  398. local function onUpdate(self,elapsed)
  399.     total = total + elapsed
  400.     -- Radius in yards
  401.     local radius = 12
  402.     if total >= tickTime then
  403.         -- Should not be called so often, better make an event for it
  404.         updateCurrentMap()
  405.         local playerList = getValidPlayerList()
  406.         updateData(playerList,radius)
  407.         total = 0
  408.         targetTime = tickTime
  409.     end
  410. end
  411.  
  412. Radar = newRadar()
  413. HolyNovaIcon = newHNIcon()
  414. Radar:SetScript("OnUpdate", onUpdate)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement