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

ABC System problems

Status
Not open for further replies.
Here's the ABC system. It needs JNGP to compile, apparently.

I'm kinda confused about it, because in the ABC map this trigger had the "Run on map initialization" box checked, but in the two spell maps that box was unchecked.

EDIT: Okay here's the tooltips and the problems.

Flash FireIgnites the target unit in flames, dealing initial damage and 10 damage per second for up to 10 seconds. After the duration/the target dies, there is a 75% chance that it will bounce to a random nearby enemy unit, igniting it and repeating the whole process. Stops bouncing if there is no nearby target/the maximum number of bounces is reached/the chance to bounce fails.

Headbutt
Charge to the target point. The first unit you encounter will take X damage and be stunned for Y seconds, you will also be stunned for Z seconds due to concussion. If you hit a building, you stop charging.

The Problem:
When I click the map button on my campaign screen (where you choose to play Chapter 1, 2, etc) it fades out like normal but then I just get a black screen. When I disabled the ABC trigger and the new spell triggers it loads, but as soon as the starting cinematic ends or I skip the cinematic then wc3 crashes with a fatal error. EDIT2: That was actually a problem with a fade filter.

This only started happening when I added those spells. I've imported lots of custom spells before (Things like Vile's knockback system, Pyrogasm's Cloud spell (haven't added the Fear one yet), and others), and those work fine.​

JASS:
//TESH.scrollpos=88
//TESH.alwaysfold=0
//==============================================================================
//  ABC -- STRUCT ATTACHMENT SYSTEM BY COHADAR -- v5.1
//==============================================================================

//==============================================================================
//  Quick function index:
//==============================================================================
//
//    ----------------------------------------------------------------------
//      Set Functions - these functions attach struct to a handle
//    ----------------------------------------------------------------------
//    SetTimerStructA(timer, struct)
//    SetTimerStructB(timer, struct)
//    SetTimerStructC(timer, struct)
//
//    SetTriggerStructA(trigger, struct)
//    SetTriggerStructB(trigger, struct)
//    SetTriggerStructC(trigger, struct)
//
//    SetDialogStructA(dialog, struct)
//    SetDialogStructB(dialog, struct)
//    SetDialogStructC(dialog, struct)
//
//    ----------------------------------------------------------------------
//      Get Functions - these functions retrieve attached structs
//    ----------------------------------------------------------------------
//    GetTimerStructA(timer) -> struct
//    GetTimerStructB(timer) -> struct
//    GetTimerStructC(timer) -> struct
//
//    GetTriggerStructA(trigger) -> struct
//    GetTriggerStructB(trigger) -> struct
//    GetTriggerStructC(trigger) -> struct
//
//    GetDialogStructA(dialog) -> struct
//    GetDialogStructB(dialog) -> struct
//    GetDialogStructC(dialog) -> struct
//
//    ----------------------------------------------------------------------
//      Clear Functions - these functions clear and return attached value
//    ----------------------------------------------------------------------
//    ClearTimerStructA(timer) -> struct
//    ClearTimerStructB(timer) -> struct
//    ClearTimerStructC(timer) -> struct
//
//    ClearTriggerStructA(trigger) -> struct
//    ClearTriggerStructB(trigger) -> struct
//    ClearTriggerStructC(trigger) -> struct
//
//    ClearDialogStructA(dialog) -> struct
//    ClearDialogStructB(dialog) -> struct
//    ClearDialogStructC(dialog) -> struct
//
//==============================================================================




//==============================================================================
//  DOCUMENTATION:
//==============================================================================
//
//  PURPOUSE OF ABC:
//       * Attaching multiple structs to a <handle>
//       * Not using stupid game cache.
//      
//       * Currently supported <handle> types are timer, trigger and dialog
//         ABC can NOT be used to attach things to units,
//         Systems that can attach stuff to units require a mission key
//         ABC does not have mission keys, witch is one of the reasons it is so fast.
//
//       * These are the only 3 handle types I found that need attaching (except units)
//         If you have the need for some other handle types please let me know
//
//  HOW TO USE:
//       * Lets assume you want to attach some spell data to a timer.
//         You would do the following:
//
//         1. Create struct that will contain all your data.
//         2. call SetTimerStructA(myTimer, myStruct) 
//
//         and then you decide you need one more struct on that timer...
// 
//         call SetTimerStructB(myTimer, myStruct2) 
//
//         Then in a periodic timer you just get the stored value
//         set myStruct = GetTimerStructA(myTimer)
//     
//         In your final itearation of periodic timer
//         you need to clear stored values
//         ClearTimerStructA(myTimer)
//         ClearTimerStructB(myTimer)
//         If you don't system will start to overflow
//
//  DIFFERENCE FROM v5.0:
//       * You cannot use SetStructA two times on the same <handle>
//         without clearing the previous value. 
//
//       * ABC v5.0 used to overwrite the old values when you did that.
//         This caused errors when collisions get over 3
//         Since collisions almost never happen in real maps noone noticed this before
//         Only some hardcore tests will detect this
//         
//       * New version of ABC treats overwrite as an error.
//         BAD:  SetStructA(X, value1); SetStructA(X, value2) 
//         GOOD: SetStructA(X, value1); ClearStructA(X); SetStructA(X, value2)
//
//       * HASH_COLLISION_LIMIT is reduced from 8 to 7 to simplyfy algorithms
//         (using null borders at modulo 8)
//         This effectively means that you can store around 6000 attachments per hash
//         before you get an overflow. (used to be 7000)
//         
//       * This simplyfication increased ABC speed a little.
//
//  PROS: 
//       * ABC is faster than any gamecache based system.
//
//       * you can attach any struct to any supported <handle> type
//
//       * you CAN attach up to 3 structs on the same <handle>
//         but only if you use different functions, for example
//         SetTriggerStructA(), SetTriggerStructB(), SetTriggerStructC()
//         
//       * get and set functions are extremelly fast (using hash algorithm)
//
//       * System reports collision, overwrite and overflow.
//         Basically if you do anything stupid system will tell you.
//
//       * This system will work even if your map leaks
//         and will NOT slow down because of it.
//
//       * This is the system that spits torment test in the eye.
//
//       * For compatibility with ABC v4.6 look at ABCC library
//         
//
//  CONS:
//       * you must manually clean the stored value - REMEMBER THIS RULE!!!
//         Don't forget to use ClearStruct() functions
//
//       * you should NOT use Get without a Set - REMEMBER THIS RULE!!!  
//         It will simply return a zero and nothing bad will happen,
//         but it will lag really really bad
//         (system will report this as an error)
//
//       * System starts to collide if you have more than 1024 structs in one hash.
//         (you can see this very obviosly with -overload test)
//         If that happens it can mean one of 2 things:
//           1. you are using more than 1024 timers, triggers or dialogs - !?
//           2. you forgot to use ClearStruct and you are leaking handles somewhere
//             if this is the case simply do a search on your code and find
//             what trigger uses ABC but has no ClearStruct calls.
//
//  DETAILS:
//       * when struct is detached from <handle> it is not destroyed
//         you still have to do that manually if necessary
//
//       * ABC will not interfere with other attachemt systems
//         You can freely use any other system alongside ABC
//         But if you use only ABC for attachments in your map
//         you don't have to null local variables.
//         The reason for this is that gamecache gets abnormaly slow
//         when you don't null locals, ABC does not have this flaw.
//
//
//  SPECIAL THANKS TO: 
//       * NagelBagel - for finding errors in versions 4.3 and 4.4
//       * Here-b-Trollz - for testing ABC and for making cool spells with it.
//       * Toadcop - for being pain in the ass and for pushing me to improve ABC.
//       * emjlr3 - for pointing out the need for non-generic trigger attachments
//       * PandaMine - I found a bug in ABC by examining his HSAS vs ABC test
//       * All those people out there who use and support ABC
//         Thank you guys.
//
//  HOW TO IMPORT:
//       * Just create a trigger named ABC
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================


//------------------------------------------------------------------------------
//  We will use textmacros to create multiple instances of system
//------------------------------------------------------------------------------
//! textmacro ABC takes X, NAME, TYPE

//------------------------------------------------------------------------------
// Global arrays represent our hash tables.
// System is currently using 3 hash tables per handle type. (A, B, C)
//------------------------------------------------------------------------------
globals
    private $TYPE$    array $TYPE$Key$X$
    private integer  array $TYPE$Value$X$
	private integer  $TYPE$maxCollision$X$ = 0
endglobals

//------------------------------------------------------------------------------
// returns the maximum collision so far
//------------------------------------------------------------------------------
function Get$NAME$Collision$X$ takes nothing returns integer
    return $TYPE$maxCollision$X$
endfunction


