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.

Unit Naming System 1.2

Submitted by Pinzu
This bundle is marked as approved. It works and satisfies the submission rules.
This is a simple little system I made using the new natives from patch 1.29. It gives regular units hero names that can be manipulated by the user. It's core functionality however, is to give units random hero names as they enter the map.

Requirements
  • GUI version requires patch 1.30+
  • vJass version requires patch 1.29+

Features
  • Allows for manipulation of both unit and hero proper names.
  • Enables creation of name pools that you attach to different unit types.
  • Combines pairs of name pools to generate a random full name that can be given to a unit.
  • Both GUI and vJass compatible
Setup:

0) Copy the necessary libraries, minimum is Table and UnitNaming.

1) To automatically name prelaced units and entering units you need a featued UnitIndexer: [System] UnitDex - Unit Indexer or (GUI Unit Indexer 1.4.0.0 with [vJASS] - [Snippet] GUI Unit Indexer -> vJass Plugin). Alternativly, you can set
INCLUDE_UNAME_EXTENDED = false
to just name units at start or when they enter the map.

2) If you wish to include extended features you must set
INCLUDE_UNAME_EXTENDED = true
in the configuration block. This will save first name, last name, unit name to units. Note that
if you aren't using any of the featured UnitIndexers you must manage deallocation yourself by using:
call DestroyUnitName(udg_yourUnit)


3) Styling
Code (vJASS):

        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
       

4) Finally you need to setup your Name pools and associate them with unit types.

  • 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] = Sylvanas
      • Trigger - Run NamePoolSetupGUI <gen> (ignoring conditions)
