This is a read only copy without any forum functionality of the old Modcraft forum.
If there is anything that you would like to have removed, message me on Discord via Kaev#5208.
Big thanks to Alastor for making this copy!

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Grymskvll

Pages: [1]
1
Resources and Tools / [TOOL] Item Balancer
« on: January 23, 2019, 08:01:13 am »
Download: https://github.com/Grymskvll/WoW-Item-Balancer/releases
Demo:


Major inaccuracies can occur, especially if it's something like mail armor with int. The budget mod is probably different for such stats.
Socket budget is also kind of a rough guess.

Sorry for my bad programming. I tried to rewrite it, but it just became a different kind of bad.

2
Miscellaneous / [WotLK][TC][Eluna][AIO] Custom secondary power types
« on: August 16, 2016, 04:46:56 pm »
This is a system for custom secondary powertypes, like combo points, DK runes or spriests' shadow orbs. Here's a demo video, I previously posted it in the showoff thread:
[media:20r7yr4d]https://www.youtube.com/watch?v=qHSFOsNAs_A[/media:20r7yr4d]

If I forgot anything or if you have improvements, please let me know.

To use this, you need to have patched Wow.exe to load modified interface files. See http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-and-programs/501200-repost-sig-md5-protection-remover.html

First we need to add some Eluna player hooks for various stages of casting.
We need 3 new hooks:
PLAYER_EVENT_ON_SPELL_CAST_START   (validation and cancellation: script can return false to cancel the cast)
PLAYER_EVENT_ON_SPELL_CAST_SUCCESS   (spell passed normal checks for range, mana, target, etc, so now we do custom validation, but NO CHANGES ARE APPLIED in case a later script that registered this hook wants to cancel the cast)
PLAYER_EVENT_ON_SPELL_LAUNCH      (spell passed all custom validation from the previous hook, so here we can take custom power or do anything else without bugs)

To add these hooks, we need to modify various files. Hopefully it's not too disorienting. Make sure you don't have any uncommited changes before beginning!

In gameSpellsSpell.cpp, at the top of Spell::prepare, add the Eluna hook:
Code: [Select]
void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura)
{

#ifdef ELUNA
if (Player* playerCaster = m_caster->ToPlayer())
{
if (!sEluna->OnSpellCastStart(playerCaster, this))
{
finish(false);
return;
}
}
#endif


In Spell::Cast, below "CallScriptOnCastHandlers();" add the Eluna hook:
Code: [Select]
CallScriptOnCastHandlers();


#ifdef ELUNA
if (Player* playerCaster = m_caster->ToPlayer())
{
if (!sEluna->OnSpellCastSuccess(playerCaster, this))
{
SendInterrupted(0);

if (playerCaster->GetTypeId() == TYPEID_PLAYER)
{
playerCaster->RestoreSpellMods(this);
// cleanup after mod system
// triggered spell pointer can be not removed in some cases
playerCaster->SetSpellModTakingSpell(this, false);
}
finish(false);
SetExecutedCurrently(false);

return;
}
}
#endif

At the top of Spell::HandleLaunchPhase(), add the Eluna hook:
Code: [Select]
void Spell::HandleLaunchPhase()
{
if (Player* playerCaster = m_caster->ToPlayer())
{
sScriptMgr->OnPlayerSpellLaunch(playerCaster, this);
}


In LuaEngineHeader FilesHooks.h, in "enum PlayerEvents" add:
Code: [Select]
PLAYER_EVENT_ON_SPELL_CAST_START =  43, // (event, player, spell)
PLAYER_EVENT_ON_SPELL_CAST_SUCCESS =  44, // (event, player, spell, skipCheck)
PLAYER_EVENT_ON_SPELL_LAUNCH =  45, // (event, player, spell)


In LuaEngineHeader FilesLuaEngine.h, add this under the "void OnTextEmote" declaration:
Code: [Select]
bool OnSpellCastStart(Player* pPlayer, Spell* pSpell);
bool OnSpellCastSuccess(Player* pPlayer, Spell* pSpell);
void OnSpellLaunch(Player* pPlayer, Spell* pSpell);


In LuaEngineSource FilesPlayerHooks.cpp, add the following:
Code: [Select]
bool Eluna::OnSpellCastStart(Player* pPlayer, Spell* pSpell)
{
START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_SPELL_CAST_START, true);
bool result = true;
Push(pPlayer);
Push(pSpell);
int n = SetupStack(PlayerEventBindings, key, 2);

while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);

if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;

lua_pop(L, 1);
}

