vrtc / chorus (public) (License: CC0) (since 2023-08-12) (hash sha1)
World of Warcraft add-on stub. The overall goal is to create a specialized raid frame.

/src/ChorusRangeFrameTemplate.lua (2bf35c3024b99cbbdddd243a260e334ed151536b) (4876 bytes) (mode 100644) (type blob)

local GetSpellName = GetSpellName
local IsSpellInRange = IsSpellInRange

local MAX_SPELLS = MAX_SPELLS

local Chorus = Chorus

--[[ See ChorusRangeFrameTemplate.lua:function spellRangeMapUpdate. ]]--
--[[ See ChorusRangeFrameTemplate.lua:function rangeFrameUpdate. ]]--
local spellRangeMap = {}

local function spellRangeMapUpdate()
	local maxSpells = MAX_SPELLS or 1024
	maxSpells = math.min(math.max(1, math.abs(math.floor(maxSpells)), 8192))

	local buffer = {}

	local i = 0
	while (i < maxSpells) do
		i = i + 1

		--[[ Get player spell book button number "i", and request it's
		     corresponding spell name. This is NOT a unique spell
		     identifier. Every spell rank is a separate button. ]]--
		local spellName = GetSpellName(i, 'player')
		if not spellName then
			break
		end

		--[[ When GetSpellInfo is called with localized spell name
		     string, it only returns data on the spells stored in the
		     current player character's spell book. ]]--
		local _, _, _, _, _, _, _, _, maxRangeYards = GetSpellInfo(spellName)
		if spellName and maxRangeYards then
			assert(spellName ~= nil)
			assert('string' == type(spellName))
			spellName = strtrim(spellName)
			assert(string.len(spellName) >= 1)
			assert(string.len(spellName) <= 8192)

			assert(maxRangeYards ~= nil)
			assert('number' == type(maxRangeYards))
			maxRangeYards = math.abs(math.floor(maxRangeYards))

			if maxRangeYards >= 1 then
				local oldRangeYards = spellRangeMap[spellName]

				--[[
				Previous rank of the spell already mapped.
				Only the most potentially efficient spell rank
				will be mapped. ]]--

				if oldRangeYards then
					maxRangeYards = math.max(maxRangeYards, oldRangeYards)
				end

				--[[
				Priest spell "Mind Vision" has range of 50_000
				yards. This isn't a useful specificity, so
				filter it out. Only allow spell ranges that can
				be reasonably displayed and understood by the
				user during game combat play. Do not round down
				the value itself. Only store correct
				values.]]--
				if maxRangeYards < 99 then
					buffer[spellName] = maxRangeYards
				end
			end
		end
	end

	--[[ At this point assume no errors occurred. Re-write the actual spell
	     range map. ]]--
	spellRangeMap = buffer
end

local function rangeFrameUpdate(self)
	assert(self ~= nil)

	local unitDesignation = SecureButton_GetUnit(self) or 'none'

	assert(unitDesignation ~= nil)
	assert('string' == type(unitDesignation))
	unitDesignation = string.lower(strtrim(unitDesignation))
	assert(string.len(unitDesignation) >= 1)
	assert(string.len(unitDesignation) <= 256)

	local label = self.label or _G[self:GetName() .. 'Text']
	assert(label ~= nil)

	--[[ Frame must be always shown to keep update processor running. ]]--
	if not UnitExists(unitDesignation) or UnitIsUnit('player', unitDesignation) then
		label:SetText(nil)
		return
	end

	local rangeFlag = nil
	local distanceYards = nil
	local maxRangeYards = 0
	for spellName, rangeYards in pairs(spellRangeMap) do
		local flag = IsSpellInRange(spellName, unitDesignation)
		--[[ 1 == flag: in range; ]]--
		--[[ 0 == flag: out of range; ]]--
		--[[ nil == flag: not applicable or cannot be cast on given target. ]]--
		if not rangeFlag and flag then
			rangeFlag = flag
		end
		if nil ~= flag then
			maxRangeYards = math.max(rangeYards, maxRangeYards)
		end
		if 1 == flag then
			rangeFlag = 1
			if not distanceYards then
				distanceYards = rangeYards
			end
			distanceYards = math.min(distanceYards, rangeYards)
		end
	end

	local t
	if 1 == rangeFlag then
		t = string.format('<%d yd', distanceYards)
		label:SetTextColor(1, 1, 1)
	elseif 0 == rangeFlag then
		t = string.format('>%d yd', maxRangeYards)
		label:SetTextColor(1, 0, 0)
	else
		t = nil
	end
	label:SetText(t)
end

local function rangeFrameUpdateProcessor(self)
	assert(self ~= nil)

	--[[ Reduce update frequency to roughly 6 frames per second. ]]--
	if self.lastUpdateInstance and 'number' == type(self.lastUpdateInstance) then
		local now = GetTime()
		if now - self.lastUpdateInstance > 0.1667 then
			self.lastUpdateInstance = now
		else
			return
		end
	end

	rangeFrameUpdate(self)
end

local function rangeFrameMain(self)
	assert(self ~= nil)

	self.label = _G[self:GetName() .. 'Text']
	self:SetScript('OnUpdate', rangeFrameUpdateProcessor)
end

local function rangeSpellMapFrameMain(self)
	assert(self ~= nil)

	self:RegisterEvent('ACTIVE_TALENT_GROUP_CHANGED')
	self:RegisterEvent('LEARNED_SPELL_IN_TAB')
	self:RegisterEvent('PLAYER_LOGIN')
	self:RegisterEvent('PLAYER_TALENT_UPDATE')
	self:RegisterEvent('SPELLS_CHANGED')
	self:SetScript('OnEvent', spellRangeMapUpdate)

	RegisterUnitWatch(self)
end

--[[ Hide reference to the internal function, for some reason. ]]--
Chorus.rangeFrameMain = function(...)
	return rangeFrameMain(...)
end

Chorus.rangeSpellMapFrameMain = function(...)
	return rangeSpellMapFrameMain(...)
end


Mode Type Size Ref File
100644 blob 22 d7f81b36af99095409dbf9a7a92e18a5c74e5ff5 .gitignore
100644 blob 2761 8660a7b6b158b3d7c82af258020ea93722ae2bee README.md
040000 tree - 386cdd1448b396d67052c9c421df4d307621c280 bin
100644 blob 376 7c6577431ffa8a42b6e2570c37b2e7bbe6f952ce chorus-0.2-1.rockspec
100644 blob 111 b22afedfa744551589b080882fdc70c11ab6b17d chorus.toc
040000 tree - cac8af7ca5d8adc7771598e6faae482998b25fa2 doc
040000 tree - b30875c0405a889b8e1ef8838ccd70adde587bdd etc
040000 tree - 89b0ab39d95faab01a754a25f5a5269d5f5bbcea rocketgit
040000 tree - 5b8dd064c04749cf19281ed90842d3996ad61dc6 share
040000 tree - 17333a2ce6b635748cd2f722d7073f41e6fe79b4 src
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/vrtc/chorus

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/vrtc/chorus

Clone this repository using git:
git clone git://git.rocketgit.com/user/vrtc/chorus

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main