• 🏆 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!

Spellweaver's Talent Kitchen

A vJass system made for implementing talent systems into a map. It provides a way to build a talent tree from an easy to use API and link game logic to it. It also provides a user interface and handles the changes automatically.

Some features it has...
  • Single rank and multi rank talents. Each rank is defined separately and can have its own text/icon/behavior
  • Logic binding on Activation/Deactivation (when talent effects are applied), Allocation (when talent is taken before confirming), Requirements (custom disable logic)
  • Talent point tracking, each talent/rank can have a varying talent point cost (0, 1 or more)
  • Requirements (custom logic based) talent disable, the user defined text reason will be shown in the tooltip
  • Talent Dependencies, in cardinal direction, talent can require its adjacent talents to have a specified level, this is shown in interface as "links" or "lines"
  • Talent-tree based configurable rows and columns, for example Pyromancer can have 6 rows, 3 columns and Fighter can have 4x4
  • Grid based talent positioning (X, Y) and automatic button placement based on rows/columns
  • Temporary talent point allocation, points can be put into tree and reset as many times as needed before "Confirm" is clicked, only then all the effects will apply
  • Talent tree reset, deactivates all talents and refunds all points spent.
  • Save-Load API for integration with save-load systems

An API reference is included, and examples should provide more than enough information for implementation/trying things out.

