• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Getting the last member of a group

Status
Not open for further replies.
Level 28
Joined
Feb 2, 2006
Messages
1,633
Hello,
for my creep respawn system I would like to get the last unit of a group. However, there seems to be an issue when getting the last member.
This is my JASS code:
JASS:
function GetLastMemberOfGroup takes group whichGroup returns unit
    local group tmpGroup = CreateGroup()
    local unit tmpLast = null
    local unit last = null
    call GroupAddGroup(whichGroup, tmpGroup)
    loop
        set tmpLast = FirstOfGroup(tmpGroup)
        exitwhen (tmpLast == null)
        set last = tmpLast
        call GroupRemoveUnit(tmpGroup, last)
    endloop
    call DestroyGroup(tmpGroup)
    set tmpGroup = null
    set tmpLast = null
    return last
endfunction

function GetLastIndexOfGroup takes group whichGroup returns integer
    local group tmpGroup = CreateGroup()
    local unit tmpLast = null
    local integer last = -1
    call GroupAddGroup(whichGroup, tmpGroup)
    loop
        set tmpLast = FirstOfGroup(tmpGroup)
        exitwhen (tmpLast == null)
        call GroupRemoveUnit(tmpGroup, tmpLast)
        set last = last + 1
    endloop
    call DestroyGroup(tmpGroup)
    set tmpGroup = null
    set tmpLast = null
    return last
endfunction

function AssignUnitToCurrentGroup takes nothing returns nothing
    local integer lastIndex = GetLastIndexOfGroup(udg_RespawnGroup[udg_TmpGroupIndex])
    local integer memberIndex = Index2D(udg_TmpGroupIndex, lastIndex, udg_RespawnGroupMaxMembers)
    local unit lastMember = GetLastMemberOfGroup(udg_RespawnGroup[udg_TmpGroupIndex])
    call BJDebugMsg("Assign to unit " + GetUnitName(lastMember) + " with handle ID " + I2S(GetHandleId(lastMember)) + " with index " + I2S(lastIndex) + " the current group " + I2S(udg_TmpGroupIndex) + " the unit group has a size of " + I2S(CountUnitsInGroup(udg_RespawnGroup[udg_TmpGroupIndex])))
    set udg_RespawnUnitType[memberIndex] = GetUnitTypeId(lastMember)
    set udg_RespawnLocationPerUnit[memberIndex] = GetUnitLoc(lastMember)
    call AssignUnitToGroup(lastMember, udg_TmpGroupIndex)
    set lastMember = null
endfunction

function InitCurrentGroup takes nothing returns nothing
    set udg_TmpGroupIndex = udg_TmpGroupIndex + 1
    set udg_RespawnGroup[udg_TmpGroupIndex] = CreateGroup()
endfunction

And this is my trigger to create a respawn group:
  • Actions
    • Set VariableSet TmpGroupIndex = -1
    • -------- KALIMDOR --------
    • -------- Trolle 1 --------
    • Custom script: call InitCurrentGroup()
    • Unit Group - Add Dunkeltrollfallensteller 0348 <gen> to RespawnGroup[TmpGroupIndex]
    • Custom script: call AssignUnitToCurrentGroup()
    • Unit Group - Add Dunkeltrollhohepriester 0350 <gen> to RespawnGroup[TmpGroupIndex]
    • Custom script: call AssignUnitToCurrentGroup()
    • Unit Group - Add Dunkeltrollberserker 0353 <gen> to RespawnGroup[TmpGroupIndex]
    • Custom script: call AssignUnitToCurrentGroup()
    • Unit Group - Add Dunkeltrollberserker 0351 <gen> to RespawnGroup[TmpGroupIndex]
    • Custom script: call AssignUnitToCurrentGroup()
    • Set VariableSet RespawnItemType[TmpGroupIndex] = Heilsalbe
GetLastMemberOfGroup returns twice the exact same unit (same handle ID) although the group is growing and I add two different units of the same type.
It behaves like I would have added the same unit twice to the group.
When I switch the two lines of "Dunkeltrollberserker":
  • Unit Group - Add Dunkeltrollberserker 0351 <gen> to RespawnGroup[TmpGroupIndex]
  • Custom script: call AssignUnitToCurrentGroup()
  • Unit Group - Add Dunkeltrollberserker 0353 <gen> to RespawnGroup[TmpGroupIndex]
  • Custom script: call AssignUnitToCurrentGroup()
It suddenly works and I have two different units in the group.
I am confused.
I have attached the corresponding map. The trigger is called "Kalimdor Creep Groups". You should see the debug output in the beginning of the game.
 

Attachments

  • wowtsr.w3x
    1.4 MB · Views: 19
If only last unit is needed, one might also just do something like:

JASS:
hashtable hash = InitHashtable()
constant integer PARENT_KEY_LAST_UNIT = 0

function GroupAddUnitTracked takes unit u, group g, returns nothing
    local integer childKey = GetHandleId(g)
    call SaveUnitHandle(hash, PARENT_KEY_LAST_UNIT, childkey, u)
endfunction

function GroupGetLastAddedUnit takes group g returns unit
    local integer childKey = GetHandleId(g)
    return LoadUnitHandle(hash, PARENT_KEY_LAST_UNIT, childkey)
endfunction

Edit:

Well, it might be needed actually to track also removed units from group etc, like in example the last unit gets removed from group, then an other unit would get last. So maybe just custom list would be good.. ;D
 
But you can select the unit via GUI, fill a unit variable with it, and then run a custom script or other trigger as next action.

Just a random other idea instead of implementing a doubly linked list:

You could try a pseudo time-stamp attempt in form of a variable tracking a unit's entry number for the group. Each group has its own counter (hashtable), and when ever a unit joins, the counter gets increased, and the number gets attached to the unit.

For example "integer array GroupEntryNumber[]" would track all units' last entry number when joining a group, using a unit's index as key.

JASS:
function AddUnit takes unit u , group greturns nothing
    local integer groupCounter = LoadInteger(hash, GetHandleId(g), 0)
    local integer groupEntryNumber = groupCounter + 1
    local integer unitIndex = GetUnitIndex(u)
    set GroupEntryNumber[unitIndex] = groupEntryNumber

And when searching for the last unit that was added there can be a loop through all units inside the group, and the unit with the highest GroupEntryNumber would win. It's not perfect, but the max integer value ( 2147483647 ) could be enough, even the counter would never reset.
 
Level 12
Joined
Jan 30, 2020
Messages
875
Hello there.

Why didn't you simply use :
JASS:
function GetLastMemberOfGroup takes group whichGroup returns unit
    return BlzGroupUnitAt(whichGroup, BlzGroupGetSize(whichGroup))
endfunction

?
 
Level 12
Joined
Jan 30, 2020
Messages
875
Because I don't know the new functions. Thx.

edit:
But if the ordering is not strict, it won't work anyway.

I know the feeling, I keep discovering these when I spend time reading the new common.j file !

I am sure this will make things much easier for you, as it did for myself !

Take care !
 
Status
Not open for further replies.
Top