//------------------------------------------------------------------------------
// initializes hash arrays to prevent lag when ABC is used for the first time
//------------------------------------------------------------------------------
private function Init$NAME$Hash$X$ takes nothing returns nothing
    set $TYPE$Key$X$[HASH_INDEX_LIMIT]   = null
	set $TYPE$Value$X$[HASH_INDEX_LIMIT] = 0
endfunction

//------------------------------------------------------------------------------
// attaches struct to a handle by using hash table
//------------------------------------------------------------------------------
function Set$NAME$Struct$X$ takes $TYPE$ t, integer s returns nothing
	debug local integer collision
	
	// hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS

	if $TYPE$Key$X$[i] == null then
	    set $TYPE$Value$X$[i] = s
		set $TYPE$Key$X$[i] = t
		return
	endif

    debug if $TYPE$Key$X$[i] == t then
        debug call BJDebugMsg("|cFFFF0000ERROR: Hash[$X$] attachment overwrite on $TYPE$ #" +I2S(H2I(t)))
        debug return
    debug endif        
    
	// if function gets below this line we have a collision
    debug set collision = 1
    loop
		debug if collision >= HASH_COLLISION_LIMIT then
            debug call BJDebugMsg("|cFFFF0000ERROR: Hash[$X$] overflow")
            debug return
		debug endif    
        debug set collision = collision + 1
    
        set i = i + 1    
	    exitwhen $TYPE$Key$X$[i] == null

        debug if $TYPE$Key$X$[i] == t then
            debug call BJDebugMsg("|cFFFF0000ERROR: Hash[$X$] attachment overwrite on $TYPE$ #" +I2S(H2I(t)))
            debug return
        debug endif    
	endloop

	debug if collision > $TYPE$maxCollision$X$ then
	debug 	call BJDebugMsg("|cFFFF4444Warning: Hash[$X$] maximum collision is now: " + I2S(collision))
	debug 	set $TYPE$maxCollision$X$ = collision
	debug endif
	
    set $TYPE$Value$X$[i] = s
    set $TYPE$Key$X$[i] = t

    return
endfunction

//------------------------------------------------------------------------------
// gets stored struct from a handle 
//------------------------------------------------------------------------------
function Get$NAME$Struct$X$ takes $TYPE$ t returns integer
	debug local integer collision
	
	// hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS
	
	if $TYPE$Key$X$[i] == t then
		return $TYPE$Value$X$[i]
	endif
	
	// if function gets below this line we have a collision
    debug set collision = 1
    loop
		debug if collision >= HASH_COLLISION_LIMIT then
		debug   call BJDebugMsg("|cFFFF0000ERROR: Hash[$X$] : get request on unknown handle")
		debug   return 0
		debug endif		
        debug set collision = collision + 1      
    
        set i = i + 1
	    exitwhen $TYPE$Key$X$[i] == t
	endloop	
	
    return $TYPE$Value$X$[i]
endfunction


//------------------------------------------------------------------------------
// clears stored struct from a handle, also returns cleared value
//------------------------------------------------------------------------------
function Clear$NAME$Struct$X$ takes $TYPE$ t returns integer
	debug local integer collision
    local integer ik
    local integer ret
	
	// hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS
	
    // first find the index on witch key is stored
    debug set collision = 0
    loop
		debug if collision >= HASH_COLLISION_LIMIT then
		debug   call BJDebugMsg("|cFFFF0000ERROR: Hash[$X$] : clear request on unknown handle")
		debug   return 0
		debug endif        
        debug set collision = collision + 1       
    
        exitwhen $TYPE$Key$X$[i] == t
        set i = i + 1
    endloop
    
    set ik = i
    set ret = $TYPE$Value$X$[ik]
    
    // then find last used key index in bucket
    loop
        set i = i + 1
        // we use the fact bucket borders (mod 8 indexes) are always null
        exitwhen $TYPE$Key$X$[i] == null  
    endloop
    
    // shift last bucket entry to the place of removed one
    set $TYPE$Key$X$[ik] = $TYPE$Key$X$[i-1]
    set $TYPE$Value$X$[ik] = $TYPE$Value$X$[i-1]
    // clear the previous last bucket entry
    set $TYPE$Key$X$[i-1] = null
    
    return ret
endfunction

//! endtextmacro

//==============================================================================
//  Macro execution -- this is where real functions get created
//==============================================================================
library ABC initializer Init

globals
	public constant integer HASH_SIZE = 8192
	public constant integer HASH_INDEX_LIMIT = 8190
	public constant integer HASH_DOWN = 524288     // 2^19	
	public constant integer HASH_UP   = 2134900736 // 2^22 * 509
	public constant integer HASH_BIAS = 4096       // HASH_SIZE / 2
	public constant integer HASH_COLLISION_LIMIT = 7 // ABC v5.0 had limit 8
	// 509 is the prime closest to 512
endglobals


//------------------------------------------------------------------------------
// conversion function used by the system internally
// you will not need to use it directly
//------------------------------------------------------------------------------
public function H2I takes handle h returns integer
    return h
    return 0
endfunction

//! runtextmacro ABC("A","Timer","timer")
//! runtextmacro ABC("B","Timer","timer")
//! runtextmacro ABC("C","Timer","timer")

//! runtextmacro ABC("A","Trigger","trigger")
//! runtextmacro ABC("B","Trigger","trigger")
//! runtextmacro ABC("C","Trigger","trigger")

//! runtextmacro ABC("A","Dialog","dialog")
//! runtextmacro ABC("B","Dialog","dialog")
//! runtextmacro ABC("C","Dialog","dialog")

private function Init takes nothing returns nothing
	call InitTimerHashA()
	call InitTimerHashB()
	call InitTimerHashC()

	call InitTriggerHashA()
	call InitTriggerHashB()
	call InitTriggerHashC()       
    
	call InitDialogHashA()
	call InitDialogHashB()
	call InitDialogHashC()
endfunction


endlibrary
//==============================================================================
//  END OF ABC STRUCT ATTACHMENT SYSTEM
//==============================================================================

Here's Lirch's Headbutt spell.

JASS:
//TESH.scrollpos=24
//TESH.alwaysfold=0
scope Headbutt

globals
    private constant integer Id = 'A61L'
    private constant real RefreshRate = 0.035
    private constant string ChargeAnim = "walk"
    private group tempgroup = null
    private unit Caster = null
endglobals
//! runtextmacro MoveStruct()
//Please just ignore that textmacro call
private function YourFilter takes nothing returns boolean
    //This is where the global 'Caster' is used
    
    return GetFilterUnit() != Caster and GetWidgetLife(GetFilterUnit()) > .405

    // By default, it filters out the Caster(because he may be caught in the radius)
    //and dead units. Structures are not filtered out, so you may do
    //anything you want in YourFunc if the Caster collides with a Structure
endfunction
private constant function Damage takes integer lvl returns real
    return 100. + (50. * (lvl - 1.))
endfunction
private function YourFunc takes data Event, unit Target returns nothing
// Event.u is the caster
// Do anything you want when the caster collides with a unit/structure

    if IsUnitType(Target,UNIT_TYPE_STRUCTURE) == false or IsUnitType(Target,UNIT_TYPE_GROUND) == false then
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(Event.u),GetUnitY(Event.u)))
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(Target),GetUnitY(Target)))
        call UnitDamageTarget(Event.u,Target,Damage(Event.lvl),true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_NORMAL,null)
    set Event.stop = true //Set this to false if you want your unit to go through
    // units ONLY if he did not hit a structure
    
    else
        set Event.stop = true //Do this if you want to stop charging when
        //the caster hits a building
        //Now do anything, like deal damage to the caster because he hit a structure
    endif
endfunction
private constant function Radius takes integer lvl returns real
    return 90.
endfunction
private constant function Speed takes integer lvl returns real
    return 700. * RefreshRate //DO NOT REMOVE the " * RefreshRate " part!
        //Returned speed is in WC3 speed, 900 speed = 900 units travelled per second.
endfunction
//! textmacro MoveStruct
private struct data
    unit u = null
    integer lvl = 1
    real casterx
    real castery
    real targetx
    real targety
    real max = 0
    real distance =  0
    real angle
    real sin
    real cos
    timer t = null
    boolean stop = false
    static method create takes unit u, location l returns data
    local data d = data.allocate()
        set d.u = u
        set d.casterx = GetUnitX(d.u)
        set d.castery = GetUnitY(d.u)
        set d.targetx = GetLocationX(l)
        set d.targety = GetLocationY(l)
        set d.t = CreateTimer()
        set d.angle = Atan2(d.targety - d.castery, d.targetx - d.casterx)
        set d.sin = Sin(d.angle)
        set d.cos = Cos(d.angle)
        set d.max = SquareRoot(((d.targetx - d.casterx) *  (d.targetx - d.casterx))+ ((d.targety - d.castery) * (d.targety - d.castery)))
        set d.distance = 0
        set d.lvl = GetUnitAbilityLevel(d.u,Id)
        call SetTimerStructA(d.t,d)
        call PauseUnit(d.u,true)
        return d
    endmethod
