• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Disciple of Life Spellpack 1.2.1

These spells use:
- KelThuzad for the icons of Prolonged Life, Smiting Zeal and Reverse Damage
- Blizzard Entertainment for the icon of Seed of Life
- Anitarf for SpellEvent, Stack, DamageEvent and DamageModifiers
- Rising_Dusk for GroupUtils and IntuitiveBuffSystem
- grim001 for AutoIndex and AbilityPreload
- Captain_Griffen for LightLeaklessDamageDetect
- TriggerHappy187 for TimedHandles
- Vexorian for JassHelper, Table and TimerUtils
- Pipedream for Grimoire
- Pitzermike and MindWorX for JassNewGenPack


25/12/2009 - Version 1.0.0
- initial release

28/12/2009 - Version 1.0.1
- multiple bugfixes to all abilities
- Prolonged life now restores to exactly the amount specified in the settings, not to the amount specified plus the units current life
- multiple Reverse Damage instances on the same unit stack (correctly) now, and dont overwrite each other.
- multiple instances of Prolonged Life on the same unit overwrite each other now. The instance with the highest level now stays on the unit.
- all spells based on buffs correctly terminate now if the unit was killed by KillUnit() (or some other way of killing a unit without damaging it).

25/01/2011 - Version 1.1.0
- made TimedHandles an optional requirement
- moved array setup functions into one function
- removed periodic checks for buffs, ProlongedLife and ReverseDamage will now leak a spell instance (which also is an instance of DamageModifier) when the user removes or kills a unit with an active instance of the spell.
- SeedOfLife now has more calibration options eg. a chance to trigger or healing a fraction of the damage dealt to the target of the spell.
- more/better documentation
- few more minor changes

28/01/2011 - Version 1.2.0
- Seed of Life, Prolonged Life and Reverse Damage are now the same spell, configured differently.
- Smiting Zeal now supports enforcing the mana cost. It will not trigger if the caster cant pay the additional cost, if you configured it accordingly.
- Reverse Damage now has a minimum damage, damage dealt to the target of this spell must be greater than or equal to 20.

08/02/2011 - Version 1.2.1
- fixed a bug with how chances are handled, the spells should actually work now.





And here are the spells:

Seed of Life

Infuses the target with the seed of life. Units around it get healed whenever the target takes damage.
Lasts 7 seconds.

Level 1 - Units in a 200 radius get healed by 15 HP.
Level 2 - Units in a 275 radius get healed by 20 HP.
Level 3 - Units in a 350 radius get healed by 25 HP.

Mana Cost: 60/75/90
Cooldown: 10/10/10

[jass=Spell Code]library SeedOfLife initializer Init uses GroupUtils, DamageModifiers, SpellEvent, AutoIndex, IntuitiveBuffSystem, optional TimedHandles

private keyword Data // DO NOT TOUCH!

globals
private constant integer AID = 'A001' // ability triggering this. Any unit targeting ability is fine. Used Bloodlust
private constant integer BUFF_PLACER_AID = 'A004' // Ability placing BID on the unit this ability is added to. Based off of Slow Aura (Tornado).
private constant integer BID = 'B000' // buff placed by BUFF_PLACER_AID on the target unit
private constant string FX = "Abilities\\Spells\\Human\\Heal\\HealTarget.mdl" // displayed on the target unit when the effect of this ability is triggered.
private constant string FX_ATTPT = "origin"
private constant real FX_DURATION = 1.833 // 0 or less only plays the death animation // ignored if TimedHandles is not present in the map
private constant string TARGET_FX = "" // displayed on the target of this spell
private constant string TARGET_FX_ATTPT = "" // where to display the effect on the target of this spell
private constant integer PRIORITY = 0 // when to trigger the effects of an instance of this spell when a unit receives damage // refer to DamageModifiers documentation
private real array DURATION // how long does the buff last?
private real array AOE // Heals all units around the damaged target in this area
private real array CHANCE // Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private integer array MAX_HEALINGS // heal at most this many times // zero or less for no limit
endglobals

// how long does the buff last?
private function Duration takes integer level returns real
return DURATION[level]
endfunction

// Heals all units around the damaged target in this area
private function Aoe takes integer level returns real
return AOE[level]
endfunction

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private function Chance takes integer level returns real
return CHANCE[level]
endfunction

