Spellpack RotG hero - R-Hand of Destruction

waaaks!

Zinctified
Reaction score
255
Its been a long time since I've been submitting spells. Here's another spell pack from a planned hero for RotG v3.00 (RotG v1.xx, RotG Reborn v2.xx), which means I'll open the map again, consider this hero as a spoiler. The hero is not yet implemented in the said map, that means you can use it in your map, but the hero has no ultimate ability, I only made 3 ability, because its just a spoiler, no one must know the complete statistic of the hero until I released the full map.

All spells are vjass enhanced, which means you need Jass New Gen Pack to use it.

Systems required:
TimerUtils - for all spells
ABC - For Flames of Destruction
All spells are MUI





Destructo, the Right Hand of Destruction

Flames of Destruction
Sends a fire ball to the target point, dealing damage to enemy units that gets near to the fire ball, after the fire ball reaches its maximum range, it will explode and deal 150 area damage.

flamesofdestructionhm3.jpg

By waaakstamad at 2008-10-25

JASS:
//Requires ABC, TimerUtils

scope FlamesOfDestruction initializer init

globals
    private constant integer spell = 'A000'  //Flames of Destruction Spell Raw Code
    private constant integer dspell = 'A001' //Fire Explosion Spell Raw Code
    private constant integer dum = 'e001' //Fire Ball DUmmy
    private constant string exp = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
                                          //Effect spawned when the fire ball explodes
    private constant real speed = 800.    //The Fire Ball's Missile Speed
    private constant real distance = 1200.//Maximum disatnce of the Fire Ball
    private constant real explosionAOE = 300. //Area of effect of the explosion
    private constant real explosionDMG = 150. //Damage of the explosion
endglobals

private constant function Damage takes integer level returns real
    return 60. * level //Fire Ball's collision damage
endfunction

private struct data
    unit cast
    unit m
    real x
    real y
    real a
    real left
    integer l
    timer t
    group g
    group add
    trigger dcast
    
    integer counter
    
    method onDestroy takes nothing returns nothing
        local unit u
        call GroupClear(this.g)
        call ShowUnit(this.m, false)
        call KillUnit(this.m)
        call GroupEnumUnitsInRange(this.g, GetUnitX(this.m), GetUnitY(this.m), explosionAOE, null)
            loop
                set u = FirstOfGroup(this.g)
                exitwhen u == null
                if IsUnitEnemy(u, GetOwningPlayer(this.cast)) and GetWidgetLife(u) > .405 and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                    call UnitDamageTarget(this.cast, u, explosionDMG, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                    call GroupRemoveUnit(this.g, u)
                endif
                call GroupRemoveUnit(this.g,u)
            endloop
        call DisableTrigger(this.dcast)
        call SetPlayerAbilityAvailable(GetOwningPlayer(this.cast), spell, true)
        call ClearTriggerStructA(this.dcast)
        call GroupClear(this.g)
        call GroupClear(this.add)
        call DestroyGroup(this.g)
        call DestroyGroup(this.add)
        call DestroyEffect(AddSpecialEffect(exp, GetUnitX(this.m), GetUnitY(this.m)))
    endmethod
    
    static method fodRun takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local data d = GetTimerData(t)
        local real offset = speed * 0.035
        local real px = GetUnitX(d.m) + offset * Cos(d.a)
        local real py = GetUnitY(d.m) + offset * Sin(d.a)
        local unit u
        set offset = 0
        call SetUnitX(d.m, px)
        call SetUnitY(d.m, py)
        call GroupEnumUnitsInRange(d.g, GetUnitX(d.m), GetUnitY(d.m), 225, null)
        loop
            set u = FirstOfGroup(d.g)
            exitwhen u == null
            if IsUnitInGroup(u, d.add) == false then
                if IsUnitEnemy(u, GetOwningPlayer(d.cast)) and GetWidgetLife(u) > .405 and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                    call GroupAddUnit(d.add, u)
                    call UnitDamageTarget(d.cast, u, Damage(d.l), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                    call GroupRemoveUnit(d.g, u)
                endif
            endif
            call GroupRemoveUnit(d.g, u)
        endloop
        set d.left = d.left - 0.035
        if d.left < 0.035 or d.counter == 1 then
            set d.left = distance/speed
            set d.counter = 0
            call ReleaseTimer(t)
            call d.destroy()
        endif
    endmethod
    
    
    static method create takes unit fodCaster, real fodx, real fody returns data
        local data d = data.allocate()
        set d.cast = fodCaster
        set d.x = GetUnitX(d.cast)
        set d.y = GetUnitY(d.cast)
        set d.a = Atan2(fody - d.y, fodx - d.x)
        set d.m = CreateUnit(GetOwningPlayer(d.cast), dum, d.x,d.y, 57.29582 * d.a)
        set d.left = distance/speed
        call UnitAddAbility(d.m, 'Aloc')
        set d.t = NewTimer()
        set d.g = CreateGroup()
        set d.add = CreateGroup()
        set d.l = GetUnitAbilityLevel(d.cast, spell)
        call TimerStart(d.t, 0.035, true, function data.fodRun)
        call SetTimerData(d.t,d)
        
        return d
    endmethod
    
endstruct

private function con takes nothing returns boolean
    return GetSpellAbilityId() == spell
endfunction

private function dcon takes nothing returns boolean
    return GetSpellAbilityId() == dspell
endfunction

private function dact takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    local data d = GetTriggerStructA(t)
    set d.counter = 1
    set t = null
endfunction

private function act takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    local data d = data.create(GetTriggerUnit(), GetLocationX(loc), GetLocationY(loc))
    set d.dcast = CreateTrigger()
    call RemoveLocation(loc)
    call TriggerRegisterAnyUnitEventBJ( d.dcast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(d.dcast, Condition(function dcon))
    call TriggerAddAction(d.dcast, function dact)
    call SetTriggerStructA(d.dcast,d)
    set loc = null
endfunction

private function addc takes nothing returns boolean
    return GetLearnedSkill() == spell and GetUnitAbilityLevel(GetTriggerUnit(), spell) == 1
endfunction

private function adda takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    call UnitAddAbility(cast, dspell)
    set cast = null
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 con))
    call TriggerAddAction( t, function act )
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(t, Condition(function addc))
    call TriggerAddAction(t, function adda)
    
endfunction

endscope



Burning Land
Destructo channels and collects heat in the atmosphere, conjuring flames on where he stands, when finished channeling, Destructo will apply the collected heat around him, dealing damage

burninglandhs4.jpg

By waaakstamad at 2008-10-25

JASS:
//Requires: TimerUtils

scope BurningLand initializer init

globals
    private constant integer spell = 'A002' //Burning Land spell raw code
    private constant string sfx = "Objects\\Spawnmodels\\Human\\HCancelDeath\\HCancelDeath.mdl"
                                            //The two effects spawned
    private constant string sfxInit = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
    private constant integer spwn = 15 //Maximum explosions
    private constant real dlay = 0.035 //The Delay each explosion spawned
    private constant real aoe = 200 //Area effect of the explosion
    private constant integer maxExprng = 600 //Maximum range of the explosions
    private constant integer minExprng = 200 //Minimum range of the explosions
endglobals

private struct data
    unit cast
    integer l
    integer c
endstruct

private function Damage takes integer level returns real
    return 70. * level //Damage per level of each explosion
endfunction

private function con takes nothing returns boolean
    return GetSpellAbilityId() == spell
endfunction

private function filter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) and GetWidgetLife(GetFilterUnit()) > .405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
    
