- Joined
- Feb 20, 2013
- Messages
- 136
So, I've been busy last few couple of days and made this little thing that I need for a map and I thought it would be nice if I made it usable by other people.
I'm mostly posting this for people to check out/use or note bugs. (1-2 I already know of)
What I would also appreciate is ideas of how to make the code's structure more efficient or manageable. It does have a lot of code, I think 1300 lines including the example Talent Tree setup. It's been okay until "Backwards dependency" (which is whether player can remove point from talent based on dependencies). It obliterated my code, forced me to think a lot and made a lot of bugs.
A lot of data is scattered around since it's only in development, and I haven't spent enough time rewriting it so I would have the least data locations/references.
It doesn't include a lot of documentation (for functionalities that were added on the fly) also because a lot of functionality is implemented through the API I provided (custom made) so it's not a standard functionality, and because I changed some things after I wrote this part of doc.
-> Maybe I would recommend not to look at the code after all ^^
I'm sorry for the bad formatting, structure and severe lack of comments. I hope the map works
Note however, the talents don't do anything. It's just a show of UI.
Changelog
> 0.1: Upload
> 0.2:
It requires Bribe's Global Initialization for Lua:
[Lua] Global Initialization
and Timer Utils for Lua:
[Lua] TimerUtils
I'm mostly posting this for people to check out/use or note bugs. (1-2 I already know of)
What I would also appreciate is ideas of how to make the code's structure more efficient or manageable. It does have a lot of code, I think 1300 lines including the example Talent Tree setup. It's been okay until "Backwards dependency" (which is whether player can remove point from talent based on dependencies). It obliterated my code, forced me to think a lot and made a lot of bugs.
A lot of data is scattered around since it's only in development, and I haven't spent enough time rewriting it so I would have the least data locations/references.
It doesn't include a lot of documentation (for functionalities that were added on the fly) also because a lot of functionality is implemented through the API I provided (custom made) so it's not a standard functionality, and because I changed some things after I wrote this part of doc.
-> Maybe I would recommend not to look at the code after all ^^
I'm sorry for the bad formatting, structure and severe lack of comments. I hope the map works
Note however, the talents don't do anything. It's just a show of UI.
Changelog
> 0.1: Upload
> 0.2:
- Reworked Backward dependency, seems to be fully working now (the standard link feature)
- Fixed the custom wow-like point requirement example
- Disabled removal requirement for example
- Exposed "RemoveRequirements" setter for callback that needs to be true in order to remove a (temporary) talent point
- Replaced the link texture with "Water00.blp" and made it thinner. Looks better imo
- Added automatic ID to talents (per tree)
- Credits ._.
It requires Bribe's Global Initialization for Lua:
[Lua] Global Initialization
and Timer Utils for Lua:
[Lua] TimerUtils
Lua:
-------------------------------------------------------------------------------------
-- CreateTalentTree(unit) returns TalentTree[unit]
-- Base function with which you prepare a TalentTree object for a unit.
-- It's not used directly, but rather within a template that also adds
-- specific list of talents and sets their dependencies / values.
-- Make a template function called CreateMageTalentTree(unit) and call this
-- first inside to map a base TalentTree object to the unit and start customizing it.
-------------------------------------------------------------------------------------
-- [talentTreeObject].AddTalent(self, x, y, talentData) returns Talent
-- [talentTreeObject]:AddTalent(x, y, talentData) returns Talent
-- Takes a talent tree object and prepares and adds a new Talent object on specified x/y.
-- "talentData" is an initializer object. If it contains one of the following,
-- they will be passed to their setter on the object before it is returned:
-- Name, Description, Icon, IconDisabled, OnActivate, OnDeactivate, Requirements
-- If talent exists on the specified position, :SetNextTalent will be called on it instead.
-------------------------------------------------------------------------------------
-- [talentTreeObject].SetNextTalent(self, x, y, talentData) returns Talent
-- [talentTreeObject]:SetNextTalent(x, y, talentData) returns Talent
-- Creates a new talent object and sets it as "next talent" to the one it's
-- called upon. When a point is gained in the base talent, it will switch
-- to the talent created by this method.
-- The method returns the NEW talent rather than old, so subsequent setters
-- will affect the NEW returned talent instead of the base one.
-------------------------------------------------------------------------------------
-- Talent Setters/Getters ------------------------------------------------------------------
-----------------------------------------------
-- .Name(self, name) or :Name(name) returns self, if name is nil returns ._name
-- This is text that is shown on top of the tooltip when hovering over the talent.
-----------------------------------------------
-- .Description(self, desc) or :Description(desc) returns self, if desc is nil returns ._desc
-- This is the text that shows under the title and Requirements.
-----------------------------------------------
-- .Icon(self, path) or :Icon(path) returns self, if path is nil returns ._icon
-- The icon that is shown for the talent. Calling this method will also set
-- the ._iconDisabled to the transformed path (added CommandButtonsDisabled/DISBTN)
-- >>> IMPORTANT: For this reason, always pass the forward slash / instead of double back \\
-----------------------------------------------
-- .IconDisabled(self, path) or :IconDisabled(path) returns self, if path is nil returns ._iconDisabled
-- This icon is shown when talent has no points in it.
-- >>> IMPORTANT: If you need icon different than enabled, always call this AFTER :Icon(path)
-- because it will get overwritten.
-----------------------------------------------
-- .OnActivate(self, callback) or :OnActivate(callback)
-- This sets a function that will get called after talent point is confirmed.
-- Use this to apply the bonus effect to the wielder of the talent tree.
-- function(self, caster) returns nothing
-- 1: [self] first parameter is always talent. You can save data to it at start and refer within callback
-- 2: [caster] second parameter will be the unit/wielder of the talent tree.
-----------------------------------------------
-- .OnDeactivate(self, callback) or :OnDeactivate(callback)
-- Currently this function is never called. But when I add ability to reset all talents,
-- This will be used to revert the changes done through onActivate.
-----------------------------------------------
-- .Requirements(self, callback) or :Requirements(callback)
-- This callback will be called when checking dependencies. If it returns false,
-- Putting points in talent will be disabled and specified text will be shown
-- function(self, caster) return isFulfilled, errorText
-- 1. [self] is the talent
-- 2. [caster] is the wielder of the Talent Tree
-- 3. [isFulfilled] is boolean. If it is not true, talent will be disabled
-- 4. [errorText] is string, it will be displayed in red as a reason
-------------------------------------------------------------------------------------
TalentTree = {}
function CreateTalentTree(unit)
TalentTree[unit] = {
unit = unit,
Talents = {},
TalentState = {},
TempTalentState = nil,
TalentLevel = {},
TempTalentLevel = nil,
Dependency = {},
BaseDependency = {},
Requirements = {},
RequiredTalents = {},
AddTalent = AddTalent,
TalentCount = 0,
CheckDependencies = function(self, state, level, i, owner)
if (not self.Talents[i].dependency) then return true, "" end
local ok = true
local returnString = ""
local dep = self.Talents[i].dependency
local tPos = { left = i - 1, up = i + TalentView.COLUMNS, right = i + 1, down = i - TalentView.COLUMNS }
-- linkFramePos = { left = i - 1, up = i, right = i, down = i - TalentView.COLUMNS }
local linkPos = { left = i - 1, up = i, right = i, down = i - TalentView.COLUMNS }
for key, req in pairs(dep) do
-- print(key, req)
-- If requirement exists, continue
if (req) then
local pos = tPos[key]
-- Set the link visibility to enabled
local link
if (key == "left" or key == "right") then
link = TalentView.horizontalLink[linkPos[key]]
else
link = TalentView.verticalLink[linkPos[key]]
end
if (GetLocalPlayer() == owner) then
BlzFrameSetTexture(link, TalentView.ACTIVE_LINK_BOX, 0, true)
BlzFrameSetVisible(link, true)
end
-- Check against the state now
if (self.Talents[pos] and state[pos] ~= true) then
if (level[pos] and level[pos] < req) then
ok = false
returnString = returnString.." "..self.Talents[pos]._name.." "..req
if (GetLocalPlayer() == owner) then
BlzFrameSetTexture(link, TalentView.INACTIVE_LINK_BOX, 0, true)
end
end
end
end
end
-- print("ok")
return ok, returnString
end,
CheckBaseDependency = function(self, level, i)
local tPos = { right = i - 1, down = i + TalentView.COLUMNS, left = i + 1, up = i - TalentView.COLUMNS }
-- Loop through all sides (left, right, up, down)
for key, pos in pairs(tPos) do
-- If a talent exists at the position at all, continue
if (self.Talents[pos]) then
-- This is dependency of the talent we are looking for (left right up or down)
local dep = {}
-- If there is a BaseDependency registered from that talent (i.e. a talent point was added)
-- We fetch its data from the dictionary
if (self.BaseDependency[pos]) then dep = self.BaseDependency[pos] end
-- If dependency has a value/requirement towards our side, check it
local depValue = 0
if (dep[key]) then depValue = dep[key] end
-- If the level is equal or lower than the requirement, we cannot allow reduction
if (level < depValue) then
return false
end
end
end
return true
end,
}
return TalentTree[unit]
end
function CreateTalent(tree, position, data, x, y)
-- print("CreateTalent")
local talent = {
Name = function(self, name)
if (name) then
self._name = name
self._activeName = name
-- print("name set")
return self
end
-- print("printing name")
return self._name
end,
Description = function(self, desc)
if (desc) then
self._desc = desc
self._activeDesc = desc
-- print("desc set")
return self
end
return self._desc
end,
IconDisabled = function(self, path)
if (path) then
self._iconDisabled = path
return self
end
return self._iconDisabled
end,
Icon = function(self, path)
if (path) then
-- print("icon set")
self._icon = path
self._activeIcon = path
self._iconDisabled = string.gsub(path, "CommandButtons/", "CommandButtonsDisabled/DIS")
return self
end
return self._icon
end,
OnActivate = function(self, callback)
if (callback) then
-- print("onActivate set")
self.onActivate = callback
return self
end
return self.onActivate
end,
OnDeactivate = function(self, callback)
if (callback) then
-- print("onDeactivate set")
self.onDeactivate = callback
return self
end
return self.onDeactivate
end,
SetDependency = function(self, direction, level)
local dep = {}
if (self.dependency) then dep = self.dependency end
local x, y = math.floor(math.fmod((position-1), TalentView.COLUMNS)), math.floor((position-1) / TalentView.COLUMNS)
local var = ({ left = x, right = x, up = y, down = y })[direction]
local lower = ({ left = 1, right = 0, up = 0, down = 1 })[direction]
local higher = ({ left = TalentView.COLUMNS, right = TalentView.COLUMNS - 1, up = TalentView.ROWS - 1, down = TalentView.ROWS })[direction]
if (var >= lower and var < higher) then
dep[direction] = level
self.dependency = dep
end
return self
end,
SetNextTalent = function(self, talentData)
-- Create a new talent and set their references.
local new = CreateTalent(tree, position, talentData, x, y)
self.nextTalent = new
new.previousTalent = self
table.insert(self.levels, new)
new.levels = self.levels
-- Set the onNext method which is called when point is added.
self.onNext = function(self)
-- Replace the old talent
tree.Talents[position] = self.nextTalent
-- Set its state as false
tree.TempTalentState[position] = false
-- If this talent has a dependency, set it as baseDependency to the new one.
if (self.dependency) then
self.nextTalent.baseDependency = self.dependency
end
return self.nextTalent
end
return new
end,
SetFinalTalent = function(self, talentData)
if (talentData.Name) then self:ActiveName(talentData.Name) end
if (talentData.Description) then self:ActiveDescription(talentData.Description) end
return self
end,
Requirements = function(self, callback)
if (callback) then
self.requirements = callback
return self
end
return self.requirements
end,
RemoveRequirements = function(self, callback)
if (callback) then
self.removeRequirements = callback
return self
end
return self.removeRequirements
end,
OnPointAdded = function(self, callback)
if (callback) then
self.onPointAdded = callback
return self
end
return self.onPointAdded
end,
OnPointRemoved = function(self, callback)
if (callback) then
self.onPointRemoved = callback
return self
end
return self.onPointRemoved
end,
ActiveName = function(self, name)
if (name) then
self._activeName = name
return self
end
return self._activeName
end,
ActiveDescription = function(self, desc)
if (desc) then
self._activeDesc = desc
return self
end
return self._activeDesc
end,
SetCustom = function(self, key, value)
if (key and value) then
self[key] = value
end
end
}
talent.requirements = function(self, tree, caster) return true, "" end
talent.removeRequirements = function(self, tree, caster) return true, "" end
talent.onPointAdded = function(self, tree, caster) return end
talent.onPointRemoved = function(self, tree, caster) print("default removed") return end
talent.onActivate = function(caster) print("Activated.") end
talent.onDeactivate = function(caster) print("Deactivated.") end
talent.x = x
talent.y = y
talent._isLink = false
talent.id = tree.TalentCount
tree.TalentCount = tree.TalentCount + 1
if (data) then
if (data.Name) then talent:Name(data.Name) end
if (data.Description) then talent:Description(data.Description) end
if (data.Icon) then talent:Icon(data.Icon) end
if (data.IconDisabled) then talent:IconDisabled(data.IconDisabled) end
if (data.OnActivate) then talent:OnActivate(data.OnActivate) end
if (data.OnDeactivate) then talent:OnDeactivate(data.OnDeactivate) end
if (data.Requirements) then talent:Requirements(data.Requirements) end
if (data.RemoveRequirements) then talent:RemoveRequirements(data.RemoveRequirements) end
if (data.OnPointAdded) then talent:OnPointAdded(data.OnPointAdded) end
if (data.OnPointRemoved) then talent:OnPointRemoved(data.OnPointRemoved) end
if (data.SetCustom) then talent:SetCustom(data.SetCustom[1], data.SetCustom[2]) end
end
return talent
end
function AddTalent(self, x, y, talent)
if (x >= TalentView.COLUMNS or y >= TalentView.ROWS) then
-- print("Error, talent position incorrect: ", x, y, "expected", TalentView.COLUMNS, TalentView.ROWS)
return nil
end
local position = x + 1 + y * TalentView.COLUMNS
-- If talent on this position already exists, call SetNextTalent instead
if (self.Talents[position]) then
local talents = self.Talents[position].levels
return talents[#talents]:SetNextTalent(talent)
end
local t = CreateTalent(self, position, talent, x, y)
t.levels = { t }
self.TalentState[position] = false
if (self.TempTalentState) then
self.TempTalentState[position] = false
end
self.TalentLevel[position] = 0
self.Dependency[position] = {}
self.Talents[position] = t
-- print(t.levels[1]._name)
return t
end
Lua:
function CreateArcaneMageTalentTree(unit)
local tt = CreateTalentTree(unit)
tt.points = { }
tt.highestTier = 0
local tier = {
"tier",
0
}
-- Arcane Concentration
local data = {
Name = "Arcane Concentration",
Icon = "ReplaceableTextures/CommandButtons/BTNManaBurn.tga",
SetCustom = tier,
OnPointAdded = function(self, tree, caster)
if (not tree.points[self.tier]) then tree.points[self.tier] = 0 end
tree.points[self.tier] = tree.points[self.tier] + 1
end,
OnPointRemoved = function(self, tree, caster)
if (not tree.points[self.tier]) then tree.points[self.tier] = 0 end
tree.points[self.tier] = tree.points[self.tier] - 1
end,
Requirements = function(self, tree, caster, debug)
local sum = 0
for i = 0, self.tier-1 do
if (tree.points[i]) then
sum = sum + tree.points[i]
end
end
-- if (debug == true) then print(sum.."sum vs point"..self.tier*5) end
if (sum >= self.tier * 5) then
return true, ""
end
return false, " "..(self.tier*5).." points"
end
-- RemoveRequirements = function(self, tree, caster)
-- local sum = 0
-- for i = 1, self.tier + 1 do
-- if (tree.points[i]) then
-- sum = sum + tree.points[i]
-- end
-- end
-- sum = sum - 1
-- print("sum "..sum.." tier "..self.tier)
-- -- local i = self.tier + 1
-- for i = self.tier + 1, 6 do
-- if (tree.points[i+1]) then
-- if (tree.points[i+1] and tree.points[i+1] > 0 and sum < i * 5) then
-- print("false")
-- return false
-- end
-- sum = sum + tree.points[i]
-- end
-- print("next")
-- end
-- return true
-- end,
}
tt:AddTalent(0, 6, data)
:Description("Rank 0/3\nGives you a 3%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%")
:SetNextTalent(data)
:Description("Rank 1/3\nGives you a 3%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%\n\nNext Rank\nGives you a 6%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%")
:SetNextTalent(data)
:Description("Rank 2/3\nGives you a 6%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%\n\nNext Rank\nGives you a 10%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%")
:SetFinalTalent({
Description = "Rank 3/3\nGives you a 10%% chance of entering a Clearcasting state after any damage spell hits a target. The Clearcasting state reduces the mana cost of your next damage spell by 100%%"
})
data.Name = "Improved Counterspell"
data.Icon = "ReplaceableTextures/CommandButtons/BTNSilence.tga"
tt:AddTalent(1, 6, data)
:Description("Rank 0/2\nYour Counterspell also silences the target for 2 sec.")
:SetNextTalent(data)
:Description("Rank 1/2\nYour Counterspell also silences the target for 2 sec.\n\nNext Rank\nYour Counterspell also silences the target for 4 sec.")
:SetFinalTalent({
Description = "Rank 2/2\nYour Counterspell also silences the target for 4 sec."
})
data.Name = "Netherwind Presence"
data.Icon = "ReplaceableTextures/CommandButtons/BTNEnchantedCrows.blp"
tt:AddTalent(2, 6, data)
:Description("Rank 0/3\nIncreases your spell haste by 1%%")
:SetNextTalent(data)
:Description("Rank 1/3\nIncreases your spell haste by 1%%\n\nNext Rank\nIncreases your spell haste by 2%%")
:SetNextTalent(data)
:Description("Rank 2/3\nIncreases your spell haste by 2%%\n\nNext Rank\nIncreases your spell haste by 3%%")
:SetFinalTalent({
Description = "Rank 3/3\nIncreases your spell haste by 3%%"
})
tier[2] = 1
data.Name = "Torment the Weak"
data.Icon = "ReplaceableTextures/CommandButtons/BTNUnholyFrenzy.tga"
tt:AddTalent(0, 5, data)
:Description("Rank 0/3\nYour Arcane damage spells deal 2%% more damage to snared or slowed targets.")
:SetNextTalent(data)
:Description("Rank 1/3\nYour Arcane damage spells deal 2%% more damage to snared or slowed targets.\n\nNext Rank\nYour Arcane damage spells deal 4%% more damage to snared or slowed targets.")
:SetNextTalent(data)
:Description("Rank 2/3\nYour Arcane damage spells deal 4%% more damage to snared or slowed targets.\n\nNext Rank\nYour Arcane damage spells deal 6%% more damage to snared or slowed targets.")
:SetFinalTalent({
Description = "Rank 3/3\nYour Arcane damage spells deal 6%% more damage to snared or slowed targets."
})
data.Name = "Invocation"
data.Icon = "ReplaceableTextures/CommandButtons/BTNDispelMagic.blp"
tt:AddTalent(1, 5, data)
:Description("Rank 0/2\nYou gain a 5%% damage bonus for 8 sec. after successfully interrupting a spell.")
:SetNextTalent(data)
:Description("Rank 1/2\nYou gain a 5%% damage bonus for 8 sec. after successfully interrupting a spell.\n\nNext Rank\nYou gain a 10%% damage bonus for 8 sec. after successfully interrupting a spell.")
:SetFinalTalent({
Description = "Rank 2/2\nYou gain a 10%% damage bonus for 8 sec. after successfully interrupting a spell."
})
data.Name = "Improved Arcane Missiles"
data.Icon = "ReplaceableTextures/CommandButtons/BTNStarfall.blp"
tt:AddTalent(2, 5, data)
:Description("Rank 0/2\n")
:SetNextTalent(data)
:Description("Rank 1/2\nIncreases the number of missiles fired by your Arcane Missiles by 1.\n\nNext Rank\nIncreases the number of missiles fired by your Arcane Missiles by 2.")
:SetFinalTalent({
Description = "Rank 2/2\nIncreases the number of missiles fired by your Arcane Missiles by 2."
})
data.Name = "Improved Blink"
data.Icon = "ReplaceableTextures/CommandButtons/BTNBlink.blp"
tt:AddTalent(3, 5, data)
:Description("Rank 0/2\nIncreases your speed by 35%% for 3 sec. after casting the Blink spell.")
:SetNextTalent(data)
:Description("Rank 1/2\nIncreases your speed by 35%% for 3 sec. after casting the Blink spell.\n\nNext Rank\nIncreases your speed by 70%% for 3 sec. after casting the Blink spell.")
:SetFinalTalent({
Description = "Rank 2/2\nIncreases your speed by 70%% for 3 sec. after casting the Blink spell."
})
tier[2] = 2
data.Name = "Prismatic Cloak"
data.Icon = "ReplaceableTextures/CommandButtons/BTNAdvancedMoonArmor.blp"
tt:AddTalent(3, 4, data)
:Description("Rank 0/3\nReduces all damage taken by 2%% and reduces the fade time of your Invisibility spell by 1 sec.")
:SetNextTalent(data)
:Description("Rank 1/3\nReduces all damage taken by 2%% and reduces the fade time of your Invisibility spell by 1 sec.\n\nNext Rank\nReduces all damage taken by 4%% and reduces the fade time of your Invisibility spell by 2 sec.")
:SetNextTalent(data)
:Description("Rank 2/3\nReduces all damage taken by 4%% and reduces the fade time of your Invisibility spell by 2 sec.\n\nNext Rank\nReduces all damage taken by 6%% and reduces the fade time of your Invisibility spell by 3 sec.")
:SetFinalTalent({
Description = "Rank 3/3\nReduces all damage taken by 6%% and reduces the fade time of your Invisibility spell by 3 sec."
})
data.Name = "Missile Barrage"
data.Icon = "ReplaceableTextures/CommandButtons/BTNScatterRockets.blp"
tt:AddTalent(2, 4, data)
:Description("Rank 0/2\nYour Arcane Missile spell will fire its missiles every 0.6 sec.")
:SetDependency("up", 2)
:SetNextTalent(data)
:Description("Rank 1/2\nYour Arcane Missile spell will fire its missiles every 0.6 sec.\n\nNext Rank\nYour Arcane Missile spell will fire its missiles every 0.5 sec.")
:SetDependency("up", 2)
:SetFinalTalent({
Description = "Rank 2/2\nYour Arcane Missile spell will fire its missiles every 0.5 sec."
})
data.Name = "Presence of Mind"
data.Icon = "ReplaceableTextures/CommandButtons/BTNHelmutPurple.blp"
tt:AddTalent(1, 4, data)
:Description("Rank 0/1\nWhen activated, your next Mage spell with a casting time less than 10 sec becomes an instant cast spell.")
:SetFinalTalent({ Description = "Rank 1/1\nWhen activated, your next Mage spell with a casting time less than 10 sec becomes an instant cast spell." })
data.Name = "Arcane Flows"
data.Icon = "ReplaceableTextures/CommandButtons/BTNPossession.tga"
tt:AddTalent(0, 4, data)
:Description("Rank 0/2\nReduces the Cooldown of your Presence of Mind, Arcane Power and Invisibility spells by 12%% and the cooldown of your Evocation spell by 1 min.")
:SetDependency("right", 1)
:SetNextTalent(data)
:Description("Rank 1/2\nReduces the Cooldown of your Presence of Mind, Arcane Power and Invisibility spells by 12%% and the cooldown of your Evocation spell by 1 min.\n\nNext Rank\nReduces the Cooldown of your Presence of Mind, Arcane Power and Invisibility spells by 25%% and the cooldown of your Evocation spell by 2 min.")
:SetDependency("right", 1)
:SetFinalTalent({
Description = "Rank 2/2\nReduces the Cooldown of your Presence of Mind, Arcane Power and Invisibility spells by 25%% and the cooldown of your Evocation spell by 2 min."
})
tier[2] = 3
data.Name = "Improved Polymorph"
data.Icon = "ReplaceableTextures/CommandButtons/BTNPolymorph.blp"
tt:AddTalent(0, 3, data)
:Description("Rank 0/2\nWhen a target you've polymorphed is damaged, that target is stunned for 1.5 sec. This effect cannot occur more often than once every 10 sec.")
:SetNextTalent(data)
:Description("Rank 1/2\nWhen a target you've polymorphed is damaged, that arget is stunned for 1.5 sec. This effect cannot occur more often than once every 10 sec.\n\nNext Rank\nWhen a target you've polymorphed is damaged, that arget is stunned for 3 sec. This effect cannot occur more often than once every 10 sec.")
:SetFinalTalent({
Description = "Rank 2/2\nWhen a target you've polymorphed is damaged, that arget is stunned for 3 sec. This effect cannot occur more often than once every 10 sec."
})
data.Name = "Arcane Tactics"
data.Icon = "ReplaceableTextures/CommandButtons/BTNMassTeleport.tga"
tt:AddTalent(1, 3, data)
:Description("Rank 0/1\nIncreases the damage of all party and raid members within 100 yards by 3%%.")
:SetDependency("up", 1)
:SetFinalTalent({ Description = "Rank 1/1\nIncreases the damage of all party and raid members within 100 yards by 3%%." })
data.Name = "Incanter's Absorption"
data.Icon = "ReplaceableTextures/CommandButtons/BTNAbsorbMagic.tga"
tt:AddTalent(2, 3, data)
:Description("Rank 0/2\nWhen your Mana Shield or Mage Ward absorbs damage your spell damage is increased by 10%% of the amount absorbed for 10 sec. In addition, when your Mana Shield destroyed, all enemies within 6 yards are knocked back 12 yards.")
:SetNextTalent(data)
:Description("Rank 1/2\nWhen your Mana Shield or Mage Ward absorbs damage your spell damage is increased by 10%% of the amount absorbed for 10 sec. In addition, when your Mana Shield destroyed, all enemies within 6 yards are knocked back 12 yards.\n\nNext Rank\nWhen your Mana Shield or Mage Ward absorbs damage your spell damage is increased by 20%% of the amount absorbed for 10 sec. In addition, when your Mana Shield destroyed, all enemies within 6 yards are knocked back 12 yards.")
:SetFinalTalent({
Description = "Rank 2/2\nWhen your Mana Shield or Mage Ward absorbs damage your spell damage is increased by 20%% of the amount absorbed for 10 sec. In addition, when your Mana Shield destroyed, all enemies within 6 yards are knocked back 12 yards."
})
data.Name = "Improved Arcane Explosion"
data.Icon = "ReplaceableTextures/CommandButtons/BTNWispSplode.blp"
tt:AddTalent(3, 3, data)
:Description("Rank 0/2\nReduces the global cooldown of your Arcane Explosion spell by 0.3 sec. Reduces the threat generated by 40%%, and reduces the mana cost by 25%%.")
:SetNextTalent(data)
:Description("Rank 1/2\nReduces the global cooldown of your Arcane Explosion spell by 0.3 sec. Reduces the threat generated by 40%%, and reduces the mana cost by 25%%.\n\nNext Rank\nReduces the global cooldown of your Arcane Explosion spell by 0.5 sec. Reduces the threat generated by 80%%, and reduces the mana cost by 50%%.")
:SetFinalTalent({
Description = "Rank 2/2\nReduces the global cooldown of your Arcane Explosion spell by 0.5 sec. Reduces the threat generated by 80%%, and reduces the mana cost by 50%%."
})
tier[2] = 4
data.Name = "Arcane Potency"
data.Icon = "ReplaceableTextures/CommandButtons/BTNPurge.blp"
tt:AddTalent(0, 2, data)
:Description("Rank 0/2\nIncreases the critical strike chance of your next two damaging spells by 7%% after gaining Clearcasting or Presence of Mind.")
:SetNextTalent(data)
:Description("Rank 1/2\nIncreases the critical strike chance of your next two damaging spells by 7%% after gaining Clearcasting or Presence of Mind.\n\nNext Rank\nIncreases the critical strike chance of your next two damaging spells by 15%% after gaining Clearcasting or Presence of Mind.")
:SetFinalTalent({
Description = "Rank 2/2\nIncreases the critical strike chance of your next two damaging spells by 15%% after gaining Clearcasting or Presence of Mind."
})
data.Name = "Slow"
data.Icon = "ReplaceableTextures/CommandButtons/BTNSlow.blp"
tt:AddTalent(1, 2, data)
:Description("Rank 0/1\nReduces target's movement speed by 60%%, increases the time between ranged attacks by 60%% and increases casting time by 30%%. Lasts 15 sec. Slow can only affect one target at a time.")
:OnPointAdded(function(self, tree, caster)
-- print("point added")
tree.TempTalentState[6] = true
end)
:OnPointRemoved(function(self, tree, caster)
-- print("point removed")
tree.TempTalentState[6] = false
end)
:SetFinalTalent({ Description = "Rank 1/1\nReduces target's movement speed by 60%%, increases the time between ranged attacks by 60%% and increases casting time by 30%%. Lasts 15 sec. Slow can only affect one target at a time." })
data.Name = "Nether Vortex"
data.Icon = "ReplaceableTextures/CommandButtons/BTNStun.blp"
tt:AddTalent(2, 2, data)
:Description("Rank 0/2\nGives your Arcane Blast spell a 50%% chance to apply the Slow spell to any target it damages if no target is currently affected by Slow.")
:SetDependency("left", 1)
:SetNextTalent(data)
:Description("Rank 1/2\nGives your Arcane Blast spell a 50%% chance to apply the Slow spell to any target it damages if no target is currently affected by Slow.\n\nNext Rank\nGives your Arcane Blast spell a 100%% chance to apply the Slow spell to any target it damages if no target is currently affected by Slow.")
:SetDependency("left", 1)
:SetFinalTalent({
Description = "Rank 2/2\nGives your Arcane Blast spell a 100%% chance to apply the Slow spell to any target it damages if no target is currently affected by Slow."
})
tier[2] = 5
data.Name = "Focus Magic"
data.Icon = "ReplaceableTextures/CommandButtons/BTNCharm.blp"
tt:AddTalent(0, 1, data)
:Description("Rank 0/1\nIncreases the target's chance to critcally hit with spells by 3%% for 30 min. When the target critically hits, your chance to critically hit with spells is increased by 3%% for 10 sec. Cannot be cast on self. Limit 1 Target.")
:SetFinalTalent({ Description = "Rank 1/1\nIncreases the target's chance to critcally hit with spells by 3%% for 30 min. When the target critically hits, your chance to critically hit with spells is increased by 3%% for 10 sec. Cannot be cast on self. Limit 1 Target." })
data.Name = "Improved Mana Gem"
data.Icon = "ReplaceableTextures/CommandButtons/BTNManaStone.tga"
tt:AddTalent(2, 1, data)
:Description("Rank 0/2\nMana gained from your Mana Gem also increases your spell power by 1%% of you maximum mana for 15 sec.")
:SetNextTalent(data)
:Description("Rank 1/2\nMana gained from your Mana Gem also increases your spell power by 1%% of you maximum mana for 15 sec.\n\nNext Rank\nMana gained from your Mana Gem also increases your spell power by 2%% of you maximum mana for 15 sec.")
:SetFinalTalent({
Description = "Rank 2/2\nMana gained from your Mana Gem also increases your spell power by 2%% of you maximum mana for 15 sec."
})
tier[2] = 6
tt:AddTalent(1, 1)
:Name("")
:Description("")
:Icon("UI/Minimap/MinimapIconCreepLoc.blp")
:SetDependency("up", 1)
:Requirements(function() return false, "" end)
._isLink = true
data.Name = "Arcane Power"
data.Icon = "ReplaceableTextures/CommandButtons/BTNControlMagic.blp"
tt:AddTalent(1, 0, data)
:Description("Rank 0/1\nWhen activated, you deal 20%% more spell damage and damaging spells cost 10%% more mana to cast. This Effect lasts 15 sec.")
:SetDependency("up", 1)
:SetFinalTalent({ Description = "Rank 1/1\nWhen activated, you deal 20%% more spell damage and damaging spells cost 10%% more mana to cast. This Effect lasts 15 sec." })
-- data.Name = "Improved Arcane Missiles"
-- data.Icon = "ReplaceableTextures/CommandButtons/BTNStarfall.blp"
-- tt:AddTalent(1, 6, data)
-- :Description("Rank 0/2\n")
-- :SetNextTalent(data)
-- :Description("Rank 1/2\n\n\nNext Rank\n")
-- :SetFinalTalent({
-- Description = "Rank 2/2\n"
-- })
-- data.Name = "Torment the Weak"
-- data.Icon = ""
-- tt:AddTalent(0, 5, data)
-- :Description("Rank 0/3\n")
-- :SetNextTalent(data)
-- :Description("Rank 1/3\n\n\nNext Rank\n")
-- :SetNextTalent(data)
-- :Description("Rank 2/3\n\n\nNext Rank\n")
-- :SetFinalTalent({
-- Description = "Rank 3/3\n"
-- })
end
Lua:
TalentView = {
-- Global number of column slots on the Talent tree
COLUMNS = 4,
-- Global number of row slots on the Talent tree
ROWS = 7,
-- Width of the Talent View box
WIDTH = 0.3,
-- Height of the Talent View box
HEIGHT = 0.44,
-- Amount of empty space between Talents and the side borders
SIDE_MARGIN = 0.1,
-- Amount of empty space between Talents and top/bottom border
VERTICAL_MARGIN = 0.15,
-- Position of the Show Talents Button
-- Above inventory, above command card default
SHOW_TALENTS_X = 0.14, -- 0.53 0.74 0.14
SHOW_TALENTS_Y = 0.182, -- 0.16 0.17 0.182
-- Global width of the Talent icons
TALENT_WIDTH = 0.04,
-- Global height of the Talent icons
TALENT_HEIGHT = 0.04,
TOOLTIP_BOX_WIDTH = 0.28,
TOOLTIP_BOX_HEIGHT = 0.16,
-- Selectable talent outline scale against talent width/height
OUTLINE_BORDER_RATIO = 0.95,
-- Whether it's possible to remove talent points by Right Clicking
RIGHT_CLICK_TALENT_REMOVAL = true,
-- Default icon to display while testing, not important
DEFAULT_TALENT_ICON = "ReplaceableTextures/CommandButtons/BTNPeasant.blp",
-- Icon for the level counter box background on bottom left of the talent
-- UI\Console\Human\human-transport-slot.blp
-- UI\Widgets\Console/Human/human-transport-slot.blp
-- UI/Widgets/Console/Human/CommandButton/human-button-lvls-overlay.blp
COUNTER_ICON_ACTIVE = "UI/Widgets/Console/Human/human-transport-slot.blp",
COUNTER_ICON_DISABLED = "UI/WidgetsBattleNet/chaticons/iconselection-border-disabled.blp",
-- ACTIVE_LINK = 'UI/Glues/SinglePlayer/Undead3D_Exp/sunwaves.blp',
-- UI/Widgets/Console/Human/human-inventory-slotfiller.blp
INACTIVE_LINK = 'UI/Widgets/Console/Human/human-inventory-slotfiller.blp',
GREEN_BORDER = 'UI/Widgets/Console/Human/CommandButton/human-activebutton.blp',
-- Texture for the Talent Dependency link
-- Textures\star6.blp
INACTIVE_LINK_BOX = 'UI/Widgets/Console/Human/human-inventory-slotfiller.blp',
-- ReplaceableTextures/WorldEditUI/Doodad-Water.blp
-- UI/Widgets/Console/Human/CommandButton/human-subgroup-background.blp
-- Textures/star6.blp
-- ReplaceableTextures\TeamGlow\TeamGlow00.blp
-- ReplaceableTextures/WorldEditUI/Doodad-Water.blp'
-- Textures\Water00.blp
-- UI\Glues\SinglePlayer\UndeadCampaign3D\gem.blp
-- UI/Glues/SinglePlayer/UndeadCampaign3D/gem.blp
ACTIVE_LINK_BOX = 'Textures/Water00.blp',
-- ====================== Internal, do not touch =================================
ActiveUnit = {},
ViewedUnit = {},
verticalLink = {},
horizontalLink = {},
playerRightClick = {},
playerClickedFrame = {}
--
}
function TalentView:OnView(owner)
local self = TalentView
-- local owner = GetTriggerPlayer()
local viewedUnit = {}
-- If there is no active or viewed unit, we break
if (self.ViewedUnit[owner] == nil and self.ActiveUnit[owner] == nil) then
return
elseif (self.ViewedUnit[owner]) then
viewedUnit = self.ViewedUnit[owner]
else
-- Now we are viewing the Active unit, so it becomes ViewedUnit instead.
viewedUnit = self.ActiveUnit[owner]
self.ViewedUnit[owner] = viewedUnit
end
if (GetLocalPlayer() == owner) then
-- Now that we have a viewed unit, we can render/re-render the TalentView
-- First we disable the Show Talents button
BlzFrameSetEnable(self.Frames.viewTalentsButton, false)
BlzFrameSetEnable(self.Frames.viewTalentsButton, true)
BlzFrameSetVisible(self.Frames.viewTalentsButton, false)
end
-- Get the TalentTree from the unit
local tt = TalentTree[viewedUnit]
local tempState = {}
local tempLevel = {}
-- Check if TempTalentState exists, if not it needs to be copied
if (tt.TempTalentState) then
tempState = tt.TempTalentState
tempLevel = tt.TempTalentLevel
else
-- Since it does not exist, it needs to be copied over
for i = 1, self.MAX_TALENTS do
if (tt.TalentState[i]) then
tempState[i] = true
else
tempState[i] = false
end
if (tt.TalentLevel[i]) then tempLevel[i] = tt.TalentLevel[i] end
end
end
if (GetLocalPlayer() == owner) then
-- Hide all the links first and reset inverse Dependencies
for i = 1, self.MAX_TALENTS do
BlzFrameSetVisible(self.horizontalLink[i], false)
BlzFrameSetVisible(self.verticalLink[i], false)
end
end
-- Now that we have our Temporary state, either fresh or from earlier re-render,
-- Loop through the talents and display them as necessary
for i = 1, self.MAX_TALENTS do
-- Fetch the Talent Frame for this index, will need it.
local frame = TalentView.Frames.Talent[i]
-- If talent exists, process it. If not, hide it.
if (tt.Talents[i]) then
local talent = tt.Talents[i]
-- Calculate the Requirements and Dependencies
local dep, depString, link = tt:CheckDependencies(tempState, tempLevel, i, owner)
local req, reqString = talent:requirements(tt, viewedUnit)
local requirements = "\n|cffff6450Requires:"..reqString.." "..depString.."|r\n"
-- if (talent._name..talent._desc == "") then
-- print("hide tooltip")
-- BlzFrameSetEnable(frame.tooltipBox, false)
-- end
if (GetLocalPlayer() == owner) then
-- If both dependencies and requirements passed, the button is enabled
if (dep and req) then
-- print("a")
BlzFrameSetEnable(frame.mainButton, true)
BlzFrameSetText(frame.tooltipText, talent._name.."\n\n"..talent._desc)
BlzFrameSetVisible(frame.availableImage, true)
else
-- print("b")
-- If either of those failed, update the tooltip with the requirements
BlzFrameSetEnable(frame.mainButton, false)
BlzFrameSetText(frame.tooltipText, talent._name.."\n"..requirements..talent._desc)
BlzFrameSetVisible(frame.availableImage, false)
end
-- If the Talent is Active and has no levels, disable it
if (tempState[i]) then
-- print("c")
BlzFrameSetTexture(frame.mainImage, talent._icon, 0, true)
BlzFrameSetEnable(frame.mainButton, false)
BlzFrameSetVisible(frame.availableImage, false)
BlzFrameSetText(frame.tooltipText, talent._activeName.."\n\n"..talent._activeDesc)
elseif (tempLevel[i] and tempLevel[i] > 0) then
-- print("d")
-- If the talent under it is Active, but there's a higher level of it
-- which is inactive, display it enabled, but Active
BlzFrameSetTexture(frame.mainImage, talent._icon, 0, true)
-- BlzFrameSetEnable(frame.mainButton, true)
else
-- If the Talent is Inactive, set it to grey icon
BlzFrameSetTexture(frame.mainImage, talent._iconDisabled, 0, true)
-- print("e")
end
-- Need to update the level change in the counter as well
if (tempLevel[i]) then
BlzFrameSetText(frame.counterText, tempLevel[i])
BlzFrameSetVisible(frame.counterText, true)
BlzFrameSetVisible(frame.counterImage, true)
else
BlzFrameSetVisible(frame.counterText, false)
BlzFrameSetVisible(frame.counterImage, false)
end
-- Set the frame to visible
if (not talent._isLink) then
BlzFrameSetVisible(frame.mainButton, true)
else
BlzFrameSetVisible(frame.mainButton, false)
end
end
elseif (GetLocalPlayer() == owner) then
BlzFrameSetVisible(frame.mainButton, false)
BlzFrameSetVisible(frame.availableImage, false)
end
end
-- Update the global TempTalentState
-- print("onView over "..type(tempState))
tt.TempTalentState = tempState
tt.TempTalentLevel = tempLevel
if (GetLocalPlayer() == owner) then
BlzFrameSetVisible(self.Frames.box, true)
end
end
function TalentView:OnConfirm()
local owner = GetTriggerPlayer()
if (not TalentView.ViewedUnit[owner]) then return end
local viewedUnit = TalentView.ViewedUnit[owner]
local tt = TalentTree[viewedUnit]
local tempState = tt.TempTalentState
local tempLevel = tt.TempTalentLevel
for i, v in ipairs(tempState) do
if (tt.Talents[i]) then
if (tempLevel[i] and tt.TalentLevel[i] ~= tempLevel[i]) then
local talents = tt.Talents[i].levels
for j = tt.TalentLevel[i]+1, tempLevel[i] do
if (tempLevel[i] > tt.TalentLevel[i]) then
talents[j]:onActivate(viewedUnit)
else
talents[j]:onDeactivate(viewedUnit)
end
end
elseif (tt.TalentState[i] ~= nil and (tt.TalentState[i] ~= v)) then
if (v == true) then tt.Talents[i].onActivate(viewedUnit)
else tt.Talents[i].onDeactivate(viewedUnit) end
end
tt.TalentLevel[i] = tempLevel[i]
tt.TalentState[i] = v
end
end
-- print("b")
tt.TempTalentState = nil
if (GetLocalPlayer() == owner) then
BlzFrameSetVisible(TalentView.Frames.box, false)
BlzFrameSetVisible(TalentView.Frames.viewTalentsButton, true)
end
end
function TalentView:OnCancel()
local owner = GetTriggerPlayer()
if (not TalentView.ViewedUnit[owner]) then return end
local viewedUnit = TalentView.ViewedUnit[owner]
local tt = TalentTree[viewedUnit]
-- Loop through talent choices and reduce their level to previous
for i = 1, TalentView.MAX_TALENTS do
if (tt.Talents[i]) then
if (tt.TalentLevel[i] ~= tt.TempTalentLevel[i]) then
for j = tt.TempTalentLevel[i], tt.TalentLevel[i] +1, -1 do
local t = tt.Talents[i].levels[j]
tt.Talents[i] = t
if (tt.Dependency[i]) then
tt.Dependency[i] = t.dependency
end
if (t.onPointRemoved) then t:onPointRemoved(tt, viewedUnit) end
end
end
end
end
-- Reset the talent state
tt.TempTalentState = nil
if (GetLocalPlayer() == owner) then
BlzFrameSetVisible(TalentView.Frames.box, false)
BlzFrameSetVisible(TalentView.Frames.viewTalentsButton, true)
BlzFrameSetEnable(self.Frames.cancelButton, false)
BlzFrameSetEnable(self.Frames.cancelButton, true)
end
end
function TalentView:OnClicked(i, owner)
local self = TalentView
local viewedUnit = {}
-- If there is no active or viewed unit, we break
if (self.ViewedUnit[owner] == nil) then return end
viewedUnit = self.ViewedUnit[owner]
local tt = TalentTree[viewedUnit]
local state = {}
-- If we clicked on the Talent whose state was false, change it into true
if (tt.TempTalentState[i] == false) then
-- print("start")
local ttl = tt.TempTalentLevel
local talent = tt.Talents[i]
-- print("before setinverse dep: "..tt.Talents[i]._name)
tt.TempTalentState[i] = true
if (ttl[i]) then ttl[i] = ttl[i] + 1 end
tt.BaseDependency[i] = talent.dependency
-- if (talent.requirements) then
-- table.insert(tt.RequiredTalents, talent)
-- print("insert", #tt.RequiredTalents)
-- end
-- On event added point
if (talent.onPointAdded) then talent:onPointAdded(tt, viewedUnit) end
if (talent.nextTalent) then
talent = talent:onNext()
end
TalentView:OnView(owner)
end
end
function TalentView:OnRightClick(i, owner)
local self = TalentView
local viewedUnit = {}
-- If there is no active or viewed unit, we break
if (self.ViewedUnit[owner] == nil) then return end
viewedUnit = self.ViewedUnit[owner]
local tt = TalentTree[viewedUnit]
-- If the temporary level is higher than the actual level, we can continue
if (tt.TalentLevel[i] < tt.TempTalentLevel[i]) then
local talent = tt.Talents[i]
local state = tt.TempTalentState[i]
-- Check if some other talent requires this one. If it exists and
-- if level is higher than its required level, it's okay to remove it.
if (tt:CheckBaseDependency(tt.TempTalentLevel[i]-1, i)) then
if (talent:removeRequirements(tt, viewedUnit)) then
-- If this talent is the last in the stack, just set its state to false
if (state == true) then
state = false
tt.TempTalentState[i] = false
else
-- If it wasn't last but its temporary level is higher than its actual,
-- That means that it's not the First talent. We can safely replace it with lower
local nextLvl = tt.TempTalentLevel[i]
if (nextLvl > 2) then nextLvl = nextLvl - 1 end
talent = tt.Talents[i].levels[nextLvl]
-- We need to apply the new base dependency to the surroundings.
end
tt.Talents[i] = talent
tt.BaseDependency[i] = talent.baseDependency
if (tt.TempTalentLevel[i]) then tt.TempTalentLevel[i] = tt.TempTalentLevel[i] - 1 end
if (tt.Talents[i].onPointRemoved) then tt.Talents[i]:onPointRemoved(tt, viewedUnit) end
-- ========= Experimental feature, reverse Requirement checking =========
-- local talentReqId = nil
-- -- Test if removing this talent would result in violation of Requirements
-- for j, t in ipairs(tt.RequiredTalents) do
-- -- If the talent we decreased is one of the Required ones, save its reference
-- print("j"..j, "tid"..t.id, "currId"..oldTalent.id, t._name)
-- if (t.id and t.id == oldTalent.id) then
-- print("REQ ID")
-- talentReqId = j
-- end
-- -- If it violates the requirements, return the state as it was before.
-- if (t:requirements(tt, viewedUnit, true) == false) then
-- print("violated")
-- TalentView:OnClicked(i, owner)
-- return;
-- end
-- end
-- print("removed")
-- -- If it didn't violate the requirement,
-- -- we remove the talent from the Requirements
-- if (talentReqId) then
-- print("req rem", talentReqId)
-- table.remove(tt.RequiredTalents, talentReqId)
-- end
end
end
end
self:OnView(owner)
end
function TalentFrameInitialize(i)
local self = TalentView
local tf = { Frames = {} }
tf.clickTrigger = CreateTrigger()
-- print("i: "..(i+1))
if (math.fmod(i, self.COLUMNS) < 3) then
tf.horizontalLink = BlzCreateFrameByType("BACKDROP", "HorizontalLink", self.Frames.box, "", 0)
self.horizontalLink[i+1] = tf.horizontalLink
end
if (i < (self.MAX_TALENTS - self.COLUMNS)) then
tf.verticalLink = BlzCreateFrameByType("BACKDROP", "VerticalLink", self.Frames.box, "", 0)
self.verticalLink[i+1] = tf.verticalLink
end
tf.availableImage = BlzCreateFrameByType("BACKDROP", "AvailableImg", self.Frames.box, "", 0)
tf.mainButton = BlzCreateFrame("ScoreScreenBottomButtonTemplate", self.Frames.box, 0, 0)
tf.mainImage = BlzGetFrameByName("ScoreScreenButtonBackdrop", 0)
tf.tooltipBox = BlzCreateFrame("ListBoxWar3", tf.mainButton, 0, 0)
tf.tooltipText = BlzCreateFrameByType("TEXT", "StandardInfoTextTemplate", tf.tooltipBox, "StandardInfoTextTemplate", 0)
tf.counterImage = BlzCreateFrameByType("BACKDROP", "Counter", tf.mainButton, "", 0)
tf.counterText = BlzCreateFrameByType("TEXT", "FaceFrameTooltip", tf.mainButton, "", 0)
-- BlzFrameSetParent(tf.availableImage, tf.mainButton)
-- BlzFrameSetLevel(tf.mainImage, 1)
-- BlzFrameSetLevel(tf.counterImage, 2)
-- BlzFrameSetLevel(tf.availableImage, 0)
BlzFrameSetTooltip(tf.mainButton, tf.tooltipBox)
BlzFrameSetTextAlignment(tf.counterText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
local xPos = math.floor(math.fmod(i, self.COLUMNS))
local yPos = math.floor((i) / self.COLUMNS)
local xIncrem = (self.WIDTH*(1-self.SIDE_MARGIN)) / (self.COLUMNS + 1)
local yIncrem = (self.HEIGHT*(1-self.VERTICAL_MARGIN)) / (self.ROWS + 1)
local xOffset = xPos * xIncrem - ((self.COLUMNS-1) * 0.5) * xIncrem
--local yOffset = self.HEIGHT*(0.1+self.VERTICAL_MARGIN) + yPos * ((self.HEIGHT*(1-self.VERTICAL_MARGIN)) / self.ROWS)
local yOffset = yPos * yIncrem - ((self.ROWS-1) * 0.5) * yIncrem
local Config = {
--mainButton = { point = true, pos = { fp = FRAMEPOINT_CENTER, frame = self.Frames.box, fp2 = FRAMEPOINT_BOTTOM, x = xOffset, y = yOffset }, size = { x = self.TALENT_WIDTH, y = self.TALENT_HEIGHT }},
mainButton = { point = true, pos = { fp = FRAMEPOINT_CENTER, frame = self.Frames.box, fp2 = FRAMEPOINT_CENTER, x = xOffset, y = yOffset }, size = { x = self.TALENT_WIDTH, y = self.TALENT_HEIGHT }},
tooltipBox = { point = true, pos = { fp = FRAMEPOINT_TOPLEFT, frame = self.Frames.box, fp2 = FRAMEPOINT_TOPRIGHT, x = 0.0, y = 0.0 }, size = { x = self.TOOLTIP_BOX_WIDTH, y = self.TOOLTIP_BOX_HEIGHT }},
tooltipText = { clear = true, point = true, pos = { fp = FRAMEPOINT_CENTER, frame = tf.tooltipBox, fp2 = FRAMEPOINT_CENTER, x = 0.0, y = 0.0 }, size = { x = self.TOOLTIP_BOX_WIDTH-0.03, y = self.TOOLTIP_BOX_HEIGHT-0.03 }, text = "Default talent name \n\nDefault talent description"},
counterImage = { point = true, pos = { fp = FRAMEPOINT_BOTTOMRIGHT, frame = tf.mainButton, fp2 = FRAMEPOINT_BOTTOMRIGHT, x = -0.0006, y = 0.0015 }, size = { x = 0.014, y = 0.014 }, texture = self.COUNTER_ICON_ACTIVE },
counterText = { clear = true, point = true, pos = { fp = FRAMEPOINT_CENTER, frame = tf.counterImage, fp2 = FRAMEPOINT_CENTER, x = 0, y = 0}, size = { x = 0.01, y = 0.012 }, text = "0"},
verticalLink = { point = true, pos = { fp = FRAMEPOINT_BOTTOM, frame = self.Frames.box, fp2 = FRAMEPOINT_CENTER, x = xOffset, y = yOffset }, size = { x = self.TALENT_WIDTH*0.10, y = yIncrem }, texture = self.INACTIVE_LINK_BOX },
horizontalLink = { point = true, pos = { fp = FRAMEPOINT_LEFT, frame = self.Frames.box, fp2 = FRAMEPOINT_CENTER, x = xOffset, y = yOffset }, size = { x = xIncrem, y = self.TALENT_HEIGHT*0.10 }, texture = self.INACTIVE_LINK_BOX },
availableImage = { point = true, pos = { fp = FRAMEPOINT_CENTER, frame = tf.mainButton, fp2 = FRAMEPOINT_CENTER, x = 0, y = 0 }, size = { x = self.TALENT_WIDTH*self.OUTLINE_BORDER_RATIO, y = self.TALENT_HEIGHT*self.OUTLINE_BORDER_RATIO }, texture = self.GREEN_BORDER },
mainImage = { texture = self.DEFAULT_TALENT_ICON }
}
ConfigFrames(Config, tf)
tf.onClick = function()
local frame = BlzGetTriggerFrame()
BlzFrameSetEnable(frame, false)
BlzFrameSetEnable(frame, true)
TalentView:OnClicked(i+1, GetTriggerPlayer())
end
TriggerAddAction(tf.clickTrigger, tf.onClick)
BlzTriggerRegisterFrameEvent(tf.clickTrigger, tf.mainButton, FRAMEEVENT_CONTROL_CLICK)
if (TalentView.RIGHT_CLICK_TALENT_REMOVAL) then
tf.mouseUpTrigger = CreateTrigger()
TriggerAddAction(tf.mouseUpTrigger, function()
local owner = GetTriggerPlayer()
if (TalentView.playerRightClick[owner] == true) then
TalentView:OnRightClick(i+1, owner)
end
end)
BlzTriggerRegisterFrameEvent(tf.mouseUpTrigger, tf.mainButton, FRAMEEVENT_MOUSE_UP)
end
return tf
end
function TalentView:Initialize()
self.Frames = {}
self.Config = {}
self.MAX_TALENTS = self.COLUMNS * self.ROWS
-- Create and setup the Talent View dialog box
self.Frames.box = BlzCreateFrame("SuspendDialog", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), 0,0)
self.Config.box = { clear = true, abs = true, pos = { x = 0.35, y = 0.34, fp = FRAMEPOINT_CENTER }, size = { x = self.WIDTH, y = self.HEIGHT }}
self.Frames.boxTitle = BlzGetFrameByName("SuspendTitleText",0)
self.Config.boxTitle = { text = "Talent Tree" }
-- Create and set up the Talent Save/Confirmation Button Frame
self.Frames.confirmButton = BlzGetFrameByName("SuspendDropPlayersButton",0)
self.Config.confirmButton = { clear = true, point = true, pos = { x = 0.0, y = 0.02, frame = self.Frames.box, fp = FRAMEPOINT_BOTTOMRIGHT, fp2 = FRAMEPOINT_BOTTOM }, size = { x = 0.12, y = 0.03 }}
self.Frames.confirmText = BlzGetFrameByName("SuspendDropPlayersButtonText",0)
self.Config.confirmText = { text = "Confirm" }
-- Create and setup the Talent Cancel/Close view Button Frame
self.Frames.cancelButton = BlzCreateFrame("ScriptDialogButton", self.Frames.box, 0,0)
self.Config.cancelButton = { clear = true, point = true, pos = { x = 0.0, y = 0.02, frame = self.Frames.box, fp = FRAMEPOINT_BOTTOMLEFT, fp2 = FRAMEPOINT_BOTTOM }, size = { x = 0.12, y = 0.03 }}
self.Frames.cancelText = BlzGetFrameByName("ScriptDialogButtonText",0)
self.Config.cancelText = { text = "Cancel" }
-- Create and setup the Show Talents Button Frame
self.Frames.viewTalentsButton = BlzCreateFrame("ScriptDialogButton", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0), 0, 0)
self.Config.viewTalentsButton = { clear = true, abs = true, pos = { x = self.SHOW_TALENTS_X, y = self.SHOW_TALENTS_Y, fp = FRAMEPOINT_CENTER }, size = { x = 0.11, y = 0.035 }}
self.Frames.viewTalentsText = BlzGetFrameByName("ScriptDialogButtonText",0)
self.Config.viewTalentsText = { text = "Show Talents" }
-- Apply the config to all created frames.
ConfigFrames(self.Config, self.Frames)
-- Create the talent frames
self.Frames.Talent = {}
for i = 0, self.COLUMNS * self.ROWS - 1 do
table.insert(self.Frames.Talent, TalentFrameInitialize(i))
end
-- Create the needed triggers for the buttons
self.confirmTrigger = CreateTrigger()
self.cancelTrigger = CreateTrigger()
self.viewTrigger = CreateTrigger()
-- Add the trigger Actions
TriggerAddAction(self.confirmTrigger, self.OnConfirm)
TriggerAddAction(self.cancelTrigger, self.OnCancel)
TriggerAddAction(self.viewTrigger, function() TalentView:OnView(GetTriggerPlayer()) end)
-- Register the event on the frames
BlzTriggerRegisterFrameEvent(self.confirmTrigger, self.Frames.confirmButton, FRAMEEVENT_CONTROL_CLICK)
BlzTriggerRegisterFrameEvent(self.cancelTrigger, self.Frames.cancelButton, FRAMEEVENT_CONTROL_CLICK)
BlzTriggerRegisterFrameEvent(self.viewTrigger, self.Frames.viewTalentsButton, FRAMEEVENT_CONTROL_CLICK)
if (self.RIGHT_CLICK_TALENT_REMOVAL) then
self.setRightClickDownTrigger = CreateTrigger()
self.unsetRightClickUpTrigger = CreateTrigger()
TriggerRegisterPlayerMouseEventBJ(self.setRightClickDownTrigger, Player(0), bj_MOUSEEVENTTYPE_DOWN)
TriggerRegisterPlayerMouseEventBJ(self.unsetRightClickUpTrigger, Player(0), bj_MOUSEEVENTTYPE_UP)
TriggerAddAction(self.setRightClickDownTrigger, function()
if (BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT) then
TalentView.playerRightClick[GetTriggerPlayer()] = true
end
end)
TriggerAddAction(self.unsetRightClickUpTrigger, function()
local player = GetTriggerPlayer()
TimerStart(NewTimer(), 0.1, false, function() ReleaseTimer(GetExpiredTimer()) TalentView.playerRightClick[player] = false end)
end)
end
BlzFrameSetVisible(self.Frames.box, false)
end
function ConfigFrames(configs, frames)
for k,v in pairs(configs) do
if (v.clear) then BlzFrameClearAllPoints(frames[k]) end
if (v.size) then BlzFrameSetSize(frames[k], v.size.x, v.size.y) end
if (v.abs) then BlzFrameSetAbsPoint(frames[k], v.pos.fp, v.pos.x, v.pos.y)
elseif (v.point) then BlzFrameSetPoint(frames[k], v.pos.fp, v.pos.frame, v.pos.fp2, v.pos.x, v.pos.y) end
if (v.text) then BlzFrameSetText(frames[k], v.text) end
if (v.texture) then BlzFrameSetTexture(frames[k], v.texture, 0, true) end
end
end
onGlobalInit(function()
TimerStart(NewTimer(), 0.5, false, function() Test() end)
end)
-- THIS IS FOR TEST ONLY
function Test()
TalentView:Initialize()
TalentView.ActiveUnit[Player(0)] = gg_unit_Hblm_0003
-- TalentView.ActiveUnit[Player(1)] = gg_unit_Hblm_0008
local tt = CreateArcaneMageTalentTree(gg_unit_Hblm_0003)
-- local tt2 = CreateTestTalentTree(gg_unit_Hblm_0008)
end
Attachments
Last edited: