• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Who can i bother with Jass questions?

Status
Not open for further replies.
Level 8
Joined
Jul 25, 2006
Messages
177
Whats the syntax for 'and' and 'or' for conditions. For example in a condition i need to check if a unit is an enemy of another unit and if the unit is not the same type as another unit would i use &&(and) between the two conditions? Or does Jass have a different symbol for that?


Edit: just typed And in JassCraft and it appears green, im guessing the syntax for and is just and? lol how convenient..
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,207
Basically, the "and" and "or" commands take a boolean on each side of them (must be boolean and no other variable), preform their tasks and then return a boolean.

A boolean is the JASS term for a variable with 2 states (your preverbial true/false variable).

A comparison opperation also returns a boolean and so can be used on eithor side of the "and" and "or" commands to return a further boolean.

Brackets also can be mixed in with the comparisons, "and" and "or" opperations. This allows you to preform a group of comparisons before the others (like maths) to get a more desired result.

Alltogether, these should probably be classified as "logical opperations" as they all have to do with comparing booleans to output a single boolean.
 
Level 8
Joined
Jul 25, 2006
Messages
177
Ok, im getting a lot of errors from the compiler, but they don't suggest how to fix. This is my code for making an ability that will fire a missile that damages one target it collides with and then the missile is removed:
Code:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==’A000’
endfunction
//=============================================================
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance
local real CurrentDistance
local location CurrentLoc
local location StartLoc
local unit Bullet
local group G
local real Direction
local player OwnerOfBullet
local boolean Hit
local unit Shooter
set Shooter = GetSpellAbilityUnit()
set CurrentDistance = 0
set EndDistance = 1200
set StartLoc = GetUnitLoc(GetSpellAbilityUnit())
set OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
set Direction = GetUnitFacing(GetSpellAbilityUnit())   
call CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
set Bullet = GetLastCreatedUnit()
loop
    exitwhen CurrentDistance >= EndDistance
    call TriggerSleepAction(.01)
    call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
    set CurrentLoc = GetUnitLoc(Bullet)
    set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
    set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
    if (CountUnitsInGroup(G) >= 1) 
    then
    call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
    call RemoveUnit(Bullet)
    endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set CurrentDistance = null
set EndDistance = null
set StartLoc = null
set OwnerOfBullet = null
set G = null
set Direction = null
set Bullet = null
set CurrentLoc =null
endfunction 
//==== Init Trigger NewTrigger =============================
function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
 
Level 11
Joined
Feb 18, 2004
Messages
394
#1: Use [code=jass] Tags not code tags:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==’A000’
endfunction
//=============================================================
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance
local real CurrentDistance
local location CurrentLoc
local location StartLoc
local unit Bullet
local group G
local real Direction
local player OwnerOfBullet
local boolean Hit
local unit Shooter
set Shooter = GetSpellAbilityUnit()
set CurrentDistance = 0
set EndDistance = 1200
set StartLoc = GetUnitLoc(GetSpellAbilityUnit())
set OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
set Direction = GetUnitFacing(GetSpellAbilityUnit())   
call CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
set Bullet = GetLastCreatedUnit()
loop
    exitwhen CurrentDistance >= EndDistance
    call TriggerSleepAction(.01)
    call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
    set CurrentLoc = GetUnitLoc(Bullet)
    set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
    set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
    if (CountUnitsInGroup(G) >= 1) 
    then
    call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
    call RemoveUnit(Bullet)
    endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set CurrentDistance = null
set EndDistance = null
set StartLoc = null
set OwnerOfBullet = null
set G = null
set Direction = null
set Bullet = null
set CurrentLoc =null
endfunction 
//==== Init Trigger NewTrigger =============================
function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction

#2: return GetSpellAbilityId()==’A000’ its ' not `, thus:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

#3: Indent your code please... you indent if, else, elseif, loop, function, pretty much every code block.

#4: You can initialize locals like so:
JASS:
local real EndDistance = 1200
local real CurrentDistance = 0
local location CurrentLoc
local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
local unit Bullet
local group G
local real Direction = GetUnitFacing(GetSpellAbilityUnit())
local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
local boolean Hit
local unit Shooter = GetSpellAbilityUnit()

