//**********************************************************************************************
//* By xD.Schurke (14.03.2009)
//*
//*
//* This is my entry for the current Spells&Systems Mini Contest 18 on hiveworkshop.com
//*
//* Version 1.2
//*
//* Changes:
//*
//* - Fixed some bugs with the second spell
//* - Reworked Effects of the second spell
//*
//*
//*
//*
//*
//*
//* xx xx DDDDD SSSS h k k EEEEE
//* xx xx DD DD SS h k k EE
//* xxxx DD DD SSS ccc hhh u u r rr ccc kk EEEE
//* xx xx DD DD _ SS cc h h u u rr cc k k EE
//* xx xx DDDDD |_| SSSS ccc h h uuuu r ccc k k EEEEE
//**********************************************************************************************
scope chargeSpell initializer chargeInt
globals
//Some variables are not private, because they are used in another scope again
//Rawcodes
constant integer dummyID = 'h000' //The rawcode of the dummyunit
constant integer chargeID = 'A002' //The rawcode of the charge spell
constant integer chargeBuffID = 'B001' //The rawcode of the charge spell debuff
constant integer flyID = 'Amrf' //The rawcode of the fly ability for spheres etc.
//Real Values
private constant real chargeDamage = 18.
private constant real chargeDamageInc = 5.
private constant real chargeDuration = 12.
private constant real chargeExtraChance = 25. //The percent chance
private constant real chargeDivisor = 45. //The divisor ==> higher = lower damage , lower = higher damage
private constant real Interval = 0.035 //The timer interval
private constant real damageInterval = 1/Interval //The 1 is 1 second
private constant real sphereDistance = 50.
private constant real angleSpeed = 10.
private constant real flySpeed = 5.
private constant real maxFlyHigh = 175.
private constant real sphereSize = 0.7
//Effect Strings
private constant string sfx = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
private constant string attach = "origin"
//Attack/Damage/Weapon Types => change for armor ignore etc.
constant attacktype atta = ATTACK_TYPE_NORMAL
constant damagetype dmg = DAMAGE_TYPE_NORMAL
constant weapontype weap = WEAPON_TYPE_WHOKNOWS
//Timer stacking issues
private timer Tim = CreateTimer()
private integer array Data
private integer Total = 0
endglobals
//Constant Functionts => Formuals for calculate damage
private constant function chargeDmg takes integer lvl returns real
return (chargeDamage+((lvl-1)*chargeDamageInc))/damageInterval
endfunction
private constant function chargeExtraDmg takes integer lvl, real time returns real
return (time*(chargeDamage+((lvl-1)*chargeDamageInc)))*(chargeDivisor/100)
endfunction
//The followning Struct is created for each 'Charge' effected unit
private struct chargeStruct
unit caster
unit target
real time = 0.
static method chargeDamageInterval takes nothing returns nothing
local chargeStruct dat
local integer i = 0
local texttag te
local real tmpReal = 0.
local real x = 0.
local real y = 0.
local real ang = 0.
local real fly = 0.
loop
exitwhen i >= Total
set dat = Data[i]
//the following if condition checks if the time is over or the debuff 'Charge' was removed from the unit and destroys the struct
if dat.time >= chargeDuration or GetUnitAbilityLevel(dat.target,chargeBuffID) <= 0 then
//the next part creates a chance to deal extra damage at the end of the spell or if the spell is removed from the target => with TextTag for showing the damage
if GetRandomReal(0,100) <= chargeExtraChance and GetUnitState(dat.target,UNIT_STATE_LIFE) > 0 then
set tmpReal = chargeExtraDmg(GetUnitAbilityLevel(dat.caster,chargeID),dat.time)
set te = CreateTextTag()
call SetTextTagText(te, I2S(R2I(tmpReal))+"!", 0.022)
call SetTextTagPos(te, GetUnitX(dat.target), GetUnitY(dat.target), 0.00)
call SetTextTagColor(te, 255, 255, 125, 155)
call SetTextTagVelocity(te, 0, 0.04)
call SetTextTagVisibility(te, true)
call SetTextTagFadepoint(te, 2)
call SetTextTagLifespan(te, 5)
call SetTextTagPermanent(te, false)
call UnitDamageTarget(dat.caster,dat.target,tmpReal,false,false,atta,dmg,weap)
endif
set Total = Total - 1
set Data[i] = Data[Total]
set i = i - 1
set dat.caster = null
set dat.target = null
call chargeStruct.destroy(dat)
else
//if the time isn't over yet the unit keeps being damaged
set dat.time = dat.time + Interval
call UnitDamageTarget(dat.caster,dat.target,chargeDmg(GetUnitAbilityLevel(dat.caster,chargeID)),false,false,atta,dmg,weap)
endif
set i = i + 1
endloop
if Total == 0 then
call PauseTimer(Tim)
endif
set te = null
endmethod
static method create takes nothing returns chargeStruct
local chargeStruct dat = chargeStruct.allocate()
if Total == 0 then
call TimerStart(Tim,Interval,true,function chargeStruct.chargeDamageInterval)
endif
set Data[Total] = dat
set Total = Total + 1
return dat
endmethod
endstruct
//standard initialization functions
private function chargeCondition takes nothing returns boolean
return GetSpellAbilityId() == chargeID
endfunction
private function chargeActions takes nothing returns nothing
local chargeStruct dat = chargeStruct.create()
local real x = 0
local real y = 0
set dat.caster = GetTriggerUnit()
set dat.target = GetSpellTargetUnit()
endfunction
private function chargeInt takes nothing returns nothing
local trigger int = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(int,Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function chargeCondition))
call TriggerAddAction(int,function chargeActions)
set int = null
endfunction
endscope
scope newElectroField initializer newInt
globals
//Rawcodes
private constant integer electroID = 'A001'
private constant integer overloadID = 'A000'
private constant integer timedLife = 'BTLF'
//Effect Strings
private constant string explusionSFX = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
private constant string fieldString = "Units\\NightElf\\Wisp\\WispExplode.mdl"
private constant string buffEffect = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl"
private constant string missileSFX = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
//Action-Strings
private constant string attach = "origin"
private constant string overhead = "overhead"
private constant string purge = "purge"
//Real Values
private constant real dmgRadius = 45.
private constant real speed = 5.
private constant real speed2 = 15.
private constant real electroDamage = 7.
private constant real electroDamageInc = 2.
private constant real electroMisDamage = 75.
private constant real electroMisDamageInc = 50.
private constant real Interval = 0.035
private constant real duration = 5.
private constant real scale = 0.7
private constant real scale2 = 1.5
private constant real scaleInc = 0.01
private constant real flyHigh = 100.
private constant real degrees = 360.
private constant real maxDistance = 800.
private constant real fadeDistance = 85.
private constant real startDistance = 50.
//Integer Values
private constant integer missilesMax = 10
private constant integer missilesInc = 5
private constant integer color = 255
private constant integer alphaDec = 15
//Time Stacking issues => 2struct 2Timers
private timer Tim = CreateTimer()
private timer Tim2 = CreateTimer()
private timer Tim3 = CreateTimer()
private integer array Data
private integer array Data2
private integer array Data3
private integer Total = 0
private integer Total2 = 0
private integer Total3 = 0
//GroupIssues
private group tmpG = CreateGroup()
private player tmpP
private boolexpr Cond
endglobals
//Constant functions formulas + filter function for aoe damage in struct electroMainStruct
private constant function electroDmg takes integer lvl returns real
return (electroDamage+((lvl-1)*electroDamageInc))
endfunction
private constant function electroMisDmg takes integer lvl returns real
return electroMisDamage+((lvl-1)*electroMisDamageInc)
endfunction
private constant function missiles takes integer lvl returns integer
return missilesMax+((lvl-1)*missilesInc)
endfunction
private function filter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),tmpP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and (GetUnitTypeId(GetFilterUnit())!= dummyID)
endfunction
//The Overload-Struct
private struct overload
unit caster
unit missile
unit target
real time = 0.
real misScale = 0.
static method loopMethod takes nothing returns nothing
local overload dat
local integer i = 0
local unit dummy
loop
exitwhen i >= Total2
set dat = Data2[i]
set dat.time = dat.time - Interval
if dat.time <= 0 or GetUnitState(dat.target,UNIT_STATE_LIFE) <= 0 then
//if 5 seconds are over, the missile damages the target + effect
call DestroyEffect(AddSpecialEffect(fieldString,GetUnitX(dat.target),GetUnitY(dat.target)))
call DestroyEffect(AddSpecialEffect(explusionSFX,GetUnitX(dat.target),GetUnitY(dat.target)))
call UnitDamageTarget(dat.missile,dat.target,electroMisDmg(GetUnitAbilityLevel(dat.caster,electroID)),false,false,atta,dmg,weap)
call KillUnit(dat.missile)
set dummy = CreateUnit(GetOwningPlayer(dat.caster),dummyID,GetUnitX(dat.target),GetUnitY(dat.target),0)
call UnitAddAbility(dummy,overloadID)
call IssueTargetOrder(dummy,purge,dat.target)
call UnitApplyTimedLife(dummy,timedLife,1)
set Total2 = Total2 - 1
set Data2[i] = Data2[Total2]
set i = i - 1
else
set dat.misScale = dat.misScale + scaleInc
call SetUnitPosition(dat.missile,GetUnitX(dat.target),GetUnitY(dat.target))
call SetUnitScale(dat.missile,dat.misScale,dat.misScale,dat.misScale)
endif
set i = i + 1
endloop
if Total2 == 0 then
call PauseTimer(Tim2)
endif
set dummy = null
endmethod
static method create takes nothing returns overload
local overload dat = overload.allocate()
if Total2 == 0 then
call TimerStart(Tim2,Interval,true,function overload.loopMethod)
endif
set Data2[Total2] = dat
set Total2 = Total2 + 1
return dat
endmethod
endstruct
//missile struct, moves the missle and attaches it to a target with the charge debuff
private struct missileStruct
unit caster
unit missile
real x = 0.
real y = 0.
real angle = 0.
real distance = 0.
real time = 0.
integer alpha = 0
effect sfx
boolean bool = false
group g = CreateGroup()
static method move takes nothing returns nothing
local missileStruct dat
local overload data
local unit u
local integer i = 0
local real x = 0.
local real y = 0.
loop
exitwhen i >= Total
set dat = Data[i]
set dat.distance = dat.distance - speed
if (dat.distance <= 0 and dat.bool == false) or dat.time <= 0 then
set Total = Total - 1
set Data[i] = Data[Total]
set i = i - 1
call RemoveUnit(dat.missile)
call DestroyEffect(dat.sfx)
call DestroyGroup(dat.g)
set dat.g = null
set dat.missile = null
set dat.sfx = null
call missileStruct.destroy(dat)
elseif dat.distance <= fadeDistance and dat.bool == false then
set dat.alpha = dat.alpha - alphaDec
call SetUnitVertexColor(dat.missile,color,color,color,dat.alpha)
elseif dat.bool == false then
set x = dat.x + speed * Cos(dat.angle * bj_DEGTORAD)
set y = dat.y + speed * Sin(dat.angle * bj_DEGTORAD)
set dat.x = x
set dat.y = y
call SetUnitPosition(dat.missile,dat.x,dat.y)
set tmpP = GetOwningPlayer(dat.missile)
call GroupEnumUnitsInRange(tmpG,dat.x,dat.y,dmgRadius,Cond)
loop
set u = FirstOfGroup(tmpG)
exitwhen u == null
call UnitDamageTarget(dat.missile,u,electroDmg(GetUnitAbilityLevel(dat.caster,electroID)),false,false,atta,dmg,weap)
call DestroyEffect(AddSpecialEffectTarget(buffEffect,u,overhead))
if GetUnitAbilityLevel(u,chargeBuffID) > 0 and IsUnitInGroup(u,dat.g) != true then
set dat.bool = true
set data = overload.create()
set data.caster = dat.caster
set data.missile = dat.missile
set data.target = u
set data.time = duration
set data.misScale = scale
call GroupAddUnit(dat.g,u)
endif
call GroupRemoveUnit(tmpG,u)
endloop
else
set dat.time = dat.time - Interval
endif
set i = i + 1
endloop
set u = null
if Total == 0 then
call PauseTimer(Tim)
endif
endmethod
static method create takes nothing returns missileStruct
local missileStruct dat = missileStruct.allocate()
if Total == 0 then
call TimerStart(Tim,Interval,true,function missileStruct.move)
endif
set Data[Total] = dat
set Total = Total + 1
return dat
endmethod
endstruct
//the first missile
private struct startStruct
unit missile
unit caster
effect sfx
real x = 0.
real y = 0.
real distance = 0.
real angle = 0.
static method move takes nothing returns nothing
local startStruct dat
local missileStruct data
local integer i = 0
local integer p = 0
local real angle = 0.
local real x = 0.
local real y = 0.
loop
exitwhen i >= Total3
set dat = Data3[i]
set dat.distance = dat.distance - speed2
if dat.distance <= 0 then
set Total3 = Total3 - 1
set Data3[i] = Data3[Total3]
set i = i - 1
call DestroyEffect(AddSpecialEffect(fieldString,dat.x,dat.y))
call DestroyEffect(AddSpecialEffect(explusionSFX,dat.x,dat.y))
set p = missiles(GetUnitAbilityLevel(dat.caster,electroID))
set angle = degrees/p
loop
exitwhen p <= 0
set data = missileStruct.create()
set data.caster = dat.caster
set data.angle = angle*p
set x = dat.x + startDistance * Cos(data.angle * bj_DEGTORAD)
set y = dat.y + startDistance * Sin(data.angle * bj_DEGTORAD)
set data.missile = CreateUnit(GetOwningPlayer(dat.caster),dummyID,x,y,0)
set data.x = x
set data.y = y
set data.time = duration
set data.distance = maxDistance
set data.alpha = color
set data.sfx = AddSpecialEffectTarget(missileSFX,data.missile,attach)
call UnitAddAbility(data.missile,flyID)
call SetUnitFlyHeight(data.missile,flyHigh,0)
call UnitRemoveAbility(data.missile,flyID)
call SetUnitScale(data.missile,scale,scale,scale)
call SetUnitPathing(data.missile,false)
set p = p - 1
endloop
call KillUnit(dat.missile)
set dat.missile = null
set dat.caster = null
call DestroyEffect(dat.sfx)
set dat.sfx = null
call startStruct.destroy(dat)
else
set x = GetUnitX(dat.missile) + speed2 * Cos(dat.angle*bj_DEGTORAD)
set y = GetUnitY(dat.missile) + speed2 * Sin(dat.angle*bj_DEGTORAD)
call SetUnitPosition(dat.missile,x,y)
endif
set i = i + 1
endloop
if Total3 == 0 then
call PauseTimer(Tim3)
endif
endmethod
static method create takes nothing returns startStruct
local startStruct dat = startStruct.allocate()
if Total3 == 0 then
call TimerStart(Tim3,Interval,true,function startStruct.move)
endif
set Data3[Total3] = dat
set Total3 = Total3 + 1
return dat
endmethod
endstruct
//standard functions
private function newCondition takes nothing returns boolean
return GetSpellAbilityId() == electroID
endfunction
private function newAction takes nothing returns nothing
local startStruct dat = startStruct.create()
local location tmpLoc = GetSpellTargetLoc()
local real dx = GetLocationX(tmpLoc) - GetUnitX(GetTriggerUnit())
local real dy = GetLocationY(tmpLoc) - GetUnitY(GetTriggerUnit())
set dat.caster = GetTriggerUnit()
set dat.x = GetLocationX(tmpLoc)
set dat.y = GetLocationY(tmpLoc)
set dat.distance = SquareRoot(dx * dx + dy * dy)
set dat.angle = bj_RADTODEG * Atan2(dat.y - GetUnitY(dat.caster), dat.x - GetUnitX(dat.caster))
set dat.missile = CreateUnit(GetOwningPlayer(dat.caster),dummyID,GetUnitX(dat.caster),GetUnitY(dat.caster),0)
set dat.sfx = AddSpecialEffectTarget(missileSFX,dat.missile,attach)
call UnitAddAbility(dat.missile,flyID)
call SetUnitFlyHeight(dat.missile,flyHigh,0)
call UnitRemoveAbility(dat.missile,flyID)
call SetUnitScale(dat.missile,scale2,scale2,scale2)
call SetUnitPathing(dat.missile,false)
call RemoveLocation(tmpLoc)
set tmpLoc = null
endfunction
private function newInt takes nothing returns nothing
local trigger int = CreateTrigger()
local integer index = 0
local unit dummy = CreateUnit(Player(14),dummyID,9999999,9999999,0)
loop
call TriggerRegisterPlayerUnitEvent(int,Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set index = index + 1
exitwhen index >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function newCondition))
call TriggerAddAction(int,function newAction)
set int = null
set Cond = Condition(function filter)
call UnitAddAbility(dummy,overloadID)
call RemoveUnit(dummy)
call Preload(fieldString)
call Preload(explusionSFX)
call Preload(buffEffect)
call Preload(missileSFX)
call PreloadStart()
set dummy = null
endfunction
endscope