Advertisement
Guest User

RangeChecker

a guest
May 30th, 2018
336
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 31.66 KB | None | 0 0
  1. -- ***************************************************
  2. -- **             DBM Range Check Frame             **
  3. -- **         http://www.deadlybossmods.com         **
  4. -- ***************************************************
  5. --
  6. -- This addon is written and copyrighted by:
  7. --    * Paul Emmerich (Tandanu @ EU-Aegwynn) (DBM-Core)
  8. --    * Martin Verges (Nitram @ EU-Azshara) (DBM-GUI)
  9. --
  10. -- The localizations are written by:
  11. --    * enGB/enUS: Tandanu              http://www.deadlybossmods.com
  12. --    * deDE: Tandanu                   http://www.deadlybossmods.com
  13. --    * zhCN: Diablohu                  http://wow.gamespot.com.cn
  14. --    * ruRU: BootWin                   bootwin@gmail.com
  15. --    * ruRU: Vampik                    admin@vampik.ru
  16. --    * zhTW: Hman                      herman_c1@hotmail.com
  17. --    * zhTW: Azael/kc10577             paul.poon.kw@gmail.com
  18. --    * koKR: BlueNyx/nBlueWiz          bluenyx@gmail.com / everfinale@gmail.com
  19. --    * esES: Snamor/1nn7erpLaY         romanscat@hotmail.com
  20. --
  21. -- Special thanks to:
  22. --    * Arta
  23. --    * Omegal @ US-Whisperwind (continuing mod support for 3.2+)
  24. --    * Tennberg (a lot of fixes in the enGB/enUS localization)
  25. --
  26. --
  27. -- The code of this addon is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License. (see license.txt)
  28. -- All included textures and sounds are copyrighted by their respective owners.
  29. --
  30. --
  31. --  You are free:
  32. --    * to Share ?to copy, distribute, display, and perform the work
  33. --    * to Remix ?to make derivative works
  34. --  Under the following conditions:
  35. --    * Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
  36. --    * Noncommercial. You may not use this work for commercial purposes.
  37. --    * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
  38. --
  39. --
  40. -- This file makes use of the following free (Creative Commons Sampling Plus 1.0) sounds:
  41. --    * alarmclockbeeps.ogg by tedthetrumpet (http://www.freesound.org/usersViewSingle.php?id=177)
  42. --    * blip_8.ogg by Corsica_S (http://www.freesound.org/usersViewSingle.php?id=7037)
  43. --  The full of text of the license can be found in the file "Sounds\Creative Commons Sampling Plus 1.0.txt".
  44.  
  45. ---------------
  46. --  Globals  --
  47. ---------------
  48. DBM.RangeCheck = {}
  49.  
  50. --------------
  51. --  Locals  --
  52. --------------
  53. local rangeCheck = DBM.RangeCheck
  54. local mainFrame = CreateFrame("Frame")
  55. local updater
  56. local textFrame
  57. local createTextFrame
  58. local radarFrame
  59. local createRadarFrame
  60. local updateIcon
  61. local updateRangeFrame
  62. local dropdownFrame
  63. local initializeDropdown
  64. local activeRange = 0
  65. local dots = {}
  66. local dims
  67.  
  68. --------------------------------------------------------
  69. --  Cache frequently used global variables in locals  --
  70. --------------------------------------------------------
  71. local UnitPosition = UnitPosition
  72. local GetPlayerFacing = GetPlayerFacing
  73. local UnitName, UnitClass, UnitIsUnit, UnitIsDeadOrGhost, UnitIsConnected, UnitInPhase, UnitAffectingCombat, UnitExists = UnitName, UnitClass, UnitIsUnit, UnitIsDeadOrGhost, UnitIsConnected, UnitInPhase, UnitAffectingCombat, UnitExists
  74. local IsInRaid, GetNumGroupMembers, GetNumSubgroupMembers = IsInRaid, GetNumGroupMembers, GetNumSubgroupMembers
  75. local GetRaidTargetIndex = GetRaidTargetIndex
  76. local GetTime = GetTime
  77. local CheckInteractDistance, IsItemInRange, UnitInRange = CheckInteractDistance, IsItemInRange, UnitInRange
  78. local max, sin, cos, pi, pi2 = math.max, math.sin, math.cos, math.pi, math.pi * 2
  79.  
  80. -- for Phanx' Class Colors
  81. local RAID_CLASS_COLORS = CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS
  82. local BLIP_TEX_COORDS = {
  83.     ["WARRIOR"]      = { 0, 0.125, 0, 0.25 },
  84.     ["PALADIN"]      = { 0.125, 0.25, 0, 0.25 },
  85.     ["HUNTER"]       = { 0.25, 0.375, 0, 0.25 },
  86.     ["ROGUE"]        = { 0.375, 0.5, 0, 0.25 },
  87.     ["PRIEST"]       = { 0.5, 0.625, 0, 0.25 },
  88.     ["DEATHKNIGHT"]  = { 0.625, 0.75, 0, 0.25 },
  89.     ["SHAMAN"]       = { 0.75, 0.875, 0, 0.25 },
  90.     ["MAGE"]         = { 0.875, 1, 0, 0.25 },
  91.     ["WARLOCK"]      = { 0, 0.125, 0.25, 0.5 },
  92.     ["DRUID"]        = { 0.25, 0.375, 0.25, 0.5 },
  93.     ["MONK"]         = { 0.125, 0.25, 0.25, 0.5 },
  94.     ["DEMONHUNTER"]  = { 0.375, 0.5, 0.25, 0.5 },
  95. }
  96. ---------------------
  97. --  Dropdown Menu  --
  98. ---------------------
  99.  
  100. -- todo: this dropdown menu is somewhat ugly and unflexible....
  101. do
  102.     local sound0 = "none"
  103.     local sound1 = "Interface\\AddOns\\DBM-Core\\Sounds\\blip_8.ogg"
  104.     local sound2 = "Interface\\AddOns\\DBM-Core\\Sounds\\alarmclockbeeps.ogg"
  105.     local function setSound(self, option, sound)
  106.         DBM.Options[option] = sound
  107.         if sound ~= "none" then
  108.             DBM:PlaySoundFile(sound)
  109.         end
  110.     end
  111.  
  112.     local function setRange(self, range)
  113.         rangeCheck:Hide(true)
  114.         rangeCheck:Show(range, mainFrame.filter, true, mainFrame.redCircleNumPlayers or 1)
  115.     end
  116.    
  117.     local function setThreshold(self, threshold)
  118.         rangeCheck:Hide(true)
  119.         rangeCheck:Show(mainFrame.range, mainFrame.filter, true, threshold)
  120.     end
  121.  
  122.     local function setFrames(self, option)
  123.         DBM.Options.RangeFrameFrames = option
  124.         rangeCheck:Hide(true)
  125.         rangeCheck:Show(mainFrame.range, mainFrame.filter, true, mainFrame.redCircleNumPlayers or 1)
  126.     end
  127.  
  128.     local function toggleLocked()
  129.         DBM.Options.RangeFrameLocked = not DBM.Options.RangeFrameLocked
  130.     end
  131.  
  132.     function initializeDropdown(dropdownFrame, level, menu)
  133.         local info
  134.         if level == 1 then
  135.             info = UIDropDownMenu_CreateInfo()
  136.             info.text = DBM_CORE_RANGECHECK_SETRANGE
  137.             info.notCheckable = true
  138.             info.hasArrow = true
  139.             info.keepShownOnClick = true
  140.             info.menuList = "range"
  141.             UIDropDownMenu_AddButton(info, 1)
  142.  
  143.             info = UIDropDownMenu_CreateInfo()
  144.             info.text = DBM_CORE_RANGECHECK_SETTHRESHOLD
  145.             info.notCheckable = true
  146.             info.hasArrow = true
  147.             info.keepShownOnClick = true
  148.             info.menuList = "threshold"
  149.             UIDropDownMenu_AddButton(info, 1)
  150.  
  151.             info = UIDropDownMenu_CreateInfo()
  152.             info.text = DBM_CORE_RANGECHECK_SOUNDS
  153.             info.notCheckable = true
  154.             info.hasArrow = true
  155.             info.keepShownOnClick = true
  156.             info.menuList = "sounds"
  157.             UIDropDownMenu_AddButton(info, 1)
  158.  
  159.             info = UIDropDownMenu_CreateInfo()
  160.             info.text = DBM_CORE_RANGECHECK_OPTION_FRAMES
  161.             info.notCheckable = true
  162.             info.hasArrow = true
  163.             info.keepShownOnClick = true
  164.             info.menuList = "frames"
  165.             UIDropDownMenu_AddButton(info, 1)
  166.  
  167.             info = UIDropDownMenu_CreateInfo()
  168.             info.text = LOCK_FRAME
  169.             if DBM.Options.RangeFrameLocked then
  170.                 info.checked = true
  171.             end
  172.             info.func = toggleLocked
  173.             UIDropDownMenu_AddButton(info, 1)
  174.  
  175.             info = UIDropDownMenu_CreateInfo()
  176.             info.text = HIDE
  177.             info.notCheckable = true
  178.             info.func = function() rangeCheck:Hide(true) end
  179.             info.arg1 = rangeCheck
  180.             UIDropDownMenu_AddButton(info, 1)
  181.  
  182.         elseif level == 2 then
  183.             if menu == "range" then
  184.                 info = UIDropDownMenu_CreateInfo()
  185.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(5)
  186.                 info.func = setRange
  187.                 info.arg1 = 5
  188.                 info.checked = (mainFrame.range == 5)
  189.                 UIDropDownMenu_AddButton(info, 2)
  190.                
  191.                 info = UIDropDownMenu_CreateInfo()
  192.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(8)
  193.                 info.func = setRange
  194.                 info.arg1 = 8
  195.                 info.checked = (mainFrame.range == 8)
  196.                 UIDropDownMenu_AddButton(info, 2)
  197.  
  198.                 info = UIDropDownMenu_CreateInfo()
  199.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(10)
  200.                 info.func = setRange
  201.                 info.arg1 = 10
  202.                 info.checked = (mainFrame.range == 10)
  203.                 UIDropDownMenu_AddButton(info, 2)
  204.  
  205.                 info = UIDropDownMenu_CreateInfo()
  206.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(11)
  207.                 info.func = setRange
  208.                 info.arg1 = 11
  209.                 info.checked = (mainFrame.range == 11)
  210.                 UIDropDownMenu_AddButton(info, 2)
  211.                
  212.                 info = UIDropDownMenu_CreateInfo()
  213.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(13)
  214.                 info.func = setRange
  215.                 info.arg1 = 13
  216.                 info.checked = (mainFrame.range == 13)
  217.                 UIDropDownMenu_AddButton(info, 2)
  218.  
  219.                 info = UIDropDownMenu_CreateInfo()
  220.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(18)
  221.                 info.func = setRange
  222.                 info.arg1 = 18
  223.                 info.checked = (mainFrame.range == 18)
  224.                 UIDropDownMenu_AddButton(info, 2)
  225.  
  226.                 info = UIDropDownMenu_CreateInfo()
  227.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(30)
  228.                 info.func = setRange
  229.                 info.arg1 = 30
  230.                 info.checked = (mainFrame.range == 30)
  231.                 UIDropDownMenu_AddButton(info, 2)
  232.                
  233.                 info = UIDropDownMenu_CreateInfo()
  234.                 info.text = DBM_CORE_RANGECHECK_SETRANGE_TO:format(43)
  235.                 info.func = setRange
  236.                 info.arg1 = 43
  237.                 info.checked = (mainFrame.range == 43)
  238.                 UIDropDownMenu_AddButton(info, 2)
  239.             elseif menu == "threshold" then
  240.                 info = UIDropDownMenu_CreateInfo()
  241.                 info.text = 1
  242.                 info.func = setThreshold
  243.                 info.arg1 = 1
  244.                 info.checked = (mainFrame.redCircleNumPlayers == 1)
  245.                 UIDropDownMenu_AddButton(info, 2)
  246.  
  247.                 info = UIDropDownMenu_CreateInfo()
  248.                 info.text = 2
  249.                 info.func = setThreshold
  250.                 info.arg1 = 2
  251.                 info.checked = (mainFrame.redCircleNumPlayers == 2)
  252.                 UIDropDownMenu_AddButton(info, 2)
  253.                
  254.                 info = UIDropDownMenu_CreateInfo()
  255.                 info.text = 3
  256.                 info.func = setThreshold
  257.                 info.arg1 = 3
  258.                 info.checked = (mainFrame.redCircleNumPlayers == 3)
  259.                 UIDropDownMenu_AddButton(info, 2)
  260.                
  261.                 info = UIDropDownMenu_CreateInfo()
  262.                 info.text = 4
  263.                 info.func = setThreshold
  264.                 info.arg1 = 4
  265.                 info.checked = (mainFrame.redCircleNumPlayers == 4)
  266.                 UIDropDownMenu_AddButton(info, 2)
  267.                
  268.                 info = UIDropDownMenu_CreateInfo()
  269.                 info.text = 5
  270.                 info.func = setThreshold
  271.                 info.arg1 = 5
  272.                 info.checked = (mainFrame.redCircleNumPlayers == 5)
  273.                 UIDropDownMenu_AddButton(info, 2)
  274.                
  275.                 info = UIDropDownMenu_CreateInfo()
  276.                 info.text = 6
  277.                 info.func = setThreshold
  278.                 info.arg1 = 6
  279.                 info.checked = (mainFrame.redCircleNumPlayers == 6)
  280.                 UIDropDownMenu_AddButton(info, 2)
  281.                
  282.                 info = UIDropDownMenu_CreateInfo()
  283.                 info.text = 8
  284.                 info.func = setThreshold
  285.                 info.arg1 = 8
  286.                 info.checked = (mainFrame.redCircleNumPlayers == 8)
  287.                 UIDropDownMenu_AddButton(info, 2)
  288.             elseif menu == "sounds" then
  289.                 info = UIDropDownMenu_CreateInfo()
  290.                 info.text = DBM_CORE_RANGECHECK_SOUND_OPTION_1
  291.                 info.notCheckable = true
  292.                 info.hasArrow = true
  293.                 info.menuList = "RangeFrameSound1"
  294.                 UIDropDownMenu_AddButton(info, 2)
  295.  
  296.                 info = UIDropDownMenu_CreateInfo()
  297.                 info.text = DBM_CORE_RANGECHECK_SOUND_OPTION_2
  298.                 info.notCheckable = true
  299.                 info.hasArrow = true
  300.                 info.menuList = "RangeFrameSound2"
  301.                 UIDropDownMenu_AddButton(info, 2)
  302.             elseif menu == "frames" then
  303.                 info = UIDropDownMenu_CreateInfo()
  304.                 info.text = DBM_CORE_RANGECHECK_OPTION_TEXT
  305.                 info.func = setFrames
  306.                 info.arg1 = "text"
  307.                 info.checked = (DBM.Options.RangeFrameFrames == "text")
  308.                 UIDropDownMenu_AddButton(info, 2)
  309.  
  310.                 info = UIDropDownMenu_CreateInfo()
  311.                 info.text = DBM_CORE_RANGECHECK_OPTION_RADAR
  312.                 info.func = setFrames
  313.                 info.arg1 = "radar"
  314.                 info.checked = (DBM.Options.RangeFrameFrames == "radar")
  315.                 UIDropDownMenu_AddButton(info, 2)
  316.  
  317.                 info = UIDropDownMenu_CreateInfo()
  318.                 info.text = DBM_CORE_RANGECHECK_OPTION_BOTH
  319.                 info.func = setFrames
  320.                 info.arg1 = "both"
  321.                 info.checked = (DBM.Options.RangeFrameFrames == "both")
  322.                 UIDropDownMenu_AddButton(info, 2)
  323.             end
  324.         elseif level == 3 then
  325.             local option = menu
  326.             info = UIDropDownMenu_CreateInfo()
  327.             info.text = DBM_CORE_RANGECHECK_SOUND_0
  328.             info.func = setSound
  329.             info.arg1 = option
  330.             info.arg2 = sound0
  331.             info.checked = (DBM.Options[option] == sound0)
  332.             UIDropDownMenu_AddButton(info, 3)
  333.  
  334.             info = UIDropDownMenu_CreateInfo()
  335.             info.text = DBM_CORE_RANGECHECK_SOUND_1
  336.             info.func = setSound
  337.             info.arg1 = option
  338.             info.arg2 = sound1
  339.             info.checked = (DBM.Options[option] == sound1)
  340.             UIDropDownMenu_AddButton(info, 3)
  341.  
  342.             info = UIDropDownMenu_CreateInfo()
  343.             info.text = DBM_CORE_RANGECHECK_SOUND_2
  344.             info.func = setSound
  345.             info.arg1 = option
  346.             info.arg2 = sound2
  347.             info.checked = (DBM.Options[option] == sound2)
  348.             UIDropDownMenu_AddButton(info, 3)
  349.         end
  350.     end
  351. end
  352.  
  353. -----------------
  354. -- Play Sounds --
  355. -----------------
  356. local soundUpdate = 0
  357. local function updateSound(num)
  358.     if not UnitAffectingCombat("player") or (GetTime() - soundUpdate) < 5 then return end
  359.     soundUpdate = GetTime()
  360.     if num == 1 then
  361.         if DBM.Options.RangeFrameSound1 ~= "none" then
  362.             DBM:PlaySoundFile(DBM.Options.RangeFrameSound1)
  363.         end
  364.     elseif num > 1 then
  365.         if DBM.Options.RangeFrameSound2 ~= "none" then
  366.             DBM:PlaySoundFile(DBM.Options.RangeFrameSound2)
  367.         end
  368.     end
  369. end
  370.  
  371. ------------------------
  372. --  Create the frame  --
  373. ------------------------
  374. local frameBackdrop = {
  375.     bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
  376.     tile = true,
  377.     tileSize = 16,
  378.     insets = { left = 2, right = 14, top = 2, bottom = 2 },
  379. }
  380.  
  381. function createTextFrame()
  382.     local elapsed = 0
  383.     local textFrame = CreateFrame("GameTooltip", "DBMRangeCheck", UIParent, "GameTooltipTemplate")
  384.     dropdownFrame = CreateFrame("Frame", "DBMRangeCheckDropdown", textFrame, "UIDropDownMenuTemplate")
  385.     textFrame:SetFrameStrata("DIALOG")
  386.     textFrame:SetBackdrop(frameBackdrop)
  387.     textFrame:SetPoint(DBM.Options.RangeFramePoint, UIParent, DBM.Options.RangeFramePoint, DBM.Options.RangeFrameX, DBM.Options.RangeFrameY)
  388.     textFrame:SetHeight(64)
  389.     textFrame:SetWidth(64)
  390.     textFrame:EnableMouse(true)
  391.     textFrame:SetToplevel(true)
  392.     textFrame:SetMovable(1)
  393.     GameTooltip_OnLoad(textFrame)
  394.     textFrame:SetPadding(16, 0)
  395.     textFrame:RegisterForDrag("LeftButton")
  396.     textFrame:SetScript("OnDragStart", function(self)
  397.         if not DBM.Options.RangeFrameLocked then
  398.             self:StartMoving()
  399.         end
  400.     end)
  401.     textFrame:SetScript("OnDragStop", function(self)
  402.         self:StopMovingOrSizing()
  403.         --ValidateFramePosition(self)
  404.         local point, _, _, x, y = self:GetPoint(1)
  405.         DBM.Options.RangeFrameX = x
  406.         DBM.Options.RangeFrameY = y
  407.         DBM.Options.RangeFramePoint = point
  408.     end)
  409.     textFrame:SetScript("OnMouseDown", function(self, button)
  410.         if button == "RightButton" then
  411.             UIDropDownMenu_Initialize(dropdownFrame, initializeDropdown)
  412.             ToggleDropDownMenu(1, nil, dropdownFrame, "cursor", 5, -10)
  413.         end
  414.     end)
  415.     return textFrame
  416. end
  417.  
  418. function createRadarFrame()
  419.     local radarFrame = CreateFrame("Frame", "DBMRangeCheckRadar", UIParent)
  420.     radarFrame:SetFrameStrata("DIALOG")
  421.     radarFrame:SetPoint(DBM.Options.RangeFrameRadarPoint, UIParent, DBM.Options.RangeFrameRadarPoint, DBM.Options.RangeFrameRadarX, DBM.Options.RangeFrameRadarY)
  422.     radarFrame:SetHeight(128)
  423.     radarFrame:SetWidth(128)
  424.     radarFrame:EnableMouse(true)
  425.     radarFrame:SetToplevel(true)
  426.     radarFrame:SetMovable(1)
  427.     radarFrame:RegisterForDrag("LeftButton")
  428.     radarFrame:SetScript("OnDragStart", function(self)
  429.         if not DBM.Options.RangeFrameLocked then
  430.             self:StartMoving()
  431.         end
  432.     end)
  433.     radarFrame:SetScript("OnDragStop", function(self)
  434.         self:StopMovingOrSizing()
  435.         --ValidateFramePosition(self)
  436.         local point, _, _, x, y = self:GetPoint(1)
  437.         DBM.Options.RangeFrameRadarX = x
  438.         DBM.Options.RangeFrameRadarY = y
  439.         DBM.Options.RangeFrameRadarPoint = point
  440.     end)
  441.     radarFrame:SetScript("OnMouseDown", function(self, button)
  442.         if button == "RightButton" then
  443.             UIDropDownMenu_Initialize(dropdownFrame, initializeDropdown)
  444.             ToggleDropDownMenu(1, nil, dropdownFrame, "cursor", 5, -10)
  445.         end
  446.     end)
  447.  
  448.     local bg = radarFrame:CreateTexture(nil, "BACKGROUND")
  449.     bg:SetAllPoints(radarFrame)
  450.     bg:SetBlendMode("BLEND")
  451.     bg:SetColorTexture(0, 0, 0, 0.3)
  452.     radarFrame.background = bg
  453.  
  454.     local circle = radarFrame:CreateTexture(nil, "ARTWORK")
  455.     circle:SetSize(85, 85)
  456.     circle:SetPoint("CENTER")
  457.     circle:SetTexture("Interface\\AddOns\\DBM-Core\\textures\\radar_circle.blp")
  458.     circle:SetVertexColor(0, 1, 0)
  459.     circle:SetBlendMode("ADD")
  460.     radarFrame.circle = circle
  461.  
  462.     local player = radarFrame:CreateTexture(nil, "OVERLAY")
  463.     player:SetSize(32, 32)
  464.     player:SetTexture("Interface\\Minimap\\MinimapArrow.blp")
  465.     player:SetBlendMode("ADD")
  466.     player:SetPoint("CENTER")
  467.  
  468.     local text = radarFrame:CreateFontString(nil, "OVERLAY", "GameTooltipText")
  469.     text:SetWidth(128)
  470.     text:SetHeight(15)
  471.     text:SetPoint("BOTTOMLEFT", radarFrame, "TOPLEFT", 0,0)
  472.     text:SetTextColor(1, 1, 1, 1)
  473.     text:Show()
  474.     radarFrame.text = text
  475.  
  476.     local inRangeText = radarFrame:CreateFontString(nil, "OVERLAY", "GameTooltipText")
  477.     inRangeText:SetWidth(128)
  478.     inRangeText:SetHeight(15)
  479.     inRangeText:SetPoint("TOPLEFT", radarFrame, "BOTTOMLEFT", 0,0)
  480.     inRangeText:SetTextColor(1, 1, 1, 1)
  481.     inRangeText:Hide()
  482.     radarFrame.inRangeText = inRangeText
  483.  
  484.     for i = 1, 40 do
  485.         local dot = radarFrame:CreateTexture(nil, "OVERLAY")
  486.         dot:SetSize(24, 24)
  487.         dot:SetTexture("Interface\\Minimap\\PartyRaidBlips")
  488.         dot:Hide()
  489.         dots[i] = dot
  490.     end
  491.  
  492.     radarFrame:Hide()
  493.     return radarFrame
  494. end
  495.  
  496. ----------------
  497. --  OnUpdate  --
  498. ----------------
  499. do
  500.     local rotation, pixelsperyard, activeDots, numPlayers, circleColor, prevRange, prevThreshold, prevNumClosePlayer, prevclosestRange, prevColor, prevType = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  501.     local unitList = {}
  502.  
  503.     local function setDot(id, sinTheta, cosTheta)
  504.         local dot = dots[id]
  505.         local x = dots[id].x
  506.         local y = dots[id].y
  507.         local range = dots[id].range
  508.         if range < (activeRange * 1.5) then -- if person is closer than 1.5 * range, show the dot. Else hide it
  509.             local dx = ((x * cosTheta) - (-y * sinTheta)) * pixelsperyard -- Rotate the X,Y based on player facing
  510.             local dy = ((x * sinTheta) + (-y * cosTheta)) * pixelsperyard
  511.             dot:ClearAllPoints()
  512.             dot:SetPoint("CENTER", radarFrame, "CENTER", dx, dy)
  513.             if not dot.isShown then
  514.                 dot.isShown = true
  515.                 dot:Show()
  516.             end
  517.         elseif dot.isShown then
  518.             dot.isShown = nil
  519.             dot:Hide()
  520.         end
  521.     end
  522.  
  523.     function updateIcon()
  524.         numPlayers = GetNumGroupMembers()
  525.         activeDots = max(numPlayers, activeDots)
  526.         for i = 1, activeDots do
  527.             local dot = dots[i]
  528.             if i <= numPlayers then
  529.                 unitList[i] = IsInRaid() and "raid"..i or "party"..i
  530.                 local uId = unitList[i]
  531.                 local _, class = UnitClass(uId)
  532.                 local icon = GetRaidTargetIndex(uId)
  533.                 dot.class = class
  534.                 if icon and icon < 9 then
  535.                     dot.icon = icon
  536.                     dot:SetTexture(format("Interface\\TargetingFrame\\UI-RaidTargetingIcon_%d", icon))
  537.                     dot:SetTexCoord(0, 1, 0, 1)
  538.                     dot:SetSize(16, 16)
  539.                     dot:SetDrawLayer("OVERLAY", 1)
  540.                 else
  541.                     dot.icon = nil
  542.                     class = class or "PRIEST"
  543.                     local c = RAID_CLASS_COLORS[class]
  544.                     dot:SetTexture("Interface\\Minimap\\PartyRaidBlips")
  545.                     dot:SetTexCoord(BLIP_TEX_COORDS[class][1], BLIP_TEX_COORDS[class][2], BLIP_TEX_COORDS[class][3], BLIP_TEX_COORDS[class][4])
  546.                     dot:SetSize(24, 24)
  547.                     dot:SetDrawLayer("OVERLAY", 0)
  548.                 end
  549.             elseif dot.isShown then
  550.                 dot.isShown = nil
  551.                 dot:Hide()
  552.             end
  553.         end
  554.     end
  555.  
  556.     function updateRangeFrame()
  557.         if mainFrame.hideTime > 0 and GetTime() > mainFrame.hideTime then
  558.             rangeCheck:Hide()
  559.             return
  560.         end
  561.         activeRange = mainFrame.range
  562.         local restricted = mainFrame.restrictions
  563.         local tEnabled = textFrame.isShown
  564.         local rEnabled = radarFrame.isShown
  565.         if tEnabled then
  566.             textFrame:ClearLines()
  567.             textFrame:SetText(DBM_CORE_RANGECHECK_HEADER:format(activeRange), 1, 1, 1)
  568.         end
  569.         if rEnabled and (prevRange ~= activeRange or prevThreshold ~= mainFrame.redCircleNumPlayers) then
  570.             prevRange = activeRange
  571.             pixelsperyard = min(radarFrame:GetWidth(), radarFrame:GetHeight()) / (activeRange * 3)
  572.             radarFrame.circle:SetSize(activeRange * pixelsperyard * 2, activeRange * pixelsperyard * 2)
  573.             radarFrame.text:SetText(DBM_CORE_RANGERADAR_HEADER:format(activeRange, mainFrame.redCircleNumPlayers))
  574.         end
  575.  
  576.         local playerMapId
  577.         if C_Map then
  578.             playerMapId = C_Map.GetBestMapForUnit("player") or 0
  579.         else
  580.             playerMapId = GetPlayerMapAreaID("player") or 0
  581.         end
  582.         if not restricted then
  583.             rotation = pi2 - (GetPlayerFacing() or 0)
  584.         end
  585.         local sinTheta = sin(rotation)
  586.         local cosTheta = cos(rotation)
  587.         local closePlayer = 0
  588.         local closestRange = nil
  589.         local closetName = nil
  590.         local reverse = mainFrame.reverse
  591.         local filter = mainFrame.filter
  592.         local type = reverse and 2 or filter and 1 or 0
  593.         for i = 1, numPlayers do
  594.             local uId = unitList[i]
  595.             local dot = dots[i]
  596.             local mapId
  597.             if C_Map then
  598.                 mapId = C_Map.GetBestMapForUnit(uId) or 0
  599.             else
  600.                 mapId = GetPlayerMapAreaID(uId) or 0
  601.             end
  602.             if UnitExists(uId) and playerMapId == mapId and not UnitIsUnit(uId, "player") and not UnitIsDeadOrGhost(uId) and UnitIsConnected(uId) and UnitInPhase(uId) and (not filter or filter(uId)) then
  603.                 local range--Juset set to a number in case any api fails and returns nil
  604.                 if restricted then--API restrictions are in play, so pretend we're back in BC
  605.                     --Start at bottom and work way up.
  606.                     --Definitely not most efficient way of doing it. Refactor later when 7.1 hits PTR
  607.                     --All ranges aer tested and compared against UnitDistanceSquared.
  608.                     --Worgsaw has a tooltip of 6 but doesn't factor in hitboxes/etc. It doesn't return false until UnitDistanceSquared of 8. bandages 18 even though spell range is 15, etc. Acorn actually is 5 in both though
  609.                     if IsItemInRange(37727, uId) then range = 5--Ruby Acorn
  610.                     elseif IsItemInRange(63427, uId) then range = 8--Worgsaw
  611.                     elseif CheckInteractDistance(uId, 3) then range = 10
  612.                     elseif CheckInteractDistance(uId, 2) then range = 11
  613.                     elseif IsItemInRange(32321, uId) then range = 13--reports 12 but actual range tested is 13
  614.                     elseif IsItemInRange(6450, uId) then range = 18--Bandages. (despite popular sites saying it's 15 yards, it's actually 18 yards verified by UnitDistanceSquared
  615.                     elseif IsItemInRange(21519, uId) then range = 22--Item says 20, returns true until 22.
  616.                     elseif CheckInteractDistance(uId, 1) then range = 30
  617.                     elseif UnitInRange(uId) then range = 43
  618.                     elseif IsItemInRange(116139, uId)  then range = 50
  619.                     elseif IsItemInRange(32825, uId) then range = 60
  620.                     elseif IsItemInRange(35278, uId) then range = 80
  621.                     else range = 1000 end--Just so it has a numeric value, even if it's unknown to protect from nil errors
  622.                 else
  623.                     range = UnitDistanceSquared(uId) ^ 0.5
  624.                 end
  625.                 local inRange = false
  626.                 if range < (activeRange+0.5) then
  627.                     closePlayer = closePlayer + 1
  628.                     inRange = true
  629.                     if not closestRange then
  630.                         closestRange = range
  631.                     elseif range < closestRange then
  632.                         closestRange = range
  633.                     end
  634.                     if not closetName then closetName = UnitName(uId) end
  635.                 end
  636.                 if tEnabled and inRange and closePlayer < 6 then-- display up to 5 players in text range frame.
  637.                     local playerName = UnitName(uId)
  638.                     local color = RAID_CLASS_COLORS[dot.class] or NORMAL_FONT_COLOR
  639.                     local icon = dot.icon
  640.                     local text = icon and ("|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%d:0|t %s"):format(icon, playerName) or playerName
  641.                     textFrame:AddLine(text, color.r, color.g, color.b)
  642.                 end
  643.                 if rEnabled then
  644.                     local playerX, playerY = UnitPosition("player")
  645.                     local x, y = UnitPosition(uId)
  646.                     if not x and not y then
  647.                         rangeCheck:Hide(true)
  648.                         return
  649.                     end
  650.                     local cy = x - playerX
  651.                     local cx = y - playerY
  652.                     dot.x = -cx
  653.                     dot.y = -cy
  654.                     dot.range = range
  655.                     setDot(i, sinTheta, cosTheta)
  656.                 end
  657.             elseif rEnabled and dot.isShown then
  658.                 dot.isShown = nil
  659.                 dot:Hide()
  660.             end
  661.         end
  662.  
  663.         local warnThreshold = mainFrame.redCircleNumPlayers
  664.         if tEnabled then
  665.             textFrame:Show()
  666.         end
  667.         if rEnabled then
  668.             if prevNumClosePlayer ~= closePlayer or prevclosestRange ~= closestRange or prevType ~= type then
  669.                 if closePlayer == 1 then
  670.                     radarFrame.inRangeText:SetText(DBM_CORE_RANGERADAR_IN_RANGE_TEXTONE:format(closetName, closestRange))
  671.                 else
  672.                     radarFrame.inRangeText:SetText(DBM_CORE_RANGERADAR_IN_RANGE_TEXT:format(closePlayer, closestRange))
  673.                 end
  674.                 if closePlayer >= warnThreshold then -- only show the text if the circle is red
  675.                     circleColor = reverse and 1 or 2
  676.                     radarFrame.inRangeText:Show()
  677.                 else
  678.                     circleColor = reverse and 2 or 1
  679.                     radarFrame.inRangeText:Hide()
  680.                 end
  681.                 prevNumClosePlayer = closePlayer
  682.                 prevclosestRange = closestRange
  683.                 prevType = type
  684.             end
  685.  
  686.             if UnitIsDeadOrGhost("player") then
  687.                 circleColor = 3
  688.             end
  689.  
  690.             if prevColor ~= circleColor then
  691.                 if circleColor == 1 then
  692.                     radarFrame.circle:SetVertexColor(0, 1, 0)
  693.                 elseif circleColor == 2 then
  694.                     radarFrame.circle:SetVertexColor(1, 0, 0)
  695.                 else
  696.                     radarFrame.circle:SetVertexColor(1, 1, 1)
  697.                 end
  698.                 prevColor = circleColor
  699.             end
  700.         end
  701.  
  702.         if closePlayer >= warnThreshold then
  703.             updateSound(closePlayer)
  704.         end
  705.     end
  706. end
  707.  
  708. updater = mainFrame:CreateAnimationGroup()
  709. updater:SetLooping("REPEAT")
  710. local anim = updater:CreateAnimation()
  711. anim:SetDuration(0.1)
  712.  
  713. mainFrame:SetScript("OnEvent", function(self, event, ...)
  714.     if event == "GROUP_ROSTER_UPDATE" or event == "RAID_TARGET_UPDATE" then
  715.         updateIcon()
  716.     end
  717. end)
  718.  
  719. -----------------------
  720. --  Check functions  --
  721. -----------------------
  722. local getDistanceBetween, getDistanceBetweenALL
  723. do
  724.     local function itsBCAgain(uId)
  725.         if IsItemInRange(37727, uId) then return 5
  726.         elseif IsItemInRange(63427, uId) then return 8
  727.         elseif CheckInteractDistance(uId, 3) then return 10
  728.         elseif CheckInteractDistance(uId, 2) then return 11
  729.         elseif IsItemInRange(32321, uId) then return 13
  730.         elseif IsItemInRange(6450, uId) then return 18
  731.         elseif IsItemInRange(21519, uId) then return 22
  732.         elseif CheckInteractDistance(uId, 1) then return 30
  733.         elseif UnitInRange(uId) then return 43
  734.         elseif IsItemInRange(116139, uId) then return 50
  735.         elseif IsItemInRange(32825, uId) then return 60
  736.         elseif IsItemInRange(35278, uId) then return 80
  737.         else return 1000 end--Just so it has a numeric value, even if it's unknown to protect from nil errors
  738.     end
  739.    
  740.     function getDistanceBetweenALL(checkrange)
  741.         local range = 1000
  742.         for uId in DBM:GetGroupMembers() do
  743.             if UnitExists(uId) and not UnitIsUnit(uId, "player") and not UnitIsDeadOrGhost(uId) and UnitIsConnected(uId) and UnitInPhase(uId) then
  744.                 if DBM:HasMapRestrictions() then--API restrictions are in play, so pretend we're back in BC
  745.                     range = itsBCAgain(uId)
  746.                 else
  747.                     range = UnitDistanceSquared(uId) ^ 0.5
  748.                 end
  749.                 if checkrange < (range+0.5) then
  750.                     return true--return and end once anyone found
  751.                 end
  752.             end
  753.         end
  754.         return false--No one was foundi nrnage
  755.     end
  756.    
  757.     function getDistanceBetween(uId, x, y)
  758.         local restrictionsActive = DBM:HasMapRestrictions()
  759.         if not x then--If only one arg then 2nd arg is always assumed to be player
  760.             if restrictionsActive then
  761.                 return itsBCAgain(uId)
  762.             else
  763.                 return UnitDistanceSquared(uId) ^ 0.5
  764.             end
  765.         end
  766.         if type(x) == "string" and UnitExists(x) then -- arguments: uId, uId2
  767.             --First attempt to avoid UnitPosition if any of args is player UnitDistanceSquared should work
  768.             if UnitIsUnit("player", uId) then
  769.                 if restrictionsActive then
  770.                     return itsBCAgain(x)
  771.                 else
  772.                     return UnitDistanceSquared(x) ^ 0.5
  773.                 end
  774.             elseif UnitIsUnit("player", x) then
  775.                 if restrictionsActive then
  776.                     return itsBCAgain(uId)
  777.                 else
  778.                     return UnitDistanceSquared(uId) ^ 0.5
  779.                 end
  780.             else--Neither unit is player, no way to avoid UnitPosition
  781.                 if restrictionsActive then return 1000 end--Cannot compare two units that don't involve player with restrictions, just fail quietly
  782.                 local uId2 = x
  783.                 x, y = UnitPosition(uId2)
  784.                 if not x then
  785.                     print("getDistanceBetween failed for: " .. uId .. " (" .. tostring(UnitExists(uId)) .. ") and " .. uId2 .. " (" .. tostring(UnitExists(uId2)) .. ")")
  786.                     return
  787.                 end
  788.             end
  789.         end
  790.         if restrictionsActive then return 1000 end--Cannot check distance between player and a location (not another unit, again, fail quietly)
  791.         local startX, startY = UnitPosition(uId)
  792.         local dX = startX - x
  793.         local dY = startY - y
  794.         return (dX * dX + dY * dY) ^ 0.5
  795.     end
  796. end
  797.  
  798. ---------------
  799. --  Methods  --
  800. ---------------
  801. local restoreRange, restoreFilter, restoreThreshold, restoreReverse = nil, nil, nil, nil
  802. function rangeCheck:Show(range, filter, forceshow, redCircleNumPlayers, reverse, hideTime)
  803.     if (DBM:GetNumRealGroupMembers() < 2 or DBM.Options.DontShowRangeFrame) and not forceshow then return end
  804.     if type(range) == "function" then -- the first argument is optional
  805.         return self:Show(nil, range)
  806.     end
  807.     range = range or 10
  808.     redCircleNumPlayers = redCircleNumPlayers or 1
  809.     textFrame = textFrame or createTextFrame()
  810.     radarFrame = radarFrame or createRadarFrame()
  811.     local restrictionsActive = DBM:HasMapRestrictions()
  812.     if (DBM.Options.RangeFrameFrames == "text" or DBM.Options.RangeFrameFrames == "both" or restrictionsActive) and not textFrame.isShown then
  813.         if restrictionsActive then
  814.             if range <= 5 then
  815.                 range = 5
  816.             elseif range <= 6 then
  817.                 range = 6
  818.             elseif range <= 8 then
  819.                 range = 8
  820.             elseif range <= 10 then
  821.                 range = 10
  822.             elseif range <= 11 then
  823.                 range = 11
  824.             elseif range <= 13 then
  825.                 range = 13
  826.             elseif range <= 18 then
  827.                 range = 18
  828.             elseif range <= 22 then
  829.                 range = 22
  830.             elseif range <= 30 then
  831.                 range = 30
  832.             elseif range <= 43 then
  833.                 range = 43
  834.             elseif range <= 50 then
  835.                 range = 50
  836.             elseif range <= 60 then
  837.                 range = 60
  838.             elseif range <= 80 then
  839.                 range = 80
  840.             end
  841.         end
  842.         textFrame.isShown = true
  843.         textFrame:Show()
  844.         textFrame:SetOwner(UIParent, "ANCHOR_PRESERVE")
  845.     end
  846.     --TODO, add check for restricted area here so we can prevent radar frame loading.
  847.     if not restrictionsActive and (DBM.Options.RangeFrameFrames == "radar" or DBM.Options.RangeFrameFrames == "both") and not radarFrame.isShown then
  848.         radarFrame.isShown = true
  849.         radarFrame:Show()
  850.     end
  851.     mainFrame.range = range
  852.     mainFrame.filter = filter
  853.     mainFrame.redCircleNumPlayers = redCircleNumPlayers
  854.     mainFrame.reverse = reverse
  855.     mainFrame.hideTime = hideTime and (GetTime() + hideTime) or 0
  856.     mainFrame.restrictions = restrictionsActive
  857.     if not mainFrame.eventRegistered then
  858.         mainFrame.eventRegistered = true
  859.         updateIcon()
  860.         mainFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
  861.         mainFrame:RegisterEvent("RAID_TARGET_UPDATE")
  862.     end
  863.     updater:SetScript("OnLoop", updateRangeFrame)
  864.     updater:Play()
  865.     if forceshow and not DBM.Options.DontRestoreRange then--Force means user activaetd range frame, store user value for restore function
  866.         restoreRange, restoreFilter, restoreThreshold, restoreReverse = mainFrame.range, mainFrame.filter, mainFrame.redCircleNumPlayers, mainFrame.reverse
  867.     end
  868. end
  869.  
  870. function rangeCheck:Hide(force)
  871.     if restoreRange and not force then--Restore range frame to way it was when boss mod is done with it
  872.         rangeCheck:Show(restoreRange, restoreFilter, true, restoreThreshold, restoreReverse)
  873.     else
  874.         restoreRange, restoreFilter, restoreThreshold, restoreReverse = nil, nil, nil, nil
  875.         DBM.Options.RestoreRange = nil--Set nil here because it means force was passed.
  876.         updater:Stop()
  877.         activeRange = 0
  878.         if mainFrame.eventRegistered then
  879.             mainFrame.eventRegistered = nil
  880.             mainFrame:UnregisterAllEvents()
  881.         end
  882.         if textFrame then
  883.             textFrame.isShown = nil
  884.             textFrame:Hide()
  885.         end
  886.         if radarFrame then
  887.             radarFrame.isShown = nil
  888.             radarFrame:Hide()
  889.         end
  890.     end
  891. end
  892.  
  893. function rangeCheck:IsShown()
  894.     return textFrame and textFrame.isShown or radarFrame and radarFrame.isShown
  895. end
  896.  
  897. function rangeCheck:IsRadarShown()
  898.     return radarFrame and radarFrame.isShown
  899. end
  900.  
  901. function rangeCheck:UpdateRestrictions(force)
  902.     mainFrame.restrictions = force or DBM:HasMapRestrictions()
  903. end
  904.  
  905. function rangeCheck:SetHideTime(hideTime)
  906.     mainFrame.hideTime = hideTime and (GetTime() + hideTime) or 0
  907. end
  908.  
  909. -- GetDistance(uId) -- distance between you and the given uId
  910. -- GetDistance(uId, x, y) -- distance between uId and the coordinates
  911. -- GetDistance(uId, uId2) -- distance between the two uIds
  912. function rangeCheck:GetDistance(...)
  913.     return getDistanceBetween(...)
  914. end
  915.  
  916. function rangeCheck:GetDistanceAll(...)
  917.     return getDistanceBetweenALL(...)
  918. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement