GUI Unit Event v2.5.3.0

This bundle is marked as approved. It works and satisfies the submission rules.
Unit Event for GUI gives you access to all kinds of events which normal GUI events can't do. Now fully integrating Unit Indexer, I've listed all substantial events and variables. In each event, the custom value of the "triggering unit" is equal to UDex and the way to get the unit with that custom value is via UDexUnits[(Custom value of Unit) --- In this case "UDex"].

  • Detect the instant when a unit starts reincarnating
    Event: Game - DeathEvent Becomes Equal to 0.50
    Unit: UDexUnits[UDex] - the reincarnating unit

  • Detect when a unit is brought back to life via Reincarnation, Resurrect or Reanimate
    Event: Game - DeathEvent Becomes Equal to 2.00
    Unit: UDexUnits[UDex] - The revived unit

    You can differentiate between the three of these as well. If it is summoned, that means it was reanimated. If IsUnitReincarnating[UDex] is true, that means it finished reincarnating. Otherwise, it was simply resurrected.

  • Detect when a unit is loaded into a transport
    Event: Game - CargoEvent Becomes Equal to 1.00
    Unit: CargoTransportUnit[UDex] --- The unit who loaded this unit
    Unit: UDexUnits[UDex] - The loaded unit

  • Detect when a unit is unloaded from a transport
    Event: Game - CargoEvent Becomes Equal to 2.00
    Unit: CargoTransportUnit[UDex] --- The unit who unloaded this unit
    Unit: UDexUnits[UDex] - The unloaded unit

  • Detect when a unit transforms into a new unit type
    Event: Game - UnitTypeEvent Becomes Equal to 1.00
    Unit Type: UnitTypeOf[UDex] --- The previous unit type
    Unit: UDexUnits[UDex] - the unit who transformed

  • Detect the instant before a unit is completely removed from the game
    Event: Game - UnitIndexEvent Becomes Equal to 2.00
    Unit: UDexUnits[UDex] - the removed unit

  • To detect when any unit get indexed by the system (including pre-placed units)
    Event: Game - UnitIndexEvent Becomes Equal to 1.00
    Unit: UDexUnits[UDex] - the new unit

  • To detect when that unit has fully been created (recommended over the above if, say, you need to get certain attributes about the unit that was created)
    Event: Game - UnitIndexEvent Becomes Equal to 1.50
    Unit: UDexUnits[UDex] - The created unit

  • To detect when a new unit is summoned (fires after the Create event)
    Event: Game - UnitIndexEvent Becomes Equal to 0.50
    Unit: SummonerOfUnit[UDex]
    Unit: UDexUnits[UDex] - The unit that was summoned

  • To detect when any unit dies (including units created dead)
    Event: Game - DeathEvent Becomes Equal to 1.00
    Unit: KillerOfUnit[UDex] - the killing unit
    Unit: UDexUnits[UDex] - the dying unit

Unit Event also gives you access to some other useful variables, such as:

  • Boolean: IsUnitAlive[(Custom value of Unit)] - never bugs (checking life is not always accurate)

  • Unit Group: CargoTransportGroup[(Custom value of Transporter)] - A unit group which holds all of the cargo of a transporting unit.

There are also some additional obscure things you can do with the system as well, such as looping through all the units in a map or reading data/events based on when the system initialized.


How to install:

- Delete Unit Indexer from your map (if you already have it)
- Copy the "Unit Event Ability" ability from Object Editor
- Copy the Unit Event trigger category
- Paste the Unit Event Ability from object editor twice
- Set the DetectRemoveAbility variable in the Unit Event Config trigger to one of the abilities.
- Set the DetectTransformAbility variable in the same trigger to the other of the two.


Inspiration:

