Advertisement
moothz

Holy Nova Scanner Addon

Sep 16th, 2014
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.25 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. Colors.radar = {}
  40. Colors.radar.r = 0.0
  41. Colors.radar.g = 1.0
  42. Colors.radar.b = 0.0
  43.  
  44.  
  45.  
  46. -- Values that will be set in a configuration file/menu
  47. local rotateRadar = false                     -- true = radar will rotate (like DBM one), false = radar will stay static (like the minimap)
  48. local RadarSize = 300                         -- Square radar Height and Width
  49. local RadarAlpha = 1                        -- Radar Circle transparency, 0 = transparent, 1 = opaque
  50. local HolyNovaOverhealCoheficient = 0.9       -- 1 = No overheal is allowed, 0 = Full overheal is allowed
  51.  
  52. -- Constants
  53. local HolyNovaRadius = 12
  54. local MapErrorFactor = 1.1
  55. local pi = math.pi
  56. -- This Global will keep all dots frames, so change them to update the radar
  57. local dots = {}
  58. SLASH_HOLYSONAR1 = '/hn'
  59. function SlashCmdList.HOLYSONAR(msg, editbox) -- 4.
  60.     if msg == "radar" then
  61.         -- Toggles Radar Visibility on /hn radar
  62.         if Radar:IsVisible() then
  63.             Radar:Hide()
  64.         else
  65.             Radar:Show()
  66.         end
  67.     elseif msg == "icon" then
  68.         -- Toggles Icon Visibility on /hn icon
  69.         if HolyNovaIcon:IsVisible() then
  70.             HolyNovaIcon:Hide()
  71.         else
  72.             HolyNovaIcon:Show()
  73.         end
  74.     else
  75.         -- Toggles Icon Visibility on  both
  76.         if HolyNovaIcon:IsVisible() then
  77.             HolyNovaIcon:Hide()
  78.             Radar:Hide()
  79.         else
  80.             HolyNovaIcon:Show()
  81.             Radar:Show()
  82.         end
  83.     end
  84. end
  85.  
  86. -- Holy Nova Icon With text initialization!
  87. local function newHNIcon()
  88.     -- Create the main frame
  89.     local IconFrame = CreateFrame("Frame", "HolyNovaTargets", UIParent)
  90.     IconFrame:SetFrameStrata("DIALOG")
  91.     IconFrame:SetPoint("CENTER", 400, 182)
  92.     IconFrame:SetSize(64,64)
  93.     IconFrame:EnableMouse(false)
  94.  
  95.     -- Set Holy Nova Icon Texture
  96.     local iconTexture = IconFrame:CreateTexture(nil,"BACKGROUND")
  97.     iconTexture:SetAllPoints(IconFrame)
  98.     iconTexture:SetTexture("Interface\\Icons\\Spell_Holy_HolyNova.blp")
  99.  
  100.     -- Overlay on the icon to display a "Good/Bad" effect
  101.     local overlay = IconFrame:CreateTexture("ARTWORK")
  102.     overlay:SetAllPoints()
  103.     -- Start with BAD Color
  104.     overlay:SetTexture(Colors.BAD.r, Colors.BAD.g, Colors.BAD.b)
  105.     overlay:SetAlpha(0.2)
  106.     overlay:Show()
  107.     IconFrame.overlay = overlay
  108.  
  109.     -- Text to display amount if people around
  110.     local iconText = IconFrame:CreateFontString();
  111.     iconText:SetFont("Fonts\\FRIZQT__.TTF", 18, "OUTLINE, MONOCHROME")
  112.     iconText:SetText("0")
  113.     iconText:SetTextColor(1,1,1)
  114.     iconText:SetPoint("CENTER",IconFrame,"CENTER",0,0)
  115.     IconFrame.text = iconText
  116.     IconFrame:Show()
  117.  
  118.     return IconFrame
  119. end
  120.  
  121. -- Radar Frame initialization code!
  122. local function newRadar()
  123.     local radarFrame = CreateFrame("Frame", "LifeRadar", UIParent)
  124.     radarFrame:SetFrameStrata("DIALOG")
  125.     radarFrame:SetPoint("CENTER", 400, 0)
  126.  
  127.     radarFrame:SetHeight(RadarSize)
  128.     radarFrame:SetWidth(RadarSize)
  129.     radarFrame:EnableMouse(false)       -- Click through
  130.     radarFrame:SetToplevel(true)
  131.  
  132.     -- Transparent Black background
  133.     local bg = radarFrame:CreateTexture(nil, "BACKGROUND")
  134.     bg:SetAllPoints(radarFrame)
  135.     bg:SetBlendMode("BLEND")
  136.     bg:SetTexture(0, 0, 0, 0)
  137.     radarFrame.background = bg
  138.  
  139.  
  140.     -- I've used DBM circle, it looks pretty
  141.     -- You can create another one and import it
  142.     local circle = radarFrame:CreateTexture(nil, "ARTWORK")
  143.     circle:SetSize(RadarSize, RadarSize)
  144.     circle:SetPoint("CENTER")
  145.     circle:SetTexture("Interface\\AddOns\\DBM-Core\\textures\\radar_circle.blp")
  146.     circle:SetBlendMode("ADD")
  147.     circle:SetVertexColor(Colors.radar.r, Colors.radar.g, Colors.radar.b,RadarAlpha)
  148.     -- Store the background circle on the variable, so we can change it's color
  149.     radarFrame.circle = circle
  150.  
  151.     -- Player arrow, not needed, but looks good for reference
  152.     local player = radarFrame:CreateTexture(nil, "OVERLAY")
  153.     player:SetSize(32, 32)
  154.     player:SetTexture("Interface\\Minimap\\MinimapArrow.blp")
  155.     player:SetBlendMode("ADD")
  156.     player:SetPoint("CENTER")
  157.  
  158.     -- Max Raid size is 40, so 40 frames (Dots) created should be enough
  159.     for i = 1, 40 do
  160.         local dot = radarFrame:CreateTexture(nil, "OVERLAY")
  161.         dot:SetSize(20, 20)
  162.         -- X,Y coords, You can start them on 0
  163.         -- TOPLEFT is the "Anchor", so x and y are 'how maby pixels of distance the frame is from the anchor'
  164.         dot:SetPoint("TOPLEFT", i*5, i*-5)
  165.  
  166.         -- PartyRaidBlips is a 'big' image containing a lot of textures, that include class icons, markeers, etc.
  167.         dot:SetTexture("Interface\\Minimap\\PartyRaidBlips")
  168.  
  169.         -- You have to remap the texture in order to "zoom" on a specific texture
  170.         -- 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
  171.         dot:SetTexCoord(0.5, 0.625, 0, 0.25)
  172.  
  173.         -- Here you can set the dot color using RGBA, so the icon original color is irrelevant
  174.         -- It'll desaturate it and colorize
  175.         -- Randomized for fun
  176.         dot:SetVertexColor(math.random(),math.random(),math.random(),1)
  177.  
  178.         -- All dots start hidden, so you can dot:Show() them after
  179.         dot:Hide()
  180.         dots[i] = dot
  181.     end
  182.  
  183.     -- Frame starts hidden
  184.     radarFrame:Show()
  185.     return radarFrame
  186. end
  187.  
  188. -- Map methods
  189. local function getUnitMapPosition(unit)
  190.     local relative_x, relative_y = GetPlayerMapPosition(unit)
  191.  
  192.     -- Only call SetMatpToCurrentZone if something went wrong
  193.     if relative_x == 0 and relative_y == 0 then
  194.         SetMapToCurrentZone()
  195.         relative_x, relative_y = GetPlayerMapPosition(unit)
  196.     end
  197.  
  198.     return currentMap.width*relative_x, currentMap.height*relative_y
  199. end
  200.  
  201.  
  202. -- Straight line distance from 2 coordinates
  203. local function getDistance(x1, y1, x2, y2)
  204.     local xx = x2 - x1
  205.     local yy = y2 - y1
  206.  
  207.     return sqrt(xx*xx + yy*yy)
  208. end
  209.  
  210.  
  211. -- Unit HP Function, all in One
  212. local function UnitHP(unit)
  213.     local maxHp = UnitHealthMax(unit)
  214.     local currentHp = UnitHealth(unit)
  215.  
  216.     if maxHp == 0 then
  217.         maxHp = 1
  218.     end
  219.     if currentHp == 0 then
  220.         currentHp = 1
  221.     end
  222.  
  223.     local pctHp = currentHp/maxHp
  224.  
  225.     return pctHp, maxHp-currentHp
  226. end
  227.  
  228. -- Deficit color
  229. -- Maybe add the possibility for a player to create various ranges?
  230. -- No need, I think. Changing colors should be enoguh, maybe only percentages fix
  231. local function getDeficitColor(HP)
  232.     if(HP >= 0.95) then
  233.         return Colors.green
  234.     elseif(HP < 0.95 and HP >= 0.75) then
  235.         return Colors.yellow
  236.     elseif(HP < 0.75 and HP >= 0.50) then
  237.         return Colors.orange
  238.     elseif(HP < 0.50) then
  239.         return Colors.red
  240.     end
  241. end
  242.  
  243.  
  244. -- Holy Nova Math!
  245. local function calculateHolyNova()
  246.     return 5000
  247. end
  248. local rotation = 0
  249. local function UpdatePinMap()
  250.     -- Holy Nova Heal amount - TBD
  251.     local HolyNovaAmount = calculateHolyNova()
  252.  
  253.     local playersInRange = 0
  254.     local playerX, playerY = getUnitMapPosition("player")
  255.  
  256.     local numMembers = GetNumGroupMembers()
  257.  
  258.     local prefix = "raid"
  259.     -- If the player is in a party, he's not on the Unit ID list
  260.     if not IsInRaid() then
  261.         prefix = "party"
  262.         numMembers = numMembers - 1
  263.     end
  264.  
  265.     local last = 1
  266.     rotation = GetPlayerFacing()*57.2957795
  267.     for i=1, numMembers do
  268.         -- String.Format is faster than concatenating strings - Or is it?
  269.         --local unit = prefix..i
  270.         local unit = format("%s%d", prefix, i)
  271.         --print(unit)
  272.         -- Don't consider units that are Dead or disconnected
  273.         -- Also, don't include the player here, he'll be taken in account after this for iteration
  274.         if UnitExists(unit) and not UnitIsDeadOrGhost(unit) and not UnitIsUnit(unit,"player") then
  275.             local pctHp, difHp = UnitHP(unit)
  276.             local unitX, unitY = getUnitMapPosition(unit)
  277.  
  278.             -- All in Yards! (Hopefully)
  279.             local distance = getDistance(playerX,playerY,unitX,unitY)
  280.            
  281.             -- Check if the HP Deficit is bigger than what we're looking to heal!
  282.             if difHp > HolyNovaAmount*HolyNovaOverhealCoheficient then
  283.                 if distance <= HolyNovaRadius*MapErrorFactor then
  284.                      playersInRange = playersInRange + 1
  285.                 end
  286.             end
  287.            
  288.              -- Get a dot
  289.             local dot = dots[i]
  290.            
  291.             -- Get dot color based on player Health percent
  292.             local color = getDeficitColor(pctHp)
  293.             dot:SetVertexColor(color.r,color.g,color.b,1)
  294.  
  295.             local dist_x = unitX - playerX
  296.             local dist_y = unitY - playerY
  297.      
  298.             -- Normalize it to pixels
  299.             -- How much does 1 yard is in pixels for our radar size? RadarRadius/Measuring radius
  300.             local yardInPixel = (RadarSize/(HolyNovaRadius*2))
  301.      
  302.             -- Multiply it so we get the values in pixel
  303.             -- Also factor in the player rotation!
  304.             local radar_x = 0
  305.             local radar_y = 0
  306.  
  307.             if rotateRadar then
  308.                 radar_x = ((dist_x * cos(rotation)) - (-dist_y * sin(rotation))) * yardInPixel
  309.                 radar_y = ((dist_x * sin(rotation)) + (-dist_y * cos(rotation))) * yardInPixel
  310.             else
  311.                 radar_x = dist_x * yardInPixel
  312.                 radar_y = dist_y * yardInPixel
  313.             end
  314.             radar_y = -radar_y
  315.            
  316.  
  317.            
  318.            
  319.  
  320.             --print(unit..": ( "..unitX..","..unitY..") ("..radar_x..","..radar_y..")")
  321.             -- Since we considered the player is in the center, we set the anchor to the center of the radar
  322.             -- and place our offsets for x and y as calculated
  323.             -- Need to clear point always
  324.             dot:ClearAllPoints();
  325.             dot:SetPoint("CENTER", Radar, "CENTER", radar_x, radar_y)
  326.            
  327.             if distance <= HolyNovaRadius then
  328.                 dot:Show()
  329.             else
  330.                dot:Hide()
  331.             end
  332.         end
  333.  
  334.         -- If this is the last, then everything beyond should be hidden (see below)
  335.         last = i + 1
  336.     end
  337.    
  338.     -- Account the player on the "players in range" count
  339.     local _,difHp = UnitHP("player")
  340.     if difHp > HolyNovaAmount*HolyNovaOverhealCoheficient then
  341.         playersInRange = playersInRange + 1
  342.     end
  343.  
  344.     -- Hide all unused dots
  345.     for i=last, 40 do
  346.         dots[i]:Hide()
  347.     end
  348.  
  349.     -- Set the amount on the icon  
  350.     HolyNovaIcon.text:SetText(playersInRange)
  351.    
  352.     -- Set the overlay based on the number of players in range
  353.     local overlay = HolyNovaIcon.overlay
  354.     if playersInRange > 4 then
  355.         overlay:SetTexture(Colors.GOOD.r, Colors.GOOD.g, Colors.GOOD.b)
  356.     else
  357.         overlay:SetTexture(Colors.BAD.r, Colors.BAD.g, Colors.BAD.b)
  358.     end
  359. end
  360.  
  361. local tickTime_Data = 0.01        -- Interval to update Player Info & Radar
  362. local targetTime_Data = 0
  363. local total_Data = 0
  364. local function onUpdate(self,elapsed)
  365.     total_Data = total_Data + elapsed
  366.     if total_Data >= tickTime_Data then
  367.         UpdatePinMap()
  368.         total_Data = 0
  369.         targetTime_Data = tickTime_Data
  370.     end
  371.  
  372.     --print(currentMap.height.."x"..currentMap.width)
  373. end
  374.  
  375. -- Map changed, better update values!
  376. local function mapChanged(event,map,floor,w,h)
  377.     currentMap.width = w
  378.     currentMap.height = h
  379.  
  380.     -- Just in case LibMapData doesn't have data about the map, get blizzard data
  381.     if(currentMap.width == 0 or currentMap.height == 0) then
  382.         local zoneIndex, a, b, c, d = GetCurrentMapZone()
  383.         if not (a and b and c and d) then
  384.             -- All hope is lost, no map data whatsoever
  385.             print("No map data found!")
  386.             currentMap.height = 0
  387.             currentMap.width = 0
  388.             return
  389.         end
  390.         currentMap.height = abs(d-b)
  391.         currentMap.width = abs(c-a)
  392.     end
  393. end
  394.  
  395. -- Handle Events
  396. --function eventHandler(self, event, ...)
  397.     --if event == "ZONE_CHANGED" or event == "ZONE_CHANGED_INDOORS" or event == "ZONE_CHANGED_NEW_AREA" then
  398.         --updateCurrentMap()
  399.     --end
  400. --end
  401.  
  402. --updateCurrentMap()
  403. Radar = newRadar()
  404. HolyNovaIcon = newHNIcon()
  405. Radar:SetScript("OnUpdate", onUpdate)
  406. --Radar:SetScript("OnEvent", eventHandler);
  407.  
  408. mapfiles = LibStub("LibMapData-1.0")
  409. mapfiles:RegisterCallback("MapChanged",mapChanged)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement