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

[Solved] Question related to Unit Indexing / Damage Events

Status
Not open for further replies.
Level 11
Joined
May 7, 2008
Messages
300
EDIT - Solution has been found, scroll down below to find it!

I'm very new to this, and I'm a little bit stuck on the next thing I want to do :p

As for now, I'm sure you all know that ''A unit is attacked'' event is highly abusive, and that's where my problem lies.

I'm trying to use this damage / unit indexing to check if the damage has been made, so far it works for one of the imported spells called ''Fatal Bonds'' which was made by one of the users here on Hive, however I have no idea how to actually apply it.


This is my code:

  • Wrath of Nature
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacking unit)) Equal to |cffff8080Elder Spirit|r
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Random integer number between 1 and 100) Less than or equal to 12
          • DamageEvent Equal to 1.00
        • Then - Actions
          • Set VariableSet TempPoint = (Position of (Attacking unit))
          • Unit - Create 1 Caster Dummy for (Owner of (Attacking unit)) at TempPoint facing Default building facing degrees
          • Unit - Add a 2.00 second Generic expiration timer to (Last created unit)
          • Unit - Add Wrath of Nature Passive to (Last created unit)
          • Unit - Order (Last created unit) to Neutral Sea Witch - Forked Lightning (Attacked unit)
          • -------- . --------
          • Floating Text - Create floating text that reads |cff80ff80Wrath of ... at TempPoint with Z offset 0.00, using font size 8.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Floating Text - Set the velocity of (Last created floating text) to 80.00 towards 140.00 degrees
          • Floating Text - Change (Last created floating text): Disable permanence
          • Floating Text - Change the lifespan of (Last created floating text) to 3.00 seconds
          • Floating Text - Change the fading age of (Last created floating text) to 2.00 seconds
          • Custom script: call RemoveLocation(udg_TempPoint)
        • Else - Actions

It works without ''DamageEvent Equal to 1.00'' but spamming hold or stop and then attacking will result in abusive scenarios, which I do not prefer.

And then I'm using this

  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • Custom script:
      • Custom script: function ClearUnitIndex takes nothing returns nothing
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Custom value of UDexUnits[UDex]) Equal to 0
        • Then - Actions
          • Set VariableSet UnitIndexLock[UDex] = (UnitIndexLock[UDex] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UnitIndexLock[UDex] Equal to 0
            • Then - Actions
              • Set VariableSet UDexNext[UDexPrev[UDex]] = UDexNext[UDex]
              • Set VariableSet UDexPrev[UDexNext[UDex]] = UDexPrev[UDex]
              • Set VariableSet UDexPrev[UDex] = 0
              • Set VariableSet UnitIndexEvent = 0.00
              • Set VariableSet UnitIndexEvent = 2.00
              • Set VariableSet UnitIndexEvent = 0.00
              • Set VariableSet UDexUnits[UDex] = No unit
              • Set VariableSet UDexNext[UDex] = UDexRecycle
              • Set VariableSet UDexRecycle = UDex
            • Else - Actions
        • Else - Actions
      • Custom script: endfunction
      • Custom script:
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- - --------
      • -------- You can customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- - --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexerEnabled Equal to True
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • Set VariableSet UDexWasted = (UDexWasted + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexWasted Equal to 32
            • Then - Actions
              • Set VariableSet UDexWasted = 0
              • Set VariableSet UDex = UDexNext[0]
              • Custom script: loop
              • Custom script: exitwhen udg_UDex == 0
              • Custom script: set ndex = udg_UDexNext[udg_UDex]
              • Custom script: call ClearUnitIndex()
              • Custom script: set udg_UDex = ndex
              • Custom script: endloop
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexRecycle Equal to 0
            • Then - Actions
              • Set VariableSet UDex = (UDexGen + 1)
              • Set VariableSet UDexGen = UDex
            • Else - Actions
              • Set VariableSet UDex = UDexRecycle
              • Set VariableSet UDexRecycle = UDexNext[UDex]
          • Set VariableSet UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • Set VariableSet UDexPrev[UDexNext[0]] = UDex
          • Set VariableSet UDexNext[UDex] = UDexNext[0]
          • Set VariableSet UDexNext[0] = UDex
          • Set VariableSet UnitIndexLock[UDex] = 1
          • Set VariableSet UnitIndexEvent = 0.00
          • Set VariableSet UnitIndexEvent = 1.00
          • Set VariableSet UnitIndexEvent = 0.00
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 16
      • Custom script: local boolexpr b = Filter(function IndexUnit)
      • Custom script: local region re = CreateRegion()
      • Custom script: local trigger t = GetTriggeringTrigger()
      • Custom script: local rect r = GetWorldBounds()
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(t, re, b)
      • Custom script: call TriggerClearActions(t)
      • Custom script: call TriggerAddAction(t, function ClearUnitIndex)
      • Set VariableSet UnitIndexerEnabled = True
      • Custom script: loop
      • Custom script: set i = i - 1
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
      • Custom script: exitwhen i == 0
      • Custom script: endloop
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: set t = null
      • Custom script: set b = null
      • Set VariableSet UnitIndexEvent = 3.00
      • Set VariableSet UnitIndexEvent = 0.00

and

  • Damage Engine Config
    • Events
    • Conditions
      • (UDexUnits[UDex] is A structure) Equal to False
    • Actions
      • -------- - --------
      • -------- This trigger's conditions let you filter out units you don't want detection for. --------
      • -------- NOTE: By default, units with Locust will not pass the check. --------
      • -------- TIP: The unit is called UDexUnits[UDex] and its custom value is UDex --------
      • -------- - --------
      • -------- Copy the Cheat Death Ability from Object Editor into your map and set the following variable respectively: --------
      • -------- - --------
      • Set VariableSet DamageBlockingAbility = Cheat Death Ability (+500,000)
      • -------- - --------
      • -------- Copy the Detect Spell Damage Ability from Object Editor into your map and set the following variable respectively: --------
      • -------- - --------
      • Set VariableSet SpellDamageAbility = Detect Spell Damage
      • -------- - --------
      • -------- You can add extra classifications here if you want to differentiate between your triggered damage --------
      • -------- Use DamageTypeExplosive (or any negative value damage type) if you want a unit killed by that damage to explode --------
      • -------- - --------
      • Set VariableSet DamageTypeExplosive = -1
      • Set VariableSet DamageTypeCriticalStrike = 1
      • Set VariableSet DamageTypeHeal = 2
      • Set VariableSet DamageTypeReduced = 3
      • Set VariableSet DamageTypeBlocked = 4
      • -------- - --------
      • -------- Leave the next Set statement disabled if you modified the Spell Damage Reduction item ability to 1.67 reduction --------
      • -------- Otherwise, if you removed that ability from Runed Bracers, you'll need to enable this line: --------
      • -------- - --------
      • Set VariableSet DmgEvBracers = Runed Bracers
      • -------- - --------
      • -------- Set the damage multiplication factor (1.00 being unmodified, increasing in damage over 1.00 and at 0 damage with 0.00) --------
      • -------- NOTE. With the default values, Runed Bracers is reduces 33%, Elune's Grace reduces 20% and Ethereal increases 67% --------
      • -------- - --------
      • Set VariableSet DAMAGE_FACTOR_BRACERS = 0.67
      • Set VariableSet DAMAGE_FACTOR_ELUNES = 0.80
      • Set VariableSet DAMAGE_FACTOR_ETHEREAL = 1.67
      • -------- - --------
      • -------- Do not enable any of the following lines as they are simply variable declarations to make copying easier --------
      • -------- - --------
      • Set VariableSet AfterDamageEvent = (DamageEvent + DamageModifierEvent)
      • Set VariableSet ClearDamageEvent = (This trigger)
      • Set VariableSet DamageEventAmount = DamageEventPrevAmt
      • Set VariableSet DamageEventOverride = NextDamageOverride
      • Set VariableSet DamageEventSource = DamageEventTarget
      • Set VariableSet DamageEventTrigger = DmgEvTrig
      • Set VariableSet DamageEventType = (LastDmgPrevType[0] + NextDamageType)
      • Set VariableSet DamageEventsWasted = DmgEvRecursionN
      • Set VariableSet DmgEvRunning = DmgEvStarted
      • Set VariableSet IsDamageSpell = LastDmgWasSpell[0]
      • Set VariableSet LastDamageHP = (Elapsed time for DmgEvTimer)
      • Set VariableSet LastDmgPrevAmount[0] = LastDmgValue[0]
      • Set VariableSet LastDmgSource[0] = LastDmgTarget[0]
      • Set VariableSet HideDamageFrom[0] = False
      • Set VariableSet UnitDamageRegistered[0] = False

and


JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
//===========================================================================
// Damage Engine lets you detect, amplify, block or nullify damage. It even
// lets you detect if the damage was physical or from a spell. Just reference
// DamageEventAmount/Source/Target or the boolean IsDamageSpell, to get the
// necessary damage event data.
//
// - Detect damage: use the event "DamageEvent Equal to 1.00"
// - To change damage before it's dealt: use the event "DamageModifierEvent Equal to 1.00"
// - Detect damage after it was applied, use the event "AfterDamageEvent Equal to 1.00"
// - Detect spell damage: use the condition "IsDamageSpell Equal to True"
// - Detect zero-damage: use the event "DamageEvent Equal to 2.00" (an AfterDamageEvent will not fire for this)
//
// You can specify the DamageEventType before dealing triggered damage. To prevent an already-improbable error, I recommend running the trigger "ClearDamageEvent (Checking Conditions)" after dealing triggered damage from within a damage event:
// - Set NextDamageType = DamageTypeWhatever
// - Unit - Cause...
// - Trigger - Run ClearDamageEvent (Checking Conditions)
//
// You can modify the DamageEventAmount and the DamageEventType from a "DamageModifierEvent Equal to 1.00" trigger.
// - If the amount is modified to negative, it will count as a heal.
// - If the amount is set to 0, no damage will be dealt.
//
// If you need to reference the original in-game damage, use the variable "DamageEventPrevAmt".
//
//===========================================================================
// Programming note about "integer i" and "udg_DmgEvRecursionN": integer i
// ranges from -1 upwards. "udg_DmgEvRecursionN" ranges from 0 upwards.
// "integer i" is always 1 less than "udg_DmgEvRecursionN"
//
function DmgEvResetVars takes nothing returns nothing
    local integer i = udg_DmgEvRecursionN - 2
    set udg_DmgEvRecursionN = i + 1
    if i >= 0 then
        set udg_DamageEventPrevAmt  = udg_LastDmgPrevAmount[i]
        set udg_DamageEventAmount   = udg_LastDmgValue[i]
        set udg_DamageEventSource   = udg_LastDmgSource[i]
        set udg_DamageEventTarget   = udg_LastDmgTarget[i]
        set udg_IsDamageSpell       = udg_LastDmgWasSpell[i]
        set udg_DamageEventType     = udg_LastDmgPrevType[i]
    endif
endfunction

function CheckDamagedLifeEvent takes boolean clear returns nothing
    if clear then
        set udg_NextDamageOverride = false
        set udg_NextDamageType = 0
    endif
    if udg_DmgEvTrig != null then
        call DestroyTrigger(udg_DmgEvTrig)
        set udg_DmgEvTrig = null
     
        if udg_IsDamageSpell then
            call SetWidgetLife(udg_DamageEventTarget, RMaxBJ(udg_LastDamageHP, 0.41))
            if udg_LastDamageHP <= 0.405 then
                if udg_DamageEventType < 0 then
                    call SetUnitExploded(udg_DamageEventTarget, true)
                endif
                //Kill the unit
                call DisableTrigger(udg_DamageEventTrigger)
                call UnitDamageTarget(udg_DamageEventSource, udg_DamageEventTarget, -999, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                call EnableTrigger(udg_DamageEventTrigger)
            endif
        elseif GetUnitAbilityLevel(udg_DamageEventTarget, udg_DamageBlockingAbility) > 0 then
            call UnitRemoveAbility(udg_DamageEventTarget, udg_DamageBlockingAbility)
            call SetWidgetLife(udg_DamageEventTarget, udg_LastDamageHP)
        endif
        if udg_DamageEventAmount != 0.00 and not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_AfterDamageEvent = 0.00
            set udg_AfterDamageEvent = 1.00
            set udg_AfterDamageEvent = 0.00
        endif
        call DmgEvResetVars()
    endif
endfunction
 
function DmgEvOnExpire takes nothing returns nothing
    set udg_DmgEvStarted = false
    call CheckDamagedLifeEvent(true)
endfunction

function PreCheckDamagedLifeEvent takes nothing returns boolean
    call CheckDamagedLifeEvent(true)
    return false
endfunction

function OnUnitDamage takes nothing returns boolean
    local boolean override = udg_DamageEventOverride
    local integer i = udg_DmgEvRecursionN - 1
    local string s
    local real prevAmount
    local real life
    local real prevLife
    local unit u
    call CheckDamagedLifeEvent(false) //in case the unit state event failed and the 0.00 second timer hasn't yet expired
    if i >= 0 then
        if i < 16 then
            set udg_LastDmgPrevAmount[i]= udg_DamageEventPrevAmt
            set udg_LastDmgValue[i]     = udg_DamageEventAmount
            set udg_LastDmgSource[i]    = udg_DamageEventSource
            set udg_LastDmgTarget[i]    = udg_DamageEventTarget
            set udg_LastDmgWasSpell[i]  = udg_IsDamageSpell
            set udg_LastDmgPrevType[i]  = udg_DamageEventType
        else
            set s = "WARNING: Recursion error when dealing damage! Make sure when you deal damage from within a DamageEvent trigger, do it like this:\n\n"
            set s = s + "Trigger - Turn off (This Trigger)\n"
            set s = s + "Unit - Cause...\n"
            set s = s + "Trigger - Turn on (This Trigger)"
         
            //Delete the next couple of lines to disable the in-game recursion crash warnings
            call ClearTextMessages()
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 999.00, s)
            return false
        endif
    endif
    set udg_DmgEvRecursionN     = i + 2
    set u                       = GetTriggerUnit()
    set prevAmount              = GetEventDamage()
    set udg_DamageEventSource   = GetEventDamageSource()
 
    set udg_DamageEventAmount   = prevAmount
    set udg_DamageEventTarget   = u
 
    set udg_DamageEventType     = udg_NextDamageType
    set udg_NextDamageType      = 0
    set udg_DamageEventOverride = udg_NextDamageOverride
    set udg_NextDamageOverride  = false
 
    if prevAmount == 0.00 then
        if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_DamageEventPrevAmt = 0.00
            set udg_DamageEvent = 0.00
            set udg_DamageEvent = 2.00
            set udg_DamageEvent = 0.00
        endif
        call DmgEvResetVars()
    else
        if not udg_DmgEvStarted then
            set udg_DmgEvStarted = true
            call TimerStart(udg_DmgEvTimer, 0.00, false, function DmgEvOnExpire)
        endif
        set udg_IsDamageSpell = prevAmount < 0.00
        if udg_IsDamageSpell then
            set prevAmount = -udg_DamageEventAmount
            set life = 1.00
            if IsUnitType(u, UNIT_TYPE_ETHEREAL) and not IsUnitType(u, UNIT_TYPE_HERO) then
                set life = life*udg_DAMAGE_FACTOR_ETHEREAL //1.67
            endif
            if GetUnitAbilityLevel(u, 'Aegr') > 0 then
                set life = life*udg_DAMAGE_FACTOR_ELUNES //0.80
            endif
            if udg_DmgEvBracers != 0 and IsUnitType(u, UNIT_TYPE_HERO) then
                //Inline of UnitHasItemOfTypeBJ without the potential handle ID leak.
                set i = 6
                loop
                    set i = i - 1
                    if GetItemTypeId(UnitItemInSlot(u, i)) == udg_DmgEvBracers then
                        set life = life*udg_DAMAGE_FACTOR_BRACERS //0.67
                        exitwhen true
                    endif
                    exitwhen i == 0
                endloop
            endif
            set udg_DamageEventAmount = prevAmount*life
        endif
        set udg_DamageEventPrevAmt = prevAmount
        set udg_DamageModifierEvent = 0.00
        if not udg_DamageEventOverride then
            set udg_DamageModifierEvent = 1.00
            if not udg_DamageEventOverride then
                set udg_DamageModifierEvent = 2.00
                set udg_DamageModifierEvent = 3.00
            endif
        endif
        set udg_DamageEventOverride = override
        if udg_DamageEventAmount > 0.00 then
            set udg_DamageModifierEvent = 4.00
        endif
        set udg_DamageModifierEvent = 0.00
        if not udg_HideDamageFrom[GetUnitUserData(udg_DamageEventSource)] then
            set udg_DamageEvent = 0.00
            set udg_DamageEvent = 1.00
            set udg_DamageEvent = 0.00
        endif
        call CheckDamagedLifeEvent(true) //in case the unit state event failed from a recursive damage event
     
        //All events have run and the damage amount is finalized.
        set life = GetWidgetLife(u)
        set udg_DmgEvTrig = CreateTrigger()
        call TriggerAddCondition(udg_DmgEvTrig, Filter(function PreCheckDamagedLifeEvent))
        if not udg_IsDamageSpell then
            if udg_DamageEventAmount != prevAmount then
                set life = life + prevAmount - udg_DamageEventAmount
                if GetUnitState(u, UNIT_STATE_MAX_LIFE) < life then
                    set udg_LastDamageHP = life - prevAmount
                    call UnitAddAbility(u, udg_DamageBlockingAbility)
                endif
                call SetWidgetLife(u, RMaxBJ(life, 0.42))
            endif
            call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, LESS_THAN, RMaxBJ(0.41, life - prevAmount/2.00))
        else
            set udg_LastDamageHP = GetUnitState(u, UNIT_STATE_MAX_LIFE)
            set prevLife = life
            if life + prevAmount*0.75 > udg_LastDamageHP then
                set life = RMaxBJ(udg_LastDamageHP - prevAmount/2.00, 1.00)
                call SetWidgetLife(u, life)
                set life = (life + udg_LastDamageHP)/2.00
            else
                set life = life + prevAmount*0.50
            endif
            set udg_LastDamageHP = prevLife - (prevAmount - (prevAmount - udg_DamageEventAmount))
            call TriggerRegisterUnitStateEvent(udg_DmgEvTrig, u, UNIT_STATE_LIFE, GREATER_THAN, life)
        endif
        set u = null
    endif
    return false
endfunction

function CreateDmgEvTrg takes nothing returns nothing
    set udg_DamageEventTrigger = CreateTrigger()
    call TriggerAddCondition(udg_DamageEventTrigger, Filter(function OnUnitDamage))
endfunction

function SetupDmgEv takes nothing returns boolean
    local integer i = udg_UDex
    local unit u
    if udg_UnitIndexEvent == 1.00 then
        set u = udg_UDexUnits[i]
        if GetUnitAbilityLevel(u, 'Aloc') == 0 and TriggerEvaluate(gg_trg_Damage_Engine_Config) then
            set udg_UnitDamageRegistered[i] = true
            call TriggerRegisterUnitEvent(udg_DamageEventTrigger, u, EVENT_UNIT_DAMAGED)
            call UnitAddAbility(u, udg_SpellDamageAbility)
            call UnitMakeAbilityPermanent(u, true, udg_SpellDamageAbility)
        endif
        set u = null
    else
        set udg_HideDamageFrom[i] = false
        if udg_UnitDamageRegistered[i] then
            set udg_UnitDamageRegistered[i] = false
            set udg_DamageEventsWasted = udg_DamageEventsWasted + 1
            if udg_DamageEventsWasted == 32 then //After 32 registered units have been removed...
                set udg_DamageEventsWasted = 0
             
                //Rebuild the mass EVENT_UNIT_DAMAGED trigger:
                call DestroyTrigger(udg_DamageEventTrigger)
                call CreateDmgEvTrg()
                set i = udg_UDexNext[0]
                loop
                    exitwhen i == 0
                    if udg_UnitDamageRegistered[i] then
                        call TriggerRegisterUnitEvent(udg_DamageEventTrigger, udg_UDexUnits[i], EVENT_UNIT_DAMAGED)
                    endif
                    set i = udg_UDexNext[i]
                endloop
            endif
        endif
    endif
    return false
endfunction
 
//===========================================================================
function InitTrig_Damage_Engine takes nothing returns nothing
    local unit u = CreateUnit(Player(15), 'uloc', 0, 0, 0)
    local integer i = 16
 
    //Create this trigger with UnitIndexEvents in order add and remove units
    //as they are created or removed.
    local trigger t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 1.00)
    call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, 2.00)
    call TriggerAddCondition(t, Filter(function SetupDmgEv))
    set t = null
 
    //Run the configuration trigger to set all configurables:
    if gg_trg_Damage_Engine_Config == null then
        //It's possible this InitTrig_ function ran first, in which case use ExecuteFunc.
        call ExecuteFunc("Trig_Damage_Engine_Config_Actions")
    else
        call TriggerExecute(gg_trg_Damage_Engine_Config)
    endif
 
    //Create trigger for storing all EVENT_UNIT_DAMAGED events.
    call CreateDmgEvTrg()
 
    //Create GUI-friendly trigger for cleaning up after UnitDamageTarget.
    set udg_ClearDamageEvent = CreateTrigger()
    call TriggerAddCondition(udg_ClearDamageEvent, Filter(function PreCheckDamagedLifeEvent))
 
    //Disable SpellDamageAbility for every player.
    loop
        set i = i - 1
        call SetPlayerAbilityAvailable(Player(i), udg_SpellDamageAbility, false)
        exitwhen i == 0
    endloop
 
    //Preload abilities.
    call UnitAddAbility(u, udg_DamageBlockingAbility)
    call UnitAddAbility(u, udg_SpellDamageAbility)
    call RemoveUnit(u)
    set u = null
endfunction


and it says in the ''Damage Engine Trigger'' that all I have to do is use ''DamageEvent Equal to 1.00'' so that's what I've implemented in my trigger, but after trying it few times the spell never actually gets triggered.


Any ideas why?


Thanks, as usual!
 
Last edited by a moderator:
Level 24
Joined
Feb 9, 2009
Messages
1,783
1636262580975.png


DamageEvent needs to be the EVENT, not the condition.
DamageEventSource/Target needs to be referenced instead of Attacked/ing

Ex
  • Example
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (Unit-type of DamageEventSource) Equal to Footman
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Random integer number between 1 and 100) Less than or equal to 12
        • Then - Actions
          • Set VariableSet TempPoint = (Position of DamageEventSource)
          • -------- Etc --------
        • Else - Actions

Also open the damage engine test map and play with the demo triggers highlighted here:
1636263070012.png


Edit:Edit
Give the description of Bribe's Damage engine read too for good measure.
 
Last edited:

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,457
Devalut summed it up nicely but I just wanted to go into detail about a concept that confuses a lot of users.

Each Event has it's own Event Responses that go with them, for example:
  • Events
    • Unit - A unit Is attacked
Attacked unit, Attacking unit, and Triggering unit are the Event Responses that are available to use in your Conditions/Actions here. Triggering unit is the Attacked unit in this case. An Event Response such as Dying unit doesn't exist in this case because no unit died in this Event.

So with that in mind if you take a look at the Events/Event Responses you'll find that there are some for Damage:
  • Damage Example
    • Events
      • Unit - Footman 0079 <gen> Takes damage
    • Conditions
      • (Triggering unit) Equal to (Damage source)
      • (Triggering unit) Equal to (Damage Target)
    • Actions
Damage source, Damage target, and other Damage-related Event Responses are all available to use here.

Now you may be wondering, why do we even need Damage Engines if we have this stuff readily available? So understand that Blizzard only provided GUI users (non-coders) with a Specific Unit version of the Takes damage event. As you may have already noticed the Specific events are not very useful... However, there is a Generic version of this event but it's only accessible in code form (Jass/Lua). That's where Damage Engines like Bribes come into play. Bribe created the generic Damage Event trigger in his code and then used GUI-accessible variables in order to give you access to it. So he created a sort of hybrid system that uses code behind the scenes while offering the standard trigger format that you're so used to working with.

So through the use of Variables he was able to create his own custom Event -> DamageEvent becomes Equal to 1.00.
This Event runs whenever any unit takes damage. He then provided us with "fake" Event Responses in the form of variables such as DamageEventSource, DamageEventTarget, and DamageEventAmount which act like a real Event Response would.

It all starts to make sense once you understand this concept of custom Events/Event Responses and what's actually going on here.
 
