Faust
You can change this now in User CP.
- Reaction score
- 123
Good evening people!
May I present you my first spellpack uploaded to thehelper:
A sorcerer of Nortrend, highly adept in using cold magics, a hero of my future AoS map. It took some time to "convert" it to this, better configurable shape, I hope it worth it.
3 of his spells were inspired by Thanatos' Frost Spiral spell (of Arthas the Death Knight), so thank you for him!
This is in vJASS, I used ABC, MUI, as far as I see it, leakless spell.
It may create minor lag when you cast the spells for the first time, and a bigger one if many of the abilities are used at the same time, but I think it's okay.
I tried to make it the most configurable possible. You can find almost all the perimeters of the spell in the beginning of each script. If you can't, look in the object editor
I'm not yet aware of any bugs, except when you cast the rotating spells near the edge of the map.
All 4 of his spells can be easily made to be channeling and back.
All productive comments are welcome; bug reports, suggestions of optimizing, ideas and features for the test map, tooltips - anything and everything.
Credit is something I don't care about, I'll happy to see him or one of his spells in another game.
The globals might be messed up a little, but I think my code is readable and easy.
So let's begin!
Freeze
Screenshot:
Hail
Screenshots:
Freezing Field
Screenshots:
Iceplosion
Screenshots:
And a small bonus, not really configurable, unique or anything:
Cold Armour
It's really nothing so no screenshot to this one.
IMPORTING INSTRUCTIONS::
Create a Player Variable called Player in the trigger editor
Copy the function in the map header
Copy the triggers
Copy the units, spells, buffs
Edit away
Tell me if I missed anything!
And now, shoot away!
May I present you my first spellpack uploaded to thehelper:
The Frost Revenant!
A sorcerer of Nortrend, highly adept in using cold magics, a hero of my future AoS map. It took some time to "convert" it to this, better configurable shape, I hope it worth it.
3 of his spells were inspired by Thanatos' Frost Spiral spell (of Arthas the Death Knight), so thank you for him!
This is in vJASS, I used ABC, MUI, as far as I see it, leakless spell.
It may create minor lag when you cast the spells for the first time, and a bigger one if many of the abilities are used at the same time, but I think it's okay.
I tried to make it the most configurable possible. You can find almost all the perimeters of the spell in the beginning of each script. If you can't, look in the object editor
I'm not yet aware of any bugs, except when you cast the rotating spells near the edge of the map.
All 4 of his spells can be easily made to be channeling and back.
All productive comments are welcome; bug reports, suggestions of optimizing, ideas and features for the test map, tooltips - anything and everything.
Credit is something I don't care about, I'll happy to see him or one of his spells in another game.
The globals might be messed up a little, but I think my code is readable and easy.
So let's begin!
Freeze
Channels powerful cold magic from the Nortrend skies into the target unit, slowing it down by trapping it into ice.
When the energy overflows, it finally burts out dealing damage and slowing neighbouring enemies.
Channeling
JASS:
scope Freeze initializer Init
globals
private constant integer FREEZEID = 039;A006039; // Raw code of the ability.
private constant integer FREEZEIDD = 039;A003039; // Raw code of the dummy's slow ability.
private constant integer FREEZEIDD2 = 039;A007039; // Raw code of the dummy's frost nova ability.
private constant string LIGHTNING = "DRAM" // String of the Lightning.
private constant string ORDERSTRINGDUMMY = "slow" // Order string of the dummy's ability.
private constant string ORDERSTRINGDUMMY2 = "frostnova" // Other order string of the dummy's ability.
private constant string EFFECTMODEL1 = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" // Model of the effect on target.
private constant string EFFECTMODEL2 = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathTargetArt.mdl" // Model of the ice chunk on target.
private constant string ATTACHPOINT = "origin" // EFFECTMODEL2's attachment point
private constant integer ORDERSTRINGID = 852663 // Order string of the ability.
private constant real RANGEOFTHEDAMAGE = 200 // Damages units withing this distance from the center.
private constant real DAMAGEBASE = 10 // The base damage it deals to enemies.
private constant real DAMAGEPERLEVEL = 25 // How much damage more it deals each level
private constant integer DUMMYUNITID = 039;u001039; // Raw code of the dummyunit.
private constant real HEIGHT = 3000 // From how high the lightning comes.
private constant real HEIGHT2 = 40 // From the unit's feet upwards how high should the lightning end
private constant real VALUE = 1.00 / 140.00 // A value in calculation of the spell
private constant real TIMEBASE = 0.100 // A base value in calculation of the spell
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL // Damage's attack type
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_NORMAL // Damage's damage type
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS // Damage's weapon type
endglobals
private function C takes nothing returns boolean
return GetSpellAbilityId() == FREEZEID
endfunction
private struct Freeze
unit caster
unit target
timer clock = CreateTimer()
lightning beam
integer ticks = 0
effect icechunk
method onDestroy takes nothing returns nothing
call DestroyEffect(.icechunk)
call PauseTimer(.clock)
call ClearTimerStructA(.clock)
call DestroyTimer(.clock)
endmethod
endstruct
private function H takes nothing returns nothing
local Freeze dat = GetTimerStructA(GetExpiredTimer())
local real tx = GetUnitX(dat.target)
local real ty = GetUnitY(dat.target)
local real cx = GetUnitX(dat.caster)
local real cy = GetUnitY(dat.caster)
local group UG = CreateGroup()
local unit target
local location tpoint = GetUnitLoc(dat.target)
local real tz = GetLocationZ(tpoint) + GetUnitFlyHeight(dat.target) + HEIGHT2
local unit dummy
call DestroyEffect(AddSpecialEffect(EFFECTMODEL1, tx, ty))
call RemoveLocation(tpoint)
set tpoint = null
call MoveLightningEx(dat.beam, true, tx, ty, tz, cx, cy, HEIGHT)
if dat.ticks == 35 then
set dat.icechunk = AddSpecialEffectTarget(EFFECTMODEL2, dat.target, ATTACHPOINT)
endif
if dat.ticks - (dat.ticks / 5) * 5 == 0 then
set dummy = CreateUnit(GetOwningPlayer(dat.caster), DUMMYUNITID, cx, cy, 0)
call UnitAddAbility(dummy, FREEZEIDD)
call SetUnitAbilityLevel(dummy, FREEZEIDD, dat.ticks / 5)
call IssueTargetOrder(dummy, ORDERSTRINGDUMMY, dat.target)
set dummy = null
endif
set dat.ticks = dat.ticks + 1
if GetUnitCurrentOrder(dat.caster) != ORDERSTRINGID then
call DestroyLightning(dat.beam)
call dat.destroy()
endif
if dat.ticks == 60 then
call IssueImmediateOrder(dat.caster, "stop")
call DestroyLightning(dat.beam)
set udg_Player = GetOwningPlayer(dat.caster)
call GroupEnumUnitsInRange(UG, GetUnitX(dat.target), GetUnitY(dat.target), RANGEOFTHEDAMAGE, Condition(function IsUnitAnEnemy))
loop
set target = FirstOfGroup(UG)
exitwhen target == null
set dummy = CreateUnit(GetOwningPlayer(dat.caster), DUMMYUNITID, cx, cy, 0)
call UnitAddAbility(dummy, FREEZEIDD2)
call SetUnitAbilityLevel(dummy, FREEZEIDD2, GetUnitAbilityLevel(dat.caster, FREEZEID))
call IssueTargetOrder(dummy, ORDERSTRINGDUMMY2, target)
call UnitDamageTarget(dat.caster, target, DAMAGEBASE + DAMAGEPERLEVEL * GetUnitAbilityLevel(dat.caster, FREEZEID), true, false, ATTACKTYPE, DAMAGETYPE, WEAPONTYPE)
call GroupRemoveUnit(UG, target)
set dummy = null
set target = null
endloop
call UnitDamageTarget(dat.caster, dat.target, DAMAGEBASE + DAMAGEPERLEVEL * GetUnitAbilityLevel(dat.caster, FREEZEID), true, false, ATTACKTYPE, DAMAGETYPE, WEAPONTYPE)
call DestroyGroup(UG)
set UG = null
call dat.destroy()
endif
call DestroyGroup(UG)
set UG = null
set dummy = null
endfunction
private function A takes nothing returns nothing
local Freeze dat = Freeze.create()
local real value = I2R(GetUnitAbilityLevel(GetTriggerUnit(), FREEZEID)) * 1.00
local real time = TIMEBASE + VALUE - value * VALUE
set dat.caster = GetTriggerUnit()
set dat.target = GetSpellTargetUnit()
set dat.beam = AddLightningEx(LIGHTNING, true, 0, 0, 0, 0, 0, 0)
call SetTimerStructA(dat.clock, dat)
call TimerStart(dat.clock, time, true, function H)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function C))
call TriggerAddAction(t, function A)
endfunction
endscope
Screenshot:
Hail
Channels powerful magic into the Nortrend skies, calling down a heavy hailstorm.
Deals damage and slows enemy units.
JASS:
scope Hail initializer Init
globals
private constant integer HAILID = 039;A004039; // Raw code of the ability.
private constant integer HAILIDD = 039;A005039; // Raw code of the dummy's frost nova ability.
private constant string ORDERSTRING = "frostnova" // Order string of the dummy's ability.
private constant real RANGEOFTHEDAMAGE = 300 // Damages units withing this distance from the center.
private constant real DAMAGEBASE = 10 // The base damage it deals to enemies.
private constant real DAMAGEPERLEVEL = 45 // How much damage more it deals each level
private constant integer EFFECTUNITID = 039;n004039; // Raw code of the flying effect unit.
private constant integer EFFECTUNITID2 = 039;n003039; // Raw code of the blizzard effect unit.
private constant integer DUMMYUNITID = 039;u001039; // Raw code of the dummyunit.
private constant real FLYINGHEIGHTINCREASE = 17 // How quickly the snowballs descend.
private constant real ANGLEINCREMENT = 6 // How quickly the snowballs rotate around the center.
private constant real EFFECTDISTANCE = 225 // How far are the effects from the center at start.
private constant real EFFECTDISTANCECHANGE = 5 // Increment of the effects from the center.
private constant real SPEEDOFH1 = 0.01 // How quickly should handler 1 run (and how fast things happen in it)
private constant real SPEEDOFH2 = 0.9 // How quickly should handler 2 run (and how fast things happen in it)
private constant real MAXHEIGHT = 2000 // At which height the effects stop spawning
private constant real LIFESPAN = 2.5 // How long the uniteffects remain
private constant real BLIZZARDSIZE = 0.8 // How big is the blizzardunit
private constant real BLIZZARDSIZEPERLEVEL = 0.1 // How bigger is the blizzardunit every level
private constant integer BLIZZARDAMOUNT = 45 // How many blizzardunits are there
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL // Damage's attack type
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_NORMAL // Damage's damage type
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS // Damage's weapon type
endglobals
private function C takes nothing returns boolean
return GetSpellAbilityId() == HAILID
endfunction
private struct Hail
unit caster
timer clock = CreateTimer()
real ex
real ey
real ez = 0
real tx
real ty
real facing = GetRandomReal(0, 360)
real distance = EFFECTDISTANCE
method onDestroy takes nothing returns nothing
call PauseTimer(.clock)
call ClearTimerStructA(.clock)
call DestroyTimer(.clock)
endmethod
endstruct
private function H2 takes nothing returns nothing
local Hail dat = GetTimerStructA(GetExpiredTimer())
local group UG = CreateGroup()
local unit target
local unit dummy
set udg_Player = GetOwningPlayer(dat.caster)
call GroupEnumUnitsInRange(UG, dat.tx, dat.ty, RANGEOFTHEDAMAGE, Condition(function IsUnitAnEnemy))
loop
set target = FirstOfGroup(UG)
exitwhen target == null
set dummy = CreateUnit(GetOwningPlayer(dat.caster), DUMMYUNITID, dat.tx, dat.ty, 0)
call UnitAddAbility(dummy, HAILIDD)
call UnitDamageTarget(dat.caster, target, DAMAGEBASE + DAMAGEPERLEVEL * GetUnitAbilityLevel(dat.caster, HAILID), true, false, ATTACKTYPE, DAMAGETYPE, WEAPONTYPE)
call SetUnitAbilityLevel(dummy, HAILIDD, GetUnitAbilityLevel(dat.caster, HAILID))
call IssueTargetOrder(dummy, ORDERSTRING, target)
call GroupRemoveUnit(UG, target)
set dummy = null
set target = null
endloop
call DestroyGroup(UG)
set UG = null
call dat.destroy()
endfunction
private function H takes nothing returns nothing
local Hail dat = GetTimerStructA(GetExpiredTimer())
local unit eunit
local integer ticks = 0
set dat.ex = dat.tx + dat.distance * Cos(dat.facing * bj_DEGTORAD)
set dat.ey = dat.ty + dat.distance * Sin(dat.facing * bj_DEGTORAD)
set dat.ez = dat.ez + FLYINGHEIGHTINCREASE
set dat.facing = dat.facing + ANGLEINCREMENT
set dat.distance = dat.distance + EFFECTDISTANCECHANGE
set eunit = CreateUnit(GetOwningPlayer(dat.caster), EFFECTUNITID, dat.ex, dat.ey, dat.facing)
call UnitApplyTimedLife(eunit, 039;omfg039;, LIFESPAN)
call SetUnitFlyHeight(eunit, dat.ez, 0)
set eunit = null
if dat.ez >= MAXHEIGHT then
call PauseTimer(dat.clock)
call TimerStart(dat.clock, SPEEDOFH2, false, function H2)
loop
exitwhen ticks == BLIZZARDAMOUNT
set ticks = ticks + 1
set dat.ex = dat.tx + GetRandomReal(0, RANGEOFTHEDAMAGE) * Cos(GetRandomReal(0, bj_PI*2))
set dat.ey = dat.ty + GetRandomReal(0, RANGEOFTHEDAMAGE) * Sin(GetRandomReal(0, bj_PI*2))
set eunit = CreateUnit(GetOwningPlayer(dat.caster), EFFECTUNITID2, dat.ex, dat.ey, GetRandomReal(1, 360))
call SetUnitScale(eunit, BLIZZARDSIZE + I2R(GetUnitAbilityLevel(dat.caster, HAILID)) * BLIZZARDSIZEPERLEVEL, BLIZZARDSIZE + I2R(GetUnitAbilityLevel(dat.caster, 039;A02O039;)) * BLIZZARDSIZEPERLEVEL, BLIZZARDSIZE + I2R(GetUnitAbilityLevel(dat.caster, 039;A02O039;)) * BLIZZARDSIZEPERLEVEL)
set eunit = null
endloop
endif
endfunction
private function A takes nothing returns nothing
local Hail dat = Hail.create()
local location tpoint = GetSpellTargetLoc()
set dat.tx = GetLocationX(tpoint)
set dat.ty = GetLocationY(tpoint)
call RemoveLocation(tpoint)
set tpoint = null
set dat.caster = GetTriggerUnit()
call SetTimerStructA(dat.clock, dat)
call TimerStart(dat.clock, SPEEDOFH1, true, function H)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function C))
call TriggerAddAction(t, function A)
endfunction
endscope
Screenshots:
Freezing Field
Draws chilling power from the skies of Northrend, continously damaging and greatly slowing enemy units in the area.
JASS:
scope FF initializer Init
globals
private constant integer FFID = 039;A001039; // Raw code of the ability.
private constant integer FFIDD = 039;A002039; // Raw code of the dummy's thunder clap ability.
private constant string ORDERSTRING = "thunderclap" // Order string of the dummy's ability.
private constant integer AMOUNTOFSLOPES = 4 // How many starting points of the snowballs and novas
private constant real DAMAGEBASEperPULSE = 25 // How much base damage it deals each pulse.
private constant real DAMAGEperLEVELperPULSE = 25 // How much addition damage it deals each level.
private constant real ANGLEINCREMENTOFTHENOVAS = 15 // How quickly the landed frost nova effects rotate.
private constant real DISTANCEOFTHENOVAS = 375 // How far the frost nova effects are from the center.
private constant real RANGEOFTHEDAMAGE = 400 // Damages units withing this distance from the center.
private constant string NOVAEFFECTMODEL = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl" // The actual model of the landed special effect. (for the flying ones, see object editor)
private constant integer EFFECTUNITID = 039;n000039; // Raw code of the effect unit.
private constant integer DUMMYUNITID = 039;u001039; // Raw code of the dummyunit.
private constant real FLYINGHEIGHTDECREASE = 12 // How quickly the snowballs descend.
private constant real ANGLEINCREMENTOFTHESNOWBALLS = 6 // How quickly the snowballs rotate around the center.
private constant real DISTANCEOFTHESNOWBALLS = 350 // How far are the snowballs from the center.
private constant real SPEEDOFH1 = 0.05 // How quickly should handler 1 run (and how fast things happen in it)
private constant real SPEEDOFH2 = 0.1 // How quickly should handler 2 run (and how fast things happen in it)
private constant real STARTINGHEIGHT = 1200 // From how high should the effect units start spawning
private constant real LIFESPAN = 0.8 // How long the "snowballs" remain
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL // Damage's attack type
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_NORMAL // Damage's damage type
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS // Damage's weapon type
endglobals
private struct FF
unit caster
timer clock = CreateTimer()
real array ex[AMOUNTOFSLOPES]
real array ey[AMOUNTOFSLOPES]
real ez = STARTINGHEIGHT
real cx
real cy
real array facing[AMOUNTOFSLOPES]
integer ticks = 0
method onDestroy takes nothing returns nothing
call PauseTimer(.clock)
call ClearTimerStructA(.clock)
call DestroyTimer(.clock)
endmethod
endstruct
private function C takes nothing returns boolean
return GetSpellAbilityId() == FFID
endfunction
private function H2 takes nothing returns nothing
local FF dat = GetTimerStructA(GetExpiredTimer())
local unit dummy
local integer ticks = 0
local integer times = R2I(I2R(GetUnitAbilityLevel(dat.caster, FFID)) + 1) / 2
local group UG = CreateGroup()
local unit victim
loop
exitwhen ticks == AMOUNTOFSLOPES
set ticks = ticks + 1
set dat.facing[ticks - 1] = dat.facing[ticks - 1] + ANGLEINCREMENTOFTHENOVAS
set dat.ex[ticks - 1] = dat.cx + DISTANCEOFTHENOVAS * Cos(dat.facing [ticks - 1] * bj_DEGTORAD)
set dat.ey[ticks - 1] = dat.cy + DISTANCEOFTHENOVAS * Sin(dat.facing [ticks - 1] * bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect(NOVAEFFECTMODEL, dat.ex[ticks - 1], dat.ey[ticks - 1]))
endloop
set dat.ticks = dat.ticks + 1
if 0 == dat.ticks - (dat.ticks / 12) * 12 or dat.ticks == 1 then
set dummy = CreateUnit(GetOwningPlayer(dat.caster), DUMMYUNITID, dat.cx, dat.cy, 0)
call UnitAddAbility(dummy, FFIDD)
set udg_Player = GetOwningPlayer(dat.caster)
call GroupEnumUnitsInRange(UG, dat.cx, dat.cy, RANGEOFTHEDAMAGE, Condition(function IsUnitAnEnemy))
loop
set victim = FirstOfGroup(UG)
exitwhen victim == null
call UnitDamageTarget(dat.caster, victim, DAMAGEBASEperPULSE + DAMAGEperLEVELperPULSE * GetUnitAbilityLevel(dat.caster, FFID), true, false, ATTACKTYPE, DAMAGETYPE, WEAPONTYPE)
call GroupRemoveUnit(UG, victim)
set victim = null
endloop
call IssueImmediateOrder(dummy, ORDERSTRING)
set dummy = null
set victim = null
call DestroyGroup(UG)
set UG = null
endif
set dummy = null
if dat.ticks == 24 * times then
call dat.destroy()
endif
endfunction
private function H takes nothing returns nothing
local FF dat = GetTimerStructA(GetExpiredTimer())
local unit eunit
local integer ticks = 0
loop
exitwhen ticks == AMOUNTOFSLOPES
set ticks = ticks + 1
set dat.facing[ticks - 1] = dat.facing[ticks - 1] + ANGLEINCREMENTOFTHESNOWBALLS
set dat.ex[ticks - 1] = dat.cx + DISTANCEOFTHESNOWBALLS * Cos(dat.facing [ticks - 1] * bj_DEGTORAD)
set dat.ey[ticks - 1] = dat.cy + DISTANCEOFTHESNOWBALLS * Sin(dat.facing [ticks - 1] * bj_DEGTORAD)
set dat.ez = dat.ez - FLYINGHEIGHTDECREASE
set eunit = CreateUnit(GetOwningPlayer(dat.caster), EFFECTUNITID, dat.ex[ticks - 1], dat.ey[ticks - 1], dat.facing[ticks - 1])
call SetUnitFlyHeight(eunit, dat.ez, 0)
call UnitApplyTimedLife(eunit, 039;omfg039;, LIFESPAN)
set eunit = null
set dat.ticks = dat.ticks + 1
endloop
if dat.ez < 25 then
call PauseTimer(dat.clock)
set dat.ticks = 0
call TimerStart(dat.clock, SPEEDOFH2, true, function H2)
endif
endfunction
private function A takes nothing returns nothing
local FF dat = FF.create()
local location tpoint = GetSpellTargetLoc()
local integer tick = 0
set dat.cx = GetUnitX(GetTriggerUnit())
set dat.cy = GetUnitY(GetTriggerUnit())
set dat.facing[0] = GetRandomReal(0, 360)
loop
exitwhen tick > AMOUNTOFSLOPES
set tick = tick + 1
set dat.facing[tick] = dat.facing[tick-1] + 360 / AMOUNTOFSLOPES
endloop
call RemoveLocation(tpoint)
set tpoint = null
set dat.caster = GetTriggerUnit()
call SetTimerStructA(dat.clock, dat)
call TimerStart(dat.clock, SPEEDOFH1, true, function H)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function C))
call TriggerAddAction(t, function A)
endfunction
endscope
Screenshots:
Iceplosion
Channels strong cold energies into two magical particles that collide above the Frost Revenant, bursting into missiles that are fired all around him.
Each missile deals 100 area damage.
Channeling
JASS:
scope Iceplosion initializer Init
globals
private constant integer ICEPLOSIONID = 039;A008039; // Raw code of the ability.
private constant integer ICEPLOSIONIDD1 = 039;A009039; // Raw code of the frost attack ability.
private constant integer ICEPLOSIONIDD2 = 039;A00A039; // Raw code of the frost attack ability.
private constant integer ICEPLOSIONIDD3 = 039;A00B039; // Raw code of the frost attack ability.
private constant integer ORDERSTRINGID = 852526 // Order string of the ability.
private constant real RANGEOFTHEATTACK = 1000 // Damages units withing this distance from the center.
private constant integer ATTACKUNITID = 039;n001039; // Raw code of the attackunit.
private constant integer EFFECTUNITID = 039;n002039; // Raw code of the effectunit.
private constant real HEIGHT = 0 // Starting height
private constant real HEIGHTCHANGE = 8 // Height change
private constant real DISTANCE = 600 // Starting distance
private constant real DISTANCECHANGE = 8 // Distance change
private constant real ANGLE = 0.05 // Starting speed of rotating
private constant real ANGLECHANGE = 0.24 // Changing of the speed base
private constant real ANGLECHANGE2 = 0.01 // Changing of the speed each hero level
private constant integer AMOUNTOFATTACKSBASE = 20 // Base amount of attacks each missile type
private constant integer AMOUNTOFATTACKS = 5 // How many tiems more each effect spawns each hero level
private constant real HANDLERSPEED = 0.05 // How quickly the H functions runs - and things happen
endglobals
private struct Ice
unit caster
timer clock = CreateTimer()
unit array eu[2]
real ez = HEIGHT
real cx
real cy
real array facing[2]
real distance = DISTANCE
real anglediff = ANGLECHANGE
method onDestroy takes nothing returns nothing
call PauseTimer(.clock)
call ClearTimerStructA(.clock)
call DestroyTimer(.clock)
endmethod
endstruct
private function C takes nothing returns boolean
return GetSpellAbilityId() == ICEPLOSIONID
endfunction
private function H takes nothing returns nothing
local Ice dat = GetTimerStructA(GetExpiredTimer())
local real x
local real y
local integer tick1 = 1
local unit dummy
local integer tick2 = 0
set dat.ez = dat.ez + HEIGHTCHANGE
set dat.anglediff = dat.anglediff + ANGLECHANGE + I2R(GetUnitAbilityLevel(dat.caster, ICEPLOSIONID)) * ANGLECHANGE2
set dat.distance = dat.distance - DISTANCECHANGE
set dat.facing[0] = dat.facing[0] + dat.anglediff
set dat.facing[1] = dat.facing[1] + dat.anglediff
set x = dat.cx + dat.distance * Cos(dat.facing[0] * bj_DEGTORAD)
set y = dat.cy + dat.distance * Sin(dat.facing[0] * bj_DEGTORAD)
call SetUnitPosition(dat.eu[0], x, y)
call SetUnitFlyHeight(dat.eu[0], dat.ez, 0)
set x = dat.cx + dat.distance * Cos(dat.facing[1] * bj_DEGTORAD)
set y = dat.cy + dat.distance * Sin(dat.facing[1] * bj_DEGTORAD)
call SetUnitPosition(dat.eu[1], x, y)
call SetUnitFlyHeight(dat.eu[1], dat.ez, 0)
if GetUnitCurrentOrder(dat.caster) != ORDERSTRINGID then
call KillUnit(dat.eu[0])
call KillUnit(dat.eu[1])
call dat.destroy()
endif
if dat.distance <= 10 then
loop
exitwhen tick1 > 3
set tick2 = 0
loop
exitwhen tick2 == AMOUNTOFATTACKSBASE + AMOUNTOFATTACKS * GetUnitAbilityLevel(dat.caster, ICEPLOSIONID)
set x = dat.cx + GetRandomReal(0, RANGEOFTHEATTACK) * Cos(GetRandomReal(0, bj_PI*2))
set y = dat.cy + GetRandomReal(0, RANGEOFTHEATTACK) * Sin(GetRandomReal(0, bj_PI*2))
set dummy = CreateUnit(GetOwningPlayer(dat.caster), ATTACKUNITID, dat.cx, dat.cy, 0)
call UnitApplyTimedLife(dummy, 039;omfg039;, 2)
call SetUnitFlyHeight(dummy, dat.ez, 0)
set tick2 = tick2 + 1
if tick1 == 1 then
call UnitAddAbility(dummy, ICEPLOSIONIDD1)
endif
if tick1 == 2 then
call UnitAddAbility(dummy, ICEPLOSIONIDD2)
endif
if tick1 == 3 then
call UnitAddAbility(dummy, ICEPLOSIONIDD3)
else
endif
call IssuePointOrder(dummy, "attackground", x, y)
endloop
set tick1 = tick1 + 1
endloop
call IssueImmediateOrder(dat.caster, "stop")
call RemoveUnit(dat.eu[0])
call RemoveUnit(dat.eu[1])
call dat.destroy()
endif
endfunction
private function A takes nothing returns nothing
local Ice dat = Ice.create()
local real x
local real y
set dat.cx = GetUnitX(GetTriggerUnit())
set dat.cy = GetUnitY(GetTriggerUnit())
set dat.caster = GetTriggerUnit()
set dat.facing[0] = GetRandomReal(0, 360)
set dat.facing[1] = dat.facing[0] + 180
set x = dat.cx + dat.distance * Cos(dat.facing[0] * bj_DEGTORAD)
set y = dat.cy + dat.distance * Sin(dat.facing[0] * bj_DEGTORAD)
set dat.eu[0] = CreateUnit(GetOwningPlayer(dat.caster), EFFECTUNITID, x, y, 0)
set x = dat.cx + dat.distance * Cos(dat.facing[1] * bj_DEGTORAD)
set y = dat.cy + dat.distance * Sin(dat.facing[1] * bj_DEGTORAD)
set dat.eu[1] = CreateUnit(GetOwningPlayer(dat.caster), EFFECTUNITID, x, y, 0)
call SetTimerStructA(dat.clock, dat)
call TimerStart(dat.clock, HANDLERSPEED, true, function H)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(t, Condition(function C))
call TriggerAddAction(t, function A)
endfunction
endscope
Screenshots:
And a small bonus, not really configurable, unique or anything:
Cold Armour
Activate Cold Armour to engulf the Frost Revenant in a protective ring, that slows enemy units trying to harm him.
Drains mana and life until deactivated.
JASS:
scope ColdArmour initializer Init
globals
trigger t = CreateTrigger()
trigger t0 = CreateTrigger()
private constant integer HEROID = 039;u000039; // The rawcode of the Frost Revenant
endglobals
private function C takes nothing returns boolean
return GetUnitAbilityLevel(GetTriggerUnit(), 039;B003039;) != 0 and GetOwningPlayer(GetTriggerUnit()) != GetOwningPlayer(GetEventDamageSource())
endfunction
private function C2 takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == HEROID
endfunction
private function A takes nothing returns nothing
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
local unit dummy = CreateUnit(GetOwningPlayer(GetTriggerUnit()), 039;h000039;, x, y, 0)
call IssueTargetOrder(dummy, "attack", GetEventDamageSource())
call UnitApplyTimedLife(dummy, 039;omfg039;, 2)
endfunction
private function A0 takes nothing returns nothing
local group UG = CreateGroup()
local unit ahero
call GroupEnumUnitsInRect(UG, bj_mapInitialPlayableArea, Condition(function C2))
loop
set ahero = FirstOfGroup(UG)
exitwhen ahero == null
call TriggerRegisterUnitEvent(t, ahero, EVENT_UNIT_DAMAGED )
set ahero = null
endloop
call DestroyGroup(UG)
set UG = null
set ahero = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call TriggerRegisterTimerEvent(t0, 0.5, false)
call TriggerAddAction(t0, function A0)
call TriggerAddCondition(t, Condition(function C))
call TriggerAddAction(t, function A)
endfunction
endscope
It's really nothing so no screenshot to this one.
IMPORTING INSTRUCTIONS::
Create a Player Variable called Player in the trigger editor
Copy the function in the map header
Copy the triggers
Copy the units, spells, buffs
Edit away
Tell me if I missed anything!
And now, shoot away!