- Joined
- Jul 19, 2007
- Messages
- 824
I currently got a problem with this JASS-triggered ability that I've imported from this ability http://www.hiveworkshop.com/forums/...2/?prev=search=touch%20of%20light&d=list&r=20 but I've edited it alot. I'm very lost and noobish at JASS-triggering so I could only edit the simplest things in it.. I got a problem I cannot solve, the orbs are supposed to drain life from enemy units in the targeted area but it also seems to drain life from buildings, wards and spell immunity units and I just want the orbs to drain life from organic units that is not immune to spells or invulnerable.. How can I change that?
The JASS-trigger of the ability.
The JASS-trigger of the ability.
JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ElvenOrbs initializer InitTrig_Elven_Orbs
// Spell Touch of Light by The_Witcher
//
// Creates orbs that patrol in a area, draining life from enemies.
// When their time has come they return and heal the caster and his allies!
//
// THE SETUP PART:
globals
// the rawcode of the spell
private constant integer SPELL_ID = 'A0D3'
// the rawcode of the dummy used as orb
private constant integer ORB_ID = 'h01Z'
// the range in which the orbs can drain
private constant integer ORB_DRAIN_RANGE = 150
// the timer interval (increase if laggy)
private constant real INTERVAL = 0.02
// the flying height of the orbs
private constant real ORB_HEIGHT = 80
// the time it takes a orb to drain life
private constant real DRAIN_TIME = 0.5
// false = only caster is healed
// true = caster and near allies are healed
private constant boolean AOE_HEAL = true
// the sfx created on units while healing
private constant string HEAL_SFX = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
// the attachement point for HEAL_SFX
private constant string HEAL_SFX_TARGET = "origin"
// the sfx created on units while draining
private constant string DRAIN_SFX = "Abilities\\Spells\\Human\\Slow\\SlowCaster.mdl"
// the sfx created on a orb when it returns to the caster
private constant string EXPLODE_SFX = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
// the lightning created while draining
private constant string LIGHTNING = "HWPB"
// false = lightning is normal
// true = lightnings endings are switched
private constant boolean LIGHTNING_TURNED = true
endglobals
private function GetOrbAmount takes integer lvl returns integer
return 1 + 2 * lvl // 2 orbs more each level !!CAN NEVER BE HIGHER THAN 50!!
endfunction
private function GetOrbDrainCooldown takes integer lvl returns real
return 1.1 - 0.1 * lvl // 1sec/0.9sec/0.8sec/0.7sec
endfunction
private function GetOrbAreaSize takes integer lvl returns real
return 200. + 50 * lvl // 250/300/350/400 radius for the area where the orbs do their work
endfunction
private function GetDrainPercentage takes integer lvl returns real
return 0.01 + 0.02 * lvl //draines 2% more each level
endfunction
private function GetDuration takes integer lvl returns real
return 4. + 1 * lvl //lasts for 5/6/7/8... seconds
endfunction
private function GetHealPercentage takes integer lvl returns real
return 0.02 + 0.02 * lvl //heals 2% more each level
endfunction
private function GetHealRange takes integer lvl returns real
return 100. + 50 * lvl //heals in a AOE of 150/200/250/300...
endfunction
private function GetOrbSpeed takes integer lvl returns real
return 5. + 1. * lvl // 6/7/8/9 per interval...
endfunction
//---------------------------------------------------------
//-----------Don't modify anything below this line---------
//---------------------------------------------------------
private struct data
unit u
real x
real y
integer lvl
unit array orb [50]
unit array target [50]
integer array phase [50]
real array drained [50]
real array delay [50]
lightning array light [50]
timer tim = CreateTimer()
integer orbs = 0
real temp = 19
real t = 0
endstruct
globals
private hashtable h = InitHashtable()
private data DATA
private group g = CreateGroup()
private location loc = Location(0,0)
endglobals
private function AngleBetweenCoords takes real x, real y, real xx, real yy returns real
return Atan2(yy - y, xx - x)
endfunction
private function DistanceBetweenCoords takes real x , real y , real xx , real yy returns real
return SquareRoot((x-xx)*(x-xx)+(y-yy)*(y-yy))
endfunction
private function DistanceBetweenUnits takes unit a, unit b returns real
local real dx = GetUnitX(b) - GetUnitX(a)
local real dy = GetUnitY(b) - GetUnitY(a)
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit a, unit b returns real
return Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
private function EnemiesOnly takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(DATA.u)) and not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction
private function AlliesOnly takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(),GetOwningPlayer(DATA.u)) and not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction
private function AOEheal takes nothing returns nothing
call SetWidgetLife(GetEnumUnit(),GetWidgetLife(GetEnumUnit()) + DATA.temp * GetHealPercentage(DATA.lvl))
call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX,GetEnumUnit(),HEAL_SFX_TARGET))
endfunction
function RandomEnemyUnit takes real x, real y, real range returns unit
local unit a=null
local unit i
local integer b=0
call GroupClear(g)
call GroupEnumUnitsInRange(g,x,y,range,Condition(function EnemiesOnly))
loop
set i=FirstOfGroup(g)
exitwhen i==null
set b=b+1
if (GetRandomInt(1,b) == 1) then
set a = i
endif
call GroupRemoveUnit(g,i)
endloop
set bj_groupRandomCurrentPick=a
set a=null
return bj_groupRandomCurrentPick
endfunction
private function Execute takes nothing returns nothing
local data dat = LoadInteger(h,GetHandleId(GetExpiredTimer()),0)
local real X
local real Y
local real a
local integer i = 0
//****check whether caster is alive****
if (IsUnitType(dat.u,UNIT_TYPE_DEAD) or GetUnitTypeId(dat.u) == 0 ) then
loop
exitwhen i >= dat.orbs
call RemoveUnit(dat.orb[i])
call DestroyLightning(dat.light[i])
set i = i + 1
endloop
set dat.orbs = 0
else
//****increase time****
set dat.t = dat.t + INTERVAL
//****new orbs****
if dat.orbs < IMinBJ(GetOrbAmount(dat.lvl),50) and dat.t <= GetDuration(dat.lvl) then
set dat.temp = dat.temp + 1
if dat.temp == 20 then
set dat.orb[dat.orbs] = CreateUnit(GetOwningPlayer(dat.u),ORB_ID,GetUnitX(dat.u),GetUnitY(dat.u),0)
call UnitAddAbility(dat.orb[dat.orbs], 'Aloc')
call UnitAddAbility(dat.orb[dat.orbs], 'Amrf')
call SetUnitFlyHeight(dat.orb[dat.orbs],ORB_HEIGHT,0)
set dat.temp = 0
set DATA = dat
set dat.target[dat.orbs] = RandomEnemyUnit(dat.x,dat.y,GetOrbAreaSize(dat.lvl))
set dat.orbs = dat.orbs + 1
endif
endif
//****process all active orbs****
loop
exitwhen i >= dat.orbs
if dat.phase[i] == 0 then
//****search a target and drain****
//****reduce cooldown****
if dat.delay[i] > 0 then
set dat.delay[i] = dat.delay[i] - INTERVAL
if dat.delay[i] < 0 then
set dat.delay[i] = 0
endif
if dat.delay[i] <= GetOrbDrainCooldown(dat.lvl) then
if IsUnitPaused(dat.orb[i]) then
call DestroyLightning(dat.light[i])
call PauseUnit(dat.orb[i],false)
//****new target****
set DATA = dat
set dat.target[i] = RandomEnemyUnit(dat.x,dat.y,GetOrbAreaSize(dat.lvl))
endif
else
call MoveLocation(loc,GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]))
set a = GetLocationZ(loc)
call MoveLocation(loc,GetUnitX(dat.target[i]),GetUnitY(dat.target[i]))
if LIGHTNING_TURNED then
call MoveLightningEx(dat.light[i],true,GetUnitX(dat.target[i]),GetUnitY(dat.target[i]),GetLocationZ(loc)+50,GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]),a+ORB_HEIGHT)
else
call MoveLightningEx(dat.light[i],true,GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]),a+ORB_HEIGHT,GetUnitX(dat.target[i]),GetUnitY(dat.target[i]),GetLocationZ(loc)+50)
endif
endif
endif
//****if time is up and the orb isn't draining, start returning to the caster****
if dat.delay[i] <= GetOrbDrainCooldown(dat.lvl) and dat.t > GetDuration(dat.lvl) then
set dat.phase[i] = 1
elseif dat.target[i] != null then
//****distance to target check*****
if DistanceBetweenUnits(dat.target[i],dat.orb[i]) < ORB_DRAIN_RANGE then
//****no cooldown left?****
if dat.delay[i] == 0 then
//****drain****
set X = GetUnitX(dat.target[i])
set Y = GetUnitY(dat.target[i])
set a = GetWidgetLife(dat.target[i]) * GetDrainPercentage(dat.lvl)
set dat.drained[i] = dat.drained[i] + a
call SetWidgetLife(dat.target[i], GetWidgetLife(dat.target[i]) - a)
//****effects****
call DestroyEffect(AddSpecialEffect(DRAIN_SFX,X,Y))
if LIGHTNING_TURNED then
set dat.light[i] = AddLightningEx(LIGHTNING,true,X,Y,GetUnitFlyHeight(dat.target[i])+50,GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]),ORB_HEIGHT)
else
set dat.light[i] = AddLightningEx(LIGHTNING,true,GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]),ORB_HEIGHT,X,Y,GetUnitFlyHeight(dat.target[i])+50)
endif
//****cooldown****
call PauseUnit(dat.orb[i],true)
set dat.delay[i] = GetOrbDrainCooldown(dat.lvl) + DRAIN_TIME
endif
//****distance too huge so go nearer****
elseif not IsUnitPaused(dat.orb[i]) then
set a = AngleBetweenUnits(dat.orb[i],dat.target[i])
set X = GetUnitX(dat.orb[i]) + GetOrbSpeed(dat.lvl) * Cos(a)
set Y = GetUnitY(dat.orb[i]) + GetOrbSpeed(dat.lvl) * Sin(a)
call SetUnitX(dat.orb[i],X)
call SetUnitY(dat.orb[i],Y)
endif
else
//****new target****
set DATA = dat
set dat.target[i] = RandomEnemyUnit(dat.x,dat.y,GetOrbAreaSize(dat.lvl))
endif
else
//****Time is up so return to caster****
set a = AngleBetweenCoords(GetUnitX(dat.orb[i]),GetUnitY(dat.orb[i]),GetUnitX(dat.u),GetUnitY(dat.u))
set X = GetUnitX(dat.orb[i]) + GetOrbSpeed(dat.lvl) * Cos(a)
set Y = GetUnitY(dat.orb[i]) + GetOrbSpeed(dat.lvl) * Sin(a)
call SetUnitX(dat.orb[i],X)
call SetUnitY(dat.orb[i],Y)
//****caster reached so heal****
if DistanceBetweenCoords(X,Y,GetUnitX(dat.u),GetUnitY(dat.u)) < 10 then
call RemoveUnit(dat.orb[i])
call DestroyEffect(AddSpecialEffect(EXPLODE_SFX,X,Y))
if AOE_HEAL then
set DATA = dat
set dat.temp = dat.drained[i]
call GroupEnumUnitsInRange(g,X,Y,GetHealRange(dat.lvl),Condition(function AlliesOnly))
call ForGroup(g, function AOEheal)
else
call SetWidgetLife(dat.u,GetWidgetLife(dat.u) + dat.drained[i] * GetHealPercentage(dat.lvl))
call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX,dat.u,HEAL_SFX_TARGET))
endif
set dat.orbs = dat.orbs - 1
set dat.orb[i] = dat.orb[dat.orbs]
set i = i - 1
endif
endif
set i = i + 1
endloop
endif
//****no orbs left ==> end spell****
if dat.orbs == 0 then
call FlushChildHashtable(h,GetHandleId(dat.tim))
call DestroyTimer(dat.tim)
call dat.destroy()
endif
endfunction
private function Cast takes nothing returns boolean
local data dat
local integer i = 0
if GetSpellAbilityId() == SPELL_ID then
set dat = data.create()
loop
exitwhen i == 50
set dat.phase[i] = 0
set dat.drained[i] = 0
set dat.delay[i] = 0
set i = i + 1
endloop
set dat.x = GetSpellTargetX()
set dat.y = GetSpellTargetY()
set dat.u = GetTriggerUnit()
set dat.lvl = GetUnitAbilityLevel(dat.u,SPELL_ID)
call SaveInteger(h,GetHandleId(dat.tim),0,dat)
call TimerStart(dat.tim,INTERVAL,true,function Execute)
endif
return false
endfunction
private function InitTrig_Elven_Orbs takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerAddCondition(t,Condition(function Cast))
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
endfunction
endlibrary