Last edited:
Level 11
Joined
May 7, 2008
Messages
300
Excellent guys, this has been bugging me for quite a while, I'll edit this post once I get home from work and I'll update you accordingly :p

Edit: everything works and I've implemented the event in my triggers, however I'm not sure how can I implement it into a trigger such as this one.

  • Flame Barrage 2
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Flame Barrage
      • (Level of Flame Barrage for (Triggering unit)) Equal to 2
    • Actions
      • Set VariableSet LocPoint1 = (Position of (Triggering unit))
      • Set VariableSet LocPoint2 = (Target point of ability being cast)
      • Unit - Create 1 Caster Dummy for (Owner of (Triggering unit)) at LocPoint2 facing LocPoint1
      • Unit - Add a 2.00 second Generic expiration timer to (Last created unit)
      • Unit - Add Rapid Fire Dummy 2 to (Last created unit)
      • Wait 1.35 game-time seconds
      • Unit - Order (Last created unit) to Neutral - Kaboom! LocPoint2
      • Special Effect - Create a special effect at LocPoint2 using Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
      • Special Effect - Destroy (Last created special effect)
      • Special Effect - Create a special effect at LocPoint2 using Abilities\Spells\Other\Doom\DoomDeath.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation (udg_LocPoint1)
      • Custom script: call RemoveLocation (udg_LocPoint2)

The ''Flame Barrage'' ability is based off Healing Spray from the Alchemist, tried using Cluster Rockets but the game kept crashing so I replaced it with Healing Spray, since the arrows my Hero shoot once the ability is casted is the same as Cluster Rockets from Tinker.

However, the trigger above is highly abusive, since you can spam hold or stop and essentially throw spell for free.

I also tried implementing ''Finishes casting an ability'' but then usually playtesters cast the ability, move half-way through and the spell never finishes actually casting. Is this achievable with the system mentioned above or is this entirely a different topic to cover?
 
Last edited by a moderator:

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,457
Excellent guys, this has been bugging me for quite a while, I'll edit this post once I get home from work and I'll update you accordingly :p

Edit: everything works and I've implemented the event in my triggers, however I'm not sure how can I implement it into a trigger such as this one.

  • Flame Barrage 2
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Flame Barrage
      • (Level of Flame Barrage for (Triggering unit)) Equal to 2
    • Actions
      • Set VariableSet LocPoint1 = (Position of (Triggering unit))
      • Set VariableSet LocPoint2 = (Target point of ability being cast)
      • Unit - Create 1 Caster Dummy for (Owner of (Triggering unit)) at LocPoint2 facing LocPoint1
      • Unit - Add a 2.00 second Generic expiration timer to (Last created unit)
      • Unit - Add Rapid Fire Dummy 2 to (Last created unit)
      • Wait 1.35 game-time seconds
      • Unit - Order (Last created unit) to Neutral - Kaboom! LocPoint2
      • Special Effect - Create a special effect at LocPoint2 using Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
      • Special Effect - Destroy (Last created special effect)
      • Special Effect - Create a special effect at LocPoint2 using Abilities\Spells\Other\Doom\DoomDeath.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation (udg_LocPoint1)
      • Custom script: call RemoveLocation (udg_LocPoint2)

