1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  5. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  6. Units have been turned into heroes in our latest Icon Contest! Vote for the best icon set at the Icon Contest #18 Poll!
    Dismiss Notice
  7. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  8. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

Naming System 1.2b.w3x
Variables
Library
Changelog
Requirements
Table
UnitNaming
Optional
WorldBounds
Extended Features
UnitIndexerGUI
Unit Indexer
or ...
UnitDex
Usage
Setup
SetupNamesVJASS
NamePoolSetupGUI
SetupNamesGUI
Wrappers
ChangeUnitName
DeallocateUnitExample
More Examples
Commands
Changing A Unit Name
OnLeave
---------------------------
Test Related
Selection
Esc
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.

		
Name Type Is Array Initial Value
i integer No
IsUnitPreplaced boolean Yes
nFirstName string No
nFirstNames string Yes
nLastName string No
nLastNames string Yes
nUnit unit No
nUnitName string No
nUnitTypes unitcode Yes
UDex integer No
UDexGen integer No
UDexNext integer Yes
UDexPrev integer Yes
UDexRecycle integer No
UDexUnits unit Yes
UDexWasted integer No
UnitIndexerEnabled boolean No
UnitIndexEvent real No
v 1.2
- Merged tables defaultUnitName and defaultHeroName into 1
- Merged library into same file with a static if to enable extended features
- Made the GUI and Jass version work together without any major conflicts
- Removed most vJass example use and instead created a GUI version
- Included optional UnitDex
- Automatically handles preplaced units and enter map event
- Can be configured to automatically setup simple unit names
- Can be configured to automatically save default names (not recomended)

1.2b
- Fixed a bug with hiding unit type names causing a crash.
- Hiding unit names now also work without extended features.
- Hiding unit names but changing unit-type name will now work when using extended features.
- Fixed a bug with names not being configured properly due to order of onInit
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
   
    One map, one hashtable. Welcome to NewTable 4.1.0.1
   
    This newest iteration of Table introduces the new HashTable struct.
    You can now instantiate HashTables which enables the use of large
    parent and large child keys, just like a standard hashtable. Previously,
    the user would have to instantiate a Table to do this on their own which -
    while doable - is something the user should not have to do if I can add it
    to this resource myself (especially if they are inexperienced).
   
    This library was originally called NewTable so it didn't conflict with
    the API of Table by Vexorian. However, the damage is done and it's too
    late to change the library name now. To help with damage control, I
    have provided an extension library called TableBC, which bridges all
    the functionality of Vexorian's Table except for 2-D string arrays &
    the ".flush(integer)" method. I use ".flush()" to flush a child hash-
    table, because I wanted the API in NewTable to reflect the API of real
    hashtables (I thought this would be more intuitive).
   
    API
   
    ------------
    struct Table
    | static method create takes nothing returns Table
    |     create a new Table
    |    
    | method destroy takes nothing returns nothing
    |     destroy it
    |    
    | method flush takes nothing returns nothing
    |     flush all stored values inside of it
    |    
    | method remove takes integer key returns nothing
    |     remove the value at index "key"
    |    
    | method operator []= takes integer key, $TYPE$ value returns nothing
    |     assign "value" to index "key"
    |    
    | method operator [] takes integer key returns $TYPE$
    |     load the value at index "key"
    |    
    | method has takes integer key returns boolean
    |     whether or not the key was assigned
    |
    ----------------
    struct TableArray
    | static method operator [] takes integer array_size returns TableArray
    |     create a new array of Tables of size "array_size"
    |
    | method destroy takes nothing returns nothing
    |     destroy it
    |
    | method flush takes nothing returns nothing
    |     flush and destroy it
    |
    | method operator size takes nothing returns integer
    |     returns the size of the TableArray
    |
    | method operator [] takes integer key returns Table
    |     returns a Table accessible exclusively to index "key"
*/

   
globals
    private integer less = 0    //Index generation for TableArrays (below 0).
    private integer more = 8190 //Index generation for Tables.
    //Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
   
    private hashtable ht = InitHashtable()
    private key sizeK
    private key listK
endglobals
   
private struct dex extends array
    static method operator size takes nothing returns Table
        return sizeK
    endmethod
    static method operator list takes nothing returns Table
        return listK
    endmethod
endstruct
   