endstruct
//! endtextmacro

private function Execute takes nothing returns nothing
local data d = data(GetTimerStructA(GetExpiredTimer())) 
        //^-- Sweet, no local timer var,         
        //this is why ABC > Gamecache and vJass > Jass
    if d.distance > d.max or d.stop or GetWidgetLife(d.u) < .405 or d.u == null then
        call PauseUnit(d.u,false)
        call PauseTimer(d.t)
        call DestroyTimer(d.t)
        call d.destroy()
    else
        set d.distance = d.distance + Speed(d.lvl)
        set d.casterx = d.casterx + Speed(d.lvl) * d.cos
        set d.castery = d.castery + Speed(d.lvl) * d.sin
        call SetUnitX(d.u,d.casterx)
        call SetUnitY(d.u,d.castery)
        call SetUnitAnimation(d.u,"walk")
        set Caster = d.u
        call GroupEnumUnitsInRange(tempgroup,d.casterx,d.castery,Radius(d.lvl),Condition(function YourFilter))
        if CountUnitsInGroup(tempgroup) > 0 then
            call YourFunc(d,FirstOfGroup(tempgroup))
        endif
        set Caster = null
        call GroupClear(tempgroup)
    endif
endfunction

private function Actions takes nothing returns nothing
    // Super inlined LOLOL
    call TimerStart(data(data.create(GetTriggerUnit(),GetSpellTargetLoc())).t,RefreshRate,true,function Execute)
endfunction

private function Check takes nothing returns boolean
    return GetSpellAbilityId() == Id
endfunction

//===========================================================================
public function InitTrig_Headbutt takes nothing returns nothing
local trigger t = CreateTrigger()
    set tempgroup = CreateGroup()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t,Condition(function Check))
    call TriggerAddAction(t,function Actions )
endfunction

endscope

And Scorch's Flash Fire spell.

JASS:
//TESH.scrollpos=84
//TESH.alwaysfold=0
scope FlashFire

globals
    private constant integer FlashFireID = 'FIRE' //Rawcode of your spell
    private constant attacktype ATYPE = ATTACK_TYPE_NORMAL
    private constant damagetype DTYPE = DAMAGE_TYPE_FIRE
    private constant boolean AffectAllies = false
    private constant string SFX = "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
    private constant string Attach = "overhead"
    private constant string SFX2 = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl" //Effect created instantly at the location each unit bounced on. Only plays the model's death anim or birth anim(if it doesn't have a death anim)
endglobals

private function Filter takes nothing returns boolean
    return not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) and GetWidgetLife(GetFilterUnit()) > .405
endfunction
private constant function Timeout takes integer lvl returns real
    return 10. //The duration of the burn
endfunction
private constant function BurnDamage takes integer lvl returns real
    return 10. //Damage done per second
endfunction
private constant function InitialDamage takes integer lvl returns real
    return (25*lvl)+25. //Initial damage done
endfunction
private constant function Interval takes integer lvl returns real
    return 1. //The interval, doh
endfunction
private constant function Bounces takes integer lvl returns integer
 return lvl //The number of bounces for each level
endfunction
private constant function Chance takes integer lvl returns integer
    return 75 //The chance to bounce
endfunction
private constant function Radius takes integer lvl returns real
    return 350. //Radius where a random unit is chosen to be the next target
endfunction

private struct data
    unit u
    unit t
    real timeout
    real dps
    effect e
    integer i
    integer bounces
    static method create takes unit u, unit t, integer i returns data
    local data d = data.allocate()
        set d.u = u
        set d.t = t
        set d.timeout = Timeout(i)
        set d.dps = BurnDamage(i)
        set d.i = i
        set d.e = AddSpecialEffectTarget(SFX,d.t,Attach)
        set d.bounces = Bounces(d.i)
        return d
    endmethod
    method onDestroy takes nothing returns nothing
        call DestroyEffect(.e)
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == FlashFireID
endfunction

