library HolyCross initializer Init requires GCU
//Configurables
globals
//Following Ability-IDs have to be set:
private constant integer SpellID = 'A000' //Triggering spell, should be targeting nothing
//Following Dummie-IDs have to be set:
private constant integer DummyCrossID = 'h002' // The Cross Dummy
private constant integer DummyCasterID = 'h001' // The Sheep Dummy
//This is the effect that is created on the hero, when casted:
private constant string EffectModel = "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl"
private constant string LightningHeal1 = "HWPB" // Healing Wave Effect
private constant string LightningHeal2 = "HWSB" // Healing Wave Effect Variation 2
private constant string LightningDamage1 = "CLPB" // Chain Lightning Effect
private constant string LightningDamage2 = "CLSB" // Chain Lightning Effect Variation 2
private constant string DamagingSoundPath = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav" // The Damaging Sound sound-path
private constant string HealingSoundPath = "Abilities\\Spells\\Orc\\HealingWave\\HealingWave.wav" // The Healing Sound sound-path
private constant real BaseHeight = 900 // This is the initial height from where the cross floats down and floats up after the spell is done
private constant real HeightToGo = 175 // This is the heigh in which the cross will be floating while the spell is active
private constant real Length = 20 // This is the spell length; DownRisingTime and UpRisingTime will be included
private constant real DownRisingTime = 1.5 // This is the time that the cross will take to float down
private constant real UpRisingTime = 1.5 // This is the time that the cross will take to float up, when it's finished
private constant real DummyCasterDistanceToCross = 200 // This is the distance in which the sheep will fly around the cross
private constant real CrossRotatingSpeed = 2 // This is the speed of the cross rotating around the hero
private constant real DummyCasterRotatingSpeed = 1.25 // This is the speed of the sheep rotating around the cross
private constant real DummyCasterNukeCooldown = 2.25 // This is the cooldown of the damaging-/healing- lightnings
private constant real DummyCasterNukeRange = 300 // This is the range of the sheep to be to trigger the damaging-/healing- lightnings
private constant real DummyCasterAttackLength = 2. // This is the length of the lightning-attack/healing, the damage will be splited on it
private constant boolean HealsCasterToo = false // true = heals spell casting unit
private constant attacktype AttackType = ATTACK_TYPE_MAGIC // This is the attack type of the lightning-attack
private constant damagetype DamageType = DAMAGE_TYPE_MAGIC // This is the damage type of the lightning-attack
endglobals
private function GetSheepNumb takes integer level returns integer
return level // Returns the number of sheep in the given level. In this case it's the amount of levels
endfunction
private function GetHealing takes integer level returns real
return 100. + (I2R(level)*50) // The formula of healing that is granted to a unit when healed by a sheep
endfunction
private function GetDamage takes integer level returns real
return 100. + (I2R(level)*50) // The formula of damage that is granted to a unit when healed by a sheep
endfunction
// This is the unit filter. Don't change this is if you don't want any special units to be not attacked/healed by the sheep
private function IsUnitViableTarget takes nothing returns boolean
if not HealsCasterToo and GetFilterUnit() == bj_lastCreatedUnit then
return false
endif
return true
endfunction
//Endconfigurables
globals
private integer Index = 0
private boolean array IsActive
private unit array Caster
private unit array Cross
private real array TimeLeft
private real array FloatingDirection
private boolean array FloatedUp
private unit array DummyCasters
private integer array DummyCastersSpellNumb
private real array DummyCasterFloatingDirection
private integer DummyCastersIndex = 0
private real array DummyCasterLeftCooldown
private lightning array DummyCasterLightningAttack
private real array DummyCasterLightningRemainingDur
private boolean array DummyCasterDoesLightningAttack
private unit array DummyCasterTargetedUnit
private boolean array DummyCasterIsHealing
private boolean array DummyCasterLightningIsDestroyed
endglobals
private function Actions takes nothing returns boolean
local real TempLocX
local real TempLocY
local real TempLoc2X
local real TempLoc2Y
local effect TempEffect
local integer i = 1
local real CasterDummyFacing
if (GetSpellAbilityId() == SpellID) then
set Index = Index + 1
set IsActive[Index] = true
set TimeLeft[Index] = Length
set FloatingDirection[Index] = GetRandomInt(0, 360)
set FloatedUp[Index] = false
set Caster[Index] = GetTriggerUnit()
set TempEffect = AddSpecialEffectTarget(EffectModel, Caster[Index], "origin")
set TempLocX = GetUnitX(Caster[Index])
set TempLocY = GetUnitY(Caster[Index])
set Cross[Index] = CreateUnit(GetOwningPlayer(Caster[Index]), DummyCrossID, TempLocX, TempLocY, GetUnitFacing(Caster[Index]))
call SetUnitFlyHeight(Cross[Index], BaseHeight, 0)
call SetUnitFlyHeight(Cross[Index], HeightToGo, (BaseHeight - HeightToGo) / DownRisingTime)
call DestroyEffect(TempEffect)
loop
set DummyCastersIndex = DummyCastersIndex + 1
set DummyCasterLightningIsDestroyed[DummyCastersIndex] = false
set DummyCasterLightningRemainingDur[DummyCastersIndex] = 0
set DummyCasterDoesLightningAttack[DummyCastersIndex] = false
set DummyCasterIsHealing[DummyCastersIndex] = false
set DummyCasterLeftCooldown[DummyCastersIndex] = DummyCasterNukeCooldown
set DummyCastersSpellNumb[DummyCastersIndex] = Index
set DummyCasterFloatingDirection[DummyCastersIndex] = (360 / GetSheepNumb(GetUnitAbilityLevel(Caster[Index], SpellID))) * i
set TempLoc2X = PolarProjectionX(TempLocX, DummyCasterDistanceToCross, DummyCasterFloatingDirection[DummyCastersIndex])
set TempLoc2Y = PolarProjectionY(TempLocY, DummyCasterDistanceToCross, DummyCasterFloatingDirection[DummyCastersIndex])
set CasterDummyFacing = AngleBetweenPointsXY(TempLoc2X, TempLoc2Y, TempLocX, TempLocY)
set DummyCasters[DummyCastersIndex] = CreateUnit(GetOwningPlayer(Caster[Index]), DummyCasterID, TempLoc2X, TempLoc2Y, CasterDummyFacing)
call SetUnitFlyHeight(DummyCasters[DummyCastersIndex], BaseHeight, 0)
call SetUnitFlyHeight(DummyCasters[DummyCastersIndex], HeightToGo, (BaseHeight - HeightToGo) / DownRisingTime)
set i = i + 1
exitwhen i > GetSheepNumb(GetUnitAbilityLevel(Caster[Index], SpellID))
endloop
endif
return false
endfunction
private function Loop takes nothing returns boolean
local integer i = 1
local integer j = 1
local location TempLoc
local location TempLoc2
local real TempLocX
local real TempLocY
local real TempLoc2X
local real TempLoc2Y
local unit UnitTarget
if (Index > 0) then
loop
if (IsActive[i]) then
set TimeLeft[i] = TimeLeft[i] - 0.03
// Set the position of cross
if (FloatingDirection[i] < 360) then
set FloatingDirection[i] = FloatingDirection[i] + CrossRotatingSpeed
else
set FloatingDirection[i] = FloatingDirection[i] - 360
endif
set TempLocX = PolarProjectionX(GetUnitX(Caster[i]), 200, FloatingDirection[i])
set TempLocY = PolarProjectionY(GetUnitY(Caster[i]), 200, FloatingDirection[i])
call SetUnitX(Cross[i], TempLocX)
call SetUnitY(Cross[i], TempLocY)
set j = 1
loop
if (DummyCastersSpellNumb[j] == i) then
if (DummyCasterFloatingDirection[j] > 0) then
set DummyCasterFloatingDirection[j] = DummyCasterFloatingDirection[j] - DummyCasterRotatingSpeed
else
set DummyCasterFloatingDirection[j] = DummyCasterFloatingDirection[j] + 360
endif
set TempLoc2X = PolarProjectionX(TempLocX, DummyCasterDistanceToCross, DummyCasterFloatingDirection[j])
set TempLoc2Y = PolarProjectionY(TempLocY, DummyCasterDistanceToCross, DummyCasterFloatingDirection[j])
call SetUnitX(DummyCasters[j], TempLoc2X)
call SetUnitY(DummyCasters[j], TempLoc2Y)
call SetUnitFacing(DummyCasters[j], AngleBetweenPointsXY(TempLoc2X, TempLoc2Y, TempLocX, TempLocY))
endif
set j = j + 1
exitwhen j > DummyCastersIndex
endloop
if (TimeLeft[i] < (Length - DownRisingTime)) and (TimeLeft[i] > UpRisingTime) then // if cross is rised down
set j = 1
loop
if (DummyCastersSpellNumb[j] == i) then
set DummyCasterLeftCooldown[j] = DummyCasterLeftCooldown[j] - 0.03
if (DummyCasterLeftCooldown[j] <= 0) then
set bj_lastCreatedUnit = Caster[i]
set UnitTarget = GetClosestUnitInRange(GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), DummyCasterNukeRange, Filter(function IsUnitViableTarget))
if (UnitTarget != null) then
set DummyCasterLeftCooldown[j] = DummyCasterNukeCooldown
if (IsUnitEnemy(UnitTarget, GetOwningPlayer(Caster[i]))) then
if (GetRandomInt(0, 1) == 1) then
set DummyCasterLightningAttack[j] = AddLightningEx(LightningDamage1, true, GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), GetUnitFlyHeight(DummyCasters[j]), GetUnitX(UnitTarget), GetUnitY(UnitTarget), GetUnitFlyHeight(UnitTarget))
else
set DummyCasterLightningAttack[j] = AddLightningEx(LightningDamage2, true, GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), GetUnitFlyHeight(DummyCasters[j]), GetUnitX(UnitTarget), GetUnitY(UnitTarget), GetUnitFlyHeight(UnitTarget))
endif
set DummyCasterLightningIsDestroyed[j] = false
set DummyCasterLightningRemainingDur[j] = DummyCasterAttackLength
set DummyCasterDoesLightningAttack[j] = true
set DummyCasterTargetedUnit[j] = UnitTarget
set DummyCasterIsHealing[j] = false
call PlaySoundAtPoint(DamagingSoundPath, GetUnitX(UnitTarget), GetUnitY(UnitTarget))
else
if not IsUnitOwnedByPlayer(UnitTarget, Player(15)) then
if (GetRandomInt(0, 1) == 1) then
set DummyCasterLightningAttack[j] = AddLightningEx(LightningHeal1, true, GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), GetUnitFlyHeight(DummyCasters[j]), GetUnitX(UnitTarget), GetUnitY(UnitTarget), GetUnitFlyHeight(UnitTarget))
else
set DummyCasterLightningAttack[j] = AddLightningEx(LightningHeal2, true, GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), GetUnitFlyHeight(DummyCasters[j]), GetUnitX(UnitTarget), GetUnitY(UnitTarget), GetUnitFlyHeight(UnitTarget))
endif
set DummyCasterLightningIsDestroyed[j] = false
set DummyCasterLightningRemainingDur[j] = DummyCasterAttackLength
set DummyCasterDoesLightningAttack[j] = true
set DummyCasterTargetedUnit[j] = UnitTarget
set DummyCasterIsHealing[j] = true
call PlaySoundAtPoint(HealingSoundPath, GetUnitX(UnitTarget), GetUnitY(UnitTarget))
endif
endif
set UnitTarget = null
endif
endif
if (DummyCasterDoesLightningAttack[j]) then
if (IsUnitAlive(DummyCasterTargetedUnit[j])) then
set DummyCasterLightningRemainingDur[j] = DummyCasterLightningRemainingDur[j] - 0.03
if (DummyCasterLightningRemainingDur[j] <= 0) then
set DummyCasterDoesLightningAttack[j] = false
if not DummyCasterLightningIsDestroyed[j] then
set DummyCasterLightningIsDestroyed[j] = true
call DestroyLightning(DummyCasterLightningAttack[j])
endif
set DummyCasterTargetedUnit[j] = null
else
if not DummyCasterLightningIsDestroyed[j] then
set TempLoc = GetUnitLoc(DummyCasters[j])
set TempLoc2 = GetUnitLoc(DummyCasterTargetedUnit[j])
call MoveLightningEx(DummyCasterLightningAttack[j], false, GetUnitX(DummyCasters[j]), GetUnitY(DummyCasters[j]), GetUnitFlyHeight(DummyCasters[j]) + GetLocationZ(TempLoc), GetUnitX(DummyCasterTargetedUnit[j]), GetUnitY(DummyCasterTargetedUnit[j]), GetUnitFlyHeight(DummyCasterTargetedUnit[j]) + GetLocationZ(TempLoc2))
call RemoveLocation(TempLoc)
call RemoveLocation(TempLoc2)
endif
endif
if (DummyCasterIsHealing[j]) then
if (GetWidgetLife(DummyCasterTargetedUnit[j]) / GetUnitState(DummyCasterTargetedUnit[j], UNIT_STATE_MAX_LIFE) * 100) != 100 then
call SetWidgetLife(DummyCasterTargetedUnit[j], GetWidgetLife(DummyCasterTargetedUnit[j]) + ((GetHealing(GetUnitAbilityLevel(Caster[i], SpellID)) / DummyCasterAttackLength) * 0.03))
endif
else
call UnitDamageTarget(Caster[i], DummyCasterTargetedUnit[j], (GetDamage(GetUnitAbilityLevel(Caster[i], SpellID)) / DummyCasterAttackLength) * 0.03, true, false, AttackType, DamageType, WEAPON_TYPE_WHOKNOWS)
endif
else
if not DummyCasterLightningIsDestroyed[j] then
set DummyCasterLightningIsDestroyed[j] = true
call DestroyLightning(DummyCasterLightningAttack[j])
endif
set DummyCasterLightningRemainingDur[j] = 0
set DummyCasterTargetedUnit[j] = null
set DummyCasterDoesLightningAttack[j] = false
endif
endif
endif
set j = j + 1
exitwhen j > DummyCastersIndex
endloop
endif
if (TimeLeft[i] < UpRisingTime and TimeLeft[i] > 0) then // if cross is rising up
if not FloatedUp[i] then
set FloatedUp[i] = true
call SetUnitFlyHeight(Cross[i], BaseHeight, (BaseHeight - HeightToGo) / UpRisingTime)
set j = 1
loop
if (DummyCastersSpellNumb[j] == i) then
if not DummyCasterLightningIsDestroyed[j] then
set DummyCasterLightningIsDestroyed[j] = true
call DestroyLightning(DummyCasterLightningAttack[j])
endif
set DummyCasterTargetedUnit[j] = null
call SetUnitFlyHeight(DummyCasters[j], BaseHeight, (BaseHeight - HeightToGo) / UpRisingTime)
endif
set j = j + 1
exitwhen j > DummyCastersIndex
endloop
endif
endif
if (TimeLeft[i] <= 0) then //Finish
set IsActive[i] = IsActive[Index]
set IsActive[Index] = false
call RemoveUnit(Cross[i])
set Cross[i] = Cross[Index]
set Cross[Index] = null
set Caster[i] = Caster[Index]
set Caster[Index] = null
set TimeLeft[i] = TimeLeft[Index]
set TimeLeft[Index] = 0
set FloatingDirection[i] = FloatingDirection[Index]
set FloatingDirection[Index] = 0
set FloatedUp[i] = FloatedUp[Index]
set FloatedUp[Index] = false
set j = 1
loop
if (DummyCastersSpellNumb[j] == Index) then
set DummyCastersSpellNumb[j] = i
set DummyCastersSpellNumb[DummyCastersIndex] = 0
if not DummyCasterLightningIsDestroyed[j] then
set DummyCasterLightningIsDestroyed[j] = true
call DestroyLightning(DummyCasterLightningAttack[j])
endif
call RemoveUnit(DummyCasters[j])
set DummyCasters[j] = DummyCasters[DummyCastersIndex]
set DummyCasters[DummyCastersIndex] = null
set DummyCasterTargetedUnit[j] = DummyCasterTargetedUnit[DummyCastersIndex]
set DummyCasterTargetedUnit[DummyCastersIndex] = null
set DummyCasterFloatingDirection[j] = DummyCasterFloatingDirection[DummyCastersIndex]
set DummyCasterFloatingDirection[DummyCastersIndex] = 0
set DummyCasterLeftCooldown[j] = DummyCasterLeftCooldown[DummyCastersIndex]
set DummyCasterLeftCooldown[DummyCastersIndex] = 0
set DummyCasterLightningAttack[j] = DummyCasterLightningAttack[DummyCastersIndex]
set DummyCasterLightningAttack[DummyCastersIndex] = null
set DummyCasterLightningRemainingDur[j] = DummyCasterLightningRemainingDur[DummyCastersIndex]
set DummyCasterLightningRemainingDur[DummyCastersIndex] = 0
set DummyCasterDoesLightningAttack[j] = DummyCasterDoesLightningAttack[DummyCastersIndex]
set DummyCasterDoesLightningAttack[DummyCastersIndex] = false
set DummyCasterTargetedUnit[j] = DummyCasterTargetedUnit[DummyCastersIndex]
set DummyCasterTargetedUnit[DummyCastersIndex] = null
set DummyCasterIsHealing[j] = DummyCasterIsHealing[DummyCastersIndex]
set DummyCasterIsHealing[DummyCastersIndex] = false
set DummyCasterLightningIsDestroyed[j] = DummyCasterLightningIsDestroyed[DummyCastersIndex]
set DummyCasterLightningIsDestroyed[DummyCastersIndex] = true
set DummyCastersIndex = DummyCastersIndex - 1
set j = j - 1
endif
set j = j + 1
exitwhen j > DummyCastersIndex
endloop
set Index = Index - 1
set i = i - 1
endif
endif
set i = i + 1
exitwhen i > Index
endloop
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Actions))
call TriggerRegisterTimerEvent( t2, 0.03, true)
call TriggerAddCondition( t2, Condition(function Loop))
set t = null
set t2 = null
endfunction
endlibrary // PaladinHolyCross