scope magicOrbs initializer init
//****************************************************
//START OF THE CONFIGURATION
//IMPORTANT: IF YOU WANT PRELOAD THE SPELL WHEN YOU WANT
//TYPE THE NEXT TEXT IN JASS SCRIPT:
//call magicOrbs_PreloadSpell()
//****************************************************
globals
private constant integer abilityId = 'A000'//Ability id of the spell
private constant integer unitTypeOrb = 'u000'//Unit type of the dummy
private constant real interval = 0.03125//Interval of the spell
private constant real orbScale = 1.5//Scale of the orb
private constant string missileModel = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"//Orb model
private constant string specialEffect = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl"//Explosion target model
private constant attacktype attackType = ATTACK_TYPE_NORMAL//Attack type
private constant damagetype damageType = DAMAGE_TYPE_NORMAL//Damage type
private constant weapontype weaponType = WEAPON_TYPE_WHOKNOWS//Weapon type
private constant boolean preloadSpell = TRUE
private real angleSpeed = 2.7//Angle moved every interval
private real normalSpeed = 3//Movement speed every interval
endglobals
private constant function orbsAmount takes integer level returns integer
return 5//Total of orbs
endfunction
private constant function distanceBTAO takes integer level returns real
return 150.//Distance between the target and the orbs
endfunction
private constant function damageTarget takes integer level returns real
return 20. + 10. * level//Damage every orb each level
endfunction
private constant function damageAOE takes integer level returns real
return 12. + 6. * level//Damage of area of effect every orb each level
endfunction
private constant function areaOfEffect takes integer level returns real
return 275. + 50. * level//Area of effect of the explosions
endfunction
private constant function immolateDamage takes integer level returns real
return 5. + 2. * level//Damage per interval of each orb
endfunction
private constant function immolateAOE takes integer level returns real
return 50. + 20. * level//Area of effect of the 'immolate' damage
endfunction
private constant function duration takes integer level returns real
return 10.//The time you have to wait to the orbs impacts the target
endfunction
private constant function filterUnits takes unit target, player owner returns boolean
if /*
*/not IsUnitType(target, UNIT_TYPE_DEAD) /*
*/and not IsUnitType(target, UNIT_TYPE_STRUCTURE) /*
*/and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) /*
*/and IsUnitEnemy(target, owner) /*
*/then
return TRUE
endif
return FALSE
endfunction
//****************************************************
//END OF THE CONFIGURATION
//****************************************************
private struct orbsData
unit caster
unit orb
unit target
real angle
integer level
real time
real distance
effect eff
player owner
endstruct
globals
private constant timer TIMER = CreateTimer()
private orbsData array ARRAY
private integer TOTAL = 0
private constant player PLAYER = Player(PLAYER_NEUTRAL_AGGRESSIVE)
endglobals
private function action takes nothing returns nothing
local orbsData mo
local integer i = 0
local real x
local real x1
local real y
local real y1
local unit j
loop
exitwhen i >= TOTAL
set mo = ARRAY[i]
set x = GetUnitX(mo.target)
set y = GetUnitY(mo.target)
set x1 = GetUnitX(mo.orb)
set y1 = GetUnitY(mo.orb)
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x1, y1, immolateAOE(mo.level), null)
loop
set j = FirstOfGroup(bj_lastCreatedGroup)
exitwhen j == null
call GroupRemoveUnit(bj_lastCreatedGroup, j)
if filterUnits(j, mo.owner) then
call UnitDamageTarget(mo.caster, j, damageAOE(mo.level) * interval, true, false, attackType, damageType, weaponType)
endif
endloop
set mo.angle = mo.angle + angleSpeed
if mo.time > 0 then
call SetUnitPosition(mo.orb, x + mo.distance * Cos(bj_DEGTORAD * mo.angle), y + mo.distance * Sin(bj_DEGTORAD * mo.angle))
else
set mo.distance = mo.distance - normalSpeed
call SetUnitPosition(mo.orb, x + mo.distance * Cos(bj_DEGTORAD * mo.angle), y + mo.distance * Sin(bj_DEGTORAD * mo.angle))
endif
if mo.distance < 30 or IsUnitType(mo.target, UNIT_TYPE_DEAD) then
call SetUnitExploded(mo.orb, TRUE)
call KillUnit(mo.orb)
call DestroyEffect(mo.eff)
call UnitDamageTarget(mo.caster, mo.target, damageTarget(mo.level), TRUE, FALSE, attackType, damageType, weaponType)
call DestroyEffect(AddSpecialEffect(specialEffect, x, y))
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, areaOfEffect(mo.level), null)
loop
set j = FirstOfGroup(bj_lastCreatedGroup)
exitwhen j == null
call GroupRemoveUnit(bj_lastCreatedGroup, j)
if filterUnits(j, mo.owner) then
call UnitDamageTarget(mo.caster, j, damageAOE(mo.level), TRUE, FALSE, attackType, damageType, weaponType)
call DestroyEffect(AddSpecialEffect(specialEffect, GetUnitX(j), GetUnitY(j)))
endif
endloop
set ARRAY[i] = ARRAY[TOTAL - 1]
set TOTAL = TOTAL - 1
set mo.caster = null
set mo.orb = null
set mo.target = null
set mo.eff = null
call mo.destroy()
endif
set mo.time = mo.time - interval
set i = i + 1
endloop
if TOTAL == 0 then
call PauseTimer(TIMER)
endif
endfunction
private function run takes nothing returns boolean
local orbsData mo
local unit caster
local unit target
local real angle
local real x
local real x1
local real y
local real y1
local integer i
local integer level
local integer INTEGER
if GetSpellAbilityId() == abilityId then
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
set level = GetUnitAbilityLevel(caster, abilityId)
set INTEGER = orbsAmount(level)
set x = GetUnitX(target)
set y = GetUnitY(target)
set i = 1
loop
exitwhen i > INTEGER
set mo = orbsData.create()
set mo.angle = (360 / INTEGER) * i
set mo.distance = distanceBTAO(level)
set x1 = x + mo.distance * Cos(bj_DEGTORAD * mo.angle)
set y1 = y + mo.distance * Sin(bj_DEGTORAD * mo.angle)
set mo.orb = CreateUnit(PLAYER, unitTypeOrb, x1, y1, mo.angle + 180)
set mo.eff = AddSpecialEffectTarget(missileModel, mo.orb, "origin")
set mo.caster = caster
set mo.target = target
set mo.level = level
set mo.time = duration(level)
set mo.owner = GetTriggerPlayer()
if TOTAL == 0 then
call TimerStart(TIMER, interval, TRUE, function action)
endif
set TOTAL = TOTAL + 1
set ARRAY[TOTAL - 1] = mo
set i = i + 1
endloop
endif
set caster = null
set target = null
return FALSE
endfunction
public function PreloadSpell takes nothing returns nothing
local unit preloader = CreateUnit(PLAYER, unitTypeOrb, 0, 0, 0)
call UnitAddAbility(preloader, abilityId)
call RemoveUnit(preloader)
call Preload(specialEffect)
call Preload(missileModel)
set preloader = null
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Condition(function run))
if preloadSpell then
call PreloadSpell()
endif
set t = null
endfunction
endscope