Quantcast

Added initial support for use effects with cooldowns

Kevin Lyles [02-19-10 - 03:21]
Added initial support for use effects with cooldowns
Handles "increases stat by x for y seconds"-type cooldowns
Filename
Regexps.lua
Upgrade.lua
WeightsWatcher.lua
config.xml
defaults.lua
diff --git a/Regexps.lua b/Regexps.lua
index eabd600..37101a2 100644
--- a/Regexps.lua
+++ b/Regexps.lua
@@ -405,6 +405,31 @@ local ElixirAffixes = {
 	"%.$",
 }

+local CooldownUseMatchLines = {
+	"^use: grants? .* cooldown%)$",
+	"^use: increases? .* cooldown%)$",
+}
+
+local CooldownUsePreprocessLines = {
+	{" (arcane spell) power ", " %1 damage "},
+	{" (fire spell) power ", " %1 damage "},
+	{" (frost spell) power ", " %1 damage "},
+	{" (holy spell) power ", " %1 damage "},
+	{" (nature spell) power ", " %1 damage "},
+	{" (shadow spell) power ", " %1 damage "},
+	{" your stats ", " all stats "},
+	{" dodge by ", " dodge rating by "},
+}
+
+local CooldownUseAffixes = {
+	"^use: +",
+	"^grants? +",
+	"^increases? +",
+	"^your +",
+	"^the target's +",
+	"^maximum +",
+}
+
 local function parseStats(text, section)
 	for _, regex in ipairs(ww_regexes[section].MultipleStat) do
 		local pattern, func = unpack(regex)
@@ -433,6 +458,7 @@ EffectHandlers = {
 	{ElixirMatchLines, {}, ElixirUnweightedLines, ElixirPreprocessLines, ElixirAffixes, parseStats, "elixir"},
 	{FishingMatchLines, {}, {}, {}, FishingAffixes, parseStats, "fishing"},
 	{UseEffectMatchLines, UseEffectIgnoreLines, UseEffectUnweightedLines, UseEffectPreprocessLines, UseEffectAffixes, parseStats, "useEffect"},
+	{CooldownUseMatchLines, {}, {}, CooldownUsePreprocessLines, CooldownUseAffixes, function(text) local stat = WeightsWatcher.useEffect(text) if stat then return {useEffect = stat} end end, "cooldownUseEffect"},
 }

 function WeightsWatcher.twoStats(text, pattern, section)
@@ -532,6 +558,42 @@ function WeightsWatcher.newStatTable(tbl)
 	return setmetatable(tbl or {}, ww_normalStatsMetatable)
 end

+function WeightsWatcher.convertToSeconds(duration)
+	local start, _, hours = string.find(duration, "^(%d+) ho?u?rs?$")
+	if start then
+		return hours * 3600
+	end
+	local start, _, minutes, seconds = string.find(duration, "^(%d+) minu?t?e?s? (%d+) seco?n?d?s?$")
+	if start then
+		return minutes * 60 + seconds
+	end
+	local start, _, minutes = string.find(duration, "^(%d+) minu?t?e?s?$")
+	if start then
+		return minutes * 60
+	end
+	local start, _, seconds = string.find(duration, "^(%d+) seco?n?d?s?$")
+	if start then
+		return tonumber(seconds)
+	end
+end
+
+function WeightsWatcher.useEffect(text)
+	local start, _, stat, value, duration, cooldown = string.find(text, "^(%a+ ?%a+ ?%a+ ?%a+) by ([+-]?%d+) for (%d+ %a+ ?%d* ?%a*)%. +%((%d+ %a+ ?%d* ?%a*) cooldown%)$")
+	if not start then
+		start, _, value, stat, duration, cooldown = string.find(text, "^([+-]?%d+) (%a+ ?%a+ ?%a+ ?%a+) for (%d+ %a+ ?%d* ?%a*)%. +%((%d+ %a+ ?%d* ?%a*) cooldown%)$")
+	end
+	if start then
+		cooldown = WeightsWatcher.convertToSeconds(cooldown)
+		duration = WeightsWatcher.convertToSeconds(duration)
+		return {
+			stat = stat,
+			value = value,
+			duration = duration,
+			cooldown = cooldown,
+		}
+	end
+end
+
 Preprocess = {
 	{"|c[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]([^|]+)|r", "%1"},
 	{" +$", ""},
diff --git a/Upgrade.lua b/Upgrade.lua
index 0ddf0f2..057e209 100644
--- a/Upgrade.lua
+++ b/Upgrade.lua
@@ -135,6 +135,18 @@ function noop_major_up(vars)
 	return vars
 end

+function upgradeAccountToUseEffectRatio(vars)
+	if not vars.options.useEffects then
+		vars.options.useEffects = {}
+	end
+	if not vars.options.useEffects.uptimeRatio then
+		vars.options.useEffects.uptimeRatio = 0.8
+	end
+
+	vars.dataMinorVersion = 11
+	return vars
+end
+
 function upgradeAccountToWorkingMeleeDamage(vars)
 	for _, class in ipairs(vars.weightsList) do
 		for _, weight in ipairs(vars.weightsList[class]) do
@@ -792,6 +804,7 @@ upgradeAccountFunctions = {
 		[7] = upgradeAccountToShowAlternateGemsTypoFix,
 		[8] = upgradeAccountToWorkingResistances,
 		[9] = upgradeAccountToWorkingMeleeDamage,
+		[10] = upgradeAccountToUseEffectRatio,
 	},
 }