- AutoEvents by grim001
- UnitEvent by Nestharus
- Transport by Jesus4Lyf


  • Unit Event Config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- --------
      • -------- Copy Unit Event Ability from Object Editor, then set DetectRemoveAbility to it as follows: --------
      • -------- --------
      • Set DetectRemoveAbility = Unit Event Ability (Removal Detect)
      • -------- --------
      • -------- Paste it a second time, then set DetectTransformAbility to it as follows: --------
      • -------- --------
      • Set DetectTransformAbility = Unit Event Ability (Transform Detect)
      • -------- --------
      • -------- One additional event to run right before Unit Indexer initializes, added 29 May 2017 for ZiBitheWand3r3r --------
      • Set UnitIndexEvent = -1.00
      • -------- --------
      • -------- Initialize Unit Event now that all the InitTrig_ functions have run --------
      • -------- --------
      • Set IsUnitPreplaced[0] = True
      • Custom script: call ExecuteFunc("UnitEventInit")
      • Set UnitIndexEvent = 3.00
      • Set IsUnitPreplaced[0] = IsUnitTransforming[0]
JASS:
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
    if udg_CargoTransportGroup[i] != null then
        call DestroyGroup(udg_CargoTransportGroup[i])
        set udg_CargoTransportGroup[i] = null
    endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
    local integer i = 0
    loop
        set i = udg_CheckDeathList[i]
        exitwhen i == 0
        set udg_UDex = i
        if udg_IsUnitNew[i] then
            //The unit was just created.
            set udg_IsUnitNew[i] = false
            set udg_UnitIndexEvent = 1.50 //New event requested by SpellBound to detect when unit fully enters scope.
            set udg_UnitIndexEvent = 0.00
        elseif udg_IsUnitTransforming[i] then
           //Added 21 July 2017 to fix the issue re-adding this ability in the same instant
           set udg_UnitTypeEvent = 0.00
           set udg_UnitTypeEvent = 1.00
           set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
           set udg_IsUnitTransforming[i] = false
           call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
        elseif udg_IsUnitAlive[i] then
            //The unit has started reincarnating.
            set udg_IsUnitReincarnating[i] = true
            set udg_IsUnitAlive[i] = false
            set udg_DeathEvent = 0.50
            set udg_DeathEvent = 0.00
        endif
        set udg_CheckDeathInList[i] = false
    endloop
    //Empty the list
    set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
    if udg_CheckDeathList[0] == 0 then
        call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
    endif
    if not udg_CheckDeathInList[i] then
        set udg_CheckDeathList[i] = udg_CheckDeathList[0]
        set udg_CheckDeathList[0] = i
        set udg_CheckDeathInList[i] = true
    endif
endfunction

function UnitEventOnUnload takes nothing returns nothing
    local integer i = udg_UDex
    call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
    set udg_IsUnitBeingUnloaded[i] = true
    set udg_CargoEvent = 0.00
    set udg_CargoEvent = 2.00
    set udg_CargoEvent = 0.00
    set udg_IsUnitBeingUnloaded[i] = false
    if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
        set udg_CargoTransportUnit[i] = null
    endif
endfunction

function UnitEventOnDeath takes nothing returns boolean
    local integer pdex = udg_UDex
    set udg_UDex = GetUnitUserData(GetTriggerUnit())
    if udg_UDex != 0 then
        set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
        set udg_IsUnitAlive[udg_UDex] = false
        set udg_DeathEvent = 0.00
        set udg_DeathEvent = 1.00
        set udg_DeathEvent = 0.00
        set udg_KillerOfUnit[udg_UDex] = null
        if udg_CargoTransportUnit[udg_UDex] != null then
            call UnitEventOnUnload()
        endif
    endif
    set udg_UDex = pdex
    return false
endfunction
 