Code (vJASS):
scope UnitNamingSetup initializer Init
    globals
        NamePool firstNamesMale
        NamePool firstNamesFem
        NamePool lastNames
        TypeNamePool females
        TypeNamePool males
    endglobals
    /*     This is the configuration of the name pools, each UniTypePool consist of two pools of first names
        and which unit-types that it should be applied to.
    */

    private function Init takes nothing returns nothing
        set firstNamesFem = NamePool.create()
        set firstNamesMale = NamePool.create()
        set lastNames = NamePool.create()
        set females = TypeNamePool.create(firstNamesFem, lastNames)
        set males = TypeNamePool.create(firstNamesMale, lastNames)
        call females.add('nvlw').add('nhef').add('hsor')
        call males.add('nvil').add('nvl2').add('Hpal').add('nvk2').add('hfoo').add('hrif')
        call ExecuteFunc("SetupFemaleFirstNames")
        call ExecuteFunc("SetupMaleFirstNames")
        call ExecuteFunc("SetupLastNames")
        endfunction
    function SetupLastNames takes nothing returns nothing
        call lastNames.add("Alcaraz")
            call lastNames.add("Anand")
            call lastNames.add("Appiah")
            call lastNames.add("Appleton")
            call lastNames.add("Archer")
            call lastNames.add("Atkins")
            call lastNames.add("Baldwin")
            call lastNames.add("Ball")
            call lastNames.add("Barker")
            call lastNames.add("Barnes")
            call lastNames.add("Barrett")
            call lastNames.add("Bartley")
            call lastNames.add("Beard")
            call lastNames.add("Beard")
            call lastNames.add("Bell")
              call lastNames.add("Betteridge")
                call lastNames.add("Biddle")
            call lastNames.add("Binns")
            call lastNames.add("Bishop")
            call lastNames.add("Boothroyd")
            call lastNames.add("Boyle")
            call lastNames.add("Briggs")
            call lastNames.add("Bright")
            call lastNames.add("Brinn")
            call lastNames.add("Brown")
            call lastNames.add("Brown")
            call lastNames.add("Capell")
            call lastNames.add("Carden")
            call lastNames.add("Carter")
            call lastNames.add("Cass")
            call lastNames.add("Casson")
            call lastNames.add("Childs")
            call lastNames.add("Clark")
            call lastNames.add("Collyer")
            call lastNames.add("Cooch")
            call lastNames.add("Cook")
            call lastNames.add("Cox")
            call lastNames.add("Cross")
            call lastNames.add("Cunningham")
            call lastNames.add("Cuthbert")
            call lastNames.add("Daines")
            call lastNames.add("Davies")
            call lastNames.add("Davis")
    endfunction
 
    function SetupMaleFirstNames takes nothing returns nothing
        call firstNamesMale.add("Paul")
            call firstNamesMale.add("Brian")
              call firstNamesMale.add("Russell")
            call firstNamesMale.add("Jurgen")
            call firstNamesMale.add("Robert")
            call firstNamesMale.add("Michael")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("Harry")
            call firstNamesMale.add("Jeremy")
            call firstNamesMale.add("Ronald")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Harpal")
            call firstNamesMale.add("Adrian")
            call firstNamesMale.add("Timothy")
            call firstNamesMale.add("Mike")
            call firstNamesMale.add("Timothy")
            call firstNamesMale.add("James")
            call firstNamesMale.add("Alastair")
            call firstNamesMale.add("Jonathan")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("Peter")
            call firstNamesMale.add("William")
            call firstNamesMale.add("Colin")
            call firstNamesMale.add("Craig")
            call firstNamesMale.add("Lucus")
            call firstNamesMale.add("Simon")
            call firstNamesMale.add("David")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Stephen")
            call firstNamesMale.add("Jason")
            call firstNamesMale.add("Doug")
            call firstNamesMale.add("Simon")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("Dennis")
            call firstNamesMale.add("Adrian")
            call firstNamesMale.add("Arthur")
            call firstNamesMale.add("William")
            call firstNamesMale.add("Daniel")
            call firstNamesMale.add("Charles")
            call firstNamesMale.add("Stephen")
            call firstNamesMale.add("John")
            call firstNamesMale.add("David")
            call firstNamesMale.add("Andrew")
            call firstNamesMale.add("Ibrar")
            call firstNamesMale.add("Richard")
            call firstNamesMale.add("Samuel")
            call firstNamesMale.add("Paul")
            call firstNamesMale.add("Patrick")
            call firstNamesMale.add("Shawn")
            call firstNamesMale.add("Gordon")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Glenn")
            call firstNamesMale.add("Edward")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("David")
            call firstNamesMale.add("Jonathan")
            call firstNamesMale.add("Moray")
            call firstNamesMale.add("Paul")
            call firstNamesMale.add("Philip")
            call firstNamesMale.add("Stefan")
            call firstNamesMale.add("Christopher")
            call firstNamesMale.add("Jp")
            call firstNamesMale.add("Simmy")
            call firstNamesMale.add("Steven")
            call firstNamesMale.add("Andrew")
            call firstNamesMale.add("Robert")
            call firstNamesMale.add("Christopher")
            call firstNamesMale.add("Paul")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Gordhanbhai")
              call firstNamesMale.add("Douglas")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Evan")
            call firstNamesMale.add("Stuart")
            call firstNamesMale.add("Timothy")
            call firstNamesMale.add("Craig")
            call firstNamesMale.add("Lukman")
            call firstNamesMale.add("David")
            call firstNamesMale.add("John")
            call firstNamesMale.add("Steven")
            call firstNamesMale.add("Baljinder")
            call firstNamesMale.add("Jag")
            call firstNamesMale.add("Nigel")
            call firstNamesMale.add("Kenneth")
            call firstNamesMale.add("Gavin")
            call firstNamesMale.add("Martin")
            call firstNamesMale.add("Anthony")
            call firstNamesMale.add("Richard")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("Christopher")
            call firstNamesMale.add("Paul")
            call firstNamesMale.add("Mark")
            call firstNamesMale.add("Philip")
            call firstNamesMale.add("Peter")
            call firstNamesMale.add("David")
            call firstNamesMale.add("Keith")
            call firstNamesMale.add("Ben")
    endfunction
 
    function SetupFemaleFirstNames takes nothing returns nothing
        call firstNamesFem.add("Mary")
            call firstNamesFem.add("Seema")
            call firstNamesFem.add("Alice")
            call firstNamesFem.add("Carolyn")
            call firstNamesFem.add("Jacqueline")
            call firstNamesFem.add("Christine")
            call firstNamesFem.add("Lesley")
            call firstNamesFem.add("Kay")
            call firstNamesFem.add("Margaret")
            call firstNamesFem.add("Inez")
            call firstNamesFem.add("Sara")
            call firstNamesFem.add("Rose")
            call firstNamesFem.add("Helena")
            call firstNamesFem.add("Sheila")
            call firstNamesFem.add("Lisa")
            call firstNamesFem.add("Pamela")
              call firstNamesFem.add("Ann")
            call firstNamesFem.add("Kandiah")
            call firstNamesFem.add("Lucia")
            call firstNamesFem.add("Sarah")
            call firstNamesFem.add("Louise")
            call firstNamesFem.add("Barbara")
            call firstNamesFem.add("Julie")
            call firstNamesFem.add("May")
            call firstNamesFem.add("Deirdre")
            call firstNamesFem.add("Susan")
            call firstNamesFem.add("Diane")
            call firstNamesFem.add("Inger")
            call firstNamesFem.add("Clare")
            call firstNamesFem.add("Yvonne")
            call firstNamesFem.add("Angela")
            call firstNamesFem.add("Charlotte")
            call firstNamesFem.add("Sally")
            call firstNamesFem.add("Elaine")
            call firstNamesFem.add("Maureen")
            call firstNamesFem.add("June")
            call firstNamesFem.add("Cheryl")
            call firstNamesFem.add("Anne")
            call firstNamesFem.add("Katie")
            call firstNamesFem.add("Judith")
            call firstNamesFem.add("Adele")
            call firstNamesFem.add("Janine")
            call firstNamesFem.add("Julia")
            call firstNamesFem.add("Rosamund")
            call firstNamesFem.add("Anna")
            call firstNamesFem.add("Anthea")
            call firstNamesFem.add("Patricia")
            call firstNamesFem.add("Jane")
            call firstNamesFem.add("Anne")
            call firstNamesFem.add("Melissa")
            call firstNamesFem.add("Carol")
            call firstNamesFem.add("Beverly")
            call firstNamesFem.add("Elizabeth")
            call firstNamesFem.add("Susan")
            call firstNamesFem.add("Margaret")
            call firstNamesFem.add("Mary")
            call firstNamesFem.add("Phyllis")
            call firstNamesFem.add("Lesley")
            call firstNamesFem.add("Ebonie")
            call firstNamesFem.add("Irene")
            call firstNamesFem.add("Maria")
            call firstNamesFem.add("Lesley")
            call firstNamesFem.add("Kim")
            call firstNamesFem.add("Amy")
            call firstNamesFem.add("Katie")
              call firstNamesFem.add("Jane")
            call firstNamesFem.add("Gillian")
            call firstNamesFem.add("Kathleen")
              call firstNamesFem.add("Claire")
            call firstNamesFem.add("Yvonne")
            call firstNamesFem.add("Mildred")
            call firstNamesFem.add("Dawn")
            call firstNamesFem.add("Brenda")
            call firstNamesFem.add("Patricia")
            call firstNamesFem.add("Elizabeth")
            call firstNamesFem.add("Susan")
            call firstNamesFem.add("Lorraine")
            call firstNamesFem.add("Pamela")
            call firstNamesFem.add("Sharon")
            call firstNamesFem.add("Maria")
            call firstNamesFem.add("Suzanne")
            call firstNamesFem.add("Susan")
            call firstNamesFem.add("Jackie")
            call firstNamesFem.add("Victoria")
            call firstNamesFem.add("Valerie")
            call firstNamesFem.add("Nichola")
            call firstNamesFem.add("Susan")
            call firstNamesFem.add("Sarah")
            call firstNamesFem.add("Rebecca")
            call firstNamesFem.add("Patricia")
            call firstNamesFem.add("Belinda")
            call firstNamesFem.add("Anne")
            call firstNamesFem.add("Sarah")
            call firstNamesFem.add("Claudia")
            call firstNamesFem.add("Harriet")
            call firstNamesFem.add("Jennifer")
            call firstNamesFem.add("Winnie")
    endfunction
