/*
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