private struct handles extends array
    method has takes integer key returns boolean
        return HaveSavedHandle(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSavedHandle(ht, this, key)
    endmethod
endstruct
   
private struct agents extends array
    method operator []= takes integer key, agent value returns nothing
        call SaveAgentHandle(ht, this, key, value)
    endmethod
endstruct
   
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$(ht, this, key, value)
    endmethod
    method has takes integer key returns boolean
        return HaveSaved$SUPER$(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSaved$SUPER$(ht, this, key)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$Handle(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$Handle(ht, this, key, value)
    endmethod
    method has takes integer key returns boolean
        return HaveSavedHandle(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSavedHandle(ht, this, key)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
   
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
   
struct Table extends array
   
    // Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
    implement realm
    implement integerm
    implement booleanm
    implement stringm
    implement playerm
    implement widgetm
    implement destructablem
    implement itemm
    implement unitm
    implement abilitym
    implement timerm
    implement triggerm
    implement triggerconditionm
    implement triggeractionm
    implement eventm
    implement forcem
    implement groupm
    implement locationm
    implement rectm
    implement boolexprm
    implement soundm
    implement effectm
    implement unitpoolm
    implement itempoolm
    implement questm
    implement questitemm
    implement defeatconditionm
    implement timerdialogm
    implement leaderboardm
    implement multiboardm
    implement multiboarditemm
    implement trackablem
    implement dialogm
    implement buttonm
    implement texttagm
    implement lightningm
    implement imagem
    implement ubersplatm
    implement regionm
    implement fogstatem
    implement fogmodifierm
    implement hashtablem
   
    method operator handle takes nothing returns handles
        return this
    endmethod
   
    method operator agent takes nothing returns agents
        return this
    endmethod
   
    //set this = tb[GetSpellAbilityId()]
    method operator [] takes integer key returns Table
        return LoadInteger(ht, this, key) //return this.integer[key]
    endmethod
   
    //set tb[389034] = 8192
    method operator []= takes integer key, Table tb returns nothing
        call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
    endmethod
   
    //set b = tb.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
    endmethod
   
    //call tb.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
    endmethod
   
    //Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
   
    //local Table tb = Table.create()
    static method create takes nothing returns Table
        local Table this = dex.list[0]
       
        if this == 0 then
            set this = more + 1
            set more = this
        else
            set dex.list[0] = dex.list[this]
            call dex.list.remove(this) //Clear hashed memory
        endif
       
        debug set dex.list[this] = -1
        return this
    endmethod
   
    // Removes all data from a Table instance and recycles its index.
    //
    //     call tb.destroy()
    //
    method destroy takes nothing returns nothing
        debug if dex.list[this] != -1 then
            debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
            debug return
        debug endif
       
        call this.flush()
       
        set dex.list[this] = dex.list[0]
        set dex.list[0] = this
    endmethod
   
    //! runtextmacro optional TABLE_BC_METHODS()
endstruct
   
//! runtextmacro optional TABLE_BC_STRUCTS()
   
struct TableArray extends array
   
    //Returns a new TableArray to do your bidding. Simply use:
    //
    //    local TableArray ta = TableArray[array_size]
    //
    static method operator [] takes integer array_size returns TableArray
        local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
        local TableArray this = tb[0]         //The last-destroyed TableArray that had this array size
       
        debug if array_size <= 0 then
            debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
            debug return 0
        debug endif
       
        if this == 0 then
            set this = less - array_size
            set less = this
        else
            set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
            call tb.remove(this)  //Clear hashed memory
        endif
       
        set dex.size[this] = array_size //This remembers the array size
        return this
    endmethod
   
    //Returns the size of the TableArray
    method operator size takes nothing returns integer
        return dex.size[this]
    endmethod
   
    //This magic method enables two-dimensional[array][syntax] for Tables,
    //similar to the two-dimensional utility provided by hashtables them-
    //selves.
    //
    //ta[integer a].unit[integer b] = unit u
    //ta[integer a][integer c] = integer d
    //
    //Inline-friendly when not running in debug mode
    //
    method operator [] takes integer key returns Table
        static if DEBUG_MODE then
            local integer i = this.size
            if i == 0 then
                call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                return 0
            elseif key < 0 or key >= i then
                call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                return 0
            endif
        endif
        return this + key
    endmethod
   
    //Destroys a TableArray without flushing it; I assume you call .flush()
    //if you want it flushed too. This is a public method so that you don't
    //have to loop through all TableArray indices to flush them if you don't
    //need to (ie. if you were flushing all child-keys as you used them).
    //
    method destroy takes nothing returns nothing
        local Table tb = dex.size[this.size]
       
        debug if this.size == 0 then
            debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
            debug return
        debug endif
       
        if tb == 0 then
            //Create a Table to index recycled instances with their array size
            set tb = Table.create()
            set dex.size[this.size] = tb
        endif
       
        call dex.size.remove(this) //Clear the array size from hash memory
       
        set tb[this] = tb[0]
        set tb[0] = this
    endmethod
   
    private static Table tempTable
    private static integer tempEnd
   
    //Avoids hitting the op limit
    private static method clean takes nothing returns nothing
        local Table tb = .tempTable
        local integer end = tb + 0x1000
        if end < .tempEnd then
            set .tempTable = end
            call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        else
            set end = .tempEnd
        endif
        loop
            call tb.flush()
            set tb = tb + 1
            exitwhen tb == end
        endloop
    endmethod
   
    //Flushes the TableArray and also destroys it. Doesn't get any more
    //similar to the FlushParentHashtable native than this.
    //
    method flush takes nothing returns nothing
        debug if this.size == 0 then
            debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
            debug return
        debug endif
        set .tempTable = this
        set .tempEnd = this + this.size
        call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
        call this.destroy()
    endmethod
   
endstruct
   
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array

    //Enables myHash[parentKey][childKey] syntax.
    //Basically, it creates a Table in the place of the parent key if
    //it didn't already get created earlier.
    method operator [] takes integer index returns Table
        local Table t = Table(this)[index]
        if t == 0 then
            set t = Table.create()
            set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
        endif
        return t
    endmethod

    //You need to call this on each parent key that you used if you
    //intend to destroy the HashTable or simply no longer need that key.
    method remove takes integer index returns nothing
        local Table t = Table(this)[index]
        if t != 0 then
            call t.destroy()
            call Table(this).remove(index)
        endif
    endmethod
   
    //Added in version 4.1
    method has takes integer index returns boolean
        return Table(this).has(index)
    endmethod
   
    //HashTables are just fancy Table indices.
    method destroy takes nothing returns nothing
        call Table(this).destroy()
    endmethod
   
    //Like I said above...
    static method create takes nothing returns thistype
        return Table.create()
    endmethod

endstruct

endlibrary
/*
    Naming System v 1.1
        by Pinzu

    This library enables the creation of name pools that can be combined to give regular units
    hero names, and a few other basic things.
   
    Requirements:

        Table by Bribe
          https://hiveworkshop.com/threads/snippet-new-table.188084/
       
    Configuraton
   
        1)  After copying the library to your map you can change public globals to your chosing.
        2)  To use it you have to create a setup trigger somewhere. See "UnitNamingOnEvent" for more.

    API
   
    function UnitHasNamePool takes unit u returns boolean  
        returns true if the unit exists in any TypeNamePool.

    function ChangeUnitFullName takes unit u, string firstname, string lastname, string unitname returns nothing
        Changes the units name to provided firstname, lastname and unitname.
       
    function GetUnitNamePool takes unit u returns TypeNamePool
        Returns the name pool that a certain unit belongs to. Useful if you want access to random names from there.
       
    function SetUnitRandomNameSimple takes unit u returns boolean
        Will assign a unit a random name if it belongs to any random unit name pool. Does not store any data about the unit names.
       
    A simple struct containing only a list of strings. You can create it, destroy it, add names to it and draw a random name from it.

    struct NamePool
       
        static method create takes nothing returns thistype
       
        method destroy takes nothing returns nothing
       
        method add takes string name returns thistype
       
        method getRandom takes nothing returns string
   
   
    This struct contains 2 NamePools and a list of unit-types that the name pool belongs to.
   
    struct TypeNamePool
   
        static method create takes NamePool firstPool, NamePool lastPool returns thistype
            Creates it. Requires 2 NamePool to draw first and last names from.
           
        method destroy takes nothing returns nothing
            Deallocates it.
       
        method remove takes integer unitTypeId returns boolean
            Removes a saved unit-type from the pool.
       
        method add takes integer unitTypeId returns thistype
            Adds a unit-type to the pool. Note a unit can only belong to one NamePool at a time.
           
        method getRandomFirstName takes nothing returns string
            Draws a random first name from the pool.
           
        method getRandomLastName takes nothing returns string
            Draws a random last name from the pool.
           
   
    //     
    //  Extended features provides additional API used to replace the regular natives for name management.
    //  Among other things allows to set units first and last name separately, and give units hero proper names. '
    //  
   
    API
   
    function SetUnitNormalName takes unit u, string normalname returns nothing
        Basically the same as 'BlzSetUnitName' except that it keeps the proper name if any such is set
 
    function GetUnitNormalName takes unit u returns string
        Basically the same as 'GetUnitName', excludes the proper names if such exist
        Note that it only works for units that have been configured by the system
   
    function SetUnitProperName takes unit u, string firstname, string lastname returns nothing
        Same as setting a heroes name, devided in first and last names
   
    function GetUnitProperName takes unit u returns string
        Returns the units proper name with both first and last name if such exist
       
    function GetUnitFirstName takes unit u returns string
        Returns the first name of the unit
   
    function SetUnitFirstName takes unit u, string firstname returns nothing
        Changes the units first name
   
    function GetUnitLastName takes unit u returns string
        Returns the last name of the unit
   
    function SetUnitLastName takes unit u, string lastname returns nothing
        Changes the units last name
 
    function SetUnitRandomName takes unit u returns boolean
        Gives a unit a random name based on the unit-type. WARNING: Will store data about the named unit which needs to be removed when the
        unit is no longer used to prevent leaks.
        Note that if the unit-type is not configured to any unit pool the unit wont be affected

    function SaveDefaultName takes unit u returns nothing
        This will save the equivalent of GetUnitName and BlzGetHeroProperName the first time its
        used by the unit. Any times called after that will be ignored, the purpose is to be able
        to reset the units name to the default name.

    function DestroyUnitName takes unit u returns nothing
        Used to deallocate unit names from units. Should be used on deindex
*/


library UnitNaming uses Table optional UnitDex, optional UnitIndexerGUI optional WorldBounds

    /* Configurables */
   
    globals
        boolean keepNormalNames     = true                  // Flag for if the unit-type name should be kept
       
        boolean colorHeroes         = true                  // Flag for if hero names should be colored
       
        string color                = "|cffffcc00"          // The unit proper name color
       
       
        // Used to include extended features, such as being able to change different names associated with a unit and retrieving it.
        //
        constant boolean INCLUDE_UNAME_EXTENDED             = false
       
        // This will save the default name of the unit when it is given a random name upon being indexed.
        // Recommended setting for this is off, unless you have a special reason for using it.
        // What it does is basically when you destroy allocated unit name it will reset to default.
        //
        private constant boolean SAVE_DEFAULT_NAME          = false
       
    endglobals
 
    /* This is the implementation of the name design, you can switch things around here to whatever you prefer, if you know what you are doing. */
    function ChangeUnitFullName takes unit u, string firstname, string lastname, string unitname returns nothing
        if IsUnitType(u, UNIT_TYPE_HERO) then
            if keepNormalNames then
                call BlzSetUnitName(u, unitname)
            else
                call BlzSetUnitName(u, " ")
            endif
            if colorHeroes then
                call BlzSetHeroProperName(u, color + firstname + " " + lastname + "|r")
            else
                call BlzSetHeroProperName(u, firstname + " " + lastname)
            endif
        else
            if StringLength(firstname) > 0 or StringLength(lastname) > 0 then
                if keepNormalNames then
                    call BlzSetUnitName(u, color + firstname + " " + lastname + "|r|n" + unitname)
                else
                    call BlzSetUnitName(u, color + firstname + " " + lastname + "|r|n")
                endif
            else
                call BlzSetUnitName(u, unitname)
            endif
        endif
    endfunction
   
    /* This is the simple method of giving a unit a random name, it will not store any data to the unit. */
    function SetUnitRandomNameSimple takes unit u returns boolean
        local TypeNamePool namepool = TypeNamePool.typesNameTable[GetUnitTypeId(u)]
        if namepool != 0 then
            call ChangeUnitFullName(u, namepool.getRandomFirstName(), namepool.getRandomLastName(), GetUnitName(u))
            return true
        endif
        return false
    endfunction
 
    function GetUnitNamePool takes unit u returns TypeNamePool
        return TypeNamePool.typesNameTable[GetUnitTypeId(u)]
    endfunction
   
    function UnitHasNamePool takes unit u returns boolean
        return TypeNamePool.typesNameTable.has(GetUnitTypeId(u))
    endfunction
 
    struct TypeNamePool
        private Table types
        private integer size
        private NamePool firstNamePool
        private NamePool lastNamePool
   
        static Table typesNameTable = 0
   
        static method setup takes nothing returns nothing
            if .typesNameTable == 0 then
                set typesNameTable = Table.create()
            endif
        endmethod
   
        method getRandomFirstName takes nothing returns string
            return firstNamePool.getRandom()
        endmethod
   
        method getRandomLastName takes nothing returns string
            return lastNamePool.getRandom()
        endmethod
   
        static method create takes NamePool firstPool, NamePool lastPool returns thistype
            local thistype this = .allocate()
            set this.types = Table.create()
            set this.firstNamePool = firstPool
            set this.lastNamePool = lastPool
            set this.size = 0
            return this
        endmethod
   
        private method indexOf takes integer unitTypeId returns integer
            local integer i = 0
            loop
                exitwhen i == .size
                if .types[i] == unitTypeId then
                    return i
                endif
                set i = i + 1
            endloop
            return -1
        endmethod
   
        method remove takes integer unitTypeId returns boolean
            if thistype.typesNameTable[unitTypeId] == this then
                call thistype.typesNameTable.remove(unitTypeId)
                set .size = .size - 1
                set .types[.indexOf(unitTypeId)] = .types[.size]
                call .types.remove(.size)
                return true
            endif
            debug call BJDebugMsg("[Library_UnitNaming] TypeNames.remove: Unit Type does not belong to this name pool.")
            return false
        endmethod
   
        method add takes integer unitTypeId returns thistype
            local thistype prev = thistype.typesNameTable[unitTypeId]
            if prev != 0 then
                call prev.remove(unitTypeId)
            endif
            set thistype.typesNameTable[unitTypeId] = this
            set .types[.size] = unitTypeId
            set .size = .size + 1
            return this
        endmethod
   
        method destroy takes nothing returns nothing
            call types.destroy()
            call .deallocate()
        endmethod
    endstruct
 
    struct NamePool
        private Table names
        private integer size
   
        static method create takes nothing returns thistype
            local thistype this = .allocate()
            set this.names = Table.create()
            set this.size = 0
            return this
        endmethod
   
        method getRandom takes nothing returns string
            debug if .size <= 0 then
                debug call BJDebugMsg("[Library_UnitNaming] NamePool.getRandom: No names to draw from.")
                debug return ""
            debug endif
            return .names.string[GetRandomInt(0, .size - 1)]
        endmethod
   
        method add takes string name returns thistype
            set .names.string[.size] = name
            set .size = .size + 1
            return this
        endmethod
   
        method destroy takes nothing returns nothing
            local integer i = 0
            loop
                exitwhen i == .size
                set .names.string[i] = null
                set i = i + 1
            endloop
            call names.destroy()
            call .deallocate()
        endmethod
    endstruct
   
/*
    Extension Library
*/

   
static if INCLUDE_UNAME_EXTENDED then

    globals
        private constant integer H_NAME     = -1
        private constant integer U_NAME     = 1
    endglobals
       
    struct UnitName

        static Table uTable = 0
        static Table defaultName = 0

        string firstname   
        string lastname
        string unitname
        private integer uid

       
        static method create takes unit u, string first, string last returns thistype
            local thistype this = .allocate()
            set this.firstname = first
            set this.lastname = last
            if not (keepNormalNames)then
                set this.unitname = " "
            else
                set this.unitname = GetUnitName(u)
            endif
            set this.uid = GetHandleId(u)
            set uTable[this.uid] = this
            return this
        endmethod
       
        method destroy takes nothing returns nothing
            call uTable.remove(.uid)
            set .firstname = null
            set .lastname = null
            set .unitname = null
            call .deallocate()
        endmethod
       
        static method setup takes nothing returns nothing
            if .uTable == 0 then
                set .uTable = Table.create()
            endif
        endmethod
    endstruct
   
    function SaveDefaultName takes unit u returns nothing
        local integer id = GetHandleId(u)
        if UnitName.defaultName == 0 then
            set UnitName.defaultName = Table.create()
        endif
        if UnitName.defaultName.string.has(U_NAME*id) then
            return
        endif
        set UnitName.defaultName.string[U_NAME*id] = GetUnitName(u)
        if IsUnitType(u, UNIT_TYPE_HERO) then
            set UnitName.defaultName.string[H_NAME*id] = GetHeroProperName(u)
        endif
    endfunction
   
    function SetUnitNormalName takes unit u, string normalname returns nothing
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        static if SAVE_DEFAULT_NAME then
            call SaveDefaultName(u)
        endif
        if name == 0 then
            if normalname == "" then
                call BlzSetUnitName(u, " ")
            else
                call BlzSetUnitName(u, normalname)
            endif
        else
            set name.unitname = normalname
            if not keepNormalNames then
                set keepNormalNames = true  // allows an exception
                call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
                set keepNormalNames = false
            else
                call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
            endif
        endif
    endfunction
   
    function SetUnitProperName takes unit u, string firstname, string lastname returns nothing
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        static if SAVE_DEFAULT_NAME then
            call SaveDefaultName(u)
        endif
        if name == 0 then
            set name = UnitName.create(u, firstname, lastname)
        else
            set name.firstname = firstname
            set name.lastname = lastname
        endif
        call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
    endfunction
   
    function SetUnitFirstName takes unit u, string firstname returns nothing
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        static if SAVE_DEFAULT_NAME then
            call SaveDefaultName(u)
        endif
        if name == 0 then
            set name = UnitName.create(u, firstname, "")
        else
            set name.firstname = firstname
        endif
        call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
    endfunction
   
    function SetUnitLastName takes unit u, string lastname returns nothing
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        static if SAVE_DEFAULT_NAME then
            call SaveDefaultName(u)
        endif
        if name == 0 then
            set name = UnitName.create(u, "", lastname)
        else
            set name.lastname = lastname
        endif
        call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
    endfunction
   
    function GetUnitProperName takes unit u returns string
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        if name == 0 then
            if (IsUnitType(u, UNIT_TYPE_HERO)) then
                return GetHeroProperName(u)
            endif
            return ""
        endif
        return name.firstname + " " + name.lastname
    endfunction
   
    function GetUnitFirstName takes unit u returns string
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        if name == 0 then
            return ""
        endif
        return name.firstname
    endfunction
   
    function GetUnitLastName takes unit u returns string
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        if name == 0 then
            return ""
        endif
        return name.lastname
    endfunction
   
    function GetUnitNormalName takes unit u returns string
        local UnitName name = UnitName.uTable[GetHandleId(u)]
        if name == 0 then
            return ""
        endif
        return name.unitname
    endfunction

    function DestroyUnitName takes unit u returns nothing
        local integer id = GetHandleId(u)
        local UnitName name = UnitName.uTable[id]
        if name != 0 then
            call name.destroy()
        endif
        if UnitName.defaultName.string.has(U_NAME*id) then
            call BlzSetUnitName(u, UnitName.defaultName.string[U_NAME*id])
            call UnitName.defaultName.string.remove(U_NAME*id)
        endif
        if UnitName.defaultName.string.has(H_NAME*id) then
            call BlzSetHeroProperName(u, UnitName.defaultName.string[H_NAME*id])
            call UnitName.defaultName.string.remove(H_NAME*id)
        endif
    endfunction
   
    function SetUnitRandomName takes unit u returns boolean
        local UnitName name
        local TypeNamePool namepool = TypeNamePool.typesNameTable[GetUnitTypeId(u)]
        if namepool == 0 then
            return false
        endif
        static if SAVE_DEFAULT_NAME then
            call SaveDefaultName(u)
        endif
        set name = UnitName.uTable[GetHandleId(u)]
        if name == 0 then
            set name = UnitName.create(u, namepool.getRandomFirstName(), namepool.getRandomLastName())
        else
            set name.firstname = namepool.getRandomFirstName()
            set name.firstname = namepool.getRandomLastName()
        endif
        call ChangeUnitFullName(u, name.firstname, name.lastname, name.unitname)
        return true
    endfunction
endif
   
    /*
        Setup
    */

    private struct Init
   
        static if LIBRARY_UnitIndexerGUI then
            private static method onIndex takes nothing returns boolean
                local unit u = GetIndexedUnit()
                static if INCLUDE_UNAME_EXTENDED then
                    call SetUnitRandomName(u)
                else
                    call SetUnitRandomNameSimple(u)
                endif
                set u = null
                return false
            endmethod
               
            static if INCLUDE_UNAME_EXTENDED then  
                private static method onDeindex takes nothing returns boolean
                    local unit u = GetIndexedUnit()
                    call DestroyUnitName(u)
                    set u = null
                    return false
                endmethod
            endif
        endif
        static if LIBRARY_UnitDex and not LIBRARY_UnitIndexerGUI then
            private static method onIndex takes nothing returns boolean
                local unit u = GetIndexedUnit()
                static if INCLUDE_UNAME_EXTENDED then
                    call SetUnitRandomName(u)
                else
                    call SetUnitRandomNameSimple(u)
                endif
                set u = null
                return false
            endmethod
               
            static if INCLUDE_UNAME_EXTENDED then  
                private static method onDeindex takes nothing returns boolean
                    static if INCLUDE_UNAME_EXTENDED then
                        local unit u = GetIndexedUnit()
                        call DestroyUnitName(u)
                        set u = null
                    endif
                    return false
                endmethod
            endif
        endif
       
        static if not LIBRARY_UnitIndexerGUI and not LIBRARY_UnitDex and not INCLUDE_UNAME_EXTENDED then
            private static method onEnterMap takes nothing returns boolean
                call SetUnitRandomNameSimple(GetTriggerUnit()) // No memory saved to unit
                return false
            endmethod
        endif
       
        private static method onTimer takes nothing returns nothing
                local timer t = GetExpiredTimer()
                local group g = CreateGroup()
                local rect r
                local unit u
                local trigger trg
                static if LIBRARY_WorldBounds then
                    set r = WorldBounds.world
                else
                    set r = GetWorldBounds()
                endif
                call GroupEnumUnitsInRect(g, r, null)
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    call GroupRemoveUnit(g, u)
                    static if INCLUDE_UNAME_EXTENDED then  
                        static if LIBRARY_UnitIndexerGUI then
                            call SetUnitRandomName(u)
                        elseif LIBRARY_UnitDex then
                            call SetUnitRandomName(u)
                        else
                            call SetUnitRandomNameSimple(u)
                        endif
                    else
                        call SetUnitRandomNameSimple(u)
                    endif
                endloop
                static if LIBRARY_UnitIndexerGUI then
                    call OnUnitIndex(function thistype.onIndex)
                    static if INCLUDE_UNAME_EXTENDED then
                        call OnUnitDeindex(function thistype.onDeindex)
                    endif
                endif
                static if LIBRARY_UnitDex and not LIBRARY_UnitIndexerGUI then
                    call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
                    static if INCLUDE_UNAME_EXTENDED then
                        call RegisterUnitIndexEvent(Filter(function thistype.onDeindex), EVENT_UNIT_DEINDEX)
                    endif
                endif
                // If no UnitIndexer and extended features disabled then handle entering units
                static if not LIBRARY_UnitDex and not LIBRARY_UnitIndexerGUI and not INCLUDE_UNAME_EXTENDED then
                    set trg = CreateTrigger()
                    call TriggerRegisterEnterRectSimple(trg, r)
                    call TriggerAddAction(trg, function thistype.onEnterMap)
                    set trg = null
                endif
                static if not LIBRARY_WorldBounds then
                    call RemoveRect(r)
                endif
                call DestroyGroup(g)
                call PauseTimer(t)
                call DestroyTimer(t)
                set t = null
                set g = null
                set r = null
        endmethod

        private static method onInit takes nothing returns nothing
            local timer t = CreateTimer()
            call TimerStart(t, 0.2, false, function thistype.onTimer)   // We delay setup slightly
            set t = null   
            call TypeNamePool.setup()
            static if INCLUDE_UNAME_EXTENDED then
                call UnitName.setup()
            endif
        endmethod
    endstruct

endlibrary
 
library WorldBounds /* v2.0.0.0

************************************************************************************
*
*   struct WorldBounds extends array
*
*       Fields
*       -------------------------
*
*           readonly static integer maxX
*           readonly static integer maxY
*           readonly static integer minX
*           readonly static integer minY
*
*           readonly static integer centerX
*           readonly static integer centerY
*
*           readonly static rect world
*           readonly static region worldRegion
*
************************************************************************************/


    private module WorldBoundInit
        private static method onInit takes nothing returns nothing
            set world = GetWorldBounds()
           
            set maxX = R2I(GetRectMaxX(world))
            set maxY = R2I(GetRectMaxY(world))
            set minX = R2I(GetRectMinX(world))
            set minY = R2I(GetRectMinY(world))
           
            set centerX = R2I((maxX + minX)/2)
            set centerY = R2I((minY + maxY)/2)
           
            set worldRegion = CreateRegion()
           
            call RegionAddRect(worldRegion, world)
        endmethod
    endmodule
   
    struct WorldBounds extends array
        readonly static integer maxX
        readonly static integer maxY
        readonly static integer minX
        readonly static integer minY
       
        readonly static integer centerX
        readonly static integer centerY
       
        readonly static rect world
       
        readonly static region worldRegion
       
        implement WorldBoundInit
    endstruct
endlibrary
 
This trigger works in two key phases:

1) During map initialization, enumerate all existing units of all players to give them an index.
2) Adds a second event to itself to index new units as they enter the map.

As a unit enters the map, check for any old units that may have been removed at some point in order to free their index.
Unit Indexer
  Events
    Map initialization
  Conditions
  Actions
    Custom script: call ExecuteFunc("InitializeUnitIndexer")
    Custom script: endfunction
    -------- --------
    -------- This is the core function - it provides an index all existing units and for units as they enter the map --------
    -------- --------
    Custom script: function IndexUnit takes nothing returns boolean
    Custom script: local integer pdex = udg_UDex
    Custom script: local integer ndex
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        IsUnitPreplaced[0] Equal to False
      Then - Actions
        -------- --------
        -------- Check for removed units for every (32) new units created --------
        -------- --------
        Set UDexWasted = (UDexWasted + 1)
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            UDexWasted Equal to 32
          Then - Actions
            Set UDexWasted = 0
            Set UDex = UDexNext[0]
            Custom script: loop
            Custom script: exitwhen udg_UDex == 0
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                (Custom value of UDexUnits[UDex]) Equal to 0
              Then - Actions
                -------- --------
                -------- Remove index from linked list --------
                -------- --------
                Custom script: set ndex = udg_UDexNext[udg_UDex]
                Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
                Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
                Set UDexPrev[UDex] = 0
                Set IsUnitPreplaced[UDex] = False
                -------- --------
                -------- Fire deindex event for UDex --------
                -------- --------
                Set UnitIndexEvent = 2.00
                Set UnitIndexEvent = 0.00
                -------- --------
                -------- Recycle the index for later use --------
                -------- --------
                Set UDexUnits[UDex] = No unit
                Set UDexNext[UDex] = UDexRecycle
                Set UDexRecycle = UDex
                Custom script: set udg_UDex = ndex
              Else - Actions
                Set UDex = UDexNext[UDex]
            Custom script: endloop
          Else - Actions
      Else - Actions
    -------- --------
    -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
    -------- - Example: --------
    -------- -- Set UnitIndexerEnabled = False --------
    -------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
    -------- -- Set UnitIndexerEnabled = True --------
    -------- --------
    -------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
    -------- --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        UnitIndexerEnabled Equal to True
        (Custom value of (Matching unit)) Equal to 0
      Then - Actions
        -------- --------
        -------- Generate a unique integer index for this unit --------
        -------- --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            UDexRecycle Equal to 0
          Then - Actions
            Set UDex = (UDexGen + 1)
            Set UDexGen = UDex
          Else - Actions
            Set UDex = UDexRecycle
            Set UDexRecycle = UDexNext[UDex]
        -------- --------
        -------- Link index to unit, unit to index --------
        -------- --------
        Set UDexUnits[UDex] = (Matching unit)
        Unit - Set the custom value of UDexUnits[UDex] to UDex
        Set IsUnitPreplaced[UDex] = IsUnitPreplaced[0]
        -------- --------
        -------- Use a doubly-linked list to store all active indexes --------
        -------- --------
        Set UDexPrev[UDexNext[0]] = UDex
        Set UDexNext[UDex] = UDexNext[0]
        Set UDexNext[0] = UDex
        -------- --------
        -------- Fire index event for UDex --------
        -------- --------
        Set UnitIndexEvent = 0.00
        Set UnitIndexEvent = 1.00
        Set UnitIndexEvent = 0.00
      Else - Actions
    Custom script: set udg_UDex = pdex
    Custom script: return false
    Custom script: endfunction
    -------- --------
    -------- The next function initializes the core of the system --------
    -------- --------
    Custom script: function InitializeUnitIndexer takes nothing returns nothing
    Custom script: local integer i = 0
    Custom script: local region re = CreateRegion()
    Custom script: local rect r = GetWorldBounds()
    Custom script: local boolexpr b = Filter(function IndexUnit)
    Set UnitIndexEvent = -1.00
    Set UnitIndexerEnabled = True
    Set IsUnitPreplaced[0] = True
    Custom script: call RegionAddRect(re, r)
    Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, b)
    Custom script: call RemoveRect(r)
    Custom script: set re = null
    Custom script: set r = null
    Custom script: loop
    Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
    Custom script: set i = i + 1
    Custom script: exitwhen i == bj_MAX_PLAYER_SLOTS
    Custom script: endloop
    Custom script: set b = null
    -------- --------
    -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
    -------- --------
    Set IsUnitPreplaced[0] = False
    Set UnitIndexEvent = 3.00
 
 
NamePoolSetupGUI
  Events
  Conditions
  Actions
    Custom script: local TypeNamePool sFullNames
    Custom script: local NamePool sFirstNames = NamePool.create()
    Custom script: local NamePool sLastNames = NamePool.create()
    -------- Setup First Names --------
    Custom script: local integer i = 0
    Custom script: loop
    Custom script: exitwhen udg_nFirstNames[i] == null
    Custom script: call sFirstNames .add(udg_nFirstNames[i])
    Custom script: set udg_nFirstNames[i] = null
    Custom script: set i = i + 1
    Custom script: endloop
    -------- Setup Last Names --------
    Custom script: set i = 0
    Custom script: loop
    Custom script: exitwhen udg_nLastNames[i] == null
    Custom script: call sLastNames.add(udg_nLastNames[i])
    Custom script: set udg_nLastNames[i] = null
    Custom script: set i = i + 1
    Custom script: endloop
    -------- Setup Unit Type Name Pool --------
    Custom script: set sFullNames = TypeNamePool.create(sFirstNames, sLastNames)
    Custom script: set i = 0
    Custom script: loop
    Custom script: exitwhen udg_nUnitTypes[i] == 0
    Custom script: call sFullNames.add(udg_nUnitTypes[i])
    Custom script: set udg_nUnitTypes[i] = 0
    Custom script: set i = i + 1
    Custom script: endloop
SetupNamesGUI
  Events
    Map initialization
  Conditions
  Actions
    -------- Group 1 --------
    -------- First Names --------
    Set nFirstNames[0] = Peter
    Set nFirstNames[1] = Kenny
    Set nFirstNames[2] = John
    Set nFirstNames[3] = Storm
    Set nFirstNames[4] = Pudge
    Set nFirstNames[5] = Kyle
    Set nFirstNames[6] = Jimbo
    -------- First Names --------
    Set nLastNames[0] = Bigley
    Set nLastNames[1] = Crook
    Set nLastNames[2] = Hartley
    -------- Last Names --------
    Set nUnitTypes[0] = Ghoul
    Set nUnitTypes[1] = Abomination
    Set nUnitTypes[2] = Necromancer
    Set nUnitTypes[3] = Zombie
    Trigger - Run NamePoolSetupGUI <gen> (ignoring conditions)
    -------- Group 2 --------
    Set nFirstNames[0] = Sarah
    Set nFirstNames[1] = Margret
    Set nFirstNames[2] = Victoria
    Set nFirstNames[3] = Sophie
    Set nFirstNames[4] = Sylvana
    -------- First Names --------
    Set nLastNames[0] = Bigley
    Set nLastNames[1] = Crook
    Set nLastNames[2] = Hartley
    -------- Last Names --------
    Set nUnitTypes[0] = Banshee
    Set nUnitTypes[1] = Dark Ranger
    Trigger - Run NamePoolSetupGUI <gen> (ignoring conditions)
ChangeUnitName
  Events
  Conditions
  Actions
    -------- Will change the unit name to a new name from the unit pool it belongs to --------
    -------- Nothing will be saved, this is the most simplest use case --------
    Custom script: call ChangeUnitFullName(udg_nUnit, udg_nFirstName, udg_nLastName, udg_nUnitName)
DeallocateUnitExample
  Events
  Conditions
  Actions
    Custom script: static if INCLUDE_UNAME_EXTENDED then
    Custom script: call DestroyUnitName(udg_nUnit)
    Custom script: endif
Commands
  Events
    Player - Player 1 (Red) types a chat message containing - as A substring
  Conditions
  Actions
    -------- These functions are all part of the extended features --------
    Custom script: static if INCLUDE_UNAME_EXTENDED then
    -------- GETTERS --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -getfirst
      Then - Actions
        Custom script: set udg_nFirstName = GetUnitFirstName(udg_nUnit)
        Game - Display to (All players) the text: (GUI first: + nFirstName)
        Skip remaining actions
      Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -getlast
      Then - Actions
        Custom script: set udg_nFirstName = GetUnitLastName(udg_nUnit)
        Game - Display to (All players) the text: (GUI Last: + nFirstName)
        Skip remaining actions
      Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -getproper
      Then - Actions
        Custom script: set udg_nFirstName = GetUnitProperName(udg_nUnit)
        Game - Display to (All players) the text: (GUI proper: + nFirstName)
        Skip remaining actions
      Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -getuname
      Then - Actions
        Custom script: set udg_nFirstName = GetUnitNormalName(udg_nUnit)
        Game - Display to (All players) the text: (GUI uname: + nFirstName)
        Skip remaining actions
      Else - Actions
    -------- SETTERS --------
    Set i = (Length of -setfirst)
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Substring((Entered chat string), 1, i)) Equal to -setfirst
      Then - Actions
        Set nFirstName = (Substring((Entered chat string), (i + 2), (Length of (Entered chat string))))
        Game - Display to (All players) the text: (first name: + nFirstName)
        Custom script: call SetUnitFirstName(udg_nUnit, udg_nFirstName)
        Skip remaining actions
      Else - Actions
    Set i = (Length of -setlast)
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Substring((Entered chat string), 1, i)) Equal to -setlast
      Then - Actions
        Set nLastName = (Substring((Entered chat string), (i + 2), (Length of (Entered chat string))))
        Game - Display to (All players) the text: (last name: + nLastName)
        Custom script: call SetUnitLastName(udg_nUnit, udg_nLastName)
        Skip remaining actions
      Else - Actions
    Set i = (Length of -setuname)
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Substring((Entered chat string), 1, i)) Equal to -setuname
      Then - Actions
        Set nFirstName = (Substring((Entered chat string), (i + 2), (Length of (Entered chat string))))
        Game - Display to (All players) the text: (unit name: + nLastName)
        Custom script: call SetUnitNormalName(udg_nUnit, udg_nFirstName)
        Skip remaining actions
      Else - Actions
    -------- DESTROY --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -destroy
      Then - Actions
        Game - Display to (All players) the text: destroy
        Custom script: call DestroyUnitName(udg_nUnit)
        Skip remaining actions
      Else - Actions
    Custom script: endif
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Entered chat string) Equal to -random
      Then - Actions
        Custom script: static if INCLUDE_UNAME_EXTENDED then
        Custom script: call SetUnitRandomName(udg_nUnit)
        Custom script: else
        Custom script: call SetUnitRandomNameSimple(udg_nUnit)
        Custom script: endif
        Skip remaining actions
      Else - Actions
        Custom script: static if not INCLUDE_UNAME_EXTENDED then
        Game - Display to (All players) the text: You are using commands without having enabled extended features. Only "-random" will work if thats the case.
        Custom script: endif
Changing A Unit Name
  Events
    Player - Player 1 (Red) types a chat message containing -hammer as An exact match
  Conditions
  Actions
    Set nFirstName = Muradin
    Set nLastName = Bronzebeard
    Set nUnitName = It's hammer time
    -------- Changes name of last selected unit to above --------
    Trigger - Run ChangeUnitName <gen> (ignoring conditions)
OnLeave
  Events
  Conditions
  Actions
    -------- RUN THIS TRIGGER TO DEALLOCATE A UNIT NAME TO PREVENT LEAKS --------
    -------- Should only be used for units that are removed from the map / permanently dies and if extended features are enabled --------
    Custom script: static if INCLUDE_UNAME_EXTENDED then
    Custom script: call DestroyUnitName(udg_nUnit)
    Custom script: endif
Selection
  Events
    Player - Player 1 (Red) Selects a unit
  Conditions
  Actions
    Set nUnit = (Triggering unit)