The ''Flame Barrage'' ability is based off Healing Spray from the Alchemist, tried using Cluster Rockets but the game kept crashing so I replaced it with Healing Spray, since the arrows my Hero shoot once the ability is casted is the same as Cluster Rockets from Tinker.

However, the trigger above is highly abusive, since you can spam hold or stop and essentially throw spell for free.

I also tried implementing ''Finishes casting an ability'' but then usually playtesters cast the ability, move half-way through and the spell never finishes actually casting. Is this achievable with the system mentioned above or is this entirely a different topic to cover?
The Wait in that trigger is a big problem. This is because you're referencing an Event Response after it as well as two global variables LocPoint1 and LocPoint2.

Understand that most Event Responses function like global variables. Global variables can be accessed GLOBALLY, meaning from any trigger, and by default they can only ever have one value at a time (arrays change this behavior). This means that (Last created unit) will get changed whenever a new unit is created. So if another trigger were to Create a unit during that 1.35 second Waiting period then this trigger will fail because you'd now be ordering the wrong unit to cast Kaboom.

Additionally, if another trigger were to Set LocPoint1/LocPoint2 during that Waiting period then you'll run into a similar problem. The special effects will be created at the wrong point. Not only that, you'll have created memory leaks because you failed to Remove the original LocPoint1/2 before Setting them again.

