• 🏆 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!

GUI Unit Event (now with a state-of-the-art Lua version)

Unit Event for GUI gives you access to all kinds of events which normal GUI events can't do:

FunctionLuavJass
Subject unit of the eventUnitEvent_unitUDexUnits[UDex]
Event index (for use within an array).UnitEvent_indexUDex
Data attachment to unitSet UnitEvent_setKey = unit
Set MyArray[UnitEvent_getKey] = data
Set MyArray2[UnitEvent_getKey] = data2
Set TempInt = (Custom value of unit)
Set MyArray[TempInt] = data
Set MyArray2[TempInt] = data2
Data retrieval from unitSet UnitEvent_setKey = unit
Set data = MyArray[UnitEvent_getKey]
Set data2 = MyArray2[UnitEvent_getKey]
Set TempInt = (Custom value of unit)
Set data = MyArray[TempInt]
Set data2 = MyArray2[TempInt]
Manually created in World Editor
Unit who summoned the subject unit
Know the previous type in a transform event
Is the unit reincarnating
Unit who is carrying the subject unit
All units carried by the unit
Detect the unit's killer in a death event
UnitEvent_preplaced
UnitEvent_summoner
UnitEvent_unitType
UnitEvent_reincarnating
UnitEvent_transporter
UnitEvent_cargo
(Killing unit)
IsUnitPreplaced
SummonerOfUnit
UnitTypeOf
IsUnitReincarnating
CargoTransportUnit
CargoTransportGroup
KillerOfUnit
Starts existing
Fully created
Stops existing
Starts reincarnating
Resurrects, reanimated or finishes reincarnating
Dies
Loaded into a transport
Unloaded from a transport
Transforms into a new unit
Is playable (alive/not loaded)
Is unplayable (dead/loaded)
OnUnitIndexed
OnUnitCreation
OnUnitRemoval
OnUnitReincarnating
OnUnitRevival
OnUnitDeath
OnUnitLoaded
OnUnitUnloaded
OnUnitTransform
OnUnitActive
OnUnitPassive
UnitIndexEvent == 1.00
UnitIndexEvent == 1.50
UnitIndexEvent == 2.00
DeathEvent == 0.50
DeathEvent == 2.00
DeathEvent == 1.00
CargoEvent == 1.00
CargoEvent == 2.00
UnitTypeEvent == 1.00
UnitInActionEvent == 1.00
UnitInActionEvent == 2.00

You can distinguish between types of unit revival with three conditions:
1) If it is summoned, that means it was reanimated (e.g. "Animate Dead (Death Knight Ultimate)").
2) If UnitEvent_reincarnating (Lua version) / IsUnitReincarnating (JASS version) is true, that means it finished reincarnating (e.g. "Reincarnation (Tauren Chieftan Ultimate)").
3) If the above are False, the unit was resurrected (e.g. "Ressurrection (Paladin Ultimate)").

Lua:
OnGlobalInit(function()
    
    Require "Timed"                         --https://www.hiveworkshop.com/threads/timed-call-and-echo.339222/
    Require "AddHook"                       --https://www.hiveworkshop.com/threads/hook.339153
    Require "GlobalRemap"                   --https://www.hiveworkshop.com/threads/global-variable-remapper.339308
    Require "RegisterAnyPlayerUnitEvent"    --https://www.hiveworkshop.com/threads/collection-gui-repair-kit.317084/
    Require "CreateEvent"                   --https://www.hiveworkshop.com/threads/event-gui-friendly.339451/
    Require "PreciseWait"                   --https://www.hiveworkshop.com/threads/precise-wait-gui-friendly.316960/
--[[
Lua Unit Event 1.2.0.2

In addition to the existing benefits enjoyed over the past years, this Lua version supports linked events that allow
your trigger to Wait until another event runs (meaning you can do attachment and cleanup from one trigger).

Variable names have been completely changed from all prior Unit Event incarnations.
> All real variable event names are now prefixed with OnUnit...
> All array references (unit properties) are now prefixed with UnitEvent_
> Lua users can access a unit's properties via UnitEvent[unit].property (e.g. reincarnating/cargo)
> Lua users can easily add a readonly GUI property to a unit via UnitEvent.addProperty("propertyName")
>>> GUI accesses it via UnitEvent_propertyName, the second is readable and writable within Lua via UnitEvent[unit].propertyName
> UnitUserData (custom value of unit) has been completely removed. This is the first unit event/indexer to not use UnitUserData nor hashtables.
>>> UnitEvent_unit is the subject unit of the event.
>>> UnitEvent_index is an integer in GUI, but points to a the unit.
>>> UnitEvent_setKey lets you assign a unit to the key.
>>> UnitEvent_getKey is an integer in GUI, but points to the unit you assigned as the key.
>>>>> Lua doesn't care about array max sizes, nor the type of information used as an index in that array (because it uses tables and not arrays).
>>>>> GUI is over 20 years old and can easily be fooled. As long as the variable is defined with the correct type, it doesn't care what happens to that variable behind the scenes.
--]]
    UnitEvent={}

    local _REMOVE_ABIL      = FourCC('A001')
    local _TRANSFORM_ABIL   = FourCC('A002') --be sure to assign these to their respective abilities if you prefer not to initialize via GUI
    
    --Un-comment this next line if you want to use the custom value of units functionality (for backwards compatibility):
    --GetUnitUserData = function(unit) return unit end

--[[
    Full list of GUI variables:
    real    udg_OnUnitIndexed
    real    udg_OnUnitCreation
    real    udg_OnUnitRemoval
    real    udg_OnUnitReincarnating
    real    udg_OnUnitRevival
    real    udg_OnUnitLoaded
    real    udg_OnUnitUnloaded
    real    udg_OnUnitTransform
    real    udg_OnUnitDeath
    real    udg_OnUnitActive
    real    udg_OnUnitPassive

    ability udg_DetectRemoveAbility
    ability udg_DetectTransformAbility

    unit    udg_UnitEvent_unit
    integer udg_UnitEvent_index

    unit    udg_UnitEvent_setKey
    integer udg_UnitEvent_getKey

    boolean   array udg_UnitEvent_preplaced
    unit      array udg_UnitEvent_summoner
    unittype  array udg_UnitEvent_unitType
    boolean   array udg_UnitEvent_reincarnating
    unit      array udg_UnitEvent_transporter
    unitgroup array udg_UnitEvent_cargo
--]]

    local eventList={}
    local udg_prefix="udg_OnUnit"
    local makeAPI = function(name)
        UnitEvent["on"..name],
        eventList["on"..name] = CreateEvent(udg_prefix..name, true)
    end
    local unitIndices={} ---@type UnitEventTable[]

    --onIndexed and onCreation occur at roughly the same time, but the unit's creation should be used instead as it will have more data.
    --Combined, they are the counterparts to onRemoval.
    makeAPI("Indexed")
    makeAPI("Creation")
    makeAPI("Removal")

    --counterparts (though revival doesn't only come from reincarnation):
    makeAPI("Reincarnating")
    makeAPI("Revival")
    
    --perfect counterparts:
    makeAPI("Loaded")
    makeAPI("Unloaded")
    
    --stand-alone events:
    makeAPI("Transform")
    makeAPI("Death")
    
    --perfect counterparts that generalize all but the "transform" event:
    makeAPI("Active")
    makeAPI("Passive")

    --Used to get the UnitEvent table from the unit to detect UnitEvent-specific properties.
    UnitEvent.__index = function(_, unit) return unitIndices[unit] end
    
    ---@param name string
    UnitEvent.addProperty = function(name)
        GlobalRemapArray("udg_UnitEvent_"..name, function(unit) return unitIndices[unit][name] end)
    end

    ---@class UnitEventTable : table
    ---@field unit          unit
    ---@field preplaced     boolean
    ---@field summoner      unit
    ---@field transporter   unit
    ---@field cargo         group
    ---@field reincarnating boolean
    ---@field private new boolean
    ---@field private alive boolean
    ---@field private unloading boolean
    
    --The below two variables are intended for GUI typecasting, because you can't use a unit as an array index.
    --What it does is bend the rules of GUI (which is still bound by strict JASS types) by transforming those
    --variables with Global Variable Remapper (which isn't restricted by any types).
    --"setKey" is write-only (assigns the key to a unit)
    --"getKey" is read-only (retrieves the key and tells GUI that it's an integer, allowing it to be used as an array index)
    local lastUnit
    GlobalRemap("udg_UnitEvent_setKey", nil, function(unit)lastUnit=unit end) --assign to a unit to unlock the getKey variable.
    GlobalRemap("udg_UnitEvent_getKey",      function() return lastUnit  end) --type is "integer" in GUI but remains a unit in Lua.

    local runEvent
    do
        local eventUnit
        local getEventUnit  = function() return eventUnit end
        runEvent            = function(event, unitTable)
            local cached    = eventUnit
            eventUnit       = unitTable.unit
            eventList[event](unitTable)
            eventUnit       = cached
        end
        GlobalRemap("udg_UnitEvent_unit",  getEventUnit) --the subject unit for the event.
        GlobalRemap("udg_UnitEvent_index", getEventUnit) --fools GUI into thinking unit is an integer
    end
    --add a bunch of read-only arrays to access GUI data. I've removed the "IsUnitAlive" array as the GUI living checks are fixed with the GUI Enhancer Colleciton.
    UnitEvent.addProperty("preplaced")
    UnitEvent.addProperty("unitType")
    UnitEvent.addProperty("reincarnating")
    UnitEvent.addProperty("transporter")
    UnitEvent.addProperty("summoner")
    
    if rawget(_G, "udg_UnitEvent_cargo") then
        UnitEvent.addProperty("cargo")
    end
    
    --Flag a unit as being able to move or attack on its own:
    local function setActive(unitTable)
        if unitTable and not unitTable.active and UnitAlive(unitTable.unit) then --be sure not to run the event when corpses are created/unloaded.
            unitTable.active = true
            runEvent("onActive", unitTable)
        end
    end
    ---Flag a unit as NOT being able to move or attack on its own:
    local function setPassive(unitTable)
        if unitTable and unitTable.active then
            unitTable.active = nil
            runEvent("onPassive", unitTable)
        end
    end
    local function getFunc(active)
        return function(unitTable) (active and setActive or setPassive)(unitTable) end
    end

    UnitEvent.onCreation(getFunc(true), 2, true)
    UnitEvent.onUnloaded(getFunc(true), 2, true)
    UnitEvent.onRevival(getFunc(true), 2, true)
    
    UnitEvent.onLoaded(getFunc(), 2, true)
    UnitEvent.onReincarnating(getFunc(), 2, true)
    UnitEvent.onDeath(getFunc(), 2, true)
    UnitEvent.onRemoval(getFunc(), 2, true)
    
    --UnitEvent.onIndex(function(unitTable) print(tostring(unitTable.unit).."/"..GetUnitName(unitTable.unit).." has been indexed.") end)
    
    setmetatable(UnitEvent, UnitEvent)

    --Wait until GUI triggers and events have been initialized. 
    OnTrigInit(function()
        if rawget(_G, "Trig_Unit_Event_Config_Actions") then
            Trig_Unit_Event_Config_Actions()
            _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(0, function()
                    unitTable.checking          = nil
                    if unitTable.new then
                        unitTable.new           = nil
                        runEvent("onCreation", unitTable) --thanks to Spellbound for the idea
                    elseif unitTable.transforming then
                        local unit = unitTable.unit
                        runEvent("onTransform", unitTable)
                        unitTable.unitType = GetUnitTypeId(unit) --Set this afterward to give the user extra reference

                        --Reset the transforming flags so that subsequent transformations can be detected.
                        unitTable.transforming  = nil
                        UnitAddAbility(unit, _TRANSFORM_ABIL)
                    elseif unitTable.alive then
                        unitTable.reincarnating = true
                        unitTable.alive         = false
                        runEvent("onReincarnating", unitTable)
                    elseif UnitAlive(unitTable.unit) then
                        unitTable.alive = true
                        runEvent("onRevival", unitTable)
                        unitTable.reincarnating = false
                    end
                end)
            end
        end
    
        local re = CreateRegion()
        local r = GetWorldBounds()
        local maxX, maxY = GetRectMaxX(r), GetRectMaxY(r)
        RegionAddRect(re, r); RemoveRect(r)
        
        local function unloadUnit(unitTable)
            local unit, transport       = unitTable.unit, unitTable.transporter
            GroupRemoveUnit(unitIndices[transport].cargo, unit)
            unitTable.unloading         = true
            runEvent("onUnloaded", unitTable)
            unitTable.unloading         = nil
            if not IsUnitLoaded(unit) or not UnitAlive(transport) or GetUnitTypeId(transport) == 0 then
                unitTable.transporter   = nil
            end
        end
        
        local preplaced = true
        local onEnter = Filter(
        function()
            local unit = GetFilterUnit()
            local unitTable = unitIndices[unit]
            if not unitTable then
                unitTable = {
                    unit    = unit,
                    new     = true,
                    alive   = true,
                    unitType= GetUnitTypeId(unit)
                }
                UnitAddAbility(unit, _REMOVE_ABIL)
                UnitMakeAbilityPermanent(unit, true, _REMOVE_ABIL)
                UnitAddAbility(unit, _TRANSFORM_ABIL)

                unitIndices[unit] = unitTable

                unitTable.preplaced = preplaced
                runEvent("onIndexed", unitTable)
                
                checkAfter(unitTable)
            elseif unitTable.transporter and not IsUnitLoaded(unit) then
                --the unit was dead, but has re-entered the map (e.g. unloaded from meat wagon)
                unloadUnit(unitTable)
            end
        end)
        TriggerRegisterEnterRegion(CreateTrigger(), re, onEnter)
        
        RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_LOADED,
        function()
            local unit = GetTriggerUnit()
            local unitTable = unitIndices[unit]
            if unitTable then
                if unitTable.transporter then
                    unloadUnit(unitTable)
                end
                --Loaded corpses do not issue an order when unloaded, therefore must
                --use the enter-region event method taken from Jesus4Lyf's Transport: https://www.thehelper.net/threads/transport-enter-leave-detection.126051/
                if not unitTable.alive then
                    SetUnitX(unit, maxX)
                    SetUnitY(unit, maxY)
                end
                local transporter = GetTransportUnit()
                unitTable.transporter = transporter
                local g = unitIndices[transporter].cargo
                if not g then
                    g=CreateGroup()
                    unitIndices[transporter].cargo = g
                end
                GroupAddUnit(g, unit)
                
                runEvent("onLoaded", unitTable)
            end
        end)
        
        RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH,
        function()
            local unitTable = unitIndices[GetTriggerUnit()]
            if unitTable then
                unitTable.alive = false
                runEvent("onDeath", unitTable)
                if unitTable.transporter then
                    unloadUnit(unitTable)
                end
            end
        end)
        
        RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SUMMON,
        function()
            local unitTable = unitIndices[GetTriggerUnit()]
            if unitTable.new then
                unitTable.summoner = GetSummoningUnit()
            end
        end)
        
        local orderB = Filter(
        function()
            local unit = GetFilterUnit()
            local unitTable = unitIndices[unit]
            if unitTable then
                if GetUnitAbilityLevel(unit, _REMOVE_ABIL) == 0 then

                    runEvent("onRemoval", unitTable)
                    unitIndices[unit] = nil
                    unitTable.cargo = nil
                elseif not unitTable.alive then
                    if UnitAlive(unit) then
                        checkAfter(unitTable)
                    end
                elseif not UnitAlive(unit) then
                    if unitTable.new then
                        --This unit was created as a corpse.
                        unitTable.alive = false
                        runEvent("onDeath", unitTable)

                    elseif not unitTable.transporter or not IsUnitType(unit, UNIT_TYPE_HERO) then
                        --The unit may have just started reincarnating.
                        checkAfter(unitTable)
                    end
                elseif GetUnitAbilityLevel(unit, _TRANSFORM_ABIL) == 0 and not unitTable.transforming then
                    unitTable.transforming = true
                    checkAfter(unitTable)
                end
                if unitTable.transporter and not unitTable.unloading and not (IsUnitLoaded(unit) and UnitAlive(unit)) then
                    unloadUnit(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 = false
    end)
end)

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 (was hosted on the now-defunct wc3c.net)
- UnitEvent by Nestharus: https://github.com/nestharus/JASS/blob/master/jass/Systems/Unit%20Event/script.j
- Transport by Jesus4Lyf: https://www.thehelper.net/threads/transport-enter-leave-detection.126051/

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

Lua Unit Event Test Map (Map)

Unit Event 2.5.3.1 (Map)

Reviews
Approved. Makes easy to detect many events that do not exist in the editor. Very useful system.
Level 24
Joined
Feb 9, 2009
Messages
1,783
Here's the test
Blood mage has the ability


Edit: That test map shows that either I'm not putting that variable in right or it doesn't work all together, would really appreciate if someone could tell me that.
 

Attachments

  • Orbit test - GUI UNIT EVENT BY BRIBE DO NOT DISTRIBUTE.w3x
    29.1 KB · Views: 60
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I fired up my rusty netbook and you have a Spell set up instead of an isolated loop. You definitely need to go to T&S for help with your spell.

Honestly, your spell would be way shorter and therefore straightfoward to debug if you used Spell System.

I don't know offhand where the error in your code is, but it has nothing to do with how Unit Event works.
 
Level 7
Joined
Jan 23, 2011
Messages
350
I know the system doesn't mess with it, it seems like a weird interaction with the Defend-based ability used.
In the testmap, if you morph the Bear, its mana resets to 0, if the system don't mess with the bear(no DetectMorph ability), its mana is maintained as usual.

Had the same problem with Robogobo on the test
 
Level 18
Joined
Nov 21, 2012
Messages
835
I had similar problem Berserk resets mana to zero

Bug in UnitEvent seems to be related to upgrade (bonus mana/life points value).
  • It may reset mana as well as set mana to max.
  • It may kill unit as well as set its life to max.
The action causes bug is in function UnitEventOnOrder where you add ability call UnitAddAbility(u, udg_DetectTransformAbility)

Why upgrade? If upgrade boosts mana points by X value, and unit (who benefits from such an upgrade) has base mana points = BASE then:
  • if X==BASE then casting some abilities will reset mana to zero
  • if x<BASE all is OK
  • if x>BASE then casting some abilities will set unit's mana to max
You're using upgrade 'Redc' for NE unit Druid of the Claw who has base mana = 200
Each level o upgrade Redc boost max mana by 100. So after 2nd upgrade it boosts mana by 200. So BASE=200 and X=2*100 and we got reset mana bug

The same will happend with unit's life.
by casting some abilities I mean (already tested with disabled spell book problem):
  • mana shield
  • immolation
  • wind walk
  • berserk
  • roar
Now it seems that "defend" also bug mana/life points. Unfortunatelly I have no solution for this now, but it may help you understand bug and fix UnitEvent.
 
Last edited:
Level 18
Joined
Nov 21, 2012
Messages
835
Add integer variable udg_UnitId[udex]=GetUnitTypeId(u) and write it after unit is indexed.
To detect transform without 2nd "defend" ability I used 2 triggers:
JASS:
native UnitAlive takes unit u returns boolean

function Trig_stopCasting_Conditions takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local integer udex=GetUnitUserData(u)
 
    call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "stop casted abi " + GetObjectName(GetSpellAbilityId()))
     
    if UnitAlive(u) and (udg_UnitId[udex] != GetUnitTypeId(u)) then
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " transformed <spell event detect>")
        set udg_UnitId[udex]=GetUnitTypeId(u) 
    endif
 
    return false
endfunction
//===========================================================================
function InitTrig_stopCasting takes nothing returns nothing
    set gg_trg_stopCasting = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_stopCasting, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
    call TriggerAddCondition( gg_trg_stopCasting, Condition( function Trig_stopCasting_Conditions ) )
endfunction
JASS:
function Trig_ordInstant_Conditions takes nothing returns boolean
    local integer ord=GetIssuedOrderId()
    local unit u=GetOrderedUnit()
    local integer udex=GetUnitUserData(u)

    if OrderId2String(ord)=="undefend" and UnitAlive(u) and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
 
    if not (udg_UnitId[udex]==GetUnitTypeId(u)) then
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " transformed! <undefend detect>")
        set udg_UnitId[udex]=GetUnitTypeId(u)
    endif
 
    endif
 
    return false
endfunction
//===========================================================================
function InitTrig_ordInstant takes nothing returns nothing
    set gg_trg_ordInstant = CreateTrigger(  )
    call DisableTrigger(gg_trg_ordInstant)
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ordInstant, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerAddCondition( gg_trg_ordInstant, Condition( function Trig_ordInstant_Conditions ) )
endfunction

order "undefend" trigger detects Militia
end spell cast detects Phoenix, metamorphosis, bear form, etc
If you won't find better take a look at this solution.
 

Attachments

  • resetMana.w3x
    19.9 KB · Views: 58

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Update! Big shoutout to @ZiBitheWand3r3r for the solution - this no longer needs an extra ability and also no longer bugs transform values such as mana.

@dtnmang I believe this would need too many new features to work. What makes Unit Event great is how everything is tied to the fewest events possible, with a lot of them sharing the order event.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
UPDATE!

The solution to the above problem is contingent on re-adding the transform ability with a delay (the delay was already set up thanks to the reincarnate detection).

This goes back to the previous method of having two separate abilities, but with the benefit of being completely devoid of bugs and detects every transform type unlike the last approach which didn't catch things like Militia.

Thanks ZiBi for not letting me slack on this!
 
There's a quite peculiar problem that I've encountered. I've made a DeathEvent trigger for a unit; and at the same time, I make a spell using the GUI Spell System. What this spell does is casting 4-12 Carrion Swarms with 0.05s interval between each (it looks like hurling a wave of shurikens). But when a unit is killed by this spell at very close range (where it eats all of the shurikens) the actions of that unit's DeathEvent trigger would not be called.
I think you meant to post this on the Unit Event map instead of this, but regardless it sounds like something needs to be investigated; perhaps you are unwittingly using both Unit Indexer and Unit Event - but you need to have either one or the other. In this case you would just stick with Unit Event.
There's no Unit Indexer in my map. There's only Unit Event which is the latest version.
 
This is the relevant part of that spell trigger:
  • Lance config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Spell__Ability = KA - Sweeping Shurikens
      • Set Spell__Trigger_OnEffect = Lance effect <gen>
      • Set Spell__Trigger_OnLoop = Lance loop <gen>
      • Trigger - Run Spell System <gen> (checking conditions)
  • Lance effect
    • Events
    • Conditions
    • Actions
      • Set LanceLoops[Spell__Index] = 0
      • Set LanceStartingAngle[Spell__Index] = ((Facing of Spell__Caster) + ((36.00 x (3.00 + (2.00 x Spell__LevelMultiplier))) / (2.00 + (2.00 x Spell__LevelMultiplier))))
      • -------- --------
      • Set Spell__Duration = 1.00
      • Set Spell__Time = 0.05
  • Lance loop
    • Events
    • Conditions
    • Actions
      • Set LanceLoops[Spell__Index] = (LanceLoops[Spell__Index] + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • LanceLoops[Spell__Index] Greater than (2 x (Spell__Level + 1))
        • Then - Actions
          • Set Spell__Duration = 0.00
        • Else - Actions
          • Set LanceCastAngle[Spell__Index] = (LanceStartingAngle[Spell__Index] - (36.00 / (1.00 + Spell__LevelMultiplier)))
          • Set LanceStartingAngle[Spell__Index] = LanceCastAngle[Spell__Index]
          • Unit - Create 1 Spell__DummyType for Spell__CasterOwner at Spell__CastPoint facing LanceCastAngle[Spell__Index] degrees
          • Animation - Change (Last created unit)'s size to (120.00%, 120.00%, 120.00%) of its original size
          • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
          • Unit - Add Dummy - Carrion Swarm to (Last created unit)
          • Unit - Set level of Dummy - Carrion Swarm for (Last created unit) to Spell__Level
          • Set LanceTarget[Spell__Index] = (Spell__CastPoint offset by 20.00 towards LanceCastAngle[Spell__Index] degrees)
          • Unit - Order (Last created unit) to Undead Dreadlord - Carrion Swarm LanceTarget[Spell__Index]
          • Custom script: call RemoveLocation(udg_LanceTarget[udg_Spell__Index])
  • Damage trig
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • IsDamageSpell Equal to True
      • (Level of Dummy - Carrion Swarm for DamageEventSource) Greater than 0
    • Actions
      • Set DamageEventAmount = 0.00
      • Unit - Cause DamageEventSource to damage DamageEventTarget, dealing ((Random real number between 18.00 and 26.00) + (4.00 x (Real((Current research level of Weapon Mastery for (Owner of DamageEventSource)))))) damage of attack type Hero and damage type Normal
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Hey Bribe, I disabled the DamageEvent trigger and let the spell apply magical damage as normal, but the result was still the same, so I think it isn't the solution.
So what's happening - is the unit dying at least? Try adding debug messages where you think the problem lies. I won't be able to do any of this stuff until mid September when I'm back from hell.
 
Level 12
Joined
Jun 12, 2010
Messages
413
This system is basically a necessity if you want more control over your units and clean up unused data. It is also extremely useful in creating spells that involve summoning units.

Maybe not as necessary as a damage detection system, but the possbilities brought by this system's usage makes it pretty much a requirement for advanced GUI maps in my book.
 
Level 12
Joined
Jun 12, 2010
Messages
413
It doesn't have damage detection at all :p

Oh I know, I meant to say that this is probably less necessary than a Damage Detection system for advanced mapmaking/mechanics. I always tell people that they should have a very good reason NOT to have a DDS in their map (when they want more complex spells), but having something like Unit Event comes pretty close in terms of "necessity".

Both these systems really broaden the capabilities of WC3, so I was just comparing them, though I wasn't as clear as I wanted to be xD
 
Last edited:

Kyrbi0

Arena Moderator
Level 44
Joined
Jul 29, 2008
Messages
9,487
Oh I know, I meant to say that this is probably less necessary than a Damage Detection system for advanced mapmaking/mechanics. I always tell people that they should have a very good reason NOT to have a DDS in their map (when they want more complex spells), but having something like Unit Event comes pretty close in terms of "necessity".

Both these systems really boarden the capabilities of WC3, so I was just comparing them, though I wasn't as clear as I wanted to be xD
Challenge Accepted. ; )