CleanUpStack(2);
return result;
}

bool Eluna::OnSpellCastSuccess(Player* pPlayer, Spell* pSpell)
{
START_HOOK_WITH_RETVAL(PLAYER_EVENT_ON_SPELL_CAST_SUCCESS, true);
bool result = true;
Push(pPlayer);
Push(pSpell);
int n = SetupStack(PlayerEventBindings, key, 2);

while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);

if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;

lua_pop(L, 1);
}

CleanUpStack(2);
return result;
}

void Eluna::OnSpellLaunch(Player* pPlayer, Spell* pSpell)
{
START_HOOK(PLAYER_EVENT_ON_SPELL_LAUNCH);
Push(pPlayer);
Push(pSpell);
CallAllFunctions(PlayerEventBindings, key);
}


In gameScriptingScriptMgr.h, add this under the "virtual void OnTextEmote" declaration:
Code: [Select]
// Called in Spell::Prepare.
virtual void OnSpellCastStart(Player* /*player*/, Spell* /*spell*/) { }

// Called in Spell::Cast.
virtual void OnSpellCastSuccess(Player* /*player*/, Spell* /*spell*/) { }

// Called in Spell::HandleLaunchPhase.
virtual void OnSpellLaunch(Player* /*player*/, Spell* /*spell*/) { }

In gameScriptingScriptMgr.cpp, add:
Code: [Select]
void ScriptMgr::OnPlayerSpellCastStart(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellCastStart(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellCastStart(player, spell);
}

void ScriptMgr::OnPlayerSpellCastSuccess(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellCastSuccess(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellCastSuccess(player, spell);
}

void ScriptMgr::OnPlayerSpellLaunch(Player* player, Spell* spell)
{
#ifdef ELUNA
sEluna->OnSpellLaunch(player, spell);
#endif
FOREACH_SCRIPT(PlayerScript)->OnSpellLaunch(player, spell);
}


Next, we need to add a new Eluna spell method: SendCastResult. This is needed so that our Eluna script can send the player's client a notification to cancel the casting state and GCD, using castresult code 0 (SPELL_FAILED_SUCCESS), which has no error notification so we can jam in our custom "Not enough powertype" message separately. In hindsight, it might've been just as good to put a call to spell->SendCastResult inside Spell::prepare and Spell::Cast... oops.

In LuaEngineMethodsSpellMethods.h, within "namespace LuaSpell" add:
Code: [Select]
int SendCastResult(Eluna* /*E*/, lua_State* L, Spell* spell)
{
SpellCastResult result = (SpellCastResult)Eluna::CHECKVAL<uint32>(L, 2);
spell->SendCastResult(result);
return 0;
}

In LuaEngineSource FilesLuaFunctions.cpp, in ElunaRegister<Spell> SpellMethods[], add this under // Other:
Code: [Select]
{ "SendCastResult", &LuaSpell::SendCastResult },


To make spells that require the custom secondary power, create a spell with no power cost (the powertype shouldn't matter).

Finally, here's an archive with an MPQ required by each client that defines some custom secure vars and has some art required by the Happy Hearts example, as well as the AIO script with two example secondary powers included ("Happy Hearts" for the shaman, "Displeasure" for the warrior). The spell IDs in the examples are basic custom spells I made for testing. There's nothing special about them besides having 0 cost in Spell.dbc. Spell costs are handled in each power's own script file, in the "consuming" and "generating" tables. The Happy Hearts example has some comments. To make a new custom secondary power, copy one of the examples (Happy Hearts probably), and modify it to your needs (token, values at the top, update function, graphic setup). You don't need to change the main script file.

Mirror: https://a.fluntcaps.me/eakwpn.zip

3
Miscellaneous / [LUA] Modifying secure variables without taint
« on: August 03, 2016, 08:27:59 pm »
If there's a better solution, or if there are any improvements to be made to this, please let me know.

I was working on a custom secondary class resource system (demo here: ) and ran into the phenomenon of interface taint (more info here: http://wowwiki.wikia.com/wiki/Secure_Ex ... d_Tainting).

From what I understand, normally when you're modding the interface for addons, you don't necessarily need to directly change the return value of API functions. However, I needed to change the return value of certain secure functions based on custom conditions (like checking custom resource values to see if a spell is usable).

The problem is that directly changing secure functions will taint them, causing interface errors (or at least it causes ugly notifications to be printed in the chat window). The good news is there's apparently a way to modify secure variables (including functions).

Here's how:


1) Requires a patched Wow.exe to load modified interface files (see http://www.ownedcore.com/forums/world-o ... mover.html).

2) Find the most up-to-date FrameXML.toc (GlueXML.toc should work too) in your client. For the standard WotLK 3.3.5 version, it should be in [your-WoW-folder]Data[locale]patch-[locale]-3.MPQ
Full path:
InterfaceFrameXMLFrameXML.toc

3) Extract FrameXML.toc to [your-WoW-folder]InterfaceFrameXML, or make a new MPQ for it. Either should work.

4) Open it up in any text editor and add this new line at the bottom (the path and filename are arbitrary, change it if you feel like it):
Code: [Select]
..CustomSecureVarsCustomSecureVars.lua
5) Create a new folder in [your-WoW-folder]Interface, name it CustomSecureVars. In the new folder, create a text file called CustomSecureVars.lua. This file will hold all the new secure variables you need. Feel free to edit secure functions all you want, they'll still be secure so long as you don't taint them by accessing any tainted variables.

