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

Made a little Name Tag System

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
Suggestions? Could use some help on what to do on Deindex/death.

JASS:
library NameTags 
    
    globals
        private hashtable hash              = InitHashtable()
        private constant real INTERVAL      = 0.06
        private constant real TAG_SIZE      = 0.020
    endglobals
    
    struct NameTag
        thistype next
        thistype prev
        unit u
        integer id
        real x
        real y
        texttag tt 
        private static integer n = 0
        private static trigger t = CreateTrigger()
        
        static method getMember takes integer id returns integer 
            return LoadInteger(hash, id, 0)
        endmethod
        
        static method isUnitTagged takes unit u returns boolean
            return thistype.getMember(GetHandleId(u)) != null 
        endmethod
        
        static method isIdTagged takes integer id returns boolean 
            return thistype.getMember(id) != null 
        endmethod
        
        static method rem takes unit u, integer id returns nothing
            local thistype a = LoadInteger(hash, GetHandleId(u), 0)
            local thistype b = LoadInteger(hash, id, 0) 
            local thistype this
            if a != b and not (a == null) and not (b == null)  then 
                call BJDebugMsg("ERROR - NameTag: tried to remove two elements at the same time!")
                return
            endif
            if a != null then 
                set this = a
            else
                set this = b
            endif
            call FlushChildHashtable(hash, GetHandleId(this.u))
            call FlushChildHashtable(hash, this.id)
            set this.next.prev = this.prev
            set this.prev.next = this.next
            set thistype.n = thistype.n - 1
            call SetTextTagVisibility(this.tt, false)
            call DestroyTextTag(this.tt)
            if thistype.n == 0 then 
                call DisableTrigger(thistype.t)
            endif
            call this.deallocate()
        endmethod
        
        static method add takes unit u, integer id, string name returns nothing
            local thistype this
            local integer uid = GetHandleId(u)
            if LoadInteger(hash, id, 0) != null or LoadInteger(hash, uid, 0) != null then
                call thistype.rem(u, id)
            endif
            set this = thistype.allocate()
            call SaveInteger(hash, uid, 0, this)
            call SaveInteger(hash, id, 0, this)
            set this.u = u
            set this.id = id
            set this.x = this.x - 1
            set this.prev = thistype(0)
            set this.next = thistype(0).next
            set this.next.prev = this
            set thistype(0).next = this
            set thistype.n = thistype.n + 1
            set this.tt = CreateTextTag()
            call SetTextTagText(this.tt, name, TAG_SIZE)
            call SetTextTagVisibility(this.tt, true)
            if thistype.n == 1 then 
                call EnableTrigger(thistype.t)
            endif
        endmethod
        
        private static method periodic takes nothing returns nothing
            local thistype index = thistype(0).next
            local real uX
            local real uY
            loop
                exitwhen index.u == null
                set uX = GetUnitX(index.u)
                set uY = GetUnitY(index.u)
                if not (index.x == uX and index.y == uY) then 
                    set index.x = uX
                    set index.y = uY
                    call SetTextTagPos(index.tt, uX, uY, 220)
                endif
                set index = index.next
            endloop
        endmethod
        
        private static method onInit takes nothing returns nothing
            call TriggerRegisterTimerEvent(thistype.t, INTERVAL, true)
            call TriggerAddAction(thistype.t, function thistype.periodic)
            call DisableTrigger(thistype.t)
        endmethod
    endstruct
endlibrary
 
Last edited:
Wrote you a library that does the same thing but much simpler and easier to understand.

JASS:
library PlayerNames //Written by UnholyDecimator/Mr.Pockets00000

globals
    private hashtable Names = InitHashtable()
    private hashtable Units = InitHashtable()
    private constant integer max = 4 //maximum possible units per player
    private constant integer players = 12 //players used
    private integer array unitIndex[players]
    private integer tmp_int = 0
endglobals

//run this function once at the start of the map
function initialize takes nothing returns nothing
    local integer i = 0
    loop
        exitwhen i >= players
        set unitIndex[i] = 0
    endloop
endfunction

//registers a unit with the system
function regPlayerUnit takes unit whichUnit, integer playerNum returns boolean
    if unitIndex[playerNum] < max then
        call SaveUnitHandle(Units, playerNum, unitIndex[playerNum], whichUnit)
        set unitIndex[playerNum] = unitIndex[playerNum] + 1
        return true
        
    else
        return false
    endif
    
    return false
endfunction

//extra functions that really only have purpose because of ForGroup
function forLoop takes nothing returns nothing
    call regPlayerUnit( GetEnumUnit(), tmp_int)
endfunction
//--------------------------------------------------

//deletes a unit from the system. Take note, this does re-assign unit index
function delPlayerUnit takes integer playerNum, integer index returns boolean
    local integer i = 0
    local integer tag_size = 0
    local boolean success
    local group tmp = CreateGroup()
    local texttag array tmp_tag
    
    set tmp_int = playerNum

    if index > unitIndex[playerNum] then
        set success = false
        
    else
        loop
            exitwhen i >= unitIndex[playerNum]
            
            if not(i == index) then
                call GroupAddUnit(tmp, LoadUnitHandle(Units, playerNum, i))
                set tmp_tag[tag_size] = LoadTextTagHandle(Names, playerNum, i)
                set tag_size= tag_size + 1
                
            else
                call DestroyTextTag(LoadTextTagHandle(Names, playerNum, i))
            endif
            
            set i = i + 1
        endloop
        
        set unitIndex[playerNum] = 0
        
        call FlushChildHashtable(Units, playerNum)
        call FlushChildHashtable(Names, playerNum)
        
        call ForGroup(tmp, function forLoop)
        
        set i = 0
        loop
            exitwhen i >= (tag_size + 1)
            call SaveTextTagHandle(Names, playerNum, i, tmp_tag[i])
            set tmp_tag[i] = null
            set i = i + 1
        endloop
        
        set success = true
    
    endif
    
    call DestroyGroup(tmp)
    set tmp = null
    return success
    