private function actInit takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local real x = GetUnitX(cast)
    local real y = GetUnitY(cast)
    local integer l = GetUnitAbilityLevel(cast, spell)
    local group g = CreateGroup()
    local unit u
    call GroupEnumUnitsInRange(g, x, y, aoe, Condition(function filter))
    call DestroyEffect(AddSpecialEffect(sfxInit, x, y))
    call DestroyEffect(AddSpecialEffect(sfx, x,y))
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call UnitDamageTarget(cast, u, Damage(l), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
        call GroupRemoveUnit(g,u)
    endloop
    set u = null
    call DestroyGroup(g)
    set cast = null
    set g = null
endfunction

private function loopFire takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local data d = GetTimerData(t)
    local group g = CreateGroup()
    local real x = GetUnitX(d.cast)
    local real y = GetUnitY(d.cast)
    local real px = x + GetRandomInt(minExprng, maxExprng) * Cos(57.29582 * GetRandomInt(10, 360))
    local real py = y + GetRandomInt(minExprng, maxExprng) * Sin(57.29582 * GetRandomInt(10, 360))
    local unit u
    call GroupEnumUnitsInRange(g, px,py, aoe, null)
    call DestroyEffect(AddSpecialEffect(sfxInit, px, py))
    call DestroyEffect(AddSpecialEffect(sfx, px,py))
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if IsUnitEnemy(u, GetOwningPlayer(d.cast)) and GetWidgetLife(d.cast) > .405 and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
            call UnitDamageTarget(d.cast, u, Damage(d.l), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
            call GroupRemoveUnit(g, u)
        endif
        call GroupRemoveUnit(g,u)
    endloop
    call DestroyGroup(g)
    set g = null
    if d.c == spwn then
        call ReleaseTimer(t)
        call d.destroy()
    else
        set d.c = d.c + 1
    endif
endfunction

private function actFinish takes nothing returns nothing
    local data d = data.create()
    local timer t = NewTimer()
    set d.cast = GetTriggerUnit()
    set d.c = 0
    set d.l = GetUnitAbilityLevel(d.cast, spell)
    call TimerStart(t, dlay, true, function loopFire)
    call SetTimerData(t,d)
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 con))
    call TriggerAddAction(t, function actInit)
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_FINISH )
    call TriggerAddCondition(t, Condition(function con))
    call TriggerAddAction(t, function actFinish)
endfunction

endscope



Inferno Trap
Plants an invisible flaming trap at the target point. When an enemy gets too close to the trap, the trap activates, locking the unit in place, dealing damage overtime and disabling it from attacking

infernotrapun7.gif

By waaakstamad at 2008-10-25

JASS:
//Requires: TimerUtils

scope InfernoTrap initializer init

globals
    private constant integer spell = 'A003' //Inferno Trap spell raw code
    private constant integer dunit = 'e002' //Inferno Trap (dummy) unit raw code
    private constant integer dspell = 'A004' //Inferno Trap Damage spwll raw code
    private constant integer globalDum = 'e000' //Global dummy unit
    private constant real duration = 45. //Duration for each Inferno Trap
    private constant string sfx = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
                                    //A special effect spawned when the Inferno trap is destroyed
endglobals

private struct data
    unit cast
    integer l
    unit m
    real dur
    real x
    real y
    
    method onDestroy takes nothing returns nothing
        call DestroyEffect(AddSpecialEffect(sfx, this.x, this.y))
        call ShowUnit(this.m, false)
        call KillUnit(this.m)
    endmethod
endstruct

private function con takes nothing returns boolean
    return GetSpellAbilityId() == spell
endfunction

private function ensnare takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local data d = GetTimerData(t)
    local group g = CreateGroup()
    local unit u
    local unit dum
    local real x = GetUnitX(d.m)
    local real y = GetUnitY(d.m)
    set d.dur = d.dur - 0.035
    call GroupEnumUnitsInRange(g, d.x,d.y, 150, null)
    set u = FirstOfGroup(g)
    if u != null and GetWidgetLife(u) > .405 and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitEnemy(u, GetOwningPlayer(d.cast)) then
        set dum = CreateUnit(GetOwningPlayer(d.cast), globalDum, d.x,d.y, 0)
        call UnitApplyTimedLife(dum, 'BTLF', 6.)
        call UnitAddAbility(dum, 'Aloc')
        call UnitAddAbility(dum, dspell)
        call SetUnitAbilityLevel(dum, dspell, d.l)
        call IssueTargetOrder(dum, "entanglingroots", u)

        call GroupClear(g)
        call DestroyGroup(g)
        call ReleaseTimer(t)
        call d.destroy()
    endif
    
    if d.dur < 0.035 then
        call ShowUnit(d.m, false)
        call KillUnit(d.m)
        call ReleaseTimer(t)
        call d.destroy()
    endif
    set dum = null
    set g = null