18.11.2021 - Posted
21.11.2021 - Multi-panel trees, Link-talents, More accessible customizability, RUID integration, github repo link + DruidClassic example
22.11.2021 - Added Relative version of the Druid map UI. Resizing or moving the frames will affect the rest of the frames.
04.12.2021 - Sneakily added a typescript version here's the repo
23.03.2023 - Various minor fixes, added Talent reset, flexible talent icon methods, performance optimizations. Updated STK map (Shepherd version)
29.03.2023 - Updated Druid example map with changes
31.03.2023 - Added interface summary and API Documentation + fix talent reset tooltip not updating bug. STK and Druid map updated.
12.07.2023 - Fixed single rank dependency message not showing required rank, updated both STK and Druid map. Updated readme.md in git.
17.07.2023 - Added Save-Load API, updated both maps. This change affected most of the files (didn't touch Interfaces and Views folder) and added new ones (Services). Setup.j was completely reworked and consolidated between Druid and STK maps. TalentTree implementations (Shepherd, Balance, Feral, Restoration) should work as is, but require a slight change (registration) in order to utilize Save-Load API.

Instead of pasting code here (since it lags a lot) here's a link to a Github Repo. Code from all current and future examples will be there as well.


Tags: Talent system, talent tree, ui

vJASS:
scope Shepherd initializer init

    public struct Shepherd extends STKTalentTree_TalentTree

        // Overriden stub methods, can delete this =================================
        // method GetTalentPoints takes nothing returns integer
        //     return GetPlayerState(this.ownerPlayer, PLAYER_STATE_RESOURCE_LUMBER)
        // endmethod

        // method SetTalentPoints takes integer points returns nothing
        //     call SetPlayerState(this.ownerPlayer, PLAYER_STATE_RESOURCE_LUMBER, points)
        // endmethod

        // method GetTitle takes nothing returns string
        //     return this.title
        // endmethod
        // =========================================================================

        method Initialize takes nothing returns nothing
            local STKTalent_Talent t

            call this.SetIdColumnsRows(1, 3, 4)
            set this.title = "Shepherd"
            call this.SetTalentPoints(6)
            // set this.icon = "FireBolt"
            // TODO: set tree background texture here
            // set this.backgroundImage = "arms.dds"

            // The tree should be built with talents here
            // ==============================================

            // Wondrous Flute <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(1)
            call t.SetName("Wondrous Flute")
            call t.SetDescription("Calls a sheep to your side.")
            call t.SetIcon("AlleriaFlute")
            call t.SetOnActivate(function thistype.Activate_CallSheep)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetCost(0) // First level of this talent is free
            call this.AddTalent(0, 0, t)

            // Rank 2
            set t = this.CreateTalent().SetChainId(1)
            call t.SetName("Wondrous Flute")
            call t.SetDescription("Calls another sheep to your side.")
            call t.SetIcon("AlleriaFlute")
            call t.SetOnActivate(function thistype.Activate_CallSheep)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call this.AddTalent(0, 0, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Soothing Song <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(2)
            call t.SetName("Soothing Song")
            call t.SetDescription("Calls a flying sheep to your side.")
            call t.SetIcon("DispelMagic")
            call t.SetOnActivate(function thistype.Activate_CallFlyingSheep)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetDependencies(1, 0, 0, 0) // left 1 (left up right down)
            call this.AddTalent(1, 0, t)

            // Rank 2
            set t = this.CreateTalent().SetChainId(2)
            call t.SetName("Soothing Song")
            call t.SetDescription("Calls another flying sheep to your side.")
            call t.SetIcon("DispelMagic")
            call t.SetOnActivate(function thistype.Activate_CallFlyingSheep)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetDependencies(1, 0, 0, 0) // left 1 (left up right down)
            call this.AddTalent(1, 0, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Shepherd Apprentice <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(3)
            call t.SetName("Shepherd Apprentice")
            call t.SetDescription("Gain an apprentice.")
            call t.SetIcon("Peasant")
            call t.SetOnActivate(function thistype.Activate_GainApprentice)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call this.AddTalent(2, 0, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Lots of Apprentices <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(4)
            call t.SetName("Lots of Apprentices")
            call t.SetDescription("Gain 2 guard apprentices.")
            call t.SetIcon("Footman")
            call t.SetOnActivate(function thistype.Activate_Gain2Guards)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetDependencies(0, 0, 0, 1) // down 1 (left up right down)
            call this.AddTalent(2, 1, t)

            // Rank 2
            set t = this.CreateTalent().SetChainId(4)
            call t.SetName("Lots of Apprentices")
            call t.SetDescription("Gain 2 guard apprentices.")
            call t.SetIcon("Footman")
            call t.SetOnActivate(function thistype.Activate_Gain2Guards)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetDependencies(0, 0, 0, 1) // down 1 (left up right down)
            call this.AddTalent(2, 1, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Coming of the Lambs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(5)
            call t.SetName("Coming of the Lambs")
            call t.SetDescription("Gain a Sheep and a Flying Sheep.")
            call t.SetIcon("Sheep")
            call t.SetOnActivate(function thistype.Activate_ComingOfTheLambs)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetDependencies(0, 0, 1, 1) // right 1 down 1 (left up right down)
            call this.AddTalent(1, 1, t)

            // Rank 2
            set t = this.CreateTalentCopy(t)
            call t.SetDescription("Gain 2 Sheep and 2 Flying Sheep.")
            call this.AddTalent(1, 1, t)

            // Rank 3
            set t = this.CreateTalentCopy(t)
            call t.SetDescription("Gain 3 Sheep and 3 Flying Sheep.")
            call this.AddTalent(1, 1, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Call of the Wilds <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            // Rank 1
            set t = this.CreateTalent().SetChainId(6)
            call t.SetName("Call of the Wilds")
            call t.SetDescription("Five hostile wolves appear.")
            call t.SetIcon("TimberWolf")
            call t.SetOnActivate(function thistype.Activate_CallOfTheWilds)
            call t.SetOnDeactivate(function thistype.Deactivate_Generic)
            call t.SetRequirements(function thistype.Requirement_CallOfTheWilds)
            call this.AddTalent(1, 2, t)
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            // Only need to call this if some talents start with certain rank
            // call this.SaveTalentRankState()
        endmethod


        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // Can use these methods inside Activate/Deactivate/Allocate/Deallocate/Requirements functions
      
        // static method GetEventUnit takes nothing returns unit
        // Returns unit that owns the talent tree
        // thistype.GetEventUnit()

        // static method GetEventTalent takes nothing returns STKTalent_Talent
        // Returns talent object that is being resolved
        // local STKTalent_Talent t = thistype.GetEventTalent()

        // static method GetEventRank takes nothing returns integer
        // Returns rank of the talent that is being activated
        // local integer r = thistype.GetEventRank()

        // static method GetEventTalentTree takes nothing returns TalentTree
        // Returns "this"
        // local STKTalentTree_TalentTree tt = thistype.GetEventTalentTree()

        // static method SetTalentRequirementsResult takes string requirements returns nothing
        // Needs to be called within Requirements function to disable the talent
        // thistype.SetTalentRequirementsResult("8 litres of milk")

        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        static method Activate_CallSheep takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            call CreateUnit(GetOwningPlayer(u), 'nshe', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
        endmethod

        static method Activate_CallFlyingSheep takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            call CreateUnit(GetOwningPlayer(u), 'nshf', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
        endmethod

        static method Activate_GainApprentice takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            call CreateUnit(GetOwningPlayer(u), 'hpea', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
        endmethod

        static method Activate_Gain2Guards takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            call CreateUnit(GetOwningPlayer(u), 'hfoo', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
            call CreateUnit(GetOwningPlayer(u), 'hfoo', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
        endmethod

        static method Activate_ComingOfTheLambs takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            local integer i = thistype.GetEventRank()
            loop
                exitwhen i <= 0
                call CreateUnit(GetOwningPlayer(u), 'nshe', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
                call CreateUnit(GetOwningPlayer(u), 'nshf', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
                set i = i - 1
            endloop
        endmethod

        static method Activate_CallOfTheWilds takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            local integer i = 0
            loop
                exitwhen i > 5
                call CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), 'nwlt', GetUnitX(u), GetUnitY(u), GetRandomDirectionDeg())
                set i = i + 1
            endloop
        endmethod

        static method IsEnumUnitSheepFilter takes nothing returns boolean
            return GetUnitTypeId(GetFilterUnit()) == 'nshe' or GetUnitTypeId(GetFilterUnit()) == 'nshf'
        endmethod

        static method Requirement_CallOfTheWilds takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            local group g = CreateGroup()
            call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 5000, Filter(function thistype.IsEnumUnitSheepFilter))
            if (CountUnitsInGroup(g) < 8) then
                call thistype.SetTalentRequirementsResult("8 nearby sheep")
            endif
        endmethod

        static method Deactivate_Generic takes nothing returns nothing
            local unit u = thistype.GetEventUnit()
            local STKTalent_Talent t = thistype.GetEventTalent()
            local integer r = thistype.GetEventRank()
            call BJDebugMsg("Deactivated " + t.name + " " + I2S(r))
        endmethod

        static method LoadCreate takes unit u returns Shepherd
            return thistype.create(u)
        endmethod
    endstruct

    private function init takes nothing returns nothing
        // Register Talent Trees
        call STKSaveLoad_RegisterTalentTree(1, Shepherd.LoadCreate)
    endfunction

endscope
Previews
Contents

Spellweaver's Talent Kitchen (Map)

STK Druid Talents (Map)

Reviews
Wrda
Must have been in STKTalentTree library (TalentTree script) DRUID version only: local player clickingPlayer variable is still leaking in TalentTreeViewModel script. By the way, cancel functionality is functioning like the "reset" in the other...
Is it possible to have multiple talent trees that can be opened independently?
Let's say I have three abilities, and each one can open a unique talent tree. How would I go about doing this?

Is there a function I need to call before calling STK_OpenTalentScreen(GetTriggerPlayer()) to open the specific tree that I want?
 
Level 39
Joined
Feb 27, 2007
Messages
5,011
Nobody can answer that because you did not specify what patch you want it to work for. There is only so far back this can possibly go because of the functions it uses.

Update your game. It’s free and does not require you to own Reforged.
 
Level 5
Joined
Nov 3, 2018
Messages
80
I Apologize you are right i did not said which version i use.
the version i use is 1.31.1 which is prereforged patch or 1.32 is fine too because 1.31 uses 1.32 natives
 
This was released after 1.31.1 was the newest patch, so there is no such thing as legacy version of this.
Anyways, it worked with 1.31.1, go here: GitHub - Gohagga/STK_vJass and copy-paste them to a testmap

See my comment here for how I got it to work:

I'm not sure, but this could be my modified files: I think you'll need all? I don't really remember tbh :p
(Note: I think this is the version released on 31.03.2023)
 

Attachments

  • SpellweaversTalentKitchen.j
    60.4 KB · Views: 2
  • SpellweaversTalentKitchen_SetupAndConstants.j
    8 KB · Views: 3
  • SpellwaversTalentKitchen_Views.j
    11.3 KB · Views: 2
  • SpellweaversTalentKitchen.j
    60.4 KB · Views: 2
Level 5
Joined
Nov 3, 2018
Messages
80
i checked the druid example plus i double checked on the shephard example but for some reason background refuses to appear i tried with your texture , my texture , in game textures (yeah no /war3imported) i'm lost on what's the reason my background texture its not showing (tried my texture on the druid example map changing the texture name and it worked...)

1708669046555.png
 
Last edited:
Top