(@Spellbound )
 
Level 7
Joined
May 30, 2013
Messages
210
Um.
I'm probably just dumb, but I can't seem to figure out how to grab the unit that gets (un-)loaded?
There only seems to be a variable to detect the transport that's (un-)loading a unit
 
Level 4
Joined
Jan 27, 2016
Messages
89
Would it be possible to make it so, if the index value exceeds 8192 the indexer creates a new global in which it indexes, so if a unit had 8200 as a custom value, it would go to the second index array, and then check the (custom value - (array number - 1 ) * 8192) value in the array, in this case it would be 8 (or 7?).

Also, does this support the configurations in unit indexer? Since those two arent compatible do you have to sacrifice one for the other?
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
Would it be possible to make it so, if the index value exceeds 8192 the indexer creates a new global in which it indexes, so if a unit had 8200 as a custom value, it would go to the second index array, and then check the (custom value - (array number - 1 ) * 8192) value in the array, in this case it would be 8 (or 7?).
How is your map even functioning with that many units?
 
Level 4
Joined
Jan 27, 2016
Messages
89
Well, its not functioning yet. However, I dont think it would ever even reach 2k, but I sometimes see the Indexer just skip numbers a lot and it worries me that it would eventually go over 8k, so its a safety net. And Im mostly suggesting it for the fun of it, so that the systen has 1 less "limitation"
 
Top