// heal at most this many times // zero or less for no limit
private function Max_Healings takes integer level returns integer
return MAX_HEALINGS[level]
endfunction

private function SetUpSpellData takes nothing returns nothing
// how long does the buff last?
set DURATION[1]=7
set DURATION[2]=7
set DURATION[3]=7

// Heals all units around the damaged target in this area
set AOE[1]=200
set AOE[2]=275
set AOE[3]=350

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
set CHANCE[1]=1
set CHANCE[2]=1
set CHANCE[3]=1

// heal at most this many times // zero or less for no limit
set MAX_HEALINGS[1]=0
set MAX_HEALINGS[2]=0
set MAX_HEALINGS[3]=0
endfunction

// if you want to get the targets current HP, use GetUnitLife(whichUnit)

// damage dealt to a unit with this buff active needs to be greater than what this function returns to be blocked
private function Minimum_Damage takes integer level, unit target returns real
return 0.
endfunction

// how much damage to block
private function Damage_Blocked takes integer level, unit target, real damage returns real
return 0.
endfunction

// how much health to restore after blocking
private function Health_Restored takes integer level, unit target, real damage returns real
return 10.+level*10.
endfunction

// how much health to heal units in the area
private function Aoe_Heal takes integer level, unit target, real damage returns real
return 10.+level*5.
endfunction

// only units matching these criteria will get healed
private function ValidTarget takes unit u, unit caster returns boolean
return IsUnitAlly(u, GetOwningPlayer(caster))/*
*/ and IsUnitType(u, UNIT_TYPE_MECHANICAL)==false/*
*/ and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false/*
*/ and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false/*
*/
endfunction

//

globals
private integer BuffType
endglobals

private struct Data extends DamageModifier
unit caster
unit target
effect targetFx
integer level
integer healings=0

static thistype Tmps
static real CurrentDamage

static thistype array Instance

private method onDestroy takes nothing returns nothing
set Instance[GetUnitId(.target)]=0
set .caster=null
set .target=null
if TARGET_FX!="" then
call DestroyEffect(.targetFx)
set .targetFx=null
endif
endmethod