private function Callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local data d = data(GetTimerStructA(t))
local group g
local boolexpr b
local unit temp
local integer i = GetRandomInt(1,100)
    debug call BJDebugMsg("|cffffaa00Callback func called!|r")
    if d.timeout <= 0 or GetWidgetLife(d.t) < .405 or d.t == null then
        debug call BJDebugMsg("|cffff00aaChance is|r "+I2S(i))
        if i <= Chance(d.i) and d.bounces > 0 then
            debug call BJDebugMsg("|cffffaa00Bouncing!|r")
            set g = CreateGroup()
            set b  = Condition(function Filter)
            call GroupEnumUnitsInRange(g,GetUnitX(d.t),GetUnitY(d.t),Radius(d.i),b)
            set d.t = null
            loop
                set temp = FirstOfGroup(g)
                exitwhen temp == null
                if IsUnitEnemy(temp,GetOwningPlayer(d.u)) or AffectAllies then
                    set d.t = temp
                endif
                call GroupRemoveUnit(g,temp)
                exitwhen d.t != null
            endloop
            call DestroyEffect(d.e)
            if d.t == null then
                call BJDebugMsg("|cffff0000No nearby enemies!|r")
                call ClearTimerStructA(t)
                call data.destroy(d)
                call DestroyTimer(t) //You can use ReleaseTimer(t) if you have CSSafety
            else
                set d.bounces = d.bounces - 1
                set d.e = AddSpecialEffectTarget(SFX,d.t,Attach)
                set d.timeout = 10.
                call DestroyEffect(AddSpecialEffect(SFX2,GetUnitX(d.t),GetUnitY(d.t)))
            endif
            call DestroyGroup(g)
            call DestroyBoolExpr(b)
            set g = null
            set b = null
        else
            call ClearTimerStructA(t)
            call data.destroy(d)
            call DestroyTimer(t) //You can use ReleaseTimer(t) if you have CSSafety
        endif
    else
        call UnitDamageTarget(d.u,d.t,d.dps,true,false,ATYPE,DTYPE,null)
    endif
    //set t = null
    //You can remove the '//' if you want to null the timer. There are known bugs about nulling timers, but I haven't encountered that yet
endfunction

private function Actions takes nothing returns nothing
local data d = data.create(GetTriggerUnit(),GetSpellTargetUnit(),GetUnitAbilityLevel(GetTriggerUnit(),FlashFireID))
local timer t = CreateTimer() //You can replace with NewTimer if you have CSSafety
    call SetTimerStructA(t,d)
    call TimerStart(t,Interval(d.i),true,function Callback)
    call UnitDamageTarget(d.u,d.t,InitialDamage(d.i),true,false,ATYPE,DTYPE,null)
    //set t = null
    //You can remove the '//' if you want to null the timer. There are known bugs about nulling timers, but I haven't encountered that yet
endfunction

//===========================================================================
function InitTrig_Flash_Fire takes nothing returns nothing
    set gg_trg_Flash_Fire = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Flash_Fire, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Flash_Fire, Condition( function Conditions ) )
    call TriggerAddAction( gg_trg_Flash_Fire, function Actions )
endfunction

endscope
 
Last edited:
Level 19
Joined
Aug 24, 2007
Messages
2,888
why the hell are you using that system
and remove comments pls looks idiot that way
ban me
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
Hey you should start learning something and make your owns spells
(trust me its easier than you can ever think)

[jass="System I use"]library CSSafety
globals
private integer array dataarray
endglobals
function H2I takes handle h returns integer
return h
return 0
endfunction
function SetData takes handle h, integer v returns nothing
local integer i=H2I(h)-0x100000
set dataarray=v
endfunction
function GetData takes handle h returns integer
local integer i=H2I(h)-0x100000
return dataarray
endfunction
endlibrary[/code]

:p a little example about usage
struct ZOMG
unit lolz
unit mass
endstruct

JASS:
private function timerfunc takes nothing returns nothing
local timer t = GetExpiredTimer()
local ZOMG b = GetData(t)
call SetUnitPosition(b.mass,somewhereinmatrixX,somewhereinmatrixY)
call SetUnitPosition(b.lolz,somewhereinmatrixX,somewhereinmatrixY)
endfunction

private function someactions takes nothing returns nothing
local timer t = CreateTimer()
local ZOMG a = ZOMG.create()
set a.lolz = GetTriggerUnit()
set a.mass = GetSpellTargetUnit()
call SetData(t,a)
call StartTimer(t,0.035,true,function timerfunc)
endfunction

Basicly H2I returns the unique integer id of a handle (handle: objects like units, locations, groups etc etc etc)
Each timer has unique integer value
We make globals variables has [UniqueIntegerValueOfTimer] and leave the X thing (variables button) blank :D
 
Status
Not open for further replies.
Top