Top tips for keeping variables secure:


If you want to call a (potentially) tainted function, use the "securecall" API function (see http://wowwiki.wikia.com/wiki/API_securecall).

If you need to provide a tainted variable as an argument from a modified secure function, provide it as a string and have the called function resolve the string to a global variable. That way the secure function stays secure, and only the called function needs to deal with taint.

For debugging, you can check individual variables with "issecurevariable" (see http://wowwiki.wikia.com/wiki/API_issecurevariable)

You can also enable taint logging (http://wow.gamepedia.com/CVar_taintLog). Any time your chat window shows "Interface action failed because of an AddOn", it'll write a report in WoWLogstaint.log. Remember to delete your taint.log in between tests for convenience! And remember to turn off logging after your tests!

I don't always get an interface error when accessing a tainted variable from a secure function, I'm not entirely sure how it works. Specific lines of code seem consistent, but different modifications don't always cause an error.

Example:


Lets say you have a tainted variable:
Code: [Select]
TaintedVar = "hi I'm a tainted variable"
You can't keep it secure because it's managed by an AIO script or addon. You also want to check TaintedVar inside the secure GetShapeshiftFormInfo API function, so you hook it:
Code: [Select]
local origGetShapeshiftFormInfo = GetShapeshiftFormInfo;
GetShapeshiftFormInfo = function(...)
local texture, name, isActive, isCastable = origGetShapeshiftFormInfo(...)

if (TaintedVar) then print(TaintedVar) end -- oops, we're accessing a tainted variable!

return texture, name, isActive, isCastable
end

Testing this on a character with a shapeshift/stances bar, I get "Interface action failed because of an AddOn" during combat. The solution is to make a new function that's allowed to get tainted (because it's not used by the official UI), the new function will return the tainted value we want to check. We'll call the new function using securecall, providing the name of the tainted value we want to check.

Code: [Select]
local function GetTaintedVar(varname)
-- _G[variable name] retrieves a global variable
return _G[varname]
end

local origGetShapeshiftFormInfo = GetShapeshiftFormInfo;
GetShapeshiftFormInfo = function(...)
local texture, name, isActive, isCastable = origGetShapeshiftFormInfo(...)

-- Even if GetTaintedVar is tainted, secure status is restored after the call
local SecureVar = securecall(GetTaintedVar, "TaintedVar")
if (SecureVar) then print(SecureVar) end

return texture, name, isActive, isCastable
end

The key here is that the function that has to stay secure (GetShapeshiftFormInfo) doesn't access any tainted variables, except the GetTaintedVar function, which it provides as an argument for securecall, but thanks to the magic of securecall, secure status is restored after the call to securecall. TaintedVar is just provided as a variable name string, and then checked by the function that we're allowing to get tainted. It seems that the function being called by securecall is allowed to be tainted, but not any arguments provided along with it, thus the need to provide the name of the variable as a string.

4
Couldn't find much info on this so I tried to add custom power types that go in the mana bar slot (like mana, energy, rage, runic power, focus). This is for TrinityCore 3.3.5 with Eluna and AIO. It's entirely possible that I forgot about a crucial core modification, so please let me know if there are any problems. I'm also not a very good programmer, so feel free to post improvements.

[media:3bjzc74y]https://www.youtube.com/watch?v=AgKHu6Z8yig[/media:3bjzc74y]

Full instructions are provided at the top of the code. Sorry for line wrap issues. It's slightly less painful on pastebin (or if you copy+paste it into an editor).

Script:
http://pastebin.com/asPaW32y

Alternative copy:
Code: [Select]
--[[INSTRUCTIONS:
1 Requires core modification to fix stance/form changing:
in Unit.cpp
void Unit::setPowerType(Powers new_powertype)
change:
case POWER_HAPPINESS:
SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
break;
  to:
case POWER_HAPPINESS:
if (GetTypeId() == TYPEID_PLAYER && GetMaxPower(POWER_HAPPINESS) >= 0)
break;
SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier)));
break;

You may want to apply other core modifications to give POWER_HAPPINESS as neutral of a behavior as possible and script
functionality specific to each custom powerType when a specific player event occurs, or add some class checks in the
core when a player's POWER_HAPPINESS is manipulated.

2 If you want a class to use a custom resource, set the SERVER SIDE powertype for that class to 4 (HAPPINESS)
in ChrClasses.dbc (the field that has a default value of 6 for Death Knights). Client side changes to ChrClasses.dbc
are not required. Happiness is simply the powertype we use behind the scenes for all custom powertypes.

3 Next, add an entry for your custom powertype in the customPowerTypes table. Each entry should have a table of classes,
an id, a powerString, a bar color table, a defaultMax value and a consumingSpells table (for correct GetSpellInfo powerType).
defaultMax should be the value you want, multiplied by 1000. All Happiness values have to be multiplied by 1000.

4 To create ANY spell (in Spell.dbc) that uses or generates your custom powertype, give it a power cost or energize effect
for powerType 4 (HAPPINESS). Make sure Happiness values (costs, energize effects etc) are multiplied by 1000.


TROUBLESHOOTING:
Make sure that the class has the powerType set to 4 (HAPPINESS) in SERVER SIDE ChrClasses.dbc.
Make sure that the class is listed in only one customPowerTypes[POWERTOKEN].classes table.
Make sure table entries are separated by commas.
MAKE SURE ALL RESOURCE VALUES ARE MULTIPLIED BY 1000. Happiness for some reason needs everything
multiplied by 1000. That includes spell costs and generation or if you're setting current power value
or maxvalue. All of them need to be multiplied by 1000.
Custom spells should always use 4 (HAPPINESS) in Spell.dbc, but everywhere in-game the powerType and
powerToken will match your custom values. Don't get confused and give a spell in Spell.dbc a custom
cost powerType (eg. a Spell.dbc entry that costs powerType 201). It should instead have cost powerType 4 (HAPPINESS).
Check the worldserver console for errors (scripts get loaded at the end).
If you get UI errors in-game, keep in mind the line number might not be accurate if you have server code and
client code in the same script file. Try subtracting the server-only line count, or split the script
into a server file and client file.


Currently this system has some (minor?) flaws:
- No error speech or text if you fail client-side resource check (not even a "Not enough happiness" message).
- Spells linked in chat simply show the cost as "X Happiness", but it should be possible to alter the tooltip if the
 spell is found in a custom powertype's consumingSpells table.
- The official Blizzard UI function UnitFrameManaBar_UpdateType(manaBar) from UnitFrame.lua is overwritten, which
 I guess is bad form because if the function is overwritten by two different addons, one of them will misbehave.
- A class can't swap between two custom primary resources on the fly (like a druid swapping between mana, energy, rage)
 because the custom resource is using Happiness and MaxHappiness to store values. You would need to store extra values
 somewhere and change how unitframes set their manabar and change how spells' usable status is determined.
]]--