function UnitEventOnOrder takes nothing returns boolean
    local integer pdex = udg_UDex
    local unit u = GetFilterUnit()
    local integer i = GetUnitUserData(u)
    if i > 0 then
        set udg_UDex = i
        if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
            if not udg_IsUnitRemoved[i] then
                set udg_IsUnitRemoved[i] = true
                set udg_IsUnitAlive[i] = false
                set udg_SummonerOfUnit[i] = null
               
                //For backwards-compatibility:
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 3.00
                set udg_DeathEvent = 0.00
               
                //Fire deindex event for UDex:
                set udg_UnitIndexEvent = 0.00
                set udg_UnitIndexEvent = 2.00
                set udg_UnitIndexEvent = 0.00
               
                set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
                set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
               
                // Recycle the index for later use
                set udg_UDexUnits[i] = null
                set udg_UDexPrev[i] = udg_UDexLastRecycled
                set udg_UDexLastRecycled = i
                call UnitEventDestroyGroup(i)
            endif
        elseif not udg_IsUnitAlive[i] then
            if not IsUnitType(u, UNIT_TYPE_DEAD) then
                set udg_IsUnitAlive[i] = true
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 2.00
                set udg_DeathEvent = 0.00
                set udg_IsUnitReincarnating[i] = false
            endif
        elseif IsUnitType(u, UNIT_TYPE_DEAD) then
            if udg_IsUnitNew[i] then
                //This unit was created as a corpse.
                set udg_IsUnitAlive[i] = false
                set udg_DeathEvent = 0.00
                set udg_DeathEvent = 1.00
                set udg_DeathEvent = 0.00
            elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
                //The unit may have just started reincarnating.
                call UnitEventCheckAfterProxy(i)
            endif
        elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
            set udg_IsUnitTransforming[i] = true
            call UnitEventCheckAfterProxy(i)  //This block has been updated on 21 July 2017
        endif
        if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
            call UnitEventOnUnload()
        endif
        set udg_UDex = pdex
    endif
    set u = null
    return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
    local integer pdex = udg_UDex
    set udg_UDex = GetUnitUserData(GetTriggerUnit())
    if udg_IsUnitNew[udg_UDex] then
        set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
        set udg_UnitIndexEvent = 0.00
        set udg_UnitIndexEvent = 0.50
        set udg_UnitIndexEvent = 0.00
    endif
    set udg_UDex = pdex
    return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
    local integer pdex = udg_UDex
    local integer i = GetUnitUserData(GetTriggerUnit())
    local integer index
    if i != 0 then
        set udg_UDex = i
        if udg_CargoTransportUnit[i] != null then
            call UnitEventOnUnload()
        endif
        //Loaded corpses do not issue an order when unloaded, therefore must
        //use the enter-region event method taken from Jesus4Lyf's Transport.
        if not udg_IsUnitAlive[i] then
            call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
            call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
        endif
       
        set udg_CargoTransportUnit[i] = GetTransportUnit()
        set index = GetUnitUserData(udg_CargoTransportUnit[i])
        if udg_CargoTransportGroup[index] == null then
            set udg_CargoTransportGroup[index] = CreateGroup()
        endif
        call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
        set udg_CargoEvent = 0.00
        set udg_CargoEvent = 1.00
        set udg_CargoEvent = 0.00
        set udg_UDex = pdex
    endif
    return false
endfunction
function UnitEventEnter takes nothing returns boolean
    local integer pdex = udg_UDex
    local integer i = udg_UDexLastRecycled
    local unit u = GetFilterUnit()
    if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
        //Generate a unique integer index for this unit
        if i == 0 then
            set i = udg_UDexMax + 1
            set udg_UDexMax = i
        else
            set udg_UDexLastRecycled = udg_UDexPrev[i]
        endif
        //Link index to unit, unit to index
        set udg_UDexUnits[i] = u
        call SetUnitUserData(u, i)
       
        //For backwards-compatibility, add the unit to a linked list
        set udg_UDexNext[i] = udg_UDexNext[0]
        set udg_UDexPrev[udg_UDexNext[0]] = i
        set udg_UDexNext[0] = i
        set udg_UDexPrev[i] = 0

        set udg_CheckDeathInList[i] = false

        call UnitAddAbility(u, udg_DetectRemoveAbility)
        call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
        call UnitAddAbility(u, udg_DetectTransformAbility)
        set udg_UnitTypeOf[i] = GetUnitTypeId(u)
        set udg_IsUnitNew[i] = true
        set udg_IsUnitAlive[i] = true
        set udg_IsUnitRemoved[i] = false
        set udg_IsUnitReincarnating[i] = false
        set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
        call UnitEventCheckAfterProxy(i)
       
        //Fire index event for UDex
        set udg_UDex = i
        set udg_UnitIndexEvent = 0.00
        set udg_UnitIndexEvent = 1.00
        set udg_UnitIndexEvent = 0.00
    else
        set udg_UDex = GetUnitUserData(u)
        if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
            //The unit was dead, but has re-entered the map.
            call UnitEventOnUnload()
        endif
    endif
    set udg_UDex = pdex
    set u = null
    return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
    local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
    local player p
    local trigger t = CreateTrigger()
    local trigger load = CreateTrigger()
    local trigger death = CreateTrigger()
    local trigger summon = CreateTrigger()
    local rect r = GetWorldBounds()
    local region re = CreateRegion()
    local boolexpr enterB = Filter(function UnitEventEnter)
    local boolexpr orderB = Filter(function UnitEventOnOrder)
    set udg_WorldMaxX = GetRectMaxX(r)
    set udg_WorldMaxY = GetRectMaxY(r)
    call RegionAddRect(re, r)
    call RemoveRect(r)
    call UnitEventDestroyGroup(0)
    call UnitEventDestroyGroup(1)
   
    set udg_CheckDeathList[0] = 0
    set udg_UnitIndexerEnabled = true
    call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
    call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
    call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
    call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
    loop
        set i = i - 1
        set p = Player(i)
        call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
        call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
        call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
        call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
        call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
        call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
        exitwhen i == 0
    endloop
    set summon = null
    set death = null
    set load = null
    set re = null
    set enterB = null
    set orderB = null
    set p = null
    set r = null
    set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction


nestharus, grim001, unitevent, autoevents, unit indexer, reincarnate, reincarnation, reanimation, resurrect, resurrection, detect, death, removal, load, unload, transport, transform, unit type
Contents

Unit Event 2.5.3.0 (Map)

Reviews
Approved. Makes easy to detect many events that do not exist in the editor. Very useful system.
Level 11
Joined
Mar 16, 2008
Messages
328
what would the event response for reincarnate be? Like 'Dying Unit'?

Also I already have an indexer from a creep respawn system and the units that will be using the reincarnate are not preset on the map, they will be trained later. Can I just delete the indexer and change it to check if it's in one of my arrays already? I just need reincarnate for 8 units that I already have set to variables. Is there a way I could trim this down for that without it being too much work?

Any feed back or tips would be appreciated.
 
Last edited:
what would the event response for reincarnate be? Like 'Dying Unit'?

Also I already have an indexer from a creep respawn system and the units that will be using the reincarnate are not preset on the map, they will be trained later. Can I just delete the indexer and change it to check if it's in one of my arrays already? I just need reincarnate for 8 units that I already have set to variables. Is there a way I could trim this down for that without it being too much work?

Any feed back or tips would be appreciated.
  • Detect the instant when a unit starts reincarnating
    Event: Game - DeathEvent Becomes Equal to 0.50

  • Detect when a unit is brought back to life via Reincarnation, Resurrect or Reanimate
    Event: Game - DeathEvent Becomes Equal to 2.00
 
Level 11
Joined
Mar 16, 2008
Messages
328
I understand the event would be "Event: Game - DeathEvent Becomes Equal to 0.50" i'm asking what the event response would be to refer to the reincarnating unit. For my map I need to manipulate some items in their inventory when they use reincarnate.
 

MyPad

Spell Reviewer
Level 23
Joined
May 9, 2014
Messages
1,713
Bribe said:
[...] the way to get the unit with that custom value is via UDexUnits[(Custom value of Unit) --- In this case "UDex"].

(...)

Detect when a unit is brought back to life via Reincarnation, Resurrect or Reanimate
Event: Game - DeathEvent Becomes Equal to 2.00

You can differentiate between the three of these as well. If it is summoned, that means it was reanimated. If IsUnitReincarnating[UDex] is true, that means it finished reincarnating. Otherwise, it was simply resurrected.

If I'm not mistaken, you can use UDexUnits[UDex] to refer to the reincarnating unit.
 
Level 11
Joined
Mar 16, 2008
Messages
328
1) is there a way to distinguish between different types of reincarnations?
2) less importantly, can i delete the index and set it equal to one of my array variables? can i delete all the other triggers for that matter?
 
1) is there a way to distinguish between different types of reincarnations?
2) less importantly, can i delete the index and set it equal to one of my array variables? can i delete all the other triggers for that matter?
1. I believe by checking IsUnitReincarnating[UDex] you can determine if the revival of a unit is Reincarnation or Resurrection. Additionally, by checking if SummonerOfUnit[UDex] equal to/not equal to No unit, you can determine if the revival is Animate Dead.
2. I don't think you can do that, the whole function of the system is consolidated inside the "Unit Event" trigger. If either the "Unit Event" or "Unit Event Config" trigger is missing, nothing will work.
 
