• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

TasHeroLearnEx

This bundle is marked as pending. It has not been reviewed by a staff member yet.

Introduction


TasHeroLearnEx is a custom UI system/addition for Warcraft 3 V1.31 or higher, in Lua or vjass.
It allows units/heroes to learn abilities from a custom/bigger Abilitypool.

Details


There is a new Box with AbilityIcons when you click any of them your current selected unit or shared controled unit will learn that ability. Swaping in Group selection is not supported.
This Learning by that custom UI will execute Any Unit Learn Event Triggers (But not if you used the unit/player specific one). Considering their condition, actions and will provide the data with the default trigger api.

That box can be shown/hidden by a new button on the users will, default next to the commandbutton card. The UI also closes when one presses the ESC-Button
One can scroll down/up, to display the other abilities when the amount of options exceed the amount of buttons. For the scrolling one points with the mouse anywhere inside the box and rolls the middle mousebutton.

The Learn options are either taken from unit, unitCode, player or [0]. But only one of them is used for the current unit.
unit > unitCode > player > 0

One can setup the Learnoptions right inside the system or later on.
TasHeroLearnEx respects Level requirments and displays needed levels.

Lua

vjass


Lua:
TasHeroLearnEx = {
    -- Data for each UnitCode 
    HeroData = {
        -- supported Keys unit, unitCode, Player, 0;  unit > unitCode > Player > 0
        -- [0] is used by everyone, if not one of the others is used currently.
        --  [bj_lastCreatedUnit] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [Player(0)] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [0] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  you can set a field from outside of this system, But if you do you should use TasHeroLearnEx.UpdateHeroData() after setting your wanted data.
        --   TasHeroLearnEx.HeroData[FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        [FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad,AHbz,AHab,AHwe,AHmt,AHtc,AHtb,AHbh,AHav,AOwk,AOcr,AOmi,AOww,AOfs,AOsf,AOcl,AOeq"
        ,[Player(1)] = "AUim,AUts,AUcb,AUls,AUfn,AUfu,AUdr,AUdd,AUav,AUsl,AUcs,AUin,AUdc,AUdp,AUau,AUan"
    }

}


--BloodMage UnitCode
TasHeroLearnEx.HeroData[FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
...
TasHeroLearnEx.UpdateHeroData()

setup
Lua:
local hookEvent = true -- Hook into Learn Event Triggers and Throw them? Only read at init
    -- when you don't use hookEvent then you need to fill TasHeroLearnEx.Action with actionFunctions(unit, abiCode, abilityLevel, owner, unitCode)
    -- TasHeroLearnEx.Action[FourCC('AHbz')] = function(unit, abiCode, abilityLevel, owner, unitCode) end
    -- TasHeroLearnEx.Action[0] allways runs (hookEvent = false)
    local action 
    if CreateFourCCTable then action  = CreateFourCCTable() else action = {} end

    -- the none hookEvent approach runs for any skill learned by TasHeroLearnEx
    action[0] = function(unit, abiCode, abilityLevel, owner, unitCode)
        print("Action 0", GetUnitName(unit), GetAbilityName(abiCode))        
    end
TasHeroLearnEx = {
    -- Where is the TOCFile in your map?
    TocPath = "war3mapImported\\TasHeroLearnEx.toc"
    
    ,HookEvent = hookEvent
    ,Action = action
    -- Data for each UnitCode 
    ,HeroData = {
        -- supported Keys unit, unitCode, Player, 0;  unit > unitCode > Player > 0
        -- [0] is used by everyone, if not one of the others is used currently.
        --  [bj_lastCreatedUnit] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [Player(0)] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        --  [0] = "AEmb,AEim,AEev,AEme,AEer,AEfn,AEah,AEtq"
        --  you can set a field from outside of this system, But if you do you should use TasHeroLearnEx.UpdateHeroData() after setting your wanted data.
        --   TasHeroLearnEx.HeroData[FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad"
        [FourCC('Hblm')] = "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad,AHbz,AHab,AHwe,AHmt,AHtc,AHtb,AHbh,AHav,AOwk,AOcr,AOmi,AOww,AOfs,AOsf,AOcl,AOeq"
        ,[Player(1)] = "AUim,AUts,AUcb,AUls,AUfn,AUfu,AUdr,AUdd,AUav,AUsl,AUcs,AUin,AUdc,AUdp,AUau,AUan"
    }
    ,HeroAbilityLevelSkip = 2 -- should match the map gameplay constant
    ,Filter = function(unit) -- used for HeroData[0]        
        if IsUnitIllusion(unit) then return false end
        -- if not IsUnitType(unit, UNIT_TYPE_HERO) then return false end

        --return true if this unit is allowed to use HeroData[0]  HeroData[player]
        return true
    end

    ,Cols = 8 --amout of buttons in one Row
    ,Rows = 1 -- amount of Rows

    ,ShowEnemy = true -- can look into enemy builts false/true?
    ,HideMaxLevelSlot = false -- true shows empty slots for max Leveld skills.
    ,UserControl = false -- Show the Buttons to toggle ShowEnemy & HideMaxLevelSlot
    ,HideWithoutUser = true -- hide TasHeroLearnEx UI when currently nothing would be displayed.

    --ToolTip
    ,ToolTipSizeX = 0.2
    ,ToolTipPosX = 0.79
    ,ToolTipPosY = 0.165
    ,ToolTipPos = FRAMEPOINT_BOTTOMRIGHT

    -- Box
    ,PosX = 0.195
    ,PosY = 0.135
    ,Pos = FRAMEPOINT_BOTTOMLEFT

    -- ShowButton
    ,OpenButtonTexture = "ReplaceableTextures\\CommandButtons\\BTNSkillz.blp"
    ,OpenPosX = 0.6
    ,OpenPosY = 0.15
    ,OpenPos = FRAMEPOINT_TOPRIGHT

    
    -- ParentFunc who you want as parent, this runs at InitBlizzard, if you need more control you need to modify the part that calls local function Init()
    ,ParentFunc = function() return BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end

    -- how many LearnPoints an unit has to spent
    ,GetLearnPoints = function(unit)
        return GetHeroSkillPoints(unit)

        --return GetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD)//100
    end
    -- pay costs function is called inside TasHeroLearnEx.CustomUnitLearnAbility
    ,Costs = function(unit, abiCode) 
        -- can't pay return false
        if TasHeroLearnEx.GetLearnPoints(unit) <= 0 then return false end

        --SetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD) - 100)

        UnitModifySkillPoints(unit, -1)
        return true
    end

-- System stuff below
...
}

On default learning a skill using the Custom UI will take up one Skillpoint. But this could be changed by changing the content of function Costs
Lua:
TasHeroLearnEx = {
...
...
-- pay costs function is called inside TasHeroLearnEx.CustomUnitLearnAbility
    ,Costs = function(unit, abiCode) 
        -- can't pay return false
        if GetHeroSkillPoints(unit) <= 0 then return false end
        UnitModifySkillPoints(unit, -1)
        return true
    end

To setup learn pools in the vjass version one uses the 2 functions
JASS:
public function AddSkillBatch takes integer key, string abiString returns nothing
public function AddSkill takes integer key, integer abiCode returns nothing
the System script in trigger editor has examples, at the top below globals in the function UserDataSetup (in the system code they are disabled).
JASS:
private function UserDataSetup takes nothing returns nothing
    // supported Keys unit, unitCode, Player, AnyUnitKey;  unit > unitCode > Player > AnyUnitKey
//bloodmage
    call AddSkillBatch('Hblm', "AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad,AHbz,AHab,AHwe,AHmt,AHtc,AHtb,AHbh,AHav,AOwk,AOcr,AOmi,AOww,AOfs,AOsf,AOcl,AOeq")

//player blue
    call AddSkillBatch(1, "AUim,AUts,AUcb,AUls,AUfn,AUfu,AUdr,AUdd,AUav,AUsl,AUcs,AUin,AUdc,AUdp,AUau,AUan")
endfunction
There is also a GUI API to setup learnpool for an unitType (like bloodmage). it like shown in this demo trigger:
SkillString you would setup in Object Editor by giving all the wanted skills to an unit/spellbook then copy paste it by opening the field while holding shift
  • DemoData
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set TasHeroLearnEx__UnitCode = Blutmagier
      • Set TasHeroLearnEx__SkillString = AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad,AHbz,AHab,AHwe,AHmt,AHtc,AHtb,AHbh,AHav,AOwk,AOcr,AOmi,AOww,AOfs,AOsf,AOcl,AOeq
      • Trigger - Run TasHeroLearnExAddSkills (ignoring conditions)
      • Custom script: call TasHeroLearnEx_AddSkillBatch(1, "AUim,AUts,AUcb,AUls,AUfn,AUfu,AUdr,AUdd,AUav,AUsl,AUcs,AUin,AUdc,AUdp,AUau,AUan")
You can change some settings for the system in the globals block of the system script file.
And in the functions right below the globals block
JASS:
globals
    // Where is the TOCFile in your map?
    public string TocPath = "war3mapImported\\TasHeroLearnEx.toc"
    public boolean ThrowEvent = true
    public integer HeroAbilityLevelSkip = 2 // should match the map gameplay constant
    
    public integer Cols = 8 //amout of buttons in one Row
    public integer Rows = 1 // amount of Rows

    public boolean ShowEnemy = true // can look into enemy builts false/true?
    public boolean HideMaxLevelSlot = false // true shows empty slots for max Leveld skills.
    public boolean UserControl = false // Show the Buttons to toggle ShowEnemy & HideMaxLevelSlot
    public boolean HideWithoutUser = true // hide TasHeroLearnEx UI when currently nothing would be displayed.

    //ToolTip
    public real ToolTipSizeX = 0.2
    public real ToolTipPosX = 0.79
    public real ToolTipPosY = 0.165
    public framepointtype ToolTipPos = FRAMEPOINT_BOTTOMRIGHT

    // Box
    public real PosX = 0.195
    public real PosY = 0.135
    public framepointtype Pos = FRAMEPOINT_BOTTOMLEFT

    // ShowButton
    public string OpenButtonTexture = "ReplaceableTextures\\CommandButtons\\BTNSkillz.blp"
    public real OpenPosX = 0.6
    public real OpenPosY = 0.15
    public framepointtype OpenPos = FRAMEPOINT_TOPRIGHT


// ParentFunc who you want as parent, this runs at InitBlizzard, if you need more control you need to modify the part that calls local function Init()
    public function ParentFunc takes nothing returns framehandle
        return BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
    endfunction
    
// used for HeroData[0]
    public function Filter takes unit u returns boolean
        if IsUnitIllusion(u) then
            return false
        endif
        //if not IsUnitType(u, UNIT_TYPE_HERO) then
        // return false
        //endif

        //return true if this unit is allowed to use HeroData[0]  HeroData[player]
        return true
    endfunction

// how many LearnPoints an unit has to spent
    public function GetLearnPoints takes unit u returns integer
        return GetHeroSkillPoints(u)
        //return GetPlayerState(GetOwningPlayer(u), PLAYER_STATE_RESOURCE_GOLD)/100
    endfunction

// Does the pay part and rejects learning when not enough resources are given
    public function Costs takes unit u, integer abiCode returns boolean
        // can't pay return false
        if GetLearnPoints(u) <= 0 then
            return false
        endif

        //SetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD) - 100)

        call UnitModifySkillPoints(u, -1)
        return true
    endfunction

    private function LearnAction takes unit u, integer abiCode  returns nothing
        set udg_TasHeroLearnEx__Skill = abiCode
        set udg_TasHeroLearnEx__Unit = u
        set udg_TasHeroLearnEx__UnitCode = GetUnitTypeId(u)
        set udg_TasHeroLearnEx__SkillLevel = GetUnitAbilityLevel(u, abiCode)
        if ThrowEvent then
            set udg_TasHeroLearnEx__Event = 1
            set udg_TasHeroLearnEx__Event = 0
        endif
    endfunction




How to install


Requiers Warcraft 3 1.31+ or higher
  • Copy the TasHeroLearnEx Folder (trigger Editor).
  • export
    • war3mapImported\TasHeroLearnEx.fdf
    • war3mapImported\TasHeroLearnEx.toc
    • WHEN USING THE EXPORT ALL BUTTON, IT CAN HAPPEN THAT THE CONTENT OF THIS FILES SWAP
    • import them into your map
  • Installed


ChangeLog


2a) HideWithoutUser
2)
Added alternative to the trigger hook system
It is easier to use something else than default learnpoints​
1e) Fixed a display bug for max Learned skills.
1d) Added a AutoCast sprite when one can skill
1c)
OnDefault Filter also affects HeroData[player]
Displays only selected Skills for Units you don't have control​

1b)
Added Level checks into this.CustomUnitLearnAbility
Displays a checked for max learned skills when displayed. (new fdf)​
1a)
Added Filter(unit) for HeroData[0]
Fixed some erros when selectdata returned nil
fixed SkilLevel reading​
Previews
Contents

TasHeroLearnEx (Map)

TasHeroLearnEx vjass (Map)

Updated to V1b) (new FDF)
Fixed some errors when selecting units without data.
Level req now works correctly.
Shows now a checked, when a skill is max leveled and max levels are shown
Added a Filter function inside TasHeroLearnEx which is used for Data[0] (any unit).
CustomUnitLearnAbility now considers Level reqs.
 
Last edited:
on default It will use skillpoints to learn abilities from a wanted pool. The pool is either for an unit, an unitcode, a player or for everyone (0). If multiple pools are possible unit is taken over unitcode over player over everyone(0)
Edit: one could even add or remove during the game from that pools .
 
Last edited:
Updated to V2)
Mostly makes it better to use for people that write Lua.

The trigger hook system can now be disabled in this case the system will call Lua functions which are stored in a table of TasHeroLearnEx. This functions are only needed when you want some custom code to run right after the learning.

Lua:
local hookEvent = true -- Hook into Learn Event Triggers and Throw them? Only read at init


TasHeroLearnEx.Action[FourCC('AHbz')] = function(unit, abiCode, abilityLevel, owner, unitCode) end
-- [0] runs for anything learned by TasHeroLearnEx (when hookEvent = false)
TasHeroLearnEx.Action[0] = function(unit, abiCode, abilityLevel, owner, unitCode) end

Added a function which returns the current useable "Learnpoints" which makes it easier to use a custom resource for the learning inside TasHeroLearnEx. if one changes the GetLearnPoints function one still would have to change function Costs to spent the new resource.
Lua:
-- how many LearnPoints an unit has to spent
    ,GetLearnPoints = function(unit)
        return GetHeroSkillPoints(unit)

        --return GetPlayerState(GetOwningPlayer(unit), PLAYER_STATE_RESOURCE_GOLD)//100
    end
 
Nice system ( : I do have a feature request though. Can you configure it so you can hide the extra learn menu icon unless you have a hero that uses the system selected? e.g. It wouldn't show in this screenshot because no unit is selected

edit: I found a neat trick for having heroes learn abilities purely using this system:
1. Create a dummy ability, in my case I used sphere as the base ability for this.
2. Set its max level to your the maximum hero level in your map.
3. Set this dummy ability as the only ability in your chosen hero's learn menu in the object editor.
4. Using triggers, disable the dummy for each player in your map ("Player enable / disable ability" in GUI).
Now, your chosen hero won't have a default learn button but can still have skill points and spend them via this system.
1693700398577.png
 
Last edited:
Level 5
Joined
Nov 3, 2018
Messages
80
great! hope it gets an update near future! any chance it will be ever be gui friendly? atleast the set abilitys for a hero part

this is the only system i ever found that works like an extended skill system
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,516
great! hope it gets an update near future! any chance it will be ever be gui friendly? atleast the set abilitys for a hero part

this is the only system i ever found that works like an extended skill system
It is GUI friendly, see the demonstration in the description:
  • DemoData
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set TasHeroLearnEx__UnitCode = Blood Mage
      • Set TasHeroLearnEx__SkillString = AHfs,AHbn,AHdr,AHpx,AHhb,AHds,AHre,AHad,AHbz,AHab,AHwe,AHmt,AHtc,AHtb,AHbh,AHav,AOwk,AOcr,AOmi,AOww,AOfs,AOsf,AOcl,AOeq
      • Trigger - Run TasHeroLearnExAddSkills (ignoring conditions)
      • Custom script: call TasHeroLearnEx_AddSkillBatch(1, "AUim,AUts,AUcb,AUls,AUfn,AUfu,AUdr,AUdd,AUav,AUsl,AUcs,AUin,AUdc,AUdp,AUau,AUan")
The SkillString takes a bunch of rawcodes, which can be found in the Object Editor when you Press Control + D (toggles to and from rawcode mode). The rawcode is that 4 digit id that you give all of your object editor data, it's just a way to identify things (every object needs a unique id).

I assume you don't need the Custom Script at the end. If it doesn't work, get rid of it.
 
You can get the "ability string" without having to write it. One chooses the abilities in an spellbook, unit, item or hero abilities inside object editor. Than hold "shift" and open the field, now one gets the single line textfield popup. The text you can copy paste and use in the system.

The vjass version and Lua version are different in supporting GUI.
The vjass version has this GUI setup & custom Real event.
While the Lua version only hooks the learn event and has no gui ability setup.

In my map using this system i removed the hook and only use the action function learn calling which works good when one writes Lua directly. I see one can disable the hook good, good.

Edit:
I assume you don't need the Custom Script at the end. If it doesn't work, get rid of it.
That example setups 2 learn pools. one for bloodmage-units and one for index 1 which should be units owned by player 1 which dont have a learn pool with a higher prio like unit handle or unitCode.
For the Lua version use Player(x) and unit instead of numbers.
 
Last edited:
Level 5
Joined
Nov 3, 2018
Messages
80
Thank you i managed to use and set up your system and it looks so nice!
i have a question i noticed that when you click an ability via GUI you can catch that event.
but is it possible to catch the event for when the skill button is clicked? (not the skill but the red button with the skills) also is it possible to have multiple per hero?
 
Only one UI.
Each unit uses one pool at one time, but one can swap the pool or the pools content anytime you want.


I did not implement an event for the Open UI button, one can attach the normal frame click event to the buttons;
Lua TasHeroLearnEx.Open
vjass call BlzTriggerRegisterFrameEvent(openTrigger, Open, FRAMEEVENT_CONTROL_CLICK)
An open gui event is out of question because the visible state is async and running triggeractions async is an desync cause. And a is clicked event is not much better than the normal frameevent (o right frameevent was not in GUI, still a bit skeptical about that open ui event).
 
Top