- Joined
- Jul 6, 2009
- Messages
- 1,885
I seem to be stuck on a little problem (or 2) so i could use some help.
I made a simple spell that fires a projectile damaging each unit it hits and dealing damage upon reaching certain range.
First problem is that i wanted the projectile to damage each unit once by adding damaged units to a group in struct instance and each next time checking whether units hit by projectile are in the group, but it doesn't work properly (Units that were supposed to be in the group pass the check).
Second problem is that when the spell is casted several times, it seems that...instances mess up. Sometimes projectiles move twice as fast and according to debug messages, at those times more than one instances refers to same unit ;/
(Note: Loop function is ran outside of library)
Here's also a test map with the spell.
I made a simple spell that fires a projectile damaging each unit it hits and dealing damage upon reaching certain range.
First problem is that i wanted the projectile to damage each unit once by adding damaged units to a group in struct instance and each next time checking whether units hit by projectile are in the group, but it doesn't work properly (Units that were supposed to be in the group pass the check).
Second problem is that when the spell is casted several times, it seems that...instances mess up. Sometimes projectiles move twice as fast and according to debug messages, at those times more than one instances refers to same unit ;/
JASS:
library Arcyling initializer Init
private keyword Instance
private keyword l
//Configuration Part
globals
private constant integer SPELL_RAW = 'A003'
private constant integer SPIRIT_RAW = 'h001'
private constant real SPEED = 10.0
private constant real BASE_DAMAGE_1 = 20.0
private constant real DAMAGE_1_INCREMENT = 50.0
private constant real BASE_DAMAGE_2 = 25.0
private constant real DAMAGE_2_INCREMENT = 20.0
private constant real MAX_RANGE = 600.0
private constant real EXPLOSION_AOE = 200.0
private constant real MOVE_AOE = 100.0
private constant string EFFECT_1 = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
private constant string EFFECT_2 = "Units\\NightElf\\Wisp\\WispExplode.mdl"
endglobals
private function filter takes unit u returns boolean
return IsUnitType(u,UNIT_TYPE_DEAD) == false and IsPlayerEnemy(GetOwningPlayer(u),GetOwningPlayer(l)) and IsUnitType(u,UNIT_TYPE_STRUCTURE) == false
endfunction
//End of configuration
//===========================================================================
globals
private Instance array I
private integer Running = 0
private integer Max = 0
private group g = CreateGroup()
private group d //Variables d,l and i are used to pass data to a filter function since filter functions can't have parameters
private unit l
private integer i
endglobals
function Damage1 takes nothing returns boolean
local unit u = GetFilterUnit()
if filter(u) then
call UnitDamageTarget(l,u,BASE_DAMAGE_1 + i * DAMAGE_1_INCREMENT,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
return false
endfunction
function Damage2 takes nothing returns boolean
local unit u = GetFilterUnit()
if filter(u) and IsUnitInGroup(u,d) == false then //This is one of the problems, units pass this check even though i added them to the group
call UnitDamageTarget(l,u,BASE_DAMAGE_2 + i * DAMAGE_2_INCREMENT,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call GroupAddUnit(d,u)
call DestroyEffect(AddSpecialEffectTarget(EFFECT_1,u,"chest"))
endif
return false
endfunction
private struct Instance
unit u
integer lvl
real r = 0.00
group g
method move takes nothing returns nothing
local real x = GetUnitX(.u)
local real y = GetUnitY(.u)
local real angle = GetUnitFacing(.u) * bj_DEGTORAD
call SetUnitX(.u,x + SPEED * Cos(angle))
call SetUnitY(.u,y + SPEED * Sin(angle))
set .r = .r + SPEED
set l = .u
set d = .g
set i = .lvl
call GroupEnumUnitsInRange(g,x,y,MOVE_AOE,function Damage2)
if .r >= MAX_RANGE then
set x = GetUnitX(.u)
set y = GetUnitY(.u)
call GroupEnumUnitsInRange(g,x,y,MOVE_AOE,function Damage1)
call DestroyEffect(AddSpecialEffect(EFFECT_2,x,y))
call KillUnit(.u)
call .destroy()
endif
endmethod
static method create takes unit u,integer lvl returns thistype
local thistype this = thistype.allocate()
set .u = CreateUnit(GetOwningPlayer(u),SPIRIT_RAW,GetUnitX(u),GetUnitY(u),GetUnitFacing(u))
set .lvl = lvl
set .g = CreateGroup()
set I[Max] = this
set Running = Running + 1
set Max = Max + 1
return this
endmethod
method onDestroy takes nothing returns nothing
set Running = Running - 1
set .u = null
call DestroyGroup(.g)
endmethod
endstruct
private function Cast takes nothing returns boolean
if GetSpellAbilityId() == SPELL_RAW then
call Instance.create(GetTriggerUnit(),GetUnitAbilityLevel(GetTriggerUnit(),SPELL_RAW))
endif
return false
endfunction
public function Loop takes nothing returns nothing
local integer i = 0
if Running != 0 then
loop
exitwhen i + 1 > Max
if I[i].u != null then
call I[i].move()
endif
set i = i + 1
if Running == 0 then
set Max = 0
endif
endloop
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set i = i + 1
exitwhen i == 16
endloop
call TriggerAddCondition(t,function Cast)
set t = null
endfunction
endlibrary
Here's also a test map with the spell.