private static method AoeHealEnum takes nothing returns boolean
local unit u=GetFilterUnit()
if u!=.Tmps.target and ValidTarget(u, .Tmps.caster) then
call SetUnitLife(u, GetUnitLife(u)+Aoe_Heal(.Tmps.level, .Tmps.target, .CurrentDamage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, u, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
endif
set u=null
return false
endmethod

private method onDamageTaken takes unit origin, real damage returns real
local real blocked=0
if GetRandomReal(0,1)<=Chance(.level) and damage+0.406>=Minimum_Damage(.level, .target) then
if ValidTarget(.target, .caster) then
call SetUnitLife(.target, GetUnitLife(.target)+Health_Restored(.level, .target, damage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, .target, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
set blocked=Damage_Blocked(.level, .target, damage)
endif
if Aoe(.level)>0. then
set .Tmps=this
set .CurrentDamage=damage
call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(.target), GetUnitY(.target), Aoe(.level), Condition(function thistype.AoeHealEnum))
endif
set .healings=.healings+1
if Max_Healings(.level)>0 and .healings>=Max_Healings(.level) then
call UnitRemoveBuff(.target, BuffType)
endif
return -blocked
endif
return 0.
endmethod

static method create takes unit caster, unit target returns thistype
local thistype s=Instance[GetUnitId(target)]
if s==0 then
set s=.allocate(target, PRIORITY)
set s.caster=caster
set s.target=target
if TARGET_FX!="" then
set s.targetFx=AddSpecialEffectTarget(TARGET_FX, target, TARGET_FX_ATTPT)
endif
set s.level=GetUnitAbilityLevel(caster, AID)
set Instance[GetUnitId(target)]=s
else
if s.level<GetUnitAbilityLevel(caster, AID) then
set s.caster=caster
set s.healings=0
set s.level=GetUnitAbilityLevel(caster, AID)
endif
endif
set UnitAddBuff(caster, target, BuffType, Duration(s.level), s.level).data=s
return s
endmethod

static method BuffRemoved takes nothing returns nothing
call thistype(GetEventBuff().data).destroy()
endmethod
endstruct

private function CastResponse takes nothing returns nothing
call Data.create(SpellEvent.CastingUnit, SpellEvent.TargetUnit)
endfunction

private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(AID, CastResponse)

set BuffType=DefineBuffType(BUFF_PLACER_AID, BID, 0, false, true, 0,0,Data.BuffRemoved)

call SetUpSpellData()
endfunction

endlibrary[/code]



Prolonged Life

Prolongs the target units life once over the next 8 seconds.

Level 1 - Restores 10% of the targets maximum health.
Level 2 - Restores 20% on the targets maximum health.
Level 3 - Restores 30% on the targets maximum health.

Mana Cost: 100/120/140
Cooldown: 5/5/5

[jass=Spell Code]library ProlongedLife initializer Init uses GroupUtils, DamageModifiers, SpellEvent, AutoIndex, IntuitiveBuffSystem, optional TimedHandles

private keyword Data // DO NOT TOUCH!

globals
private constant integer AID = 'A000' // ability triggering this. Any unit targeting ability is fine. Used Channel
private constant integer BUFF_PLACER_AID = 'A005' // Ability placing BID on the unit this ability is added to. Based off of Slow Aura (Tornado).
private constant integer BID = 'B001' // buff placed by BUFF_PLACER_AID on the target unit
private constant string FX = "Abilities\\Spells\\Items\\AIre\\AIreTarget.mdl" // displayed on the target unit when the effect of this ability is triggered.
private constant string FX_ATTPT = "origin"
private constant real FX_DURATION = 0. // 0 or less only plays the death animation // ignored if TimedHandles is not present in the map
private constant string TARGET_FX = "Abilities\\Spells\\Items\\HealingSalve\\HealingSalveTarget.mdl" // displayed on the target of this spell
private constant string TARGET_FX_ATTPT = "head" // where to display the effect on the target of this spell
private constant integer PRIORITY = 0 // when to trigger the effects of an instance of this spell when a unit receives damage // refer to DamageModifiers documentation
private real array DURATION // how long does the buff last?
private real array AOE // Heals all units around the damaged target in this area
private real array CHANCE // Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private integer array MAX_HEALINGS // heal at most this many times // zero or less for no limit
endglobals

// how long does the buff last?
private function Duration takes integer level returns real
return DURATION[level]
endfunction

// Heals all units around the damaged target in this area
private function Aoe takes integer level returns real
return AOE[level]
endfunction

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private function Chance takes integer level returns real
return CHANCE[level]
endfunction

// heal at most this many times // zero or less for no limit
private function Max_Healings takes integer level returns integer
return MAX_HEALINGS[level]
endfunction

private function SetUpSpellData takes nothing returns nothing
// how long does the buff last?
set DURATION[1]=8
set DURATION[2]=8
set DURATION[3]=8

// Heals all units around the damaged target in this area
set AOE[1]=0
set AOE[2]=0
set AOE[3]=0

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
set CHANCE[1]=1
set CHANCE[2]=1
set CHANCE[3]=1

// heal at most this many times // zero or less for no limit
set MAX_HEALINGS[1]=1
set MAX_HEALINGS[2]=1
set MAX_HEALINGS[3]=1
endfunction

// if you want to get the targets current HP, use GetUnitLife(whichUnit)

// damage dealt to a unit with this buff active needs to be greater than what this function returns to be blocked
private function Minimum_Damage takes integer level, unit target returns real
return GetUnitLife(target)
endfunction

// how much damage to block
private function Damage_Blocked takes integer level, unit target, real damage returns real
return damage
endfunction

// how much health to restore after blocking
private function Health_Restored takes integer level, unit target, real damage returns real
return GetUnitLife(target)*0.1*level
endfunction

// how much health to heal units in the area
private function Aoe_Heal takes integer level, unit target, real damage returns real
return 0.
endfunction

// only units matching these criteria will get healed
private function ValidTarget takes unit u, unit caster returns boolean
return IsUnitAlly(u, GetOwningPlayer(caster))/*
*/ and IsUnitType(u, UNIT_TYPE_MECHANICAL)==false/*
*/ and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false/*
*/ and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false/*
*/
endfunction

//

globals
private integer BuffType
endglobals

private struct Data extends DamageModifier
unit caster
unit target
effect targetFx
integer level
integer healings=0

static thistype Tmps
static real CurrentDamage

static thistype array Instance

private method onDestroy takes nothing returns nothing
set Instance[GetUnitId(.target)]=0
set .caster=null
set .target=null
if TARGET_FX!="" then
call DestroyEffect(.targetFx)
set .targetFx=null
endif
endmethod

private static method AoeHealEnum takes nothing returns boolean
local unit u=GetFilterUnit()
if u!=.Tmps.target and ValidTarget(u, .Tmps.caster) then
call SetUnitLife(u, GetUnitLife(u)+Aoe_Heal(.Tmps.level, .Tmps.target, .CurrentDamage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, u, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
endif
set u=null
return false
endmethod

private method onDamageTaken takes unit origin, real damage returns real
local real blocked=0
if GetRandomReal(0,1)<=Chance(.level) and damage+0.406>=Minimum_Damage(.level, .target) then
if ValidTarget(.target, .caster) then
call SetUnitLife(.target, GetUnitLife(.target)+Health_Restored(.level, .target, damage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, .target, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
set blocked=Damage_Blocked(.level, .target, damage)
endif
if Aoe(.level)>0. then
set .Tmps=this
set .CurrentDamage=damage
call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(.target), GetUnitY(.target), Aoe(.level), Condition(function thistype.AoeHealEnum))
endif
set .healings=.healings+1
if Max_Healings(.level)>0 and .healings>=Max_Healings(.level) then
call UnitRemoveBuff(.target, BuffType)
endif
return -blocked
endif
return 0.
endmethod

static method create takes unit caster, unit target returns thistype
local thistype s=Instance[GetUnitId(target)]
if s==0 then
set s=.allocate(target, PRIORITY)
set s.caster=caster
set s.target=target
if TARGET_FX!="" then
set s.targetFx=AddSpecialEffectTarget(TARGET_FX, target, TARGET_FX_ATTPT)
endif
set s.level=GetUnitAbilityLevel(caster, AID)
set Instance[GetUnitId(target)]=s
else
if s.level<GetUnitAbilityLevel(caster, AID) then
set s.caster=caster
set s.healings=0
set s.level=GetUnitAbilityLevel(caster, AID)
endif
endif
set UnitAddBuff(caster, target, BuffType, Duration(s.level), s.level).data=s
return s
endmethod

static method BuffRemoved takes nothing returns nothing
call thistype(GetEventBuff().data).destroy()
endmethod
endstruct

private function CastResponse takes nothing returns nothing
call Data.create(SpellEvent.CastingUnit, SpellEvent.TargetUnit)
endfunction

private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(AID, CastResponse)

set BuffType=DefineBuffType(BUFF_PLACER_AID, BID, 0, false, true, 0,0,Data.BuffRemoved)

call SetUpSpellData()
endfunction

endlibrary[/code]



Smiting Zeal

Every time the hero casts a spell, all unit surrounding the target point get damaged. Drains 20 additional Mana Points with every cast.

Level 1 - Damages for 2 times the hero's intelligence.
Level 2 - Damages for 3 times the hero's intelligence.
Level 3 - Damages for 4 times the hero's intelligence.

[jass=Spell Code]library SmitingZeal initializer Init uses SpellEvent, GroupUtils

globals
private constant integer AID = 'A002' // any passive ability should do fine, preferably one that doesnt place a buff.
private constant string DAMAGE_FX = "Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl" // effect displayed when a unit gets damaged by this ability
private constant string DAMAGE_FX_ATTPT = "overhead" // where to display the effect
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC // what type of damage is dealt to enemy units surrounding the caster (magic, physical, pure, ...)
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC // what type of damage is dealt to enemy units surrounding the caster (magic, physical, pure, ...)
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS // sound played when a unit is damaged by this ability, WHOKNOWS or null for no sound.
private real array AOE // enemy units within this radius get damaged
private real array MANA_COST // this ability drains this much additional mana from the caster, values >0 but <1 are values relative to the maximum mana of the caster
private constant boolean ENFORCE_MANA_COST = false // if true, the effects of this ability will only be triggered if the hero has enough mana,
// if false, it will be triggered whether or not the caster has enough mana, and if he doesnt,
// it will subtract the remaining mana points
endglobals

private function Aoe takes integer level returns real
return AOE[level]
endfunction

private function Mana_Cost takes integer level returns real
return MANA_COST[level]
endfunction

private function Damage takes unit caster, integer level returns real
return GetHeroInt(caster, true)*(1.+level)
endfunction

private function SetUpSpellData takes nothing returns nothing
set AOE[1]=300.
set AOE[2]=375.
set AOE[3]=450.

set MANA_COST[1]=20.
set MANA_COST[2]=20.
set MANA_COST[3]=20.
endfunction

private function ValidateTarget takes unit u, unit caster returns boolean
return IsUnitEnemy(u, GetOwningPlayer(caster))/*
*/ and IsUnitType(u, UNIT_TYPE_DEAD)==false/*
*/ and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false/*
*/ and IsUnitType(u, UNIT_TYPE_MECHANICAL)==false/*
*/ and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false/*
*/ and IsUnitVisible(u, GetOwningPlayer(caster))/*
*/
endfunction

//

globals
private boolexpr DamageFilter
private real tmpdam
endglobals

private function DamageFilterFunc takes nothing returns boolean
local unit u=GetFilterUnit()
if ValidateTarget(u, SpellEvent.CastingUnit) then
call UnitDamageTarget(SpellEvent.CastingUnit, u, tmpdam, true, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_FX, u, DAMAGE_FX_ATTPT))
endif
set u=null
return false
endfunction

private function CastResponse takes nothing returns nothing
local integer level = GetUnitAbilityLevel(SpellEvent.CastingUnit, AID)
local real cost=0
if level>0 then
if Mana_Cost(level)>=1 then
set cost=Mana_Cost(level)
elseif Mana_Cost(level)>0 then
set cost=Mana_Cost(level)*GetUnitState(SpellEvent.CastingUnit, UNIT_STATE_MANA)
endif
if not ENFORCE_MANA_COST or GetUnitState(SpellEvent.CastingUnit, UNIT_STATE_MANA)>=cost then
call SetUnitState(SpellEvent.CastingUnit, UNIT_STATE_MANA, RMaxBJ(GetUnitState(SpellEvent.CastingUnit, UNIT_STATE_MANA)-Mana_Cost(level), 0))
set tmpdam=Damage(SpellEvent.CastingUnit, level)
call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(SpellEvent.CastingUnit), GetUnitY(SpellEvent.CastingUnit), Aoe(level), DamageFilter)
endif
endif
endfunction

private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(0, CastResponse)

set DamageFilter=Condition(function DamageFilterFunc)

call SetUpSpellData()
endfunction

endlibrary[/code]



Reverse Damage

Surrounds the target unit with a shield which reverses the next damage greater than 20 within 5 seconds the unit would receive and instead heals the unit for the same amount.
Maximum reversed damage is 100.

Mana Cost: 25
Cooldown: 2

[jass=Spell Code]library ReverseDamage initializer Init uses GroupUtils, DamageModifiers, SpellEvent, AutoIndex, IntuitiveBuffSystem, optional TimedHandles

private keyword Data // DO NOT TOUCH!

globals
private constant integer AID = 'A003' // ability triggering this. Any unit targeting ability is fine. Used Bloodlust
private constant integer BUFF_PLACER_AID = 'A006' // Ability placing BID on the unit this ability is added to. Based off of Slow Aura (Tornado).
private constant integer BID = 'B002' // buff placed by BUFF_PLACER_AID on the target unit
private constant string FX = "Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl" // displayed on the target unit when the effect of this ability is triggered.
private constant string FX_ATTPT = "head"
private constant real FX_DURATION = 0. // 0 or less only plays the death animation // ignored if TimedHandles is not present in the map
private constant string TARGET_FX = "Abilities\\Spells\\Items\\HealingSalve\\HealingSalveTarget.mdl" // displayed on the target of this spell
private constant string TARGET_FX_ATTPT = "head" // where to display the effect on the target of this spell
private constant integer PRIORITY = 0 // when to trigger the effects of an instance of this spell when a unit receives damage // refer to DamageModifiers documentation
private real array DURATION // how long does the buff last?
private real array AOE // Heals all units around the damaged target in this area
private real array CHANCE // Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private integer array MAX_HEALINGS // heal at most this many times // zero or less for no limit
endglobals

// how long does the buff last?
private function Duration takes integer level returns real
return DURATION[level]
endfunction

// Heals all units around the damaged target in this area
private function Aoe takes integer level returns real
return AOE[level]
endfunction

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
private function Chance takes integer level returns real
return CHANCE[level]
endfunction

// heal at most this many times // zero or less for no limit
private function Max_Healings takes integer level returns integer
return MAX_HEALINGS[level]
endfunction

private function SetUpSpellData takes nothing returns nothing
// how long does the buff last?
set DURATION[1]=5
set DURATION[2]=5
set DURATION[3]=5

// Heals all units around the damaged target in this area
set AOE[1]=0
set AOE[2]=0
set AOE[3]=0

// Chance to trigger this ability // 1.0 = 100% // 0.0 = 0%
set CHANCE[1]=1
set CHANCE[2]=1
set CHANCE[3]=1

// heal at most this many times // zero or less for no limit
set MAX_HEALINGS[1]=1
set MAX_HEALINGS[2]=1
set MAX_HEALINGS[3]=1
endfunction

// if you want to get the targets current HP, use GetUnitLife(whichUnit)

// damage dealt to a unit with this buff active needs to be greater than what this function returns to be blocked
private function Minimum_Damage takes integer level, unit target returns real
return 20.
endfunction

// how much damage to block
private function Damage_Blocked takes integer level, unit target, real damage returns real
return RMinBJ(damage, 100.)
endfunction

// how much health to restore after blocking
private function Health_Restored takes integer level, unit target, real damage returns real
return RMinBJ(damage, 100.)
endfunction

// how much health to heal units in the area
private function Aoe_Heal takes integer level, unit target, real damage returns real
return 0.
endfunction

// only units matching these criteria will get healed
private function ValidTarget takes unit u, unit caster returns boolean
return IsUnitAlly(u, GetOwningPlayer(caster))/*
*/ and IsUnitType(u, UNIT_TYPE_MECHANICAL)==false/*
*/ and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false/*
*/ and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false/*
*/
endfunction

//

globals
private integer BuffType
endglobals

private struct Data extends DamageModifier
unit caster
unit target
effect targetFx
integer level
integer healings=0

static thistype Tmps
static real CurrentDamage

static thistype array Instance

private method onDestroy takes nothing returns nothing
set Instance[GetUnitId(.target)]=0
set .caster=null
set .target=null
if TARGET_FX!="" then
call DestroyEffect(.targetFx)
set .targetFx=null
endif
endmethod

private static method AoeHealEnum takes nothing returns boolean
local unit u=GetFilterUnit()
if u!=.Tmps.target and ValidTarget(u, .Tmps.caster) then
call SetUnitLife(u, GetUnitLife(u)+Aoe_Heal(.Tmps.level, .Tmps.target, .CurrentDamage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, u, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, u, FX_ATTPT))
endif
endif
set u=null
return false
endmethod

private method onDamageTaken takes unit origin, real damage returns real
local real blocked=0
if GetRandomReal(0,1)<=Chance(.level) and damage+0.406>=Minimum_Damage(.level, .target) then
if ValidTarget(.target, .caster) then
call SetUnitLife(.target, GetUnitLife(.target)+Health_Restored(.level, .target, damage))
static if LIBRARY_TimedHandles then
if FX_DURATION>0 then
call DestroyEffectTimed(AddSpecialEffectTarget(FX, .target, FX_ATTPT), FX_DURATION)
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
else
call DestroyEffect(AddSpecialEffectTarget(FX, .target, FX_ATTPT))
endif
set blocked=Damage_Blocked(.level, .target, damage)
endif
if Aoe(.level)>0. then
set .Tmps=this
set .CurrentDamage=damage
call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(.target), GetUnitY(.target), Aoe(.level), Condition(function thistype.AoeHealEnum))
endif
set .healings=.healings+1
if Max_Healings(.level)>0 and .healings>=Max_Healings(.level) then
call UnitRemoveBuff(.target, BuffType)
endif
return -blocked
endif
return 0.
endmethod

static method create takes unit caster, unit target returns thistype
local thistype s=Instance[GetUnitId(target)]
if s==0 then
set s=.allocate(target, PRIORITY)
set s.caster=caster
set s.target=target
if TARGET_FX!="" then
set s.targetFx=AddSpecialEffectTarget(TARGET_FX, target, TARGET_FX_ATTPT)
endif
set s.level=GetUnitAbilityLevel(caster, AID)
set Instance[GetUnitId(target)]=s
else
if s.level<GetUnitAbilityLevel(caster, AID) then
set s.caster=caster
set s.healings=0
set s.level=GetUnitAbilityLevel(caster, AID)
endif
endif
set UnitAddBuff(caster, target, BuffType, Duration(s.level), s.level).data=s
return s
endmethod

static method BuffRemoved takes nothing returns nothing
call thistype(GetEventBuff().data).destroy()
endmethod
endstruct

private function CastResponse takes nothing returns nothing
call Data.create(SpellEvent.CastingUnit, SpellEvent.TargetUnit)
endfunction

private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(AID, CastResponse)

set BuffType=DefineBuffType(BUFF_PLACER_AID, BID, 0, false, true, 0,0,Data.BuffRemoved)

call SetUpSpellData()
endfunction

endlibrary[/code]

Keywords:
Disciple of Life, Healing, Protection, Holy
Contents

Turtle Rock [Disciple of Light] (Map)

Reviews
22:39, 24th Dec 2009 TriggerHappy: Review for Spell First of all, thanks for using TimedHanldes =) In SmitingZeal you could be using static ifs for the attribute, but that is most likely overkill to get rid of a simple BJ. In...

Moderator

M

Moderator

22:39, 24th Dec 2009
TriggerHappy:

Review for Spell

First of all, thanks for using TimedHanldes =)
  • In SmitingZeal you could be using static ifs for the attribute, but
    that is most likely overkill to get rid of a simple BJ.
  • In SeedOfLife you forget to require TimedHandles.
Overall, the spells are bit simple for my taste but whatever.

Status

Feel free to message me here if you have any issues with
my review or if you have updated your resource and want it reviewed again.

Approved
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
Prolongs the target units life once over the next 8 seconds.
Prolonged Life's tooltip is unclear... It does not nescescarilly imply that it actually only fires when the unit would take a fatal blow and may lead people to thinking it heals them over 8 seconds.
Should be more like
Blocks a fatal blow once in the next 8 seconds by restoring health.

Also this spell pack uses a stupid number of dependiencies. You can not honestly expect people to import all that just for a couple of spells?
 
Last edited:
Level 22
Joined
Nov 14, 2008
Messages
3,256
This is good, really good. I don't get it why people complain about requirements, they're used by almost every single spell (although some might prefer AIDS or UnitIndexer over AutoIndex but whatever).

In 3 create methods you can always store in ability level but I guess one call more or less wouldn't make it worse.
 
Level 14
Joined
Nov 18, 2007
Messages
816
What the fuck.
I cant comprehend how this is relevenat AT ALL.
Youve made your point, ive made mine. Im not going to change my mind and your complaining also wont change a thing for anyone else. Either they use one of these spells, or they dont.

I wish you a happy reinventing the wheel. May you go insane over reimplementing TimedHandles or GroupUtils for the hundredth time.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Im going to need a bit more to go on than a simple "It doesnt work."

  • Your version of warcraft 3 (lower left or right corner on the main menu screen)
  • Did you try to test the map through the editor, or WC3 itself?
  • If you used the editor to test the map, did you modify anything before trying to test it?
  • Are you using any version of the editor that comes with a recent version of jasshelper?
  • If starting the map is not the problem, what exactly doesnt work (which spell)?
 
Level 6
Joined
May 11, 2013
Messages
205
Im going to need a bit more to go on than a simple "It doesnt work."

  • Your version of warcraft 3 (lower left or right corner on the main menu screen)
  • Did you try to test the map through the editor, or WC3 itself?
  • If you used the editor to test the map, did you modify anything before trying to test it?
  • Are you using any version of the editor that comes with a recent version of jasshelper?
  • If starting the map is not the problem, what exactly doesnt work (which spell)?

Well to be tested ability its always tested in game. And once i load the map i can't start it. First i download and tried to test in game before i open editor. I have newgen 5e version. I wanted to test the abilities in game to see what they can do, but i couldn't
 
Top