@@ -819,6 +832,7 @@ downgradeAccountFunctions = {
 		[8] = noop_down,
 		[9] = noop_down,
 		[10] = noop_down,
+		[11] = noop_down,
 	},
 }

diff --git a/WeightsWatcher.lua b/WeightsWatcher.lua
index 544f0f5..575dd1b 100644
--- a/WeightsWatcher.lua
+++ b/WeightsWatcher.lua
@@ -72,11 +72,12 @@ ww_weightCacheWeightMetatable = {
 		local itemStats = ww_bareItemCache[splitItemLink(key)]
 		local normalStats = itemStats.normalStats
 		local socketBonusStat = itemStats.socketBonusStat
+		local useEffects = itemStats.useEffects
 		itemStats = ww_itemCache[key]
 		local socketBonusActive = itemStats.socketBonusActive
 		local gemStats = itemStats.gemStats

-		tbl[key] = WeightsWatcher.calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, tbl.weight)
+		tbl[key] = WeightsWatcher.calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, useEffects, tbl.weight)
 		return tbl[key]
 	end,
 }
@@ -125,6 +126,7 @@ ww_weightIdealCacheWeightMetatable = {
 		local normalStats = itemStats.normalStats
 		local sockets = itemStats.sockets
 		local socketBonusStat = itemStats.socketBonusStat
+		local useEffects = itemStats.useEffects
 		local socketBonusWeight = 0
 		if socketBonusStat then
 			for stat, value in pairs(socketBonusStat) do
@@ -151,10 +153,10 @@ ww_weightIdealCacheWeightMetatable = {
 			end
 		end
 		gemStats = WeightsWatcher.getGemStats(bestGems)
-		weightVal = WeightsWatcher.calculateWeight(normalStats, true, socketBonusStat, gemStats, tbl.weight)
+		weightVal = WeightsWatcher.calculateWeight(normalStats, true, socketBonusStat, gemStats, useEffects, tbl.weight)
 		if breakSocketColors then
 			gemStatsIgnoreSockets = WeightsWatcher.getGemStats(bestGemsIgnoreSocket)
-			weightValIgnoreSockets = WeightsWatcher.calculateWeight(normalStats, false, socketBonusStat, gemStatsIgnoreSockets, tbl.weight)
+			weightValIgnoreSockets = WeightsWatcher.calculateWeight(normalStats, false, socketBonusStat, gemStatsIgnoreSockets, useEffects, tbl.weight)

 			if weightVal < weightValIgnoreSockets then
 				weightVal = weightValIgnoreSockets
@@ -780,7 +782,7 @@ function WeightsWatcher.bestGemForSocket(socketColor, weightScale, qualityLimit)
 						if gems[quality] then
 							for gemId, gemStats in pairs(gems[quality]) do
 								if WeightsWatcher.matchesSocket(gemStats[1], socketColor) then
-									weight = WeightsWatcher.calculateWeight({}, true, nil, {{gemStats}}, weightScale)
+									weight = WeightsWatcher.calculateWeight({}, true, nil, {{gemStats}}, {}, weightScale)
 									if #(bestGem) == 0 or weight > bestWeight then
 										bestGem = {gemId}
 										bestWeight = weight
@@ -845,7 +847,7 @@ function WeightsWatcher.matchesSocket(gemId, socketColor)
 	return false
 end

-function WeightsWatcher.calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, weightsScale)
+function WeightsWatcher.calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, useEffects, weightsScale)
 	local weight = 0

 	for stat, value in pairs(normalStats) do
