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

[JASS] ChainHook (ChainLightning)

A small resource mimicing the timing of chain lightning, setting an flag for the unit at the time chain lightning should hit. That way you can inside a "damage takes" event check udg_ChainHookDamaging[UnitUserData(DamageSource)] to know that this damge is a result of chain lightning.

The idea is that chain lightning has a fixed jump/damage intervale of 0.25s from the moment it starts its effect. -> Set a flag every 0.25s for that unit after a 0s timer passed remove the flag again. Damage done while the flag is set is result of chain lightning.

Also allows to detect which number inside the chain lightning that hit is.

Theoreticaly there is a chance that the flag affects other damage instances. Although i was not able to detect that in a demo map with a far seer attacking 10 times a second.

Edit: Did now tests with first placing a flamestrike with damage intervale = 0.01. Then far sear was casting a chain lightning: no wrong detections.

JASS:
//ChainHook
//by Tasyen

//API
//=========
   //function ChainHookStart takes unit u, integer spell, integer targetsHit returns nothing
       //u the unit starting a ChainLightning
       //spell; the ChainLightning spell
       //targetsHit; the amount of hits the ChainLightning can do.
 
   //function ChainHookStartEx takes integer targetsHit returns nothing
       //Wrapper to be used inside "Starts the effect of an ability" Event

//Requiers
//=========
//Unit Indexer.
//udg_Hash, to connect timers and unit array Index
   
//How to use?
//=========
//When casting an ChainLightning ability you want to manipulate with damage detection call inside "Starts the effect of an ability" Event ChainHookStartEx(amountOfTargetsHit).
   //you can also use GUI only by seting udg_ChainHookCounterMax[0] = amountOfTargetsHit and run Trigger ChainHookDetect
//set up a Damage Detecion Trigger which checks udg_ChainHookDamaging[UnitUserData(DamageSource)] = true.
//Actions run if that damage is done by a ChainLightning beeing detected by this system.

   //udg_ChainHookCounter[uDex]; Current Chain Number beeing Affected, for the first unit affect = 1, for the second 2, for the third 3....
   //udg_ChainHookSpell[uDex]; The Chainlightning spell started this
   //udg_ChainHookDamaging[uDex]; The flag telling you this damage is from ChainLightning based spell.
   //udg_ChainHookCounterMax[uDex]; Max amount of Targets allowed (the number you called this with)

//How this works?
//=========
//ChainLightning has a fixed jump intervale of 0.25 sec from the moment it was casted. This System mimics this intervale and sets for a 0.00sec timer a flag saying this is ChainLightning.
//This techniq is not 100% safe, but it does not requier to mimic the targeting of ChainLightning (which would result into recreating ChainLightning).
//worked in the test map with a far seer with 10 attacks a second.

//Limitations
//=========
//This System is MUI (one usage for each unit at the same time), so don't use 2 detected ChainLightnings at the same time for one unit.

//=========
function ChainHookHitStartEnd takes nothing returns nothing
   local integer uDex = LoadInteger(udg_Hash, GetHandleId(gg_trg_ChainHookDetect), GetHandleId(GetExpiredTimer()))
   set udg_ChainHookDamaging[uDex] = false
endfunction
function ChainHookHitStart takes nothing returns nothing
   local integer uDex = LoadInteger(udg_Hash, GetHandleId(gg_trg_ChainHookDetect), GetHandleId(GetExpiredTimer()))
   set udg_ChainHookCounter[uDex] = udg_ChainHookCounter[uDex] + 1
   call TimerStart(udg_ChainHookSec[uDex], 0.00, false, function ChainHookHitStartEnd)
   set udg_ChainHookDamaging[uDex] = true
   if udg_ChainHookCounter[uDex] >= udg_ChainHookCounterMax[uDex] then
       call PauseTimer(GetExpiredTimer())   
   endif
endfunction

function ChainHookStart takes unit u, integer spell, integer targetsHit returns nothing
   local integer uDex = GetUnitUserData(u)
   if udg_ChainHookMain[uDex] == null then//First use -> CreateTimer s for that unit Index
       set udg_ChainHookMain[uDex] = CreateTimer()
       set udg_ChainHookSec[uDex] = CreateTimer()
       call SaveInteger(udg_Hash, GetHandleId(gg_trg_ChainHookDetect), GetHandleId(udg_ChainHookSec[uDex]), uDex) //Safe Index for timers
       call SaveInteger(udg_Hash, GetHandleId(gg_trg_ChainHookDetect), GetHandleId(udg_ChainHookMain[uDex]), uDex)
   endif
   set udg_ChainHookCounter[uDex] = 0
   set udg_ChainHookCounterMax[uDex] = targetsHit
   set udg_ChainHookSpell[uDex] = spell
   set udg_ChainHookDamaging[uDex] = false
   call TimerStart(udg_ChainHookMain[uDex], 0.25, true, function ChainHookHitStart)
endfunction
function ChainHookStartEx takes integer targetsHit returns nothing
   call ChainHookStart(GetTriggerUnit(), GetSpellAbilityId(), targetsHit)
endfunction
function ChainHookStartGUI takes nothing returns nothing
   call ChainHookStart(GetTriggerUnit(), GetSpellAbilityId(), udg_ChainHookCounterMax[0])
endfunction
function InitTrig_ChainHookDetect takes nothing returns nothing
   set gg_trg_ChainHookDetect = CreateTrigger()
   call TriggerAddAction(gg_trg_ChainHookDetect, function ChainHookStartGUI)
endfunction
 
Last edited:
Top