local AIO = AIO or require("AIO")

local customPowerTypes = {} -- Table for custom class resource data, used by server and client. Not all of it is used by both the server and client, but it's convenient to have everything in one place.


customPowerTypes["BRAINCELLS"] = -- Our first custom class resource, used by Shamans and Rogues (remember to set ChrClasses.dbc powerTypes to use this example)
{
classes = { "Shaman", "Rogue" }, -- List of classes that use this as primary resource. Remember to set powertype to 4 (HAPPINESS) in server's ChrClasses.dbc
defaultMax = 300000, -- Happiness values need to be multiplied by 1000, so for the power bar to read "powertype 0 / 123", set defaultMax to 123000
id = 200, -- The id for our custom resource (first value returned by UnitPowerType). MUST BE UNIQUE. Some values below 200 are reserved for existing powerTypes.
powerString = "Braincells", -- The string to be displayed for our powertype
color = { r = 0.83, g = 0.76, b = 0.60 }, -- RGB colors for our power bar. Values should be between 0 and 1
consumingSpells = { 90031 } -- Spell IDs that consume this resource. Required for correct GetSpellInfo(spellID) API functionality
}

customPowerTypes["TEMPER"] = -- Our second custom class resource, used by Warriors
{
classes = { "Warrior" },
defaultMax = 100000,
id = 201,
powerString = "Temper",
color = { r = 1.0, g = 1.0, b = 1.0 },
consumingSpells = { 90032 },
passiveUpdate = { -- Optional passive update data, containing update interval and an update function. Event gets automatically registered, so long as you use these names ("interval" and "UpdateFunc")
interval = 100, -- Update interval in milliseconds
UpdateFunc = function(event, delay, repeats, player) -- power update function that gets called every [interval] milliseconds
-- points (re/de)generation per second
local regen = -10000
if (player:IsInCombat()) then
regen = 10000
end
local prevPower = player:GetPower(4)
local newPower = prevPower + (regen * (delay / 1000))
local maxPower = player:GetMaxPower(4)

if (newPower < 0) then
newPower = 0
elseif ( newPower > maxPower ) then
newPower = maxPower
end

player:SetPower(4, newPower)
end
}
}