#5:
JASS:
call CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
set Bullet = GetLastCreatedUnit()
#5.1: GetLastCreatedUnit() only works with blizzard.j unit creation functions. that is a native one.
#5.2: CreateUnitAtLoc() returns the created unit.
#5.3: Again, local initialization. Thus:
JASS:
local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
Because StatLoc is declared before Bullet, we can use it like that.

#6:
JASS:
set Shooter = null
set CurrentDistance = null
set EndDistance = null
set StartLoc = null
set OwnerOfBullet = null
set G = null
set Direction = null
set Bullet = null
set CurrentLoc =null

You only have to null types which extend from the handle type, and you only have to null locals that will contain a handle that will eventually be destroyed. thus:
JASS:
set Shooter = null
set StartLoc = null
set G = null
set Bullet = null
set CurrentLoc = null

So heres what where up to:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction
//=============================================================
function Trig_Shoot_Actions takes nothing returns nothing
	local real EndDistance = 1200
	local real CurrentDistance = 0
	local location CurrentLoc
	local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
	local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
	local real Direction = GetUnitFacing(GetSpellAbilityUnit())
	local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
	local group G	
	local boolean Hit
	local unit Shooter = GetSpellAbilityUnit()
	
	loop
	    exitwhen CurrentDistance >= EndDistance
	    call TriggerSleepAction(.01)
	    call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
	    set CurrentLoc = GetUnitLoc(Bullet)
	    set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
	    set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
	    if (CountUnitsInGroup(G) >= 1) 
	    then
	    call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
	    call RemoveUnit(Bullet)
	    endif
	endloop
	
	call RemoveUnit(Bullet)
	set Shooter = null
	set StartLoc = null
	set G = null
	set Bullet = null
	set CurrentLoc = null
endfunction

#7:
JASS:
if (CountUnitsInGroup(G) >= 1) 
then

#7.1: if condition then, all on one line.
#7.2: You don't need the outermost parenthesis. thus:
JASS:
if CountUnitsInGroup(G) >= 1 then

#8: This line is just completely wrong:
JASS:
set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())

#8.1: GetUnitsInRangeOfLocMatching() is a BJ function. (Blizzard.J) BJ's are coded in JASS, whereas natives are coded in C++ within the game. Natives are always preferable, especially considering most blizzard.j functions are so poorly coded.
JASS:
function GetUnitsInRangeOfLocMatching takes real radius, location whichLocation, boolexpr filter returns group
    local group g = CreateGroup()
    call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, filter)
    call DestroyBoolExpr(filter)
    return g
endfunction

#8.1.1: Don't destroy boolexprs.
#8.1.2: Don't use locations. Use real x and y coordinated.

#8.2: A boolexpr is a pointer to a function that returns a boolean type value. You create a boolexpr with the Condition() or Filter() functions as such: Condition(function YourFunctionName) YourFunctionName is the name of a function which takes nothing and returns a boolean. Thus, ignoring the BJ function so far and just using a proper boolexpr:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Shoot_Filter takes nothing returns boolean
	return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction

function Trig_Shoot_Actions takes nothing returns nothing
	local real EndDistance = 1200
	local real CurrentDistance = 0
	local location CurrentLoc
	local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
	local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
	local real Direction = GetUnitFacing(GetSpellAbilityUnit())
	local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
	local group G	
	local boolean Hit
	local unit Shooter = GetSpellAbilityUnit()
	
	loop
	    exitwhen CurrentDistance >= EndDistance
	    call TriggerSleepAction(.01)
	    call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
	    set CurrentLoc = GetUnitLoc(Bullet)
	    set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
	    set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, Condition(function Shoot_Filter))
	    if CountUnitsInGroup(G) >= 1 then
	    call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
	    call RemoveUnit(Bullet)
	    endif
	endloop
	
	call RemoveUnit(Bullet)
	set Shooter = null
	set StartLoc = null
	set G = null
	set Bullet = null
	set CurrentLoc = null
endfunction 
//==== Init Trigger NewTrigger =============================
function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction

#9: You use locations... which you don't have to do. Switching to using X and Y coordinates, and inlining the GetUnitsInRangeOfLocMatching() BJ and a few others, we end up with:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Shoot_Filter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction

function Trig_Shoot_Actions takes nothing returns nothing
    local real EndDistance = 1200
    
    local real CurrentDistance = 0
    local unit Shooter = GetTriggerUnit() // TriggerUnit == GetSpellAbilityUnit()
    local player OwnerOfBullet = GetOwningPlayer(Shooter)
    local real Direction = GetUnitFacing(Shooter)
    
    local real StartX = GetUnitX(Shooter)
    local real StartY = GetUnitY(Shooter)
    local real CurrentX
    local real CurrentY
    
    local unit Bullet = CreateUnit(OwnerOfBullet, 'H000', StartX, StartY, Direction)
    local group G
    
    loop
        exitwhen CurrentDistance >= EndDistance

        call TriggerSleepAction(.01)
        
        // Polar projection:
        set CurrentX = GetUnitX(Bullet) + 20 * Cos(Direction * bj_DEGTORAD)
        set CurrentY = GetUnitY(Bullet) + 20 * Sin(Direction * bj_DEGTORAD)
        call SetUnitPosition(Bullet, CurrentX, CurrentY)
        
        set CurrentDistance = SquareRoot(CurrentX*StartX + CurrentY*StartY)
        
        set G = CreateGroup()
        call GroupEnumUnitsInRange(G, CurrentX, CurrentY, 45, Condition(function Shoot_Filter))
        
        if CountUnitsInGroup(G) >= 1 then
            call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
            call RemoveUnit(Bullet)
        endif
    endloop
    
    call RemoveUnit(Bullet)
    set Shooter = null
    set G = null
    set Bullet = null
endfunction 

function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction

#10: if CountUnitsInGroup(G) >= 1 then CountUnitsInGroup() is a BJ. a not completely useless one, however: FirstOfGroup() will return null if a group is empty, so:
JASS:
if FirstOfGroup(G) != null then

#11:
JASS:
        if FirstOfGroup(G) != null then
            call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
            call RemoveUnit(Bullet)
        endif
A minor logic error: If the bullet is removed before its out of distance, then the loop will continue iterating. Adding an exitwhen true fixes that. Also, if you're editing the loop, you don't need to remove the unit here, as its done after the loop anyway.

So, heres what we have:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Shoot_Filter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction

function Trig_Shoot_Actions takes nothing returns nothing
    local unit Shooter = GetTriggerUnit() // TriggerUnit == GetSpellAbilityUnit()
    local real Direction = GetUnitFacing(Shooter)
    
    local real StartX = GetUnitX(Shooter)
    local real StartY = GetUnitY(Shooter)
    local real CurrentX
    local real CurrentY
    
    local real CurrentDistance = 0
    local real EndDistance = 1200
    
    local unit Bullet = CreateUnit(GetOwningPlayer(Shooter), 'H000', StartX, StartY, Direction)
    local group G
    
    loop
        exitwhen CurrentDistance >= EndDistance

        call TriggerSleepAction(.01)
        
        // Polar projection:
        set CurrentX = GetUnitX(Bullet) + 20 * Cos(Direction * bj_DEGTORAD)
        set CurrentY = GetUnitY(Bullet) + 20 * Sin(Direction * bj_DEGTORAD)
        call SetUnitPosition(Bullet, CurrentX, CurrentY)
        
        set CurrentDistance = SquareRoot(CurrentX*StartX + CurrentY*StartY)
        
        set G = CreateGroup()
        call GroupEnumUnitsInRange(G, CurrentX, CurrentY, 45, Condition(function Shoot_Filter))
        
        if FirstOfGroup(G) != null then
            call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
            exitwhen true
        endif
    endloop
    
    call RemoveUnit(Bullet)
    
    set Shooter = null
    set G = null
    set Bullet = null
endfunction 

function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction


Theres more problems with this code that I'm too lazy to go over right now:
  • It uses TriggerSleepAction() instead of a timer
  • The exitwhen it based on a distance between points calculation, whereas it could be optimized to work on a static number of iterations. (As you're always moving at most 1500 units, you can just iterate 1500/20 times.)
  • There are constant values like the speed of 20 and unit rawcodes all over. You can use constant functions which only return a value to get them all in one place. eg:
    JASS:
    constant function Shoot_GetBulletSpeed takes nothing returns real
        return 20
    endfunction

Hope this helps...


Edit: Oh, and if you have any JASS questions and want some real-time help, drop by the chat room: http://www.hiveworkshop.com/resources_new/chat/ the link to it is also at the top of every THW page :)
 
Level 8
Joined
Jul 25, 2006
Messages
177
Wow thanks for going over my code, i appreciate it -- you taught me a lot i needed to know. Ill be sure to read a tut on timers and yeah i know there's a lot of raw values but I was more concerned getting things to work at the time. Thanks again!
 
Level 8
Joined
Jul 25, 2006
Messages
177
Ok this is my code for the spell as of now, the biggest problem is with the calling the TimerStart, it wont let me use any arguments for that function in the timer start, whats my alternative for making this work?
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Shoot_Filter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) != 'u000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction

function Trig_Shoot_Unit takes unit bullet, unit shooter returns nothing
local real Direction = GetUnitFacing(bullet)
local real Direction = GetUnitFacing(bullet)
local real CurrentX = GetUnitX(bullet) + 60 * Cos(Direction * bj_DEGTORAD)
local real CurrentY = GetUnitY(bullet) + 60 * Sin(Direction * bj_DEGTORAD)
local group G = CreateGroup()
if GetWidgetLife(bullet) > 0.405 then
    call SetUnitPosition(bullet, CurrentX, CurrentY)
    call GroupEnumUnitsInRange(G, CurrentX, CurrentY, 45, Condition(function Trig_Shoot_Filter))

    if FirstOfGroup(G) != null then
        call UnitDamageTarget(shooter, FirstOfGroup(G), 700, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
    endif
endif

set G = null
endfunction 


function Trig_Shoot_Actions takes nothing returns nothing
    local unit Shooter = GetTriggerUnit()
    local real Direction = GetUnitFacing(Shooter)
    local real StartX = GetUnitX(Shooter)
    local real StartY = GetUnitY(Shooter)
    local unit Bullet = CreateUnit(GetOwningPlayer(Shooter), 'u000', StartX, StartY, Direction)
    local timer t
    call TimerStart(t, .035, true, function Trig_Shoot_Unit(Bullet, Shooter))
    call TriggerSleepAction(.5)
    call DestroyTimer(t)
    call KillUnit(Bullet)

    set Shooter = null
    set Bullet = null
    set t = null
endfunction

function InitTrig_Shoot takes nothing returns nothing
    set gg_trg_Shoot = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
    call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,207
You can not pass argumants to a function run in a timer directly. This is quite logical since it clearly says it wants a function name rather than a call of some kind. Thus you need to store the arguments you want to pass to the timers in a variable of some kind so that they can be axcessed when the timer wants them.

However this results in a problem for multyinstantcastibility and so a system needs to be made that from the timer object, it can get the arguments you passed through that specific timer and so not collide with arguments passed with other timers.

An easy way to avioid systems like PurplePoot wanted to use and remain realtivly efficent is the array loop method. Basically it can be easy to program at the time but might not cut it as far as efficency goes if there are a lot of ocjects stored.

Below is a vJASS spell I made that uses that system.
JASS:
library Attract initializer int requires TimerBank
   globals
        private constant integer ACTIVATOR_SPELL = 'A005'
        private constant integer EFFECTED_SPELL = 'A004'
        private unit array units
        private timer array timers
        private integer n = 0
        public trigger MAIN = CreateTrigger()
    endglobals
    
    private function condition takes nothing returns boolean
        return GetSpellAbilityId() == ACTIVATOR_SPELL
    endfunction
    
    private function end takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer i = 0
        loop
            exitwhen timers[i] == t
            set i=i+1
        endloop
        call SetUnitAbilityLevel(units[i],EFFECTED_SPELL,1)
        call TimerBank_Deposit(t)
        set n=n-1
        set timers[i] = timers[n]
        set units[i] = units[n]
        set timers[n] = null
        set units[n] = null
        set t = null
    endfunction
    
    private function action takes nothing returns nothing
        local unit u = GetSpellAbilityUnit()
        set units[n] = u
        set timers[n] = TimerBank_Withdraw()
        call TimerStart(timers[n],15,false,function end)
        set n=n+1
        call SetUnitAbilityLevel(u,EFFECTED_SPELL,GetUnitAbilityLevel(u,ACTIVATOR_SPELL)+1)
        set u = null
    endfunction
    
    private function int takes nothing returns nothing
        call TriggerAddAction(MAIN,function action)
        call TriggerAddCondition(MAIN,Condition(function condition))
        call TriggerRegisterAnyUnitEventBJ(MAIN,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    endfunction
endlibrary
 
Status
Not open for further replies.
Top