You have to get rid of that Wait and find an alternate method to handling this trigger. A simple solution that comes to mind is to give the Dummy's Kaboom ability a 1.35 second Casting Time. Then create another trigger that detects when the Dummy casts the Kaboom ability and create the Special Effects then.

Other potential solutions: use local variables, Shadowing techniques, Unit Indexing, Dynamic Indexing, etc.

Healing Spray/Cluster Rockets are Channeling abilities which means that they run their Cast Events in a special way. I don't quite understand how the unit would cast the spell for free though, does it not have a cooldown/mana cost? You didn't really explain what your intended effect was so I can't quite help you with this just yet.
 
Last edited:
Level 11
Joined
May 7, 2008
Messages
300
The Wait in that trigger is a big problem. This is because you're referencing an Event Response after it as well as two global variables LocPoint1 and LocPoint2.

Understand that most Event Responses function like global variables. Global variables can be accessed GLOBALLY, meaning from any trigger, and by default they can only ever have one value at a time (arrays change this behavior). This means that (Last created unit) will get changed whenever a new unit is created. So if another trigger were to Create a unit during that 1.35 second Waiting period then this trigger will fail because you'd now be ordering the wrong unit to cast Kaboom.

Additionally, if another trigger were to Set LocPoint1/LocPoint2 during that Waiting period then you'll run into a similar problem. The special effects will be created at the wrong point. Not only that, you'll have created memory leaks because you failed to Remove the original LocPoint1/2 before Setting them again.

You have to get rid of that Wait and find an alternate method to handling this trigger. A simple solution that comes to mind is to give the Dummy's Kaboom ability a 1.35 second Casting Time. Then create another trigger that detects when the Dummy casts the Kaboom ability and create the Special Effects then.

Other potential solutions: use local variables, Shadowing techniques, Unit Indexing, Dynamic Indexing, etc.

Healing Spray/Cluster Rockets are Channeling abilities which means that they run their Cast Events in a special way. I don't quite understand how the unit would cast the spell for free though, does it not have a cooldown/mana cost? You didn't really explain what your intended effect was so I can't quite help you with this just yet.

I didn't even realize it can be done that way, well done, I fixed another problem thanks to you :p

I've changed the code and now it does exactly the same without the wait.

  • Flame Barrage 1
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Flame Barrage
      • (Level of Flame Barrage for (Casting unit)) Equal to 1
    • Actions
      • Set VariableSet LocPoint1 = (Position of (Casting unit))
      • Set VariableSet LocPoint2 = (Target point of ability being cast)
      • Unit - Create 1 Caster Dummy for (Owner of (Casting unit)) at LocPoint2 facing LocPoint1
      • Unit - Add a 2.00 second Generic expiration timer to (Last created unit)
      • Unit - Add Rapid Fire Dummy 1 to (Last created unit)
      • Unit - Order (Last created unit) to Neutral - Kaboom! LocPoint2
      • Custom script: call RemoveLocation (udg_LocPoint1)
      • Custom script: call RemoveLocation (udg_LocPoint2)
Whenever I cast the ability, press hold instantly after that, the ability does not cast, meaning I don't lose mana on casting, however the trigger still runs its course, therefore the dummy unit spawns and kabooms the place he was designed to, that's what I was trying to say.
 
Status
Not open for further replies.
Top