• 0

    posted a message on Changing texture color in OnUpdate handler
    Well, I tried to respond to this post twice, but my login session timed out both times (at times I am lengthy with my responses) and I lost my write-ups. I would like to precede this post by expressing gratitude for the thoughtful responses I received, and thank you all for your time (especially Torhal for his extensive efforts).

    To keep this short, I found a solution to my problem, which was essentially calling SetVertexColor() in the OnUpdate handler, rather than SetTexture(). To facilitate this change with the existing code, besides changing the function call, I only needed to set the original texture to white. I'm thinking that SetTexture() creates an entirely new texture each time, and being called so frequently was not intended, especially when you only want to change the color, and not the actual texture, as in my case.

    Again, thanks all for the responses, it was actually your responses that indirectly led me to my solution, so thanks a ton!
    Posted in: AddOn HELP!
  • 0

    posted a message on Changing texture color in OnUpdate handler
    Hey OrionShock, thanks for the reply.

    As requested, here is a link to the full code I am running right now, http://www.wowace.com/paste/4163/. It is very much a work in progress, so please forgive some of the sloppiness.

    If anything else I can provide, please advise. :D
    Posted in: AddOn HELP!
  • 0

    posted a message on Changing texture color in OnUpdate handler
    Hey everyone :)

    I am changing the color of a texture in an OnUpdate script, but the results become unexpected after a while of running.

    For background, the mod will track and show party debuffs. The interface takes the form of "timer bars" similar to what you would find in something like a boss mod or spell cooldown mod.

    For the "timer bars", I was playing with the idea of having their texture change color as the time remaining on the debuff changed. Below is an image of what I'm going for.



    The code I came up with seems to work fine, but after a while the texture will flicker to green (low timer remaining) when it is supposed to be red (high time remaining). Alternatively, at times, when it is supposed to be green, it will flicker to red for a very brief moment. Below is an image showing the undesired behavior, you can see that Zaxbys, Subslol and Vinox's bars are green, when they should appear red. Also note that, the image only reflects that one moment. When calling TestDisplay(), several of the bars had this flickering effect, but only 3 were captured the moment the image was taken. In addition, again note, that this undesired behavior only occurs for a very brief moment, around 0.1 second, after which, the color appears as expected again.



    Some of the things I have checked in my debugging that do NOT seem to have any effect.
    • Throttling vs. not
    • New Frames vs. Reused Frames
    • When the texture flickers to the opposite color, it is not because it is taking the wrong branch in the if-else construct
    • Truncating values vs. not (current code is truncating several values)

    I have included a prototype of the code, I tried to make it as simple as possible, yet show all the things I am doing with the interface in order to determine the problem. If you run this code in-game, you can call global function TestDisplay(), to get a preview of what it looks like.

    As I mentioned earlier, at first, everything appears to be working fine, but after extended play, in a battleground for example, the texture color errors begin. To speed up the process of getting to the "buggy" stuff, just write a loop that calls TestDisplay() about 200 times, then the next time you call TestDisplay() once, you should see the problem I am referring to.

    Any advice or suggestions is greatly appreciated, thanks in advance. If any further details or explanation is required, sorry in advance for omitting, let me know and I'll respond accordingly.

    --some constants
    local SPELLNAME = 1
    local DURATION = 6
    local EXP_TIME = 7
    local SPELL_ID = 11
    local UNLIMITED = 999999 -- represents unlmited time duration
    
    
    --some user options
    local growthDirection = {[1] = "TOP", [2] = "BOTTOM"}
    local barHeight = 18
    local barWidth = 175
    local barPad = -3
    
    
    --an anchor frame
    local a = CreateFrame("Frame", nil, UIParent)
    a:SetSize(barWidth, barHeight)
    a:SetPoint("CENTER")
    a:SetMovable(true)
    a:EnableMouse(true)
    a:SetClampedToScreen(true)
    a:RegisterForDrag("LeftButton")
    a:SetScript("OnDragStart", a.StartMoving)
    a:SetScript("OnDragStop", a.StopMovingOrSizing)
    
    
    --container for recycled frames
    local unusedDebuffFrames = {}
    
    
    --called when inserting a debuff into visual list
    function NewDebuff(unitName, debuff, test)
    	if UnitIsVisible(unitName) or test then
    	
    		local debuffFrame		
    		--get a debuff frame, make new frame if no old frame to recyle
    		if #unusedDebuffFrames == 0 then
    			debuffFrame = CreateDebuffFrame()
    		else
    			debuffFrame = table.remove(unusedDebuffFrames)
    			debuffFrame.hidden = false
    		end	
    		--set debuff frame attributes
    		SetDebuffFrameElements(debuffFrame, unitName, debuff)	
    
    		--insert debuff frame into visible list
    		InsertDebuffFrame(debuffFrame)
    		
    		return debuffFrame
    	end
    end
    
    
    --create frame if none available
    function CreateDebuffFrame()
    	local self = CreateFrame("Frame")
    	self:SetHeight(barHeight)
    	self:SetWidth(barWidth)
    	
    	local element
    
    	--create background texture for debuff frame
    	element = self:CreateTexture("BACKGROUND")
    	element:SetAllPoints()
    	element:SetTexture(0.0, 0.0, 0.0); element:SetAlpha(0.5)
    	self.backTex = element
    	
    	--create spell icon texture for debuff frame
    	element = self:CreateTexture("ARTWORK")
    	element:SetPoint("TOPLEFT", self, "TOPLEFT")
    	element:SetPoint("BOTTOMRIGHT", self, "BOTTOMLEFT", barHeight, 0)
    	self.spellIconTex = element
    	
    	--create unit name fontstring for debuff frame
    	element = self:CreateFontString(nil, nil, "GameFontHighlight")
    	element:SetPoint("LEFT", self, "LEFT", barHeight + 5, 0)
    	self.unitNameFS = element
    	
    	--create timer fontstring for debuff frame
    	element = self:CreateFontString(nil, nil, "GameFontHighlight")
    	element:SetPoint("RIGHT", self, "RIGHT")
    	element:SetWidth(40)
    	self.timerFS = element
    	
    	--create timer texture
    	--top texture
    	element = self:CreateTexture("OVERLAY")
    	element:SetTexture(0.5, 0, 0.1); element:SetAlpha(0.7)
    	element:SetHeight(barHeight)
    	element:SetWidth(barWidth - barHeight)
    	element:SetPoint("TOPLEFT", self, "TOPLEFT", barHeight, 0)
    	self.timerTexTop = element
    
    	return self
    	
    end
    
    
    --set debuff frame's elements to match debuff's attributes
    function SetDebuffFrameElements(debuffFrame, unitName, debuff)
    	debuffFrame.unitNameFS:SetText(unitName)
    	debuffFrame.spellIconTex:SetTexture(GetSpellTexture(debuff[SPELL_ID]))
    	debuffFrame.spellName = debuff[SPELLNAME]
    	
    	--if debuff has duration
    	if debuff[DURATION] > 0 then
    		debuffFrame.duration = debuff[DURATION]
    		debuffFrame.expirationTime = debuff[EXP_TIME]
    		debuffFrame.timeRemaining = debuff[EXP_TIME] - GetTime()
    		debuffFrame.throttle = 0
    		debuffFrame:SetScript("OnUpdate", DebuffFrameOnUpdate)
    	else --no duration
    		debuffFrame.timeRemaining = UNLIMITED --ensure it has longest time for later comparison
    		--reset stuff
    		debuffFrame.timerFS:SetText(nil)
    		debuffFrame.timerTexTop:SetWidth(barWidth - barHeight)
    		debuffFrame.timerTexTop:SetTexture(0.5, 0, 0.1)
    	end
    end
    
    function DebuffFrameOnUpdate(self, elapsed)	
    	self.throttle = self.throttle + elapsed
    	if self.throttle < 0.05 then
    		--throttle
    	else
    		local timeRemaining = self.expirationTime - GetTime()
    		if timeRemaining > 0 then
    			local duration = self.duration
    			local percentRemaining = timeRemaining / duration
    			local texLength = math.ceil(percentRemaining * (barWidth - barHeight))
    			
    			self.timeRemaining = timeRemaining
    			
    			self.timerFS:SetText(FormatTimeRemaining(timeRemaining))	
    			self.timerTexTop:SetWidth(texLength)
    				
    			--STUFF FOR COLOR CHANGING BAR
    			if percentRemaining >= 0.5 then --100% - 50%, increase green from 0 to 1
    				local g = math.ceil(((1 - percentRemaining) * 2) * 100) / 100
    				self.timerTexTop:SetTexture(1.0, g, 0.0, 0.9)
    			else --time remaining is less than 50% of duration, decrease red from 1 to 0
    				local r = math.ceil((percentRemaining * 2) * 100) /100
    				self.timerTexTop:SetTexture(r, 1.0, 0.0, 0.9)
    			end
    			--END STUFF FOR COLOR CHANGING BAR
    			
    		else --timeRemaining <= 0
    			RemoveDebuffFrame(self)
    		end
    		self.throttle = 0
    	end
    end
    
    function FormatTimeRemaining(seconds)
    	local fstring	
    	if seconds > 60 then
    	  fstring = string.format("%d%s", math.ceil(seconds / 60), "m")
    	elseif seconds < 10 then
    	  fstring = string.format("%.1f%s", math.ceil(seconds * 10) / 10, "s")
    	else
    	  fstring = string.format("%d%s", math.floor(seconds), "s")
    	end
    	return fstring
    end
    
    
    function GroupByTime(currentFrame, debuffFrame)
    	while currentFrame do
    		if (currentFrame.timeRemaining > debuffFrame.timeRemaining) then 	
    			currentFrame:ClearAllPoints()
    			currentFrame:SetPoint(growthDirection[1], debuffFrame, growthDirection[2], 0, barPad)
    			debuffFrame:SetPoint(growthDirection[1], currentFrame.prev, growthDirection[2], 0, barPad)
    			debuffFrame.next = currentFrame
    			debuffFrame.prev = currentFrame.prev
    			currentFrame.prev.next = debuffFrame
    			currentFrame.prev = debuffFrame
    			debuffFrame:SetParent(a)
    			debuffFrame:Show()
    			break	
    		end
    		if currentFrame.next == nil then
    			--currently at last frame in list, new frame needs insert after
    			currentFrame.next = debuffFrame
    			debuffFrame.prev = currentFrame
    			debuffFrame:SetPoint(growthDirection[1], currentFrame, growthDirection[2], 0, barPad)
    			debuffFrame:SetParent(a)
    			debuffFrame:Show()
    			break
    		end
    		currentFrame = currentFrame.next
    	end
    end
    
    
    function InsertDebuffFrame(debuffFrame)
    	if a.next == nil then
    		a.next = debuffFrame
    		debuffFrame.prev = a
    		
    		debuffFrame:SetPoint(growthDirection[1], a, growthDirection[2], 0, barPad)
    		debuffFrame:SetParent(a)
    		debuffFrame:Show()
    	else
    		local currentFrame = a.next
    		GroupByTime(currentFrame, debuffFrame)
    	end
    end
    
    
    function RemoveDebuffFrame(debuffFrame)
    	--debuffFrame will come nil if not creating visible frames for out of range units
    	if debuffFrame and not debuffFrame.hidden then
    		debuffFrame:ClearAllPoints()
    		if debuffFrame.next == nil then
    			debuffFrame.prev.next = nil
    		else
    			debuffFrame.prev.next = debuffFrame.next
    			debuffFrame.next.prev = debuffFrame.prev
    			debuffFrame.next:SetPoint(growthDirection[1], debuffFrame.prev, growthDirection[2], 0, barPad)
    			debuffFrame.next = nil
    		end
    		debuffFrame.prev = nil
    		debuffFrame:Hide()
    		debuffFrame:SetParent(nil)
    		debuffFrame.hidden = true
    		debuffFrame:SetScript("OnUpdate", nil)
    		table.insert(unusedDebuffFrames, debuffFrame)
    	end
    end
    
    function TestDisplay()
    	NewDebuff("Beornhelm", {[SPELLNAME] = "Arcane Blast", [DURATION] = 6, [EXP_TIME] = GetTime() + 6, [SPELL_ID] = 36032}, true)
    	NewDebuff("Beornhelm", {[SPELLNAME] = "Curse of Agony", [DURATION] = 24, [EXP_TIME] = GetTime() + 24, [SPELL_ID] = 68138}, true)
    	NewDebuff("Beornhelm", {[SPELLNAME] = "Living Bomb", [DURATION] = 12, [EXP_TIME] = GetTime() + 12, [SPELL_ID] = 44461}, true)
    	NewDebuff("Zaxbys", {[SPELLNAME] = "Slow", [DURATION] = 10, [EXP_TIME] = GetTime() + 10, [SPELL_ID] = 32921}, true)
    	NewDebuff("Zaxbys", {[SPELLNAME] = "Living Bomb", [DURATION] = 12, [EXP_TIME] = GetTime() + 12, [SPELL_ID] = 44461}, true)
    	NewDebuff("Shaker", {[SPELLNAME] = "Curse of Agony", [DURATION] = 24, [EXP_TIME] = GetTime() + 24, [SPELL_ID] = 68138}, true)
    	NewDebuff("Shaker", {[SPELLNAME] = "Living Bomb", [DURATION] = 12, [EXP_TIME] = GetTime() + 12, [SPELL_ID] = 44461}, true)
    	NewDebuff("Subslol", {[SPELLNAME] = "Living Bomb", [DURATION] = 12, [EXP_TIME] = GetTime() + 12, [SPELL_ID] = 44461}, true)
    	NewDebuff("Subslol", {[SPELLNAME] = "Slow", [DURATION] = 10, [EXP_TIME] = GetTime() + 10, [SPELL_ID] = 32921}, true)
    	NewDebuff("Zaxbys", {[SPELLNAME] = "Curse of Agony", [DURATION] = 24, [EXP_TIME] = GetTime() + 24, [SPELL_ID] = 68138}, true)
    	NewDebuff("Kozzwoah", {[SPELLNAME] = "Arcane Blast", [DURATION] = 6, [EXP_TIME] = GetTime() + 6, [SPELL_ID] = 36032}, true)
    	NewDebuff("Vinox", {[SPELLNAME] = "Slow", [DURATION] = 10, [EXP_TIME] = GetTime() + 10, [SPELL_ID] = 32921}, true)
    end
    Posted in: AddOn HELP!
  • 0

    posted a message on ObsTracker (Official)
    ObsTracker is a Loot Tracking tool for raiding guilds, also usable by anyone who wishes to create a history of in-game trades. Records the name of player and name of item associated with an in-game trade. When recording is complete, user may copy the information to clipboard in order to save to a permanent location. For example, saving to a text file, or inserting into a database through a web form.

    The motivation for this mod mostly comes from using tracking mods in the past, and found that they were not able to do their job in realistic environments. I have not used any tracking mods over the last few months, so things may have changed.

    A past problem was that anytime somebody was out of range of the master looter (who is tied to the corpse of the mob containing the loot) and received an item, the record would not be recorded. This problem arises when the raid group moves ahead to start clearing thrash immediately after downing a boss, or the raid group goes through some sort of "phase" change to continue through the dungeon.

    Also, since Blizzard allows items dropped in dungeons to be BoE for up to 2 hours to any players in the raid, a new option for handling loot is allowed to guilds. For us, it works best for the Master Looter to scoop up all the loot, and then the raid and master looter continue through the dungeon until a decision is made by the loot council. This avoids the raid AND the ML from having to stay hunched around a dead corpse, waiting for the loot council "process" to complete. Instead allowing continuous dungeon progress for the entire raid, and the ML can trade the item at any time that is appropriate within 2 hours.

    This mod is brand new, and still at it's very early stages, with improvements and additions planned for the future. This is also the first mod I am developing, so any feedback, suggestions, or even complaints are greatly appreciated.

    Images, Files, and Instructions can be found at: http://wow.curseforge.com/addons/obstracker/
    Posted in: General AddOns
  • To post a comment, please or register a new account.