endscope


Library: UnitNaming
Code (vJASS):

/*
    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     = false                    // 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("error - 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("error - 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()
                call BJDebugMsg("indexed")
                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

 


Credits

Bribe for his [Snippet] New Table resource.

Changelog

0.10
- Made a vJass version
- GUI portion disabled
0.12
- Added default returns of of hero and unit name if the provided unit is not recorded in the table.
- Now nulls UnitName first, last, and unit names onDestroy.
- Now removes UnitName from the table if the data saved there can be represented through normal blizzard API.
- Removed the OnEvent part from the library and placed it in a separate trigger.
- Removed HasUnitName
- WorldBounds moved from required to recomended.
0.13
- Removed a needless allocation from SetUnitNormalName
- Fixed a bug with SetUnitNormalName not changing unit name for some cases.
0.14
- Made the vJass version into the main submission.
- Changed the Testing triggers.
- DestroyUnitName now reverts back the unit naming somewhat to mimic blizzard standard.
0.15
- Changed from onDestroy to destroy
- NamePool;destroy added a loop for removing all instances also stored inside typeTable.
- UnitName destroy now resets to *warcraft default* with the data it currently sits on.
- NamePool;onInit added to setup typeTable and uTable.
- Separated uTable into typeTable(NamePool) and uTable(UnitName)
- UnitName:setNormal, setFirst and setLast removed.
- UnitName is now public and designed to be useable on its own.
- Added unit as member variable to UnitName.
- Added a few debug messages
- IsUnitTypeInPool --> NamePool.containsType
- Moved recomended documentation.
1.0
- Remade the system from scratch and divided the system into two parts. The first part handles name pools and changing unit names without being able to remeber what names a unit has configured. The extention contains utility functions to manipulate unit names through getters and setters.
- Remade the GUI setup trigger so it’s easier to implement and also made it compatible with the vJass code (using patch 1.30) - It's now back.
- Fixed a minor issue with test commands.
- The setup now splits names up into first and last names and then pairs a random combination of names into a new full name.
1.1
- Changed example setup to use UnitDex
- If the unit has a saved default name it will be reset when destroy is called.
- Removed the debug message, if one wants to catch errors they just have to use the boolean that is returned.
- Added: function UnitHasNamePool takes unit u returns boolean
- Added: function SaveDefaultName takes unit u returns nothing
- Made the extended version be the default for the test map
- Removed Bribe's Unit Indexer from the GUI version.
- Removed all none configured units from the test map (except for MK)
- Added GUI trigger for changing unit names manually.
- Modifed the GUI setup slightly.
- Fixed a bug where using the random command would only change firstname after the setproper command had been used.
- Fixed so that you can now enter longer last names than one word.
- Added constant to UnitnamingExtended to toggle if the default name should be saved automatically whenver a set-function is used (default is false).
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
- 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


Future works
Nothing at this point.


Keywords: NPC, RP, LOAP, RPG, Custom, Naming, Name.
Contents

NPC Unit Naming System 1.2b (Map)

Reviews
MyPad
Tested the demo map again. This time, the system works with no issues that I have had previously encountered. These issues are now resolved, and everything seems to be in order, from the code itself, to the documentation. There is no reason not to...
  1. Pinzu

    Pinzu

    Joined:
    Nov 30, 2007
    Messages:
    1,177
    Resources:
    3
    Spells:
    2
    Tutorials:
    1
    Resources:
    3
    I finished a spread sheet script for name to code conversion. If anyone could re-submit it for me on google sheet and provide a link it would be great (Message me).

    To use it the user would have to clone it to their google drive and just modify the relevant cells and then copy the generated code into their map.

    upload_2018-8-11_7-37-33.png

    Also, I've decided to remove all the getters and setters (for different name-types) from the core of the system. It will be in a secondary library which then would be optional.

    Update: v 1.0
    - The GUI version has made a comeback with patch 1.30 so they now share the same library.
    - Divided the system into two parts to please Chaosy.
    - Removed alot of useless code.
     
    Last edited: Aug 12, 2018
  2. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,303
    Resources:
    7
    Models:
    1
    Icons:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    7

    Test Environment:



    As the test map started, 6 error messages popped up. An error message popping up on startup could cast some doubt on the reliability of the resource, so I had managed to trace it down to the footmen and the Blademaster. It turns out they were not added into the setup trigger.

    I am reporting this part as something that needs to be addressed.

    Notes:


    • Destroying the unit's name does not actually reset the given name. Is this intended? (Tested on units. Link to the video footage: Here) {Needs fix}
    • The logic of adding of names to units on map initialization could be outsourced to an existing library that catches unit creation. (See [System] UnitDex - Unit Indexer )
      {Not so urgent fix}

    Nitpicks:


    • None

    Status:


    • Awaiting Update
     
    Last edited: Aug 17, 2018
  3. Pinzu

    Pinzu

    Joined:
    Nov 30, 2007
    Messages:
    1,177
    Resources:
    3
    Spells:
    2
    Tutorials:
    1
    Resources:
    3
    *cough* The double naming is due to having multiple events fiering for indexing in the test map. Seem to have forgotten to disable the GUI OnUnitIndexEvent, my bad. :)

    As for the debug messages I could add a check function for if the unit type exists in a pool. It's not really an error though as it simply returns false if it failed to find a name pool.

    I'm not sure if the destroy method should reset the name to whatever, it's just to free the associated memory from that unit, though it would be logical use that destroy resets the name I question the utility of such an implementation. I suppose I could save unit-type names in a table as they are first managed by the system, hero names would also have to be saved.

    And on the setup/configuration part well Im unsure. There are currently 2 types of setups either one calls ChangeToRandomName or SetUnitRandomName it's not the same thing. The first simply will change the name and the latter will also configure it with the extended version. So if you use ChangeUnitFullName and then use a command like -setfirst Timmy, you will get double names and it won't work properly, but if you instead use SetUnitRandomName and then use the command it will work.
     
    Last edited: Aug 17, 2018
  4. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,303
    Resources:
    7
    Models:
    1
    Icons:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    7
    When testing the commands, the one on top is the proper name, while the one in the bottom is the unit name, although that is not what I had intended to report.
     
  5. Pinzu

    Pinzu

    Joined:
    Nov 30, 2007
    Messages:
    1,177
    Resources:
    3
    Spells:
    2
    Tutorials:
    1
    Resources:
    3
    You accuse me of false advertising? ^^

    Startup changes
    Code (vJASS):

    scope NamingUnits initializer Init
     
        /* Caution:
        ChangeToRandomName does not work exactly the same as SetUnitRandomName. The former
        will simply rename the unit WITHOUT saving the unit name data. Using any of the extended
        functions AFTER using ChangeToRandomName will NOT work together properly, so keep that in mind
        when you chose how you want ur units to be named.
     
        The reason for the separation, is if you don't want to allocate memory that you won't need and
        simply want to rename the unit once.
        */

     
        function onIndex takes nothing returns boolean
        local unit u = GetIndexedUnit()
        // EX 1
        //if UnitHasNamePool(u) then
        //    call ChangeToRandomName(u)
        //endif
        // EX 2
        //if not ChangeToRandomName(u) then
            // Failed to rename the unit due to it not having a name pool
        //endif
     
        // EX 3 (Recomended)
        //call ChangeToRandomName(u)
     
        // Extremly optional but will save the units current name the first time it's called.
        call SaveDefaultName(u)
        if UnitHasNamePool(u) then
            call SetUnitRandomName(u)
        endif
            set u = null
            return false
        endfunction
        function onDeindex takes nothing returns boolean
        local unit u = GetIndexedUnit()
        call DestroyUnitName(u)        // Only necessary if using any of the extended features.
            set u = null
            return false
        endfunction
        private function Init takes nothing returns nothing
            call RegisterUnitIndexEvent(Filter(function onIndex)  , EVENT_UNIT_INDEX)
            call RegisterUnitIndexEvent(Filter(function onDeindex), EVENT_UNIT_DEINDEX)
        endfunction
    endscope
     


    Changes 1.1.2

    - Changed example setup to use UnitDex
    - If the unit has a saved default name it will be reset when destroy is called.
    - Removed the debug message, if one wants to catch errors they just have to use the boolean that is returned.
    - Added: function UnitHasNamePool takes unit u returns boolean
    - Added: function SaveDefaultName takes unit u returns nothing
    - Made the extended version be the default for the test map
    - Removed Bribe's Unit Indexer from the GUI version.
    - Removed all none configured units from the test map (except for MK)
    - Added GUI trigger for changing unit names manually.
    - Modifed the GUI setup slightly.
    - Fixed a bug where using the random command would only change firstname after the setproper command had been used.
    - Fixed so that you can now enter longer last names than one word.
    - Added constant to UnitnamingExtended to toggle if the default name should be saved automatically whenver a set-function is used (default is false).


    Updated: v 1.1

    Note 1: if the indention looks bad I blame the vanilla editor and having to copy code over from notepad.
     
    Last edited: Aug 17, 2018
  6. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,303
    Resources:
    7
    Models:
    1
    Icons:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    7
    Tested the demo map again. This time, the system works with no issues that I have had previously encountered.

    These issues are now resolved, and everything seems to be in order, from the code itself, to the documentation. There is no reason not to approve this any longer. However, any improvements to the system are welcome.

    Status:


    • Approved
     
  7. Pinzu

    Pinzu

    Joined:
    Nov 30, 2007
    Messages:
    1,177
    Resources:
    3
    Spells:
    2
    Tutorials:
    1
    Resources:
    3
    Updated to 1.2b

    Removed most of the vjass examples of how to use and instead created a GUI compatible command use so both can learn how to use it.

    Added automatic setup for handling Unit Enter Map and Name Preplaced Units. It works for the following scenarios:

    1) Library used UnitIndexerGUI (bribe)
    2) Library used UnitDex
    3) No UnitIndexer and no ExtendedFeatures

    The only scenario that won't automatically setup properly is if you have extended features enabled but it didn't find any UnitIndexer. The reason for this is that Extended Features require data to be deallocated from units (i.e deindex events) this must then be handled manually by the user.

    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)

    Update fixed a few minor bugs
    - Fixed a bug with hiding unit type names causing a crash.
    - Hiding unit names (config) 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

    I have an idea for including a third slot for unit kill count or rank display in the naming but I'm not sure if it fits in this library. Also, it probably would be possible to encode the different names inside the unit like so:

    FirstName|r|rLastName|nUnit Name

    Thus removing the need to store them inside a hashtabl, but I'm not sure if I have considered all the cases in which this can break. To retrieve the name one would simply loop through the string.
     
    Last edited: Feb 2, 2019