if AIO.AddAddon() then
local function OnLogin(event, player)
local playerclass = player:GetClassAsString()

for powerToken, powerTable in pairs(customPowerTypes) do
for _, class in pairs(powerTable.classes) do
if (playerclass == class) then
player:SetMaxPower(4, powerTable.defaultMax)

-- Prevent tiny mana bar from re-appearing below the main resource bar by setting max mana to 0 (normally appears for druids while they're shapeshifted)
-- Ideally you would set this class to never get any mana or maxmana increases in class levelup data
player:SetMaxPower(0, 0)

if (powerTable.passiveUpdate ~= nil) then
player:RegisterEvent(powerTable.passiveUpdate.UpdateFunc, powerTable.passiveUpdate.interval, 0)
end
end
end
end

end

-- Prevent player's maximum Happiness from being reset to core default 1050 (aka 1050000). Preferably you would remove the reset in the core, because
-- this way you can't change a player's maximum value without resetting it to the defaultMax, unless you store and restore desired maxpower per character
local function OnLevelChange(event, player, oldLevel)
local playerclass = player:GetClassAsString()
for _, powerTable in pairs(customPowerTypes) do
for _, class in pairs(powerTable.classes) do
if (playerclass == class) then
if (powerTable.defaultMax ~= nil) then
player:SetMaxPower(4, powerTable.defaultMax)
end
end
end
end
end

RegisterPlayerEvent( 3, OnLogin )
RegisterPlayerEvent( 13, OnLevelChange )
return
end


HAPPINESS_COST = "%d Happiness";
local myclass = UnitClass("player")

for customToken, powerTable in pairs(customPowerTypes) do
_G[customToken] = powerTable.powerString
PowerBarColor[customToken] = powerTable.color
PowerBarColor[powerTable.id] = PowerBarColor[customToken]
end


-- Hook official Blizzard UI function GetSpellInfo(spellId or spellName or spellLink), to fix custom powerType return, if applicable
-- SpellLink as argument is broken in the official API, apparently.
local origGetSpellInfo = GetSpellInfo;
GetSpellInfo = function(...)
local spellID = ...;
local name, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange = origGetSpellInfo(...)

-- if a spellName was passed as argument, jump through some hoops to get the spellID
if (type(spellID) == "string") then
spellLink = GetSpellLink(spellID)
if (spellLink ~= nil) then
spellID = tonumber(strmatch(spellLink, "^124c%x+124Hspell:(%d+)124h%[.*%]"))
end
end

if (spellID ~= nil) then
for _, powerTable in pairs(customPowerTypes) do
local earlyReturn = false
for _, id in pairs(powerTable.consumingSpells) do
if (id == spellID) then
powerType = powerTable.id
break
end
end
if earlyReturn then break end
end
end

return name, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange;
end

-- Hook official Blizzard UI function UnitPower(unit, powerType), to add custom value return, if applicable
local origUnitPower = UnitPower;
UnitPower = function(...)
local unit, powerType = ...;

if (UnitIsPlayer(unit)) then
--local unitClass = UnitClass(unit)
for customToken, powerTable in pairs(customPowerTypes) do
if (powerTable.id == powerType) then
-- ask for Happiness value instead
return origUnitPower(unit, 4)
end
end
end

return origUnitPower(...);
end

-- Hook official Blizzard UI function UnitPowerMax(unit, powerType), to add custom value return, if applicable
local origUnitPowerMax = UnitPowerMax;
UnitPowerMax = function(...)
local unit, powerType = ...;

if (UnitIsPlayer(unit)) then
for customToken, powerTable in pairs(customPowerTypes) do
if (powerTable.id == powerType) then
-- ask for Happiness value instead
return origUnitPowerMax(unit, 4)
end
end
end

return origUnitPowerMax(...);
end

-- Hook official Blizzard UI function UnitPowerType(unit), to add custom powerType and powerToken return, if applicable
local origUnitPowerType = UnitPowerType;
UnitPowerType = function(...)
local unit = ...;

local unitClass = UnitClass(unit)
for customToken, powerTable in pairs(customPowerTypes) do
for _, class in pairs(powerTable.classes) do
if (unitClass == class) then
local powerType, _, altR, altG, altB = origUnitPowerType(unit)
powerType = powerTable.id
return powerType, customToken, altR, altG, altB
end
end
end

return origUnitPowerType(...);
end

-- Overwrite official Blizzard UI function UnitFrameManaBar_UpdateType(manaBar), hacky fix to display Happiness value and maxvalue in mana bar
function UnitFrameManaBar_UpdateType(manaBar)
if ( not manaBar ) then
return;
end
local unitFrame = manaBar:GetParent();
local powerType, powerToken, altR, altG, altB = UnitPowerType(manaBar.unit);
local prefix = _G[powerToken];
local info = PowerBarColor[powerToken];
if ( info ) then
if ( not manaBar.lockColor ) then
manaBar:SetStatusBarColor(info.r, info.g, info.b);
end
else
if ( not altR) then
-- couldn't find a power token entry...default to indexing by power type or just mana if we don't have that either
info = PowerBarColor[powerType] or PowerBarColor["MANA"];
else
if ( not manaBar.lockColor ) then
manaBar:SetStatusBarColor(altR, altG, altB);
end
end
end

-- We still want to use Happiness behind the scenes, so if we're using a custom resource, restore the powerType ID to 4: HAPPINESS
if (customPowerTypes[powerToken] ~= nil) then
powerType = 4;
end
manaBar.powerType = powerType;

-- Update the manabar text
if ( not unitFrame.noTextPrefix ) then
SetTextStatusBarTextPrefix(manaBar, prefix);
end
TextStatusBar_UpdateTextString(manaBar);

-- Setup newbie tooltip
-- FIXME: Fix this to use powerToken instead of powerType
if ( manaBar.unit ~= "pet" or powerToken == "HAPPINESS" ) then
   if ( unitFrame:GetName() == "PlayerFrame" ) then
   manaBar.tooltipTitle = prefix;
   manaBar.tooltipText = _G["NEWBIE_TOOLTIP_MANABAR_"..powerType];
   else
   manaBar.tooltipTitle = nil;
   manaBar.tooltipText = nil;
   end
end
end

local function CustomPrimaryResourceTooltip_OnShow(self, ...)
local _, _, spellID = GameTooltip:GetSpell()
if (spellID == nil) then
return
end

local numLines = GameTooltip:NumLines();
local i = 1;

for currentLine=1, numLines do
local line = {};
local left = _G["GameTooltipTextLeft"..currentLine];
if ( left ) then
line.w = true;
line.leftR, line.leftG, line.leftB = left:GetTextColor();
local t = left:GetText();

local happinessCost = strmatch(t, "(%d+) Happiness")
if (happinessCost ~= nil) then
local _, powerToken = UnitPowerType("player")
left:SetText(happinessCost.." ".._G[powerToken])
end

line.left = t;
end
i = i + 1;
end

GameTooltip:Show();
end


for powerToken, powerTable in pairs(customPowerTypes) do
for _, class in pairs(powerTable.classes) do
if (myclass == class) then
UnitFrameManaBar_UpdateType(PlayerFrameManaBar)
-- Hide mini mana bar
AlternatePowerBar_UpdatePowerType(PlayerFrameAlternateManaBar)
end
end
end

GameTooltip:HookScript( "OnShow", CustomPrimaryResourceTooltip_OnShow )

Pages: [1]