Moderator
M
Moderator
19:05, 4th Oct 2009
TriggerHappy187:
This spell is well coded and good enough for hive's database.
TriggerHappy187:
This spell is well coded and good enough for hive's database.
//***********************************************************************************************************\\
//* *\\
//* HOLY BIRDS *\\
//* v2.1b *\\
//* *\\
//* Made by: Kricz & Cedi *\\
//* *\\
//* Description: *\\
//* Summons 5 birds, surrounding the caster, *\\
//* each bird damages enemy units on contact or heals allied units on contact *\\
//* (caster gets 50% of that heal) *\\
//* *\\
//* Requires: *\\
//* TimerUtils by Vexorian *\\
//* xe by Vexorian *\\
//* GroupUtils by Rising_Dusk *\\
//***********************************************************************************************************\\
scope HolyBirds //requires TimerUtils, GroupUtils, xebasic, xefx, xedamage, xepreload
globals
//Rawcode of the spell
private constant integer SPELL_ID = 'A000'
//Raw-Code of the created buff
private constant integer BUFF_ID = 'B000'
//The missile model
private constant string MISSILE_MODEL = "Abilities\\Weapons\\SorceressMissile\\SorceressMissile.mdl"
//The missile size
private constant real MISSILE_SIZE = 1.7
//The missile heigh
private constant real MISSILE_HEIGH = 60.0
//The distance between missiles and caster
private constant real MISSILE_DISTANCE = 225.
//The speed of the missiles
private constant real MISSILE_SPEED = 200.
//Number of created missile
private constant integer MISSILES = 5
//Missile Color Setups
private constant integer MISSILE_RED = 255
private constant integer MISSILE_GREEN = 200
private constant integer MISSILE_BLUE = 255
private constant integer MISSILE_ALPHA = 145
//How much percent should the caster get when a target is healed
private constant real CASTER_HEAL_PERCENT = 0.5
//The AoE of the missile
private constant real AOE = 65.0
//when collides with an ally-unit:
private constant string HEAL_EFFECT = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
//when collides with an enemy-unit:
private constant string DAMAGE_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
//effect created on the caster when an allied unit was healed
private constant string CASTER_HEAL_EFFECT = "Abilities\\Spells\\Human\\Heal\\HealTarget.mdl"
//dont chance!
private real array DURATION
private real array DAMAGE
private real array HEAL
endglobals
//The duration of each level
private function SETUP_DURATION takes nothing returns nothing
set DURATION[1] = 7.5
set DURATION[2] = 10.0
set DURATION[3] = 12.5
endfunction
//The Damage to enemys
private function SETUP_DAMAGE takes nothing returns nothing
set DAMAGE[1] = 20.0
set DAMAGE[2] = 40.0
set DAMAGE[3] = 60.0
endfunction
//The Heal to allies
private function SETUP_HEAL takes nothing returns nothing
set HEAL[1] = 15
set HEAL[2] = 30
set HEAL[3] = 45
endfunction
//! textmacro HB_SETUP_DAMAGE
set .dtype = DAMAGE_TYPE_MAGIC
set .atype = ATTACK_TYPE_MAGIC
//set .wtype = WEAPON_TYPE_WHOKNOWS //By default
//! endtextmacro
//Everything below here is the spellcode. If you can not vJass, don't change here anything!
private struct spelldata
unit caster = null //The caster
group array targets[MISSILES] //The group for each missile to check if a unit was already hit
xefx array missile[MISSILES] //The birds
real duration = 0.00 //The duration the spell has (will be changed)
integer lvl = 0 //The level of the ability
timer t = null //The timer which is used for the update
static group group //Used for filtering units
static boolexpr filter //This is the filter
static delegate xedamage dmg //The xedamager used to deal damage
//creates everything the struct requires
static method create takes unit caster returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local real pos = (GetUnitFacing(caster) + 360 / MISSILES + 90) * bj_DEGTORAD
//fills the struct datas
set .caster = caster
set .lvl = GetUnitAbilityLevel(.caster, SPELL_ID)
set .t = NewTimer()
//creates the birds
loop
set .missile[i] =xefx.create(GetUnitX(.caster) + MISSILE_DISTANCE * Cos(pos), GetUnitY(.caster) + MISSILE_DISTANCE * Sin(pos), pos + bj_PI / 2)
set .missile[i].fxpath = MISSILE_MODEL
set .missile[i].scale = MISSILE_SIZE
set .missile[i].z = MISSILE_HEIGH
call .missile[i].recolor(MISSILE_RED, MISSILE_GREEN, MISSILE_BLUE, MISSILE_ALPHA)
set pos = pos + (2 * bj_PI / MISSILES)
set .targets[i] = NewGroup()
set i = i + 1
exitwhen i >= MISSILES
endloop
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.periodic)
return this
endmethod
//destroys the missiles if the duration is over or if the caster is dead
private method onDestroy takes nothing returns nothing
local integer i = 0
call UnitRemoveAbility(.caster, BUFF_ID)
loop
call .missile[i].destroy()
call ReleaseGroup(.targets[i])
set i = i + 1
exitwhen i >= MISSILES
endloop
endmethod
//The filterfunction checks which units can be added to the group
private static method FilterFunc takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and GetUnitAbilityLevel(GetFilterUnit(), 'Amim') <= 0 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endmethod
//This method damages or heals unit in the group
private method DamageHeal takes unit u returns nothing
//If ally, heal the target and caster
if IsUnitAlly(u, GetOwningPlayer(.caster)) and u != .caster then
call DestroyEffect(AddSpecialEffectTarget(HEAL_EFFECT, u, "origin"))
call SetWidgetLife(u, GetWidgetLife(u) + HEAL[.lvl])
call DestroyEffect(AddSpecialEffectTarget(CASTER_HEAL_EFFECT, .caster, "origin"))
call SetWidgetLife(.caster, GetWidgetLife(.caster) + HEAL[.lvl] * CASTER_HEAL_PERCENT)
//If enemy then damage the unit
elseif IsUnitEnemy(u, GetOwningPlayer(.caster)) then
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT, u, "origin"))
call .damageTarget(.caster, u, DAMAGE[.lvl])
endif
endmethod
//This method is called every INTERVAL and will update the birds position and checks for units in range
private static method periodic takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local integer i = 0
local unit u = null
set .duration = .duration + XE_ANIMATION_PERIOD
//loop through every missile
loop
exitwhen i >= MISSILES
set .missile[i].xyangle = .missile[i].xyangle + (MISSILE_SPEED * XE_ANIMATION_PERIOD * XE_ANIMATION_PERIOD)
set .missile[i].x = GetUnitX(.caster) + MISSILE_DISTANCE * Cos(.missile[i].xyangle - bj_PI / 2)
set .missile[i].y = GetUnitY(.caster) + MISSILE_DISTANCE * Sin(.missile[i].xyangle - bj_PI / 2)
call GroupEnumUnitsInRange(.group, .missile[i].x, .missile[i].y, AOE, .filter)
//loop through the unitgroup and damage/heal them
loop
set u = FirstOfGroup(.group)
exitwhen u == null
if not IsUnitInGroup(u, .targets[i]) then
call GroupAddUnit(.targets[i], u)
call .DamageHeal(u)
endif
call GroupRemoveUnit(.group, u)
endloop
set i = i + 1
endloop
if .duration >= DURATION[.lvl] or GetUnitAbilityLevel(.caster, BUFF_ID) <= 0 or GetWidgetLife(.caster) <= 0.405 then
call .destroy()
call ReleaseTimer(GetExpiredTimer())
endif
endmethod
//This method is called, whenever an ability is casted, and checks if that ability is the for this spell.
private static method register takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID and GetUnitAbilityLevel(GetTriggerUnit(), BUFF_ID) <= 0 then
call thistype.create(GetTriggerUnit())
return true
endif
return false
endmethod
//Initializates everything
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition(function thistype.register))
call SETUP_DURATION()
call SETUP_DAMAGE()
call SETUP_HEAL()
set .dmg = xedamage.create()
//! rentextmacro HB_SETUP_DAMAGE()
set .group = NewGroup()
set .filter = Condition(function thistype.FilterFunc)
call XE_PreloadAbility(SPELL_ID)
set t = null
endmethod
endstruct
endscope