endfunction

private function act takes nothing returns nothing
    local data d = data.create()
    local timer t = NewTimer()
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    set d.cast = GetTriggerUnit()
    set d.l = GetUnitAbilityLevel(d.cast, spell)
    set d.m = CreateUnit(GetOwningPlayer(d.cast), dunit, x, y, 90)
    set d.x = GetUnitX(d.m)
    set d.y = GetUnitY(d.m)
    call SetUnitTimeScale(d.m, 0)
    set d.dur = duration
    call TimerStart(t, 0.035, true, function ensnare)
    call SetTimerData(t,d)
    call RemoveLocation(loc)
    set loc = null
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 con ) )
    call TriggerAddAction( t, function act )
endfunction

endscope



Unknown Ultimate :p

The screenshots are weird, its better to test the spells in game
Enjoy

EDIT 1: made Flames of Destruction fully MUI
EDIT 2: updated the spell
EDIT 3: updated the spell once again
 

emjlr3

Change can be a good thing
Reaction score
395
from the code you posted

FoD:

how the hell is someone supposed to know what all those constants do unless you tell them
why not create your trigger and all that good stuff in your create method, if your going to use those infernal things, atleast use them
your leaking a trigger pointer indact
use a boolexpr to enumunits in your groups
you remove your unit twice in fodRun and onDestroy, and you don't need to null u, its done for you in the loop
your leaking a trigger, and using a dynamic trigger at that when you don't need one
re-use unit groups, dont use dynamic ones
and alot of your constants should be configurable functions

BL:

don't need to null timers from a stack
range of creation of explosions should be configurable
and your random isn't exactly so, but I don't really care
and here your actually creating dynamic groups but never removing them, which is even worse then the last spell

IT:

this could actually benefit from an onDestroy method


all critiques presented hold true for subsequent spells
 

waaaks!

Zinctified
Reaction score
255
if your going to use those infernal things, atleast use them
what infernal?
you remove your unit twice in fodRun and onDestroy, and you don't need to null u, its done for you in the loop
what unit, the dummy or the enum units?
don't need to null timers from a stack
and stack is from a timer loop?
and here your actually creating dynamic groups but never removing them, which is even worse then the last spell
i forgot to remove that

thanks, ill fix the spellpack later
 

UndeadDragon

Super Moderator
Reaction score
447
Flames of destruction needs it's screenshot fixed.
 

waaaks!

Zinctified
Reaction score
255
Flames of destruction needs it's screenshot fixed.
theres not much to see in Flames of Destruction, its a pretty straight forward spell, throw fire ball, then u can explode it using the Explosion ability or, if the missile reaches its maximum range

spell updated
 

emjlr3

Change can be a good thing
Reaction score
395
what infernal?

methods themselves are usually just wrappers at best, though ppl abuse them to no end to increase "readability"

what unit, the dummy or the enum units?

enum

and stack is from a timer loop?

cssafety is a timer stack, since you use timers that are recylced, they do not need to be nulled because they are never removed from the game
 

jonadrian619

-___-
Reaction score
240
Hi waaaks!

I played RotG and seen this character before.

From the code you posted...
:nuts::nuts::nuts::nuts::banghead::banghead::banghead::(:(:thdown:
I'm a total loser to vJass and I only use the Handle Vars or do GUI spellmaking.

I can't check what's wrong with the code, but from what I can see, burning lands is the most chaotic. Fire-based abilities in maps are meant to be chaotic. For as long as there are no memory leaks and inefficient/unnecessary code it can be safely imported to any map.

The name, to me, looks a bit weird, to me I guess. But the ;right hand of destruction; creates an air of mystery and makes him really cool in the exterior.
 

emjlr3

Change can be a good thing
Reaction score
395
i dont think you have updated what I tol dyou to

and please let us know what you have changed so we dont need to re-read it all again looking for it
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top