Level 10
Joined
Jul 4, 2016
Messages
558
I know that having another defend ability can interfere with this system, so how does this work with the default units like the footman that already has defend?
 

Bribe

Code Moderator
Level 43
Joined
Sep 26, 2009
Messages
8,925
it uses a custom defend ability so it shouldn't be a problem???
Correct. This system takes advantage of the "Undefend" issued order bug/feature in order to catch certain unit events. I have tested it thoroughly with units who have the normal Defend ability, and any bugs that I detected along the way were squashed.
 
Level 1
Joined
May 31, 2021
Messages
4
Is it possible to get the killer unit of a resurrecting unit?

JASS:
scope Revival initializer init
    private function beginReincarnation takes nothing returns boolean
        call BJDebugMsg(GetUnitName(udg_UDexUnits[udg_UDex]) + "has died.")
        call BJDebugMsg("KILLER: " + GetUnitName(udg_KillerOfUnit[udg_UDex]) )

        return false
    endfunction

    private function endReincarnation takes nothing returns boolean
        local player User = GetOwningPlayer(udg_UDexUnits[udg_UDex])
        local real SpawnX = GetRectCenterX(gg_rct_startingSpawnPoint)
        local real SpawnY = GetRectCenterY(gg_rct_startingSpawnPoint)

        call SetUnitX(udg_UDexUnits[udg_UDex], SpawnX)
        call SetUnitY(udg_UDexUnits[udg_UDex], SpawnY)
        call GameMessage(User, "has revived.")

        if GetLocalPlayer() == User then
            call ClearSelection()
            call SelectUnit(udg_UDexUnits[udg_UDex], true)
            call PanCameraToTimed(SpawnX, SpawnY, 0)
        endif

        set User = null
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger trgBegin = CreateTrigger()
        local trigger trgEnd = CreateTrigger()

        call TriggerRegisterVariableEvent(trgBegin, "udg_DeathEvent", EQUAL, .5)
        call TriggerAddCondition(trgBegin, Condition(function beginReincarnation))

        call TriggerRegisterVariableEvent(trgEnd, "udg_DeathEvent", EQUAL, 2)
        call TriggerAddCondition(trgEnd, Condition(function endReincarnation))

        set trgBegin = null
        set trgEnd = null
    endfunction
endscope
 

Bribe

Code Moderator
Level 43
Joined
Sep 26, 2009
Messages
8,925
Is it possible to get the killer unit of a resurrecting unit?

JASS:
scope Revival initializer init
    private function beginReincarnation takes nothing returns boolean
        call BJDebugMsg(GetUnitName(udg_UDexUnits[udg_UDex]) + "has died.")
        call BJDebugMsg("KILLER: " + GetUnitName(udg_KillerOfUnit[udg_UDex]) )

        return false
    endfunction

    private function endReincarnation takes nothing returns boolean
        local player User = GetOwningPlayer(udg_UDexUnits[udg_UDex])
        local real SpawnX = GetRectCenterX(gg_rct_startingSpawnPoint)
        local real SpawnY = GetRectCenterY(gg_rct_startingSpawnPoint)

        call SetUnitX(udg_UDexUnits[udg_UDex], SpawnX)
        call SetUnitY(udg_UDexUnits[udg_UDex], SpawnY)
        call GameMessage(User, "has revived.")

        if GetLocalPlayer() == User then
            call ClearSelection()
            call SelectUnit(udg_UDexUnits[udg_UDex], true)
            call PanCameraToTimed(SpawnX, SpawnY, 0)
        endif

        set User = null
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger trgBegin = CreateTrigger()
        local trigger trgEnd = CreateTrigger()

        call TriggerRegisterVariableEvent(trgBegin, "udg_DeathEvent", EQUAL, .5)
        call TriggerAddCondition(trgBegin, Condition(function beginReincarnation))

        call TriggerRegisterVariableEvent(trgEnd, "udg_DeathEvent", EQUAL, 2)
        call TriggerAddCondition(trgEnd, Condition(function endReincarnation))

        set trgBegin = null
        set trgEnd = null
    endfunction