endfunction

//easier (but slower) way to remove units from the system since it gets around the changing index
function delUnitByHandle takes integer playerNum, unit whichUnit returns boolean
    local integer i = 0
    local boolean retval = false
    loop
        exitwhen i >= unitIndex[playerNum]
        
        if whichUnit == LoadUnitHandle(Units, playerNum, i) then
            set retval = delPlayerUnit(playerNum, i)
            return retval
        endif
        
        set i = i + 1
        
    endloop
    
    return retval

endfunction

//registers a name tag with the system, and locks it to the unit. Best to register the unit before doing this!
function regName takes integer playerNum, integer index, string name, real size returns boolean
    local texttag tmp_tag = CreateTextTag()
    local unit  tmp_unit 
    
    if(index >= unitIndex[playerNum]) then
        call DestroyTextTag(tmp_tag)
        set tmp_tag = null
        set tmp_unit = null
        return false
    endif
    
    set tmp_unit = LoadUnitHandle(Units, playerNum, index)
    call SetTextTagTextBJ(tmp_tag, name, size)
    call SaveTextTagHandle(Names, playerNum, index, tmp_tag)
    call SetTextTagPosUnit(tmp_tag, tmp_unit, 0.0)
    
    set tmp_tag = null
    set tmp_unit = null
    return true
    
endfunction

//easier (but slower) register name tag by unit Handle
function regNameByHandle takes integer playerNum, unit whichUnit, string name, real size returns boolean
    local integer i = 0
    local boolean retval = false
    loop
        exitwhen i >= unitIndex[playerNum]
        
        if whichUnit == LoadUnitHandle(Units, playerNum, i) then
            set retval = regName(playerNum, i, name, size)
            return retval
        endif
        
        set i = i + 1
        
    endloop
    
    return retval
endfunction

//sets a Unit's Name Tag
function setName takes integer playerNum, integer index, string newName, real size returns boolean
    if index >= unitIndex[playerNum] then
        return false
    endif
        
    call SetTextTagTextBJ(LoadTextTagHandle(Names, playerNum, index), newName, size)
    return true
endfunction

//easier (but slower) sets a Unit's Name Tag by unit Handle
function setNameByHandle takes integer playerNum, unit whichUnit, string newName, real size returns boolean
    local integer i = 0
    local boolean retval = false
    loop
        exitwhen i >= unitIndex[playerNum]
        
        if whichUnit == LoadUnitHandle(Units, playerNum, i) then
            set retval = setName(playerNum, i, newName, size)
            return retval
        endif
        
        set i = i + 1
        
    endloop
    
    return retval
endfunction

//updates the text position of a player's units
function updateTextPosPlayer takes integer playerNum returns nothing
    local integer i = 0
    loop
        exitwhen i >= unitIndex[playerNum]
        call SetTextTagPosUnit(LoadTextTagHandle(Names, playerNum, i), LoadUnitHandle(Units, playerNum, i), 0.0)
        set i = i + 1
    endloop
endfunction

//updates the text position of all units registered in the system
function updateTextPosAll takes nothing returns nothing
    local integer i = 0
    loop
        exitwhen i >= players
        call updateTextPosPlayer(i)
        set i = i + 1
    endloop
endfunction

function getArraySize takes integer playerNum returns integer

    return unitIndex[playerNum]
    
endfunction

endlibrary

example usage trigger:


[trigger= exampleInitialize]
exampeInitialize
Events
Time - Elapsed game time is 0.01 seconds
Conditions
Actions
Custom script: call initialize()

[/trigger]


[trigger=ExampleUnitRegister]
exampleRegUnit
Events
Time - Elapsed game time is 1.00 seconds
Conditions
Actions
Set unit = Peasant 0001 <gen>
Custom script: call regPlayerUnit(udg_unit, 0)
Custom script: call regName(0, 0, "Peasant", 10.0)
Set unit = Footman 0002 <gen>
Custom script: call regPlayerUnit(udg_unit, 0)
Custom script: call regName(0, 1, "Footman", 10.0)
Set unit = Knight 0003 <gen>
Custom script: call regPlayerUnit(udg_unit, 0)
Custom script: call regName(0, 2, "Knight", 10.0)

[/trigger]


[trigger=ExampleDelUnit]
exampleDeletion
Events
Time - Elapsed game time is 1.01 seconds
Conditions
Actions
Set unit = Knight 0003 <gen>
Custom script: call delUnitByHandle(0 , udg_unit)

[/trigger]


[trigger=ExampleUpdate]
exampleUpdate
Events
Time - Every 0.04 seconds of game time
Conditions
Actions
Custom script: call updateTextPosAll()

[/trigger]




edit: It might be easier to use regNameByHandle rather than regName in some cases!

edit2: optimized the code a bit by chaning where a regNameByHandle and delUnitByHandle return!
 
Last edited:
Status
Not open for further replies.
Top