@@ -889,6 +891,9 @@ function WeightsWatcher.calculateWeight(normalStats, socketBonusActive, socketBo
 		end
 		weight = weight + maxWeight
 	end
+	for _, useEffect in pairs(useEffects) do
+		weight = weight + WeightsWatcher.getWeight(useEffect.stat, useEffect.value * useEffect.duration / useEffect.cooldown * ww_vars.options.useEffects.uptimeRatio, weightsScale)
+	end
 	if ww_vars.options.tooltip.normalizeWeights == true then
 		local total = 0

@@ -1001,7 +1006,7 @@ end

 function WeightsWatcher.getItemStats(link)
 	local textL, textR, pattern, func, start
-	local normalStats, nonStats, socketList, socketBonusStat = WeightsWatcher.newStatTable(), {}, {}, WeightsWatcher.newStatTable()
+	local normalStats, nonStats, socketList, socketBonusStat, useEffects = WeightsWatcher.newStatTable(), {}, {}, WeightsWatcher.newStatTable(), {}
 	local ranged = false

 	-- Populate hidden tooltip
@@ -1038,6 +1043,9 @@ function WeightsWatcher.getItemStats(link)
 			if stats.socketBonusStat then
 				socketBonusStat = socketBonusStat + stats.socketBonusStat
 			end
+			if stats.useEffect then
+				table.insert(useEffects, stats.useEffect)
+			end
 		end
 	end

@@ -1051,6 +1059,7 @@ function WeightsWatcher.getItemStats(link)
 		nonStats = nonStats,
 		sockets = socketList,
 		socketBonusStat = socketBonusStat,
+		useEffects = useEffects,
 	}
 end

diff --git a/config.xml b/config.xml
index e4df82d..3e09300 100644
--- a/config.xml
+++ b/config.xml
@@ -413,6 +413,77 @@
 							</OnLoad>
 						</Scripts>
 					</CheckButton>
+					<Frame name="$parentUseEffectUptimeRatio" parentKey = "useEffectUptimeRatio" inherits="ww_labeledElement">
+						<Anchors>
+							<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentNormalizeWeights"/>
+						</Anchors>
+						<Size>
+							<AbsDimension y="25"/>
+						</Size>
+						<Frames>
+							<EditBox letters="16" name="$parentRatio" parentKey="ratio" autoFocus="false">
+								<Anchors>
+									<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentLabel"/>
+								</Anchors>
+								<Size>
+									<AbsDimension x="50" y="22"/>
+								</Size>
+								<Backdrop edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
+									<EdgeSize>
+										<AbsValue val="10"/>
+									</EdgeSize>
+									<TileSize>
+										<AbsValue val="10"/>
+									</TileSize>
+									<BackgroundInsets>
+										<AbsInset left="0" right="0" top="5" bottom="5"/>
+									</BackgroundInsets>
+								</Backdrop>
+								<FontString inherits="GameFontNormal">
+									<Anchors>
+										<Anchor point="LEFT"/>
+									</Anchors>
+								</FontString>
+								<Scripts>
+									<OnLoad>
+										self:SetTextInsets(5, 5, 0, 0)
+									</OnLoad>
+									<OnShow>
+										self:SetText(ww_vars.options.useEffects.uptimeRatio * 100)
+									</OnShow>
+									<OnTextChanged>
+										local text = self:GetText()
+										if self:GetNumber() ~= 0 or text:match("^[0.]+$") or text == "" then
+											self.number = text
+											ww_vars.options.useEffects.uptimeRatio = self:GetNumber() / 100
+											ww_weightCache = setmetatable({}, ww_weightCacheMetatable)
+											ww_weightIdealCache = setmetatable({}, ww_weightIdealCacheMetatable)
+										end
+									</OnTextChanged>
+									<OnChar>
+										if validateNumber(text, self:GetText()) then
+											self.number = self:GetText()
+											ww_vars.options.useEffects.uptimeRatio = self:GetNumber() / 100
+											ww_weightCache = setmetatable({}, ww_weightCacheMetatable)
+											ww_weightIdealCache = setmetatable({}, ww_weightIdealCacheMetatable)
+										else
+											local cursorPosition = self:GetCursorPosition() - 1
+											self:SetText(self.number)
+											self:SetCursorPosition(cursorPosition)
+										end
+									</OnChar>
+									<OnEscapePressed>
+										self:ClearFocus()
+									</OnEscapePressed>
+								</Scripts>
+							</EditBox>
+						</Frames>
+						<Scripts>
+							<OnLoad>
+								self.label:SetText("Percent of ideal use effect uptime:")
+							</OnLoad>
+						</Scripts>
+					</Frame>
 				</Frames>
 			</Frame>
 			<Frame name="$parentDisplayOptions" parentKey="displayOptions" inherits="ww_borderedFrame">
diff --git a/defaults.lua b/defaults.lua
index be52734..8805e00 100644
--- a/defaults.lua
+++ b/defaults.lua
@@ -208,7 +208,7 @@ classNameOptions = {

 defaultVars = {
 	dataMajorVersion = 1,
-	dataMinorVersion = 10,
+	dataMinorVersion = 11,
 	weightsList = {
 		[1] = "DEATHKNIGHT",
 		[2] = "DRUID",
@@ -633,6 +633,9 @@ defaultVars = {
 			showIdealWeights = "Shift",
 			showWeights = "Always",
 		},
+		useEffects = {
+			uptimeRatio = 0.8,
+		}
 	},
 }