endscope
No, you have to use a damage engine to determine if the damage will put the unit’s life below 0.41 (or, better, use LethalDamageEvent). If so, then do something like:

JASS:
//globals
    private unit array killedBy

//in the damage event:
set killedBy[GetUnitUserData(udg_DamageEventTarget)] = udg_DamageEventSource

//in the reincarnation event:
GetUnitName(killedBy[udg_UDex])
 

Bribe

Code Moderator
Level 43
Joined
Sep 26, 2009
Messages
8,925
I have updated this bundle with a feature requested by @Spellbound who needed something which could fire after a unit has fully entered the scope of the map.

There is now an event one can use:

UnitIndexEvent becomes Equal to 1.50

This event would ensure, for example, that a Ghoul created dead into a meat wagon would already be loaded and declared dead prior to the UnitIndexEvent 1.50 going off.

It is also beneficial for buildings where the building-construction start event hadn't already deployed.

It is possible, as well, that not all units' abilities would be pre-loaded onto them at the original UnitIndexEvent 1.00 point.

Therefore, it is recommended to most users to switch their events which have been using UnitIndex 1.00 to use 1.50 instead.
 

Bribe

Code Moderator
Level 43
Joined
Sep 26, 2009
Messages
8,925
I've run out of time for tonight, was hoping to get a Lua map published with this code already, but I just want to leave this here:

Lua:
if  Timed                   --https://www.hiveworkshop.com/threads/timed-call-and-echo.339222/
and GlobalRemap             --https://www.hiveworkshop.com/threads/global-variable-remapper.339308
and AnyPlayerUnitEvent      --https://www.hiveworkshop.com/threads/collection-gui-repair-kit.317084/
and Event then              --https://www.hiveworkshop.com/threads/event.339451/

OnGlobalInit(1, function()
    local _USER_DATA    = true --Whether to use SetUnitUserData to map the unit's handle Id to its userdata (true) or just use GetHandleId(false)
    
    local _REMOVE_ABIL      --= FourCC('A001')
    local _TRANSFORM_ABIL   --= FourCC('A002') --un-comment these and assign them to the respective abilities if you prefer not to initialize via GUI
    
    local _USE_ACTIVITY = true --adds a small overhead if true and you don't use the "active/inactive" events
    
    UnitEvent = { --Lua Unit Event 0.1.0.0
        onIndex         = Event.create("udg_OnUnitIndex"),
        onCreate        = Event.create("udg_OnUnitCreate"),
        onRemoval       = Event.create("udg_OnUnitRemoval"),
        onDeath         = Event.create("udg_OnUnitDeath"),
        onRevival       = Event.create("udg_OnUnitRevival"),
        onLoaded        = Event.create("udg_OnUnitLoaded"),
        onUnloaded      = Event.create("udg_OnUnitUnloaded"),
        onTransform     = Event.create("udg_OnUnitTransform"),
        onReincarnate   = Event.create("udg_OnUnitReincarnate"),
        onActive        = Event.create("udg_UnitActiveEvent"),
        onInactive      = Event.create("udg_UnitInactiveEvent")
    }

    [email protected] unitIndex
    [email protected] cargo group
    [email protected] transporter unit
    [email protected] summoner unit
    [email protected] private new boolean
    [email protected] private alive boolean
    [email protected] unit unit
    [email protected] preplaced boolean
    [email protected] reincarnating boolean
    [email protected] private unloading boolean

    local lastUnit  = nil
    local lastId    = 0
    local unitIndices = {}    [email protected] unitIndex[]

    --The below two functions are useful for GUI when _USER_DATA is set to "false". To use them:
    --Set UnitIndexUnit = (Triggering unit)
    -- OR 
    --Set UnitIndexId = (Index that belongs to said unit)
    --Once either of those were set, you can reference "UnitIndexUnit" and "UnitIndexId" as a unit and integer, respectively.
    --For GUI, it is obviously easier to just use (Custom value of Unit) so in such cases I just recommend setting _USER_DATA to "true"
    GlobalRemap("udg_UnitIndexUnit", function() return lastUnit end, function(whichUnit) lastUnit = whichUnit; lastId = GetHandleId(whichUnit) end)
    GlobalRemap("udg_UnitIndexId", function() return lastId end, function(whichId) lastUnit = unitIndices[whichId].unit; lastId = whichId end)

    GlobalRemap("udg_UDex", function() return Event.args[1].id end)
    
    local function map(arrStr, valStr)
        GlobalRemapArray(arrStr, function(id) return unitIndices[id][valStr] end)
    end
    
    map("udg_UDexUnits", "unit")
    map("udg_IsUnitPreplaced", "preplaced")
    map("udg_UnitTypeOf", "unitType")
    map("udg_IsUnitNew", "new")
    map("udg_IsUnitAlive", "alive")
    map("udg_IsUnitReincarnating", "reincarnating")
    map("udg_CargoTransportUnit", "transporter")
    map("udg_SummonerOfUnit", "summoner")
    
    do
        local cargo = udg_CargoTransportGroup
        if cargo then
            DestroyGroup(cargo[0])
            DestroyGroup(cargo[1])
            map("udg_CargoTransportGroup", "cargo")
        end
    end
    
    if _USE_ACTIVITY then
        local function setActive()
            local unitTable = Event.args[1]
            if unitTable and not unitTable.active and UnitAlive(unitTable.unit) then
                unitTable.active = true
                UnitEvent.onActive:run(unitTable)
            end
        end
        local function setInactive()
            local unitTable = Event.args[1]
            if unitTable and unitTable.active then
                unitTable.active = nil
                UnitEvent.onInactive:run(unitTable)
            end
        end
        
        UnitEvent.onCreate(setActive)
        UnitEvent.onRevival(setActive)
        UnitEvent.onUnloaded(setActive)
        
        UnitEvent.onDeath(setInactive)
        UnitEvent.onRemoval(setInactive)
        UnitEvent.onLoaded(setInactive)
        UnitEvent.onReincarnate(setInactive)
    end
    
    --UnitEvent.onIndex:register(function(id) print(id.id) end)
    
    OnTrigInit(function()
        local func = Trig_Unit_Event_Config_Actions
        if func then
            func()
            _REMOVE_ABIL    = udg_DetectRemoveAbility or _REMOVE_ABIL
            _TRANSFORM_ABIL = udg_DetectTransformAbility or _TRANSFORM_ABIL
        end
        
        local function checkAfter(unitTable)
            if not unitTable.checking then
                unitTable.checking = true
                Timed.call(function()
                    unitTable.checking = nil
                    if unitTable.new then
                        unitTable.new = nil
                        UnitEvent.onCreate:run(unitTable) --thanks to Spellbound for the idea
                    elseif unitTable.transforming then
                       UnitEvent.onTransform:run(unitTable)
                       unitTable.unitType = GetUnitTypeId(unitTable.unit) --Set this afterward to give the user extra reference
                       unitTable.transforming = nil
                       UnitAddAbility(unitTable.unit, _TRANSFORM_ABIL)
                    elseif unitTable.alive then
                        unitTable.reincarnating = true
                        unitTable.alive = false
                        UnitEvent.onReincarnate:run(unitTable)
                    end
                end)
            end
        end
    
        local re = CreateRegion()
        local r = GetWorldBounds()
        local maxX, maxY = GetRectMaxX(r), GetRectMaxY(r)
        RegionAddRect(re, r); RemoveRect(r)
        
        local function unload(unitTable)
            GroupRemoveUnit(unitIndices[GetHandleId(unitTable.transporter)].cargo, unitTable.unit)
            unitTable.unloading = true
            UnitEvent.onUnloaded:run(unitTable)
            unitTable.unloading = nil
            if not IsUnitLoaded(unitTable.unit) or not UnitAlive(unitTable.transporter) or GetUnitTypeId(unitTable.transporter) == 0 then
                unitTable.transporter = nil
            end
        end
        
        local preplaced = true
        local onEnter = Filter(
        function()
            local u = GetFilterUnit()
            local id = GetHandleId(u)
            local unitTable = unitIndices[id]
            if not unitTable then
                unitTable = {
                    unit    = u,
                    id      = id,
                    new     = true,
                    alive   = true,
                    unitType= GetUnitTypeId(u)
                }
                
                UnitAddAbility(u, _REMOVE_ABIL)
                UnitMakeAbilityPermanent(u, true, _REMOVE_ABIL)
                UnitAddAbility(u, _TRANSFORM_ABIL)

                unitIndices[id] = unitTable
                
                --print(GetUnitName(u) .. " has been indexed to " .. id)

                if _USER_DATA then SetUnitUserData(u, id) end

                unitTable.preplaced = preplaced
                UnitEvent.onIndex:run(unitTable)
                
                checkAfter(unitTable)
            elseif unitTable.transporter and not IsUnitLoaded(u) then
                --the unit was dead, but has re-entered the map (unloaded from meat wagon)
                unload(unitTable)
            end
        end)
        TriggerRegisterEnterRegion(CreateTrigger(), re, onEnter)
        
        AnyPlayerUnitEvent.add(EVENT_PLAYER_UNIT_LOADED,
        function()
            local u = GetTriggerUnit()
            local unitTable = unitIndices[GetHandleId(u)]
            if unitTable then
                if unitTable.transporter then
                    unload(unitTable)
                end
                --Loaded corpses do not issue an order when unloaded, therefore must
                --use the enter-region event method taken from Jesus4Lyf's Transport.
                if not unitTable.alive then
                    SetUnitX(u, maxX)
                    SetUnitY(u, maxY)
                end
               
                unitTable.transporter = GetTransportUnit()
                if not unitTable.transporter.cargo then
                    unitTable.transporter.cargo = CreateGroup()
                end
                GroupAddUnit(unitTable.transporter.cargo, u)
                
                UnitEvent.onLoaded:run(unitTable)
            end
        end)
        
        AnyPlayerUnitEvent.add(EVENT_PLAYER_UNIT_DEATH,
        function()
            local unitTable = unitIndices[GetTriggerUnit()]
            if unitTable then
                unitTable.alive = false
                UnitEvent.onDeath:run(unitTable)
                if unitTable.transporter then
                    unload(unitTable)
                end
            end
        end)
        
        AnyPlayerUnitEvent.add(EVENT_PLAYER_UNIT_SUMMON,
        function()
            local unitTable = GetHandleId(GetTriggerUnit())
            if unitTable.new then
                unitTable.summoner = GetSummoningUnit()
            end
        end)
        
        local orderB = Filter(
        function()
            local u = GetFilterUnit()
            local unitTable = unitIndices[GetHandleId(u)]
            if unitTable then
                if GetUnitAbilityLevel(u, _REMOVE_ABIL) == 0 then
                    unitTable[GetHandleId(u)] = nil

                    if unitTable.cargo then DestroyGroup(unitTable.cargo) end
                    
                    UnitEvent.onRemoval:run(unitTable)
                    
                elseif not unitTable.alive then
                    if UnitAlive(u) then
                        unitTable.alive = true
                        UnitEvent.onRevival:run(unitTable)
                        unitTable.reincarnating = nil
                    end
                elseif not UnitAlive(u) then
                    if unitTable.new then
                        --This unit was created as a corpse.
                        unitTable.alive = nil
                        UnitEvent.onDeath:run(unitTable)

                    elseif unitTable.transporter or not IsUnitType(u, UNIT_TYPE_HERO) then
                        --The unit may have just started reincarnating.
                        checkAfter(unitTable)
                    end
                elseif GetUnitAbilityLevel(u, _TRANSFORM_ABIL) == 0 and not unitTable.transforming then
                    unitTable.transforming = true
                    checkAfter(unitTable)
                end
                if unitTable.transporter and not unitTable.unloading and (not IsUnitLoaded(u) or not UnitAlive(u)) then
                    unload(unitTable)
                end
            end
        end)
        
        local p
        local order = CreateTrigger()
        for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
            p = Player(i)
            GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, onEnter)
            SetPlayerAbilityAvailable(p, _REMOVE_ABIL, false)
            SetPlayerAbilityAvailable(p, _TRANSFORM_ABIL, false)
            TriggerRegisterPlayerUnitEvent(order, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
        end
        preplaced = nil
    end)
end)
end
 
Top