--[[
 abilityInfo should be defined with the following functions:
 {
 	:GetAbilityID()		- returns the ID of the ability
 	:GetCooldown()		- returns the current cooldown remaining on the ability (0 if this tooltip is not associated with a battle).
 	:GetRemainingDuration() - returns the remaining duration of an aura (0 if this is not an aura).
 	:IsInBattle()		- returns true if this tooltip is associated with a particular battle (and we can get the target's info)
 	:GetHealth(target)	- returns the current health of the associated unit. If not in a battle, returns the max health for self and 0 any other tokens.
 	:GetMaxHealth(target)- returns the max health of the associated unit. If not in a battle, returns 0 for all tokens but self.
 	:GetAttackStat(target)	- returns the value of the attack stat of the pet
 	:GetSpeedStat(target)	- returns the value of the speed stat of the pet
 	:GetState(stateID, target) - returns the value of a state associated with a unit. If not associated with a battle, return 0.
 	:GetWeatherState(stateID) - returns the value of the state associated with the weather. If not associated with a battle, return 0.
 	:GetPadState(stateID, target) - returns the value of the state associated with the pad on target's side. If not associated with a battle, return 0.
 	:GetPetOwner(target)	- returns either LE_BATTLE_PET_ALLY, LE_BATTLE_PET_ENEMY, or LE_BATTLE_PET_WEATHER while in combat.
 	:HasAura(auraID, target) - returns true if the unit has the aura active, false if they don't or we aren't in combat.
 	:GetPetType(target) - returns the pet type ID of the target. May return nil if the target doesn't exist (e.g. when clicking on the link in chat.)
 
 	Values for target are:
 	For abilities: self(default), enemy(affected)
 	For auras: auracaster(default), aurawearer(affected), auraenemy(the enemy of aurawearer)
 }
 --]]
 DEFAULT_PET_BATTLE_ABILITY_INFO = {};
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetAbilityID() error("UI: Unimplemented Function") end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetCooldown() return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetRemainingDuration() return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:IsInBattle() error("UI: Unimplemented Function") end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetHealth(target) return 100 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetMaxHealth(target) return 100 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetAttackStat(target) return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetSpeedStat(target) return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetState(stateID, target) return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetWeatherState(stateID) return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetPadState(stateID) return 0 end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetPetOwner(taget) return LE_BATTLE_PET_ALLY end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:HasAura(auraID, target) return false end
 function DEFAULT_PET_BATTLE_ABILITY_INFO:GetPetType(target) if ( self:IsInBattle() ) then error("UI: Unimplemented Function"); else return nil end end
 
 function SharedPetBattleAbilityTooltip_GetInfoTable()
 	local info = {};
 	setmetatable(info, { __index = DEFAULT_PET_BATTLE_ABILITY_INFO; });
 	return info;
 end
 
 function SharedPetBattleAbilityTooltip_OnLoad(self)
 	self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
 	self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
 
 	self.strongAgainstTextures = { self.StrongAgainstType1 };
 	self.weakAgainstTextures = { self.WeakAgainstType1 };
 end
 
 function SharedPetBattleAbilityTooltip_SetAbility(self, abilityInfo, additionalText)
 	local abilityID = abilityInfo:GetAbilityID();
 	if ( not abilityID ) then
 		return;
 	end
 
 	local id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfoByID(abilityID);
 
 	local bottom = self.AbilityPetType;
 
 	--Update name
 	self.Name:SetText(name);
 	
 	if ( numTurns and numTurns > 1 ) then
 		self.Duration:SetFormattedText(BATTLE_PET_ABILITY_MULTIROUND, numTurns);
 		self.Duration:Show();
 		bottom = self.Duration;
 	else
 		self.Duration:Hide();
 	end
 	
 	--Update cooldown
 	if ( maxCooldown > 0 ) then
 		self.MaxCooldown:SetFormattedText(PET_BATTLE_TURN_COOLDOWN, maxCooldown);
 		self.MaxCooldown:SetPoint("TOPLEFT", bottom, "BOTTOMLEFT", 0, -5);
 		self.MaxCooldown:Show();
 		bottom = self.MaxCooldown;
 	else
 		self.MaxCooldown:Hide();
 	end
 
 	--Current cooldown remaining
 	local currentCooldown = abilityInfo:GetCooldown();
 	if ( currentCooldown > 0 ) then
 		self.CurrentCooldown:SetFormattedText(PET_BATTLE_TURN_CURRENT_COOLDOWN, currentCooldown);
 		self.CurrentCooldown:Show();
 		bottom = self.CurrentCooldown;
 	else
 		self.CurrentCooldown:Hide();
 	end
 
 	--Any additional text the callers wants us to display
 	if ( additionalText ) then
 		self.AdditionalText:SetText(additionalText);
 		self.AdditionalText:SetPoint("TOPLEFT", bottom, "BOTTOMLEFT", 0, -5);
 		self.AdditionalText:Show();
 		bottom = self.AdditionalText;
 	else
 		self.AdditionalText:Hide();
 	end
 
 	--Update description
 	local description = SharedPetAbilityTooltip_ParseText(abilityInfo, unparsedDescription);
 	self.Description:SetText(description);
 	self.Description:SetPoint("TOPLEFT", bottom, "BOTTOMLEFT", 0, -5);
 	bottom = self.Description;
 
 	--Update ability type
 	if ( petType and petType > 0 ) then
 		self.Name:SetSize(190, 32);
 		self.Name:SetPoint("LEFT", self.AbilityPetType, "RIGHT", 5, 0);
 		self.AbilityPetType:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[petType]);
 		self.AbilityPetType:Show();
 	else
 		self.Name:SetSize(223, 32);
 		self.Name:SetPoint("LEFT", self, "TOPLEFT", 11, -26);
 		self.AbilityPetType:Hide();
 	end
 
 	--Update weaknesses/strengths
 	if ( petType and not noStrongWeakHints ) then
 		bottom = self.WeakAgainstIcon;
 		self.StrongAgainstIcon:Show();
 		self.StrongAgainstLabel:Show();
 		self.Delimiter1:Show();
 		self.WeakAgainstIcon:Show();
 		self.WeakAgainstLabel:Show();
 		self.Delimiter2:Show();
 
 		local nextStrongIndex, nextWeakIndex = 1, 1;
 		for i=1, C_PetJournal.GetNumPetTypes() do
 			local modifier = C_PetBattles.GetAttackModifier(petType, i);
 			if ( modifier > 1 ) then
 				local icon = self.strongAgainstTextures[nextStrongIndex];
 				if ( not icon ) then
 					self.strongAgainstTextures[nextStrongIndex] = self:CreateTexture(nil, "ARTWORK", "SharedPetBattleStrengthPetTypeTemplate");
 					icon = self.strongAgainstTextures[nextStrongIndex];
 					icon:ClearAllPoints();
 					icon:SetPoint("LEFT", self.strongAgainstTextures[nextStrongIndex - 1], "RIGHT", 2, 0);
 				end
 				if ( nextStrongIndex == 1 ) then
 					self.StrongAgainstType1Label:SetText(_G["BATTLE_PET_NAME_"..i]);
 					self.StrongAgainstType1Label:Show();
 				else
 					self.StrongAgainstType1Label:Hide(); --Don't show any text if there are multiple
 				end
 				icon:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[i]);
 				icon:Show();
 				nextStrongIndex = nextStrongIndex + 1;
 			elseif ( modifier < 1 ) then
 				local icon = self.weakAgainstTextures[nextWeakIndex];
 				if ( not icon ) then
 					self.weakAgainstTextures[nextWeakIndex] = self:CreateTexture(nil, "ARTWORK", "SharedPetBattleStrengthPetTypeTemplate");
 					icon = self.weakAgainstTextures[nextWeakIndex];
 					icon:ClearAllPoints();
 					icon:SetPoint("LEFT", self.weakAgainstTextures[nextWeakIndex - 1], "RIGHT", 2, 0);
 				end
 				if ( nextWeakIndex == 1 ) then
 					self.WeakAgainstType1Label:SetText(_G["BATTLE_PET_NAME_"..i]);
 					self.WeakAgainstType1Label:Show();
 				else
 					self.WeakAgainstType1Label:Hide(); --Don't show any text if there are multiple
 				end
 				icon:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[i]);
 				icon:Show();
 				nextWeakIndex = nextWeakIndex + 1;
 			end
 		end
 
 		for i=nextStrongIndex, #self.strongAgainstTextures do
 			self.strongAgainstTextures[i]:Hide();
 		end
 		for i=nextWeakIndex, #self.weakAgainstTextures do
 			self.weakAgainstTextures[i]:Hide();
 		end
 	else
 		self.StrongAgainstIcon:Hide();
 		self.StrongAgainstLabel:Hide();
 		self.StrongAgainstType1Label:Hide();
 		self.Delimiter1:Hide();
 		self.WeakAgainstIcon:Hide();
 		self.WeakAgainstLabel:Hide();
 		self.WeakAgainstType1Label:Hide();
 		self.Delimiter2:Hide();
 		for _, texture in pairs(self.strongAgainstTextures) do
 			texture:Hide();
 		end
 		for _, texture in pairs(self.weakAgainstTextures) do
 			texture:Hide();
 		end
 	end
 
 	--We haven't updated frame rects yet, so we'll alpha out the frame and update the size (and show it) next frame.
 	self.bottomFrame = bottom;
 	self:SetAlpha(0);
 	self:SetScript("OnUpdate", SharedPetBattleAbilityTooltip_UpdateSize);
 end
 
 function SharedPetBattleAbilityTooltip_UpdateSize(self)
 	self:SetScript("OnUpdate", nil);
 	self:SetHeight(self:GetTop() - self.bottomFrame:GetBottom() + 10);
 	self:SetAlpha(1);
 end
 
 --Enclosure for parsing tooltips
 --We use Lua to parse our tooltips instead of writing a custom parser to save development time.
 --TODO: Look into caching returns to decrease garbage collection.
 do
 	local parsedAbilityInfo;
 	function SharedPetAbilityTooltip_ParseText(abilityInfo, unparsed)
 		parsedAbilityInfo = abilityInfo;
 		local parsed = string.gsub(unparsed, "%b[]", SharedPetAbilityTooltip_ParseExpression);
 		return parsed;
 	end
 
 	local parserEnv = {
 		--Constants
 		SELF = "self",
 		ENEMY = "enemy",
 		AURAWEARER = "aurawearer",
 		AURACASTER = "auracaster",
 		AURAENEMY = "auraenemy",
 		AFFECTED = "affected",
 
 		--Proc types (for use in getProcIndex)
 		PROC_ON_APPLY = PET_BATTLE_EVENT_ON_APPLY,
 		PROC_ON_DAMAGE_TAKEN = PET_BATTLE_EVENT_ON_DAMAGE_TAKEN,
 		PROC_ON_DAMAGE_DEALT = PET_BATTLE_EVENT_ON_DAMAGE_DEALT,
 		PROC_ON_HEAL_TAKEN = PET_BATTLE_EVENT_ON_HEAL_TAKEN,
 		PROC_ON_HEAL_DEALT = PET_BATTLE_EVENT_ON_HEAL_DEALT,
 		PROC_ON_AURA_REMOVED = PET_BATTLE_EVENT_ON_AURA_REMOVED,
 		PROC_ON_ROUND_START = PET_BATTLE_EVENT_ON_ROUND_START,
 		PROC_ON_ROUND_END = PET_BATTLE_EVENT_ON_ROUND_END,
 		PROC_ON_TURN = PET_BATTLE_EVENT_ON_TURN,
 		PROC_ON_ABILITY = PET_BATTLE_EVENT_ON_ABILITY,
 		PROC_ON_SWAP_IN = PET_BATTLE_EVENT_ON_SWAP_IN,
 		PROC_ON_SWAP_OUT = PET_BATTLE_EVENT_ON_SWAP_OUT,
 
 		--We automatically populate with state constants as well in the form STATE_%s
 
 		--Utility functions
 		ceil = math.ceil,
 		floor = math.floor,
 		abs = math.abs,
 		min = math.min,
 		max = math.max,
 		cond = function(conditional, onTrue, onFalse) if ( conditional ) then return onTrue; else return onFalse; end end,
 		clamp = function(value, minClamp, maxClamp) return min(max(value, minClamp), maxClamp); end,
 
 		--Data fetching functions
 		unitState = function(stateID, target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetState(stateID, target);
 				end,
 		unitPower = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetAttackStat(target);
 				end,
 		unitSpeed = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetSpeedStat(target);
 				end,
 		unitMaxHealth = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetMaxHealth(target);
 				end,
 		unitHealth = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetHealth(target);
 				end,
 		unitIsAlly = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetPetOwner(target) == LE_BATTLE_PET_ALLY;
 				end,
 		unitHasAura = function(auraID, target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:HasAura(auraID, target);
 				end,
 		unitPetType = function(target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetPetType(target);
 				end,
 		isInBattle = function()
 					return parsedAbilityInfo:IsInBattle();
 				end,
 		numTurns = function(abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local id, name, icon, maxCooldown, description, numTurns = C_PetBattles.GetAbilityInfoByID(abilityID);
 					return numTurns;
 				end,
 		currentCooldown = function()
 					return parsedAbilityInfo:GetCurrentCooldown();
 				end,
 		maxCooldown = function(abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local id, name, icon, maxCooldown, description, numTurns = C_PetBattles.GetAbilityInfoByID(abilityID);
 					return maxCooldown;
 				end,
 		abilityPetType = function(abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local id, name, icon, maxCooldown, description, numTurns, petType = C_PetBattles.GetAbilityInfoByID(abilityID);
 					return petType;
 				end,
 		petTypeName = function(petType)
 					return _G["BATTLE_PET_DAMAGE_NAME_"..petType]
 				end,
 		remainingDuration = function()
 					return parsedAbilityInfo:GetRemainingDuration();
 				end,
 		getProcIndex = function(procType, abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local turnIndex = C_PetBattles.GetAbilityProcTurnIndex(abilityID, procType);
 					if ( not turnIndex ) then
 						error("No such proc type: "..tostring(procType));
 					end
 					return turnIndex;
 				end,
 		abilityName = function(abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local id, name, icon, maxCooldown, description, numTurns, petType = C_PetBattles.GetAbilityInfoByID(abilityID);
 					return name;
 				end,
 		abilityHasHints = function(abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					local id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfoByID(abilityID);
 					return petType and not noStrongWeakHints;
 				end,
 		padState = function(stateID, target)
 					if ( not target ) then
 						target = "default";
 					end
 					return parsedAbilityInfo:GetPadState(stateID, target);
 				end,
 		weatherState = function(stateID)
 					return parsedAbilityInfo:GetWeatherState(stateID);
 				end,
 		abilityStateMod = function(stateID, abilityID)
 					if ( not abilityID ) then
 						abilityID = parsedAbilityInfo:GetAbilityID();
 					end
 					return C_PetBattles.GetAbilityStateModification(abilityID, stateID);
 				end,
 	};
 	
 	-- Dynamic fetching functions
 	local effectParamStrings = {C_PetBattles.GetAllEffectNames()};
 	for i = 1, #effectParamStrings do
 		parserEnv[effectParamStrings[i]] = 
 			function(turnIndex, effectIndex, abilityID)
 				if ( not abilityID ) then
 					abilityID = parsedAbilityInfo:GetAbilityID();
 				end
 				local value = C_PetBattles.GetAbilityEffectInfo(abilityID, turnIndex, effectIndex, effectParamStrings[i]);
 				if ( not value ) then
 					error("No such attribute: "..effectParamStrings[i]);
 				end
 				return value;
 			end;
 	end
 
 	-- Fill out the environment with all states (format: STATE_%s)
 	C_PetBattles.GetAllStates(parserEnv);
 		
 	
 	--Alias helpers
 	local function FormatDamageHelper(baseDamage, attackType, defenderType)
 		local output = "";
-		local multi = C_PetBattles.GetAttackModifier(attackType, defenderType);
+		local multi = 1;
+		
+		-- If there is no type for the defender, then don't check the multiplier.
+		-- (This could happen for some things like weather effects that have an ambiguous target.)
+		if ( defenderType ~= 0 ) then
+			multi = C_PetBattles.GetAttackModifier(attackType, defenderType);
+		end
+		
 
 		if ( multi > 1 ) then 
 			output = GREEN_FONT_COLOR_CODE..math.floor(baseDamage * multi)..FONT_COLOR_CODE_CLOSE;
 			if ( ENABLE_COLORBLIND_MODE == "1" ) then
 				output = output.."|Tinterface\\petbattles\\battlebar-abilitybadge-strong-small:0|t";
 			end
 			return output;
 		elseif ( multi < 1 ) then 
 			output = RED_FONT_COLOR_CODE..math.floor(baseDamage * multi)..FONT_COLOR_CODE_CLOSE;
 			if ( ENABLE_COLORBLIND_MODE == "1" ) then
 				output = output.."|Tinterface\\petbattles\\battlebar-abilitybadge-weak-small:0|t";
 			end
 			return output;
 		end
 		
 		return math.floor(baseDamage);
 	end
 
 	local function FormatHealingHelper(baseHeal, healingDone, healingTaken)
 		local output = "";
 
 		local doneMulti = (healingDone / 100)
 		local takenMulti = (healingTaken / 100);
 		
 		local finalHeal = baseHeal + baseHeal * doneMulti;
 		finalHeal = finalHeal + finalHeal * takenMulti;
 
 		local finalMulti = finalHeal / baseHeal;
 
 		if ( finalMulti > 1 ) then 
 			output = GREEN_FONT_COLOR_CODE..math.floor(baseHeal * finalMulti)..FONT_COLOR_CODE_CLOSE;
 			if (ENABLE_COLORBLIND_MODE == "1") then
 				output = output.."|Tinterface\petbattles\battlebar-abilitybadge-strong-small:0|t";
 			end
 			return output;
 		elseif( finalMulti < 1 ) then 
 			output = RED_FONT_COLOR_CODE..math.floor(baseHeal * finalMulti)..FONT_COLOR_CODE_CLOSE;
 			if (ENABLE_COLORBLIND_MODE == "1") then
 				output = output.."|Tinterface\petbattles\battlebar-abilitybadge-weak-small:0|t";
 			end
 			return output;
 		end
 
 		return math.floor(baseHeal);
 	end
 
 	--Aliases
 	parserEnv.OnlyInBattle = function(text) if ( parserEnv.isInBattle() ) then return text else return ""; end end;
 	parserEnv.School = function(abilityID) return parserEnv.petTypeName(parserEnv.abilityPetType(abilityID)); end;
 	parserEnv.SumStates = function(stateID, target)
 		if ( parserEnv.unitPetType(target) == 7 ) then --Elementals aren't affected by weathers.
 			return parserEnv.unitState(stateID, target) + parserEnv.padState(stateID, target);
 		else
 			return parserEnv.unitState(stateID, target) + parserEnv.padState(stateID, target) + parserEnv.weatherState(stateID);
 		end
 	end;
 	parserEnv.AccuracyBonus = function(...) return parserEnv.SumStates(parserEnv.STATE_Stat_Accuracy) end
 	parserEnv.SimpleAccuracy = function(...) return parserEnv.accuracy(...) + parserEnv.AccuracyBonus() end
 	parserEnv.StandardAccuracy = function(...)
 		local accuracyBonus = parserEnv.AccuracyBonus(...);
 		local output = string.format("%d%%", math.floor(parserEnv.SimpleAccuracy(...)));
 		if ( accuracyBonus > 0 ) then
 			if ( ENABLE_COLORBLIND_MODE == "1" ) then
 				output = output.."(+)";
 			end
 			output = GREEN_FONT_COLOR_CODE..output..FONT_COLOR_CODE_CLOSE;
 		elseif ( accuracyBonus < 0 ) then
 			if ( ENABLE_COLORBLIND_MODE == "1" ) then
 				output = output.."(-)";
 			end
 			output = RED_FONT_COLOR_CODE..output..FONT_COLOR_CODE_CLOSE;
 		else
 			output = HIGHLIGHT_FONT_COLOR_CODE..output..FONT_COLOR_CODE_CLOSE;
 		end
 		return output;
 	end
 
 
 	--Attack aliases
 	parserEnv.AttackBonus = function() return (1 + 0.05 * parserEnv.unitPower()); end;
 	parserEnv.SimpleDamage = function(...) return parserEnv.points(...) * parserEnv.AttackBonus(); end;
 	parserEnv.StandardDamage = function(...)
 		local turnIndex, effectIndex, abilityID = ...;
 		return parserEnv.FormatDamage(parserEnv.SimpleDamage(...), abilityID);
 	end;
 	parserEnv.FormatDamage = function(baseDamage, abilityID, affected)
 		if ( not affected ) then
 			affected = parserEnv.AFFECTED;
 		end
 
 		if ( parserEnv.isInBattle() and parserEnv.abilityHasHints(abilityID) ) then
 			return FormatDamageHelper(baseDamage, parserEnv.abilityPetType(abilityID), parserEnv.unitPetType(affected));
 		else
 			return parserEnv.floor(baseDamage);
 		end
 	end;
 	
 	--Healing aliases
 	parserEnv.HealingBonus = function() return (1 + 0.05 * parserEnv.unitPower()); end;
 	parserEnv.SimpleHealing = function(...) return parserEnv.points(...) * parserEnv.HealingBonus(); end;
 	parserEnv.StandardHealing = function(...)
 		return parserEnv.FormatHealing(parserEnv.SimpleHealing(...));
 	end;
 	parserEnv.FormatHealing = function(baseHealing)
 		if ( parserEnv.isInBattle() ) then
 			return FormatHealingHelper(baseHealing, parserEnv.SumStates(65), parserEnv.SumStates(66));
 		else
 			return parserEnv.floor(baseHealing);
 		end
 	end;
 	
 	--Don't allow designers to accidentally change the environment
 	local safeEnv = {};
 	setmetatable(safeEnv, { __index = parserEnv, __newindex = function() end });
 
 	function SharedPetAbilityTooltip_ParseExpression(expression)
 		--Load the expression, chopping off the [] on the side.
 		local expr = loadstring("return ("..string.sub(expression, 2, -2)..")");
 		if ( expr ) then
 			--Set the environment up to restrict functions
 			setfenv(expr, safeEnv);
 
 			--Don't let designer errors cause us to stop execution
 			local success, repl = pcall(expr);
 			if ( success ) then
 				if ( type(repl) == "number" ) then
 					return math.floor(repl);	--We don't want to display any decimals.
 				else
 					return repl or "";
 				end
 			elseif ( IsGMClient() ) then
 				local err = string.match(repl, ":%d+: (.*)");
 				return "[DATA ERROR: "..err.."]";
 			else
 				return "DATA ERROR";
 			end
 		else
 			return "PARSING ERROR";
 		end
 	end
 end