• 🏆 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!

Shadowfiend Spellpack v1.4

  • Like
Reactions: aki15
Spells of Shadowfiend from DotA. Here's a link for a more detailed information on the hero.

Do note that I created all the spells from scratch, I did not copy these spells from any other map. Presence of the Dark Lord is simply a negative valued Devotion Aura. It was added for the sake of making this a completed "Shadowfiend Spellpack".

Overview
  • Shadowraze [Active]
  • Necromastery [Passive]
  • Presence of the Dark Lord [Passive]
  • Requiem of Souls [Active]


Details
- The spells are vJASS
- They should be leak-less and lag-less
- It is MUI, meaning can be cast many times at the same instance
- Shadowfiend from DoTA


Implementation
JASS:
//==============================================================================
//                      SHADOW FIELD SPELLPACK v1.4                       
//                            BY Ayanami                            
//==============================================================================

//==============================================================================
//                            REQUIREMENTS                                      
//==============================================================================
//
// - JNGP
// - Alloc
// - RegisterPlayerUnitEvent                                                            
// - SpellEffectEvent
// - Timer32
// - WorldBounds                                                             
//                                                            
//==============================================================================

//==============================================================================
//                           IMPLEMENTATION                                     
//==============================================================================
//
// 1) Copy the whole "Required Systems" Trigger folder & paste in map
// 2) Save the map, it will take a bit longer than usual
// 3) After saving, close the map and re-open it
// 4) Delete or disable the trigger "Objects"
// 5) Copy all 8 abilities under "Undead" & paste in map
// 6) Copy the single buff under "Undead" & paste in map
// 7) Ensure that the following abilities have their buff set properly:
//      Presence of the Dark Lord - Presence of the Dark Lord
// 8) Copy the whole "Shadowfiend" Trigger folder
// 9) Go through all the spell Configurations
//
//==============================================================================


Spell Codes



Gives the Shadow Fiend the power to desecrate regions in front of him at varying distances (200/450/700).

Level 1 - 75 damage.
Level 2 - 150 damage.
Level 3 - 225 damage.
Level 4 - 300 damage.

Cast Range: Varies
Target Type: Instant
Cooldown: 10 seconds

JASS:
library Shadowraze uses Alloc, RegisterPlayerUnitEvent, SpellEffectEvent, WorldBounds

//===========================================================================
//                           CONFIGURABLES                        
//===========================================================================

globals
    private constant integer ABILID = 'ABSR' // raw code of ability "Shadowraze"
    private constant integer ABILIDZ = 'ASR0' // raw code of ability "Shadowraze (Z)"
    private constant integer ABILIDX = 'ASR1' // raw code of ability "Shadowraze (X)"
    private constant integer ABILIDC = 'ASR2' // raw code of ability "Shadowraze (C)"
    
    private constant integer DUMMYID = 'sHAD' // raw code of unit "Shadowraze Dummy", acts as the visual effect itself
    private constant real ANIMDUR = 2.0 // duration of DUMMYID
    private constant integer RED = 0 // red vertex color of DUMMYID
    private constant integer GREEN = 0 // green vertex color of DUMMYID
    private constant integer BLUE = 0 // blue vertex color of DUMMYID
    private constant integer TRANS = 255 // transparency of DUMMYID, where 0 is fully transparent
    private constant real SCALE = 1.2 // scale size of DUMMYID
    private constant real PERIOD = 0.1 // checking period for dummy expiration
    
    private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
    
    private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
    private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
endglobals

// damage dealt
private function GetDamage takes integer level returns real
    return 75.0 * level
endfunction

// area of effect
private function GetArea takes integer level returns real
    return 250.0
endfunction

// range of "Shadowraze (Z)"
private function GetRangeZ takes integer level returns real
    return 200.0
endfunction

// range of "Shadowraze (X)"
private function GetRangeX takes integer level returns real
    return 450.0
endfunction

// range of "Shadowraze (C)"
private function GetRangeC takes integer level returns real
    return 700.0
endfunction

// target types allowed for dealing damage
private function GetFilter takes unit caster, unit target returns boolean
    return /*
    */ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
    */ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
    */ not IsUnitType(target, UNIT_TYPE_STRUCTURE) // target is not a structure
endfunction

//===========================================================================
//                          END CONFIGURABLES                        
//===========================================================================

globals
    private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
    
    private group G = bj_lastCreatedGroup
endglobals

private struct Main extends array
    implement Alloc

    private thistype next
    private thistype prev
    private unit u
    private real dur
    private static timer linkTimer = CreateTimer()
    
    private method destroy takes nothing returns nothing
        set this.next.prev = this.prev
        set this.prev.next = this.next
        
        if thistype(0).next == 0 then
            call PauseTimer(thistype.linkTimer)
        endif
        
        call RemoveUnit(this.u)
        call this.deallocate()
    endmethod
    
    private static method iterate takes nothing returns nothing
        local thistype this = thistype(0)
        
        loop
            set this = this.next
            exitwhen this == 0
            
            if this.dur <= 0 then
                call this.destroy()
            else
                set this.dur = this.dur - PERIOD
            endif
        endloop
    endmethod

    private static method onCast takes nothing returns boolean
        local thistype this
        local unit caster = GetTriggerUnit()
        local unit u
        local integer spellid = GetSpellAbilityId()
        local integer level
        local real r
        local real a
        local real x
        local real y
        
        set level = GetUnitAbilityLevel(caster, ABILID)
            
        if spellid == ABILIDZ then
            set r = GetRangeZ(level)
        elseif spellid == ABILIDX then
            set r = GetRangeX(level)
        else
            set r = GetRangeC(level)
        endif
        
        set a = GetUnitFacing(caster) * bj_DEGTORAD
        set x = GetUnitX(caster) + r * Cos(a)
        set y = GetUnitY(caster) + r * Sin(a)
        
        if x >= WorldBounds.minX and x <= WorldBounds.maxX and y >= WorldBounds.minY and y <= WorldBounds.maxY then
            set this = thistype.allocate()
            set this.u = CreateUnit(NEUTRAL_PASSIVE, DUMMYID, x, y, a * bj_RADTODEG)
            set this.dur = ANIMDUR
            set a = GetArea(level)
            set r = GetDamage(level)
        
            call SetUnitVertexColor(this.u, RED, GREEN, BLUE, TRANS)
            call SetUnitScale(this.u, SCALE, SCALE, SCALE)
            call GroupEnumUnitsInRange(G, x, y, a + ENUM_RADIUS, null)
            
            loop
                set u = FirstOfGroup(G)
                exitwhen u == null
                call GroupRemoveUnit(G, u)
                
                if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, a) then
                    call UnitDamageTarget(caster, u, r, true, false, ATK, DMG, null)
                endif
            endloop
            
            if thistype(0).next == 0 then
                call TimerStart(thistype.linkTimer, PERIOD, true, function thistype.iterate)
            endif
            
            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
        endif
        
        set caster = null
        return false
    endmethod

    private static method onLearn takes nothing returns boolean
        local unit u
        local integer level
        
        if ABILID == GetLearnedSkill() then
            set u = GetTriggerUnit()
            set level = GetUnitAbilityLevel(u, ABILID)
            if level == 1 then
                call UnitAddAbility(u, ABILIDZ)
                call UnitAddAbility(u, ABILIDX)
                call UnitAddAbility(u, ABILIDC)
            else
                call SetUnitAbilityLevel(u, ABILIDZ, level)
                call SetUnitAbilityLevel(u, ABILIDX, level)
                call SetUnitAbilityLevel(u, ABILIDC, level)
            endif
        endif

        set u = null
        return false
    endmethod

    private static method onInit takes nothing returns nothing
        local unit u
        
        call RegisterSpellEffectEvent(ABILIDZ, function thistype.onCast)
        call RegisterSpellEffectEvent(ABILIDX, function thistype.onCast)
        call RegisterSpellEffectEvent(ABILIDC, function thistype.onCast)
        call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
        
        //preload
        set u = CreateUnit(NEUTRAL_PASSIVE, DUMMYID, 0, 0, 0)
        call UnitAddAbility(u, ABILIDZ)
        call UnitAddAbility(u, ABILIDX)
        call UnitAddAbility(u, ABILIDC)
        call RemoveUnit(u)
        set u = null
    endmethod

endstruct

endlibrary




Whenever the Shadow Fiend kills a target, he stores the unfortunate soul inside of him. For each stored soul he gains 2 bonus damage until his own death releases half of them from bondage.

Level 1 - 16 damage limit.
Level 2 - 30 damage limit.
Level 3 - 46 damage limit.
Level 4 - 60 damage limit.

Passive

Note: The soul (black projectile) must reach the hero before providing its damage bonus

JASS:
library Necromastery uses Alloc, RegisterPlayerUnitEvent, T32

globals
    private integer array DAMAGEID[4]
endglobals

//===========================================================================
//                           CONFIGURABLES                        
//===========================================================================

globals
    private constant integer ABILID = 'ABNe' // raw code of ability "Necromastery"
    public constant integer DUMABILID = 'ANe0' // raw code of ability "Necromastery (Display)"
    private constant integer DUMMYID = 'nECD' // raw code of unit "Necromastery Dummy"
    
    private constant integer DAMAGE = 2 // damage bonus per soul
    
    private constant real COL = 50.0 // collision size of the soul
    private constant real SPEED = 500.0 // distance traveled by the soul per second
    private constant real TRUESPEED = SPEED * T32_PERIOD // distance traveled by the soul per period
    private constant string DEATHART = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl" // death art used upon soul expiration
    private constant string DEATHARTPOINT = "chest" // attachment point of DEATHART
endglobals

private function InitFunc takes nothing returns nothing
    local integer i = 0
    local unit u = CreateUnit(Player(13), DUMMYID, 0, 0, 0)

    set DAMAGEID[0] = 'dmg0' // raw code of ability "Damage (10000's) (Necromastery)"
    set DAMAGEID[1] = 'dmg1' // raw code of ability "Damage (1000's) (Necromastery)"
    set DAMAGEID[2] = 'dmg2' // raw code of ability "Damage (100's) (Necromastery)"
    set DAMAGEID[3] = 'dmg3' // raw code of ability "Damage (10's) (Necromastery)"
    set DAMAGEID[4] = 'dmg4' // raw code of ability "Damage (1's) (Necromastery)"
    
    //preload
    loop
        exitwhen i > 4
        call UnitAddAbility(u, DAMAGEID[i])
        set i = i + 1
    endloop
    call UnitAddAbility(u, DUMABILID)
    call RemoveUnit(u)
    set u = null
endfunction

// maximum number of souls
private function GetMaxSoul takes integer level returns integer
    if level == 1 then
        return 8
    elseif level == 2 then
        return 15
    elseif level == 3 then
        return 23
    elseif level == 4 then
        return 30
    endif
    return 0
endfunction

// amount of souls lost on death, where 1.0 = 100%
private function GetSoulLost takes integer level returns real
    return 0.50
endfunction

//===========================================================================
//                          END CONFIGURABLES                        
//===========================================================================

globals
    private constant real TRUE_COLLISION = COL * COL
endglobals

private struct Main extends array
    implement Alloc

    private unit killer
    private unit dummy

    private method destroy takes nothing returns nothing
        call RemoveUnit(this.dummy)
        call this.stopPeriodic()
        call this.deallocate()
    endmethod
    
    private static method setDamage takes unit u returns nothing
        local integer damage = DAMAGE * (GetUnitAbilityLevel(u, DUMABILID) - 1)
        local integer factor = 10000
        local integer level
        local integer i = 0
        
        loop
            exitwhen i > 4
            set level = damage / factor
            call SetUnitAbilityLevel(u, DAMAGEID[i], level + 1)
            set damage = damage - (level * factor)
            set factor = factor / 10
            set i = i + 1
        endloop
    endmethod
    
    private method periodic takes nothing returns nothing
        local integer level
        local real x = GetUnitX(this.dummy)
        local real y = GetUnitY(this.dummy)
        local real dx = GetUnitX(this.killer) - x
        local real dy = GetUnitY(this.killer) - y
        local real a
        local real height
        local real dist = dx * dx + dy * dy
        
        if dist <= TRUE_COLLISION then
            set level = GetUnitAbilityLevel(this.killer, DUMABILID)
            if level < GetMaxSoul(GetUnitAbilityLevel(this.killer, ABILID)) + 1 then
                call UnitRemoveAbility(this.killer, DUMABILID)
                call UnitAddAbility(this.killer, DUMABILID)
                call SetUnitAbilityLevel(this.killer, DUMABILID, level + 1)
                call setDamage(this.killer)
            endif
            
            call DestroyEffect(AddSpecialEffectTarget(DEATHART, this.killer, DEATHARTPOINT))
            call this.destroy()
        elseif IsUnitType(this.killer, UNIT_TYPE_DEAD) or GetUnitTypeId(this.killer) == 0 then
            call this.destroy()
        else
            set a = Atan2(dy, dx)
            call SetUnitX(this.dummy, x + TRUESPEED * Cos(a))
            call SetUnitY(this.dummy, y + TRUESPEED * Sin(a))
            set height = GetUnitFlyHeight(this.dummy)
            call SetUnitFlyHeight(this.dummy, height + ((GetUnitFlyHeight(this.killer) + 100) - height) / (dist / TRUESPEED), 0)
        endif
    endmethod
    implement T32x

    private static method onDeath takes nothing returns boolean
        local thistype this
        local unit u = GetTriggerUnit()
        local unit killer = GetKillingUnit()
        local integer ulevel = GetUnitAbilityLevel(u, ABILID)
        local integer klevel = GetUnitAbilityLevel(killer, ABILID)
        local integer i
        local real x
        local real y
        
        if ulevel > 0 then
            set i = R2I((GetUnitAbilityLevel(u, DUMABILID) - 1) * GetSoulLost(ulevel))
            call UnitRemoveAbility(u, DUMABILID)
            call UnitAddAbility(u, DUMABILID)
            call SetUnitAbilityLevel(u, DUMABILID, i + 1)
            call setDamage(u)
        elseif klevel > 0 then
            set this = this.allocate()
            set x = GetUnitX(u)
            set y = GetUnitY(u)
            set this.killer = killer
            set this.dummy = CreateUnit(Player(13), DUMMYID, x, y, Atan2(GetUnitY(this.killer) - y, GetUnitX(this.killer) - x) * bj_RADTODEG)
            
            call this.startPeriodic()
        endif
        
        set u = null
        set killer = null
        return false
    endmethod

    private static method onLearn takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer i
        
        if GetLearnedSkill() == ABILID then
            if GetUnitAbilityLevel(u, DUMABILID) == 0 then
                call UnitAddAbility(u, DUMABILID)
                
                set i = 0
                loop
                    exitwhen i > 4
                    call UnitAddAbility(u, DAMAGEID[i])
                    set i = i + 1
                endloop
            endif
        endif
        
        set u = null
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
        call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
        
        call InitFunc()
    endmethod
endstruct

endlibrary




The presence of such a horrible creature terrifies nearby enemies, reducing their armor.

Level 1 - 2 armor reduction.
Level 2 - 3 armor reduction.
Level 3 - 4 armor reduction.
Level 4 - 5 armor reduction.

Passive

Note: No code




Summons evil spirits around you dealing damage to units in the area. Number of spirits is related to the number of souls stored and the movement/damage reduction is related to the distance from the Shadow Fiend. Lowers movement speed and damage of nearby units. The closer the units are the greater the effect. Reduction lasts 5 seconds.

Level 1 - 80 damage for each line, 15% reduction.
Level 2 - 120 damage for each line, 20% reduction.
Level 3 - 160 damage for each line, 25% reduction.

Cast Range: Self
Target Type: Instant
Cast Time: 1 second
Cooldown: 120/110/100 seconds

Note: I believe DotA actually uses multiple carrion swarms for Requiem of Souls. However, for configuration purposes and better visual effects, I did not. Plus, in DotA, kills by Requiem of Souls do not give souls, as the killing unit is actually a dummy unit. My approach fixes this too.

JASS:
library RequiemOfSouls uses Alloc, SpellEffectEvent, T32, WorldBounds, Necromastery

//===========================================================================
//                           CONFIGURABLES                        
//===========================================================================

globals
    private constant integer ABILID = 'ABRS' // raw code of ability "Requiem of Souls"
    private constant integer DUMABILID = 'ARS0' // raw code of ability "Requiem of Souls (Reduction)"
    private constant integer DUMMYID = 'rOSD' // raw code of unit "Requiem of Souls Dummy"
    private constant integer CASTERID = 'cAST' // raw code of unit "Caster Dummy"
    
    private constant integer SOULCOUNT = 2 // number of souls required to create a "line"
    private constant real SOULAOE = 150.0 // area of effect of each "line"
    private constant real SPEED = 1000.0 // distance travelled by "line" per second
    private constant real TRUESPEED = SPEED * T32_PERIOD // distance travelled by "line" per period
    private constant real REDUCTIONAOE = 675.0 // area of effect where units will be affected by damage and move speed reduction
    private constant real INTERVAL = 200.0 // distance interval where effect is spawned
    private constant string EFFECT = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" // effect spawned every interval
    
    private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
    
    private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
    private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
endglobals

private function GetDamage takes integer level returns real
    return 40.0 + (40.0 * level) // damage dealt per line of soul
endfunction

private function GetArea takes integer level returns real
    return 1350.0 + (25.0 * level) // area of effect
endfunction

// target types allowed for dealing damage
private function GetFilter takes unit caster, unit target returns boolean
    return /*
    */ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
    */ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
    */ not IsUnitType(target, UNIT_TYPE_STRUCTURE) // target is not a structure
endfunction

//===========================================================================
//                          END CONFIGURABLES                        
//===========================================================================

globals
    private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
    
    private group G = bj_lastCreatedGroup
endglobals

private struct Main extends array
    implement Alloc

    private unit u
    private unit dummy
    private group g
    private real dmg
    private real dist
    private real a
    private real interval
    private static unit castDummy
    
    private method destroy takes nothing returns nothing
        call RemoveUnit(this.dummy)
        call DestroyGroup(this.g)
        call this.stopPeriodic()
        call this.deallocate()
    endmethod
    
    private method periodic takes nothing returns nothing
        local unit u
        local real x = GetUnitX(this.dummy)
        local real y = GetUnitY(this.dummy)
        
        if this.dist <= 0 then
            call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
            call this.destroy()
        else
            if this.interval <= 0 then
                call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
                set this.interval = INTERVAL
            else
                set this.interval = this.interval - TRUESPEED
            endif
            
            set this.dist = this.dist - TRUESPEED
            set x = x + TRUESPEED * Cos(this.a)
            set y = y + TRUESPEED * Sin(this.a)
            
            if x >= WorldBounds.minX and x <= WorldBounds.maxX and y >= WorldBounds.minY and y <= WorldBounds.maxY then
                call SetUnitX(this.dummy, x)
                call SetUnitY(this.dummy, y)
                call GroupEnumUnitsInRange(G, x, y, SOULAOE + ENUM_RADIUS, null)
                
                loop
                    set u = FirstOfGroup(G)
                    exitwhen u == null
                    call GroupRemoveUnit(G, u)
                    
                    if GetFilter(this.u, u) and not IsUnitInGroup(u, this.g) then
                        call UnitDamageTarget(this.u, u, this.dmg, true, false, ATK, DMG, null)
                        call GroupAddUnit(this.g, u)
                    endif
                endloop
            endif
        endif
    endmethod
    implement T32x
    
    private static method onCast takes nothing returns boolean
        local thistype this
        local unit caster = GetTriggerUnit()
        local unit u
        local integer level = GetUnitAbilityLevel(caster, ABILID)
        local integer i = (GetUnitAbilityLevel(caster, Necromastery_DUMABILID) - 1) / SOULCOUNT
        local real a = 0
        local real aRate
        local real x
        local real y
    
        if i > 0 then
            set aRate = (2 * bj_PI) / i
        endif
        set x = GetUnitX(caster)
        set y = GetUnitY(caster)
        
        loop
            exitwhen i == 0
            set this = thistype.allocate()
            set this.u = caster
            set this.dummy = CreateUnit(GetTriggerPlayer(), DUMMYID, x, y, a)
            set this.g = CreateGroup()
            set this.dmg = GetDamage(level)
            set this.dist = GetArea(level)
            set this.a = a
            set this.interval = INTERVAL
            
            call this.startPeriodic()
            set a = a + aRate
            set i = i - 1
        endloop
        
        call SetUnitAbilityLevel(castDummy, DUMABILID, level)
        call GroupEnumUnitsInRange(G, x, y, REDUCTIONAOE + ENUM_RADIUS, null)

        loop
            set u = FirstOfGroup(G)
            exitwhen u == null
            call GroupRemoveUnit(G, u)
            
            if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, REDUCTIONAOE) then
                call IssueTargetOrder(castDummy, "cripple", u)
            endif
        endloop

        set caster = null
        return false
    endmethod

    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ABILID, function thistype.onCast)
        
        set castDummy = CreateUnit(NEUTRAL_PASSIVE, CASTERID, 0, 0, 0)
        call UnitAddAbility(castDummy, DUMABILID)
    endmethod
endstruct

endlibrary



Credits
Sevion - Alloc
Magtheridon96 - RegisterPlayerUnitEvent
Bribe - SpellEffectEvent
Jesus4Lyf - Timer32
Nestharus - WorldBounds


Changelogs

- Initial relase


- Optimized codes
- Made Attack Type, Weapon Type and Damage Type configurable for Shadowraze and Requiem of Souls


- Rewrote codes using Timer32 and GroupUtils, instead of KT2 and Recycle


- Optimized codes using GTrigger
- Damage is now required


- Removed Damage, GroupUtils and GTrigger
- Now requires Alloc, RegisterPlayerUnitEvent, SpellEffectEvent and WorldBounds

Shadowraze
- Changed from scope to library
- Replaced UnitAlive native with UNIT_TYPE_DEAD
- Dummy expiration now uses a timer rather than dynamic triggers
- Added a check for creating dummies out-of-bound, to prevent crashes

Necromastery
- Changed from scope to library
- Added a check to determine if the killer is alive/exists at the time when the soul travels

Requiem of Souls
- Changed from scope to library
- Replaced UnitAlive native with UNIT_TYPE_DEAD
- Added a check for moving dummies out-of-bound, to prevent crashes
- Now uses a single caster dummy rather than creating a dummy for every unit


Feedback will be appreciated.

Keywords:
shadowfiend, nevermore, shadowraze, necromastery, presence of the dark lord, requiem of souls, shadow
Contents

Shadowfiend Spellpack v1.4 (Map)

Reviews
13 Nov 2011 Bribe: Approved. Another good resource.

Moderator

M

Moderator

13 Nov 2011
Bribe: Approved. Another good resource.
 
Level 9
Joined
Aug 21, 2010
Messages
362
First...Command aura? Ain't it suppose to be Devotion aura? And another dota spell pack? Souls don't decrease when I used requiem of souls and when the shadow fiend is dead... it dont automatically select him because your order of the trigger is wrong...how can you select the hero before it is revived?
 
Last edited:
Level 9
Joined
Dec 3, 2010
Messages
162
First...Command aura? Ain't it suppose to be Devotion aura? And another dota spell pack? Souls don't decrease when I used requiem of souls and when the shadow fiend is dead... it dont automatically select him because your order of the trigger is wrong...how can you select the hero before it is revived?

Oops, I meant Devotion Aura. I did use Devotion Aura, just worded it incorrectly when posting this. Requiem of Souls isn't supposed to reduce souls. The description didn't said so. Plus, yes, I did screw up the selection hero part. But that isn't even part of the spell? I wish you would stick to commenting on the spell code, rather than other unnecessary codes. Thanks.
 
Level 9
Joined
Aug 21, 2010
Messages
362
First impression are important,it shows how professional or neat u are :p i cant code in jass or vjass so i cant help u there,and u said it was shadow field from dota so the requiem of souls should reduce your souls...
 
Level 2
Joined
Nov 24, 2008
Messages
25
^
^ But Requiem of Souls DOESN'T reduce the number of souls...
Anyways, units killed by Requiem of Souls don't give You additional souls.

Edit: Ninja'ed by Barathum.
 
Level 5
Joined
Oct 24, 2007
Messages
90
I don't play DotA, so I was impressed by the originality of these spells. I guess that doesn't count anymore, though. Despite that, these spells are well made and coded. I gave the coding an overview, and noted some minor things you could change (nothing very important to speed and efficiency, really):
JASS:
set e = AddSpecialEffect(EFFECT, x, y)
call DestroyEffect(e)
You do this eveytime you spawn a special effect, in the three spells. Why? Why not just create it and destroy it in the same line and save a local variable?
JASS:
call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
In the Shadowraze spell:
JASS:
set a = GetUnitFacing(u)
set x = GetUnitX(u) + dist * Cos(a * bj_DEGTORAD)
set y = GetUnitY(u) + dist * Sin(a * bj_DEGTORAD)
You can do this instead:
JASS:
set a = GetUnitFacing(u) * bj_DEGTORAD
set x = GetUnitX(u) + dist * Cos(a)
set y = GetUnitY(u) + dist * Sin(a)
JASS:
public constant integer DUMABILID = 'ANe0' // raw code of ability "Necromastery (Visual)"
I think you mean "Necromastery (Display)" (lol at the little details I find).
Also, I suggest you make attack type, damage type, and weapon type of the spells' damage configurable in the setup section.

All in all, I really liked this spellpack. I vote for approval :thumbs_up:
 
Level 2
Joined
Oct 26, 2010
Messages
10
^
^ But Requiem of Souls DOESN'T reduce the number of souls...
Anyways, units killed by Requiem of Souls don't give You additional souls.

1st is true, 2nd is false
The spell pack, as far as I can see, is MUI/lagless, but it is a bit uneeded to code with additional libraries since all these could've been done easily even with GUI (though Requiem will cost lags then)

Edit: My bad. Necromastery here is DotA 6.69 and above, meaning the missle thing can't be done easily with GUI. So nevermind on that part. Good pack overall

Edit2: Since you use trigger with damaged groups for Requiem, it somewhat destroys the point of Requiem's Carrion Swarm stacking, so that should be noted. (example is when someone is hit by Carrion, then blink infront of it to be hit again)
 
Level 2
Joined
Oct 26, 2010
Messages
10
@Edit2 - almost all spells here doesn't hit units more than once, so I think that is okay...

and he already wrote this when he first uploaded this spell (on the code of RoS):

I believe DoTA actually uses multiple carrion swarms for Requiem of Souls. However, for configuration purposes and better visual effects, I did not.

I've noticed. However, I'm just trying to point out what impact it has on actual gameplay,
I think that should be noted
Of course basing it off Carrion Swarm would require other types of configuration (essentially making it a level based dummy unit skill), but it could be done just as easily
 
but its better to make it this way so you can easily customize the damage if someone would use this in a map which is not a copy of DotA...

example: I would make the DamagePerSoul based on int... with this config, its just a simple code edit. if ur using carrion, then its impossible...

Anyway, I really hate DotA based spells but for this one I will vote for approval for making the spells easily configurable and changeable.
 
Level 9
Joined
Dec 3, 2010
Messages
162
I don't play DotA, so I was impressed by the originality of these spells. I guess that doesn't count anymore, though. Despite that, these spells are well made and coded. I gave the coding an overview, and noted some minor things you could change (nothing very important to speed and efficiency, really):
JASS:
set e = AddSpecialEffect(EFFECT, x, y)
call DestroyEffect(e)
You do this eveytime you spawn a special effect, in the three spells. Why? Why not just create it and destroy it in the same line and save a local variable?
JASS:
call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
In the Shadowraze spell:
JASS:
set a = GetUnitFacing(u)
set x = GetUnitX(u) + dist * Cos(a * bj_DEGTORAD)
set y = GetUnitY(u) + dist * Sin(a * bj_DEGTORAD)
You can do this instead:
JASS:
set a = GetUnitFacing(u) * bj_DEGTORAD
set x = GetUnitX(u) + dist * Cos(a)
set y = GetUnitY(u) + dist * Sin(a)
JASS:
public constant integer DUMABILID = 'ANe0' // raw code of ability "Necromastery (Visual)"
I think you mean "Necromastery (Display)" (lol at the little details I find).
Also, I suggest you make attack type, damage type, and weapon type of the spells' damage configurable in the setup section.

All in all, I really liked this spellpack. I vote for approval :thumbs_up:

Thanks for the feedback. Will change the necessary things.

I've noticed. However, I'm just trying to point out what impact it has on actual gameplay,
Of course basing it off Carrion Swarm would require other types of configuration (essentially making it a level based dummy unit skill), but it could be done just as easily

After I implement to Attack type and damage type to be configurable, you could basically change this spell to be physical, magical or universal, which Carrion Swarm doesn't provide. Plus, as mentioned, you could easily change the damage to depend on stats like STR, which Carrion Swarm, again, does not provide. And if people really do mind the fact about Carrion Swarm hitting twice, after blinking, I code it so that it imitates that effect, if wanted.

RANDOM QUESTION THOUGH: whats up with the random green box next to the shadowfiend in WE?

It's a pre-loader. It's just to pre-load abilities to prevent mini-spikes when you add the abilities for the first time.
 
Level 2
Joined
Nov 24, 2008
Messages
25
1st is true, 2nd is false

2nd is true aswell, really;
I mean, in DotA, killing units with RoS doesn't give You souls.
I've checked it a few times with -wtf.

Maybe iAyanami actually forgot about it and You still gain souls by RoS kills.
But then, it's not the true Requiem of Souls.
 
Level 9
Joined
Dec 3, 2010
Messages
162
2nd is true aswell, really;
I mean, in DotA, killing units with RoS doesn't give You souls.
I've checked it a few times with -wtf.

Maybe iAyanami actually forgot about it and You still gain souls by RoS kills.
But then, it's not the true Requiem of Souls.

Actually, didn't have any idea that RoS doesn't give souls. But yeah, it's not the real RoS anyways. I believe the real RoS uses multiple Carrion Swarms in a circular manner.

just a detail , because I liked the whole spell pack: Shadowraze does damage at a HUGE area of effect and the damage is reduced by the distance from the effect.Requiem of souls uses some dummies and moves them, doesn't create dummies. I will rate this with a 5/5 though.

Shadowraze? Shadowraze has an area of effect of 250 and a fixed damage. I think you meant Requiem of Souls? RoS actually uses Carrion Swarm in a circular manner, I think. And I do move dummy units. The effect that are created are special effects, not dummies, just for extra eye candy. The reason why closer units receive more damage is because they're hit by more "Lines" that are created based on number of souls that you have. 2 souls creates 1 line. Each line dealing 160 damage at level 3.

Thanks for the feedback guys :3
 
Level 9
Joined
Dec 3, 2010
Messages
162
Maybe iAyanami actually forgot about it and You still gain souls by RoS kills.
But then, it's not the true Requiem of Souls.

Actually I found out the reason for this. I think it's more of a bug than an intended effect. RoS does use Carrion Swarm/Shockwave in an circular angle. This means that the dummy units will have to cast the Carrion Swarm/Shockwave. Thus, when a unit dies due to RoS, the killer is actually the dummy, not the Shadowfiend, thus Nevermore doesn't gain souls when units are killed by RoS.
 
Level 2
Joined
Oct 26, 2010
Messages
10
Actually I found out the reason for this. I think it's more of a bug than an intended effect. RoS does use Carrion Swarm/Shockwave in an circular angle. This means that the dummy units will have to cast the Carrion Swarm/Shockwave. Thus, when a unit dies due to RoS, the killer is actually the dummy, not the Shadowfiend, thus Nevermore doesn't gain souls when units are killed by RoS.

I thought it was the damage transistion for dummy units thing, like with some wards with marker. tested, I was wrong, my apologies
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
This is good I guess but I don't understand the "hardcoded" about the aura. It's just object editor and a bit irony.

You should mention that you are declaring the UnitAlive native. Also you declare it in each trigger why? It's only needed in one (declaration).

You should add support for GroupUtils as Recycle is not as common as GroupUtils. Also if you add this support, you should make static ifs for the group enums too, to GroupEnumUnitsInArea.

Your enum group in shadowraze should probably be renamed to Group as capitalized letters are used for constants (not a big deal anyway).

In ROS and necromastery you are using 0.03 as period, make it changeable among the constants. Also the caluclation SPEED * 0.03 should be set into a constant as well. Just make it among the globals that are supposed not to be changed.

You know that Shadowraze is damaging buildings?

Also shouldn't it be better to preload these abilities you add to the hero? Doesn't it create a small lagg to add it the first time.

In necromastery you are creating 3 triggers but you aren't using this one:

local trigger t3 = CreateTrigger()

Still this problem in the onDestroy method in Necromastery

DestroyEffect(e)

into this

call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl", GetUnitX(this.soul), GetUnitY(this.soul)))

Also this effect should be stored into a constant so you can change it easier.

In ROS

why aren't you using the constant in the ondestroy method?

the struct member interval could be initialized as 0

real interval into
real interval = 0.

and also I think damagegroup should be renamed to damagedgroup :p

else I like this, especially the triggered ROS, good work.
 
Level 9
Joined
Jun 25, 2009
Messages
427
Edit: My bad. Necromastery here is DotA 6.69 and above, meaning the missle thing can't be done easily with GUI. So nevermind on that part. Good pack overall

Yes, yes it is possible, i've made such things for other purposes, but the computer is in the village now so i can't show you any REAL proof.

Yeah, it's GUI and MUST be MUI :)

I believe DoTA actually uses multiple carrion swarms for Requiem of Souls. However, for configuration purposes and better visual effects, I did not.

Actually it could be carrion swarms, but seeing the ground deformation like shockwave i could argue that it is multiple shockwaves. (Though not all the range, since those souls are dummy units and shockwave is a dummy with no model)

Anyway, back to the pack. Actually it is good, i mean actually well made.

And yeah, it's possible to make it GUI (just for the record)
Voting for approval
 
Level 9
Joined
Dec 3, 2010
Messages
162
Thanks for the long feedback baassee. And about the hardcoded aura, it was just added for "Completing" the Shadowfiend Spellpack. About the unit alive declaration, if the person decides to only import part of the spell, it could be a problem, thus I declared in all of the triggers. I left the "GROUP" in capitals as that's a group solely used for Enumerations, so acting like a "constant".

@ Tiche3
Well, it can be done in GUI, that's for sure. But GUI is generally harder to configure compared to vJASS. Plus, GUI in general is pretty inefficient to start off with.
 
Last edited:
ahh... from my experience hardcoded is used for things that are not easily changeable in the top of the code... ^_^

example:

JASS:
globals
  integer time = 0
endglobals
   
  //.01 is hardcoded
  call TimerStart(CreateTimer(), 0.1, true, null)
  //time is not
  call TimerStart(CreateTimer(), time, true, null)

anyway, hope to see this spellpack approved.
 
Level 2
Joined
Oct 26, 2010
Messages
10
Yes, yes it is possible, i've made such things for other purposes, but the computer is in the village now so i can't show you any REAL proof.

Yeah, it's GUI and MUST be MUI :)

I know it's possible, I've made one. I'm just saying it's not entirely easily done (and coding it with VJass already makes adding a GUI version redundant)
 
Level 2
Joined
Jan 7, 2010
Messages
19
awesome... my favourite hero in DotA... XD
same as the original Shadowfiend in DotA... =D
anyway, if possible, can u change from JASS to GUI... if can, thanks... if no, nevermind...
anyway, this is awesome... nice... :thumbs_up:
 
Level 9
Joined
Dec 3, 2010
Messages
162
awesome... my favourite hero in DotA... XD
same as the original Shadowfiend in DotA... =D
anyway, if possible, can u change from JASS to GUI... if can, thanks... if no, nevermind...
anyway, this is awesome... nice... :thumbs_up:

Changing vJASS to GUI means rewriting the whole thing. Plus, I don't really like coding in GUi anymore, it's inefficient. Especially for spells.
 
Level 2
Joined
Jan 7, 2010
Messages
19
Yeah, i know GUI it's kinda not efficient..., but, i know nothing about vJASS... :vw_wtf: ... i still can't understand how to import vJASS spells into my map..., eventhough, i read the info... LOL... :vw_sleep: ... can you explain it to me, step by step... :grin:
 
Level 9
Joined
Dec 3, 2010
Messages
162
Yeah, i know GUI it's kinda not efficient..., but, i know nothing about vJASS... :vw_wtf: ... i still can't understand how to import vJASS spells into my map..., eventhough, i read the info... LOL... :vw_sleep: ... can you explain it to me, step by step... :grin:

You mean how to import this spell? There's a detailed READ ME in the map. If you're talking about other vJASS spells, it depends. But one thing for sure is that you need JASS NewGen Pack.
 
Level 9
Joined
Dec 3, 2010
Messages
162
dude your raze have to be black so first create dummy for razes make it black 0-0-0 then rework razes ;x

Is it really necessary to use a dummy unit for an effect? It looks pretty much the same. You can change the effect to what you want. I mean, a greener effect isn't going to ruin the whole spell. I'm not trying to directly replicate DoTA's Shadowfiend. And creating a dummy unit for such a simple effect is kind of an overkill in my opinion.
 
though using a dummy unit means that you can easily resize the special effect by modifying the size of the dummy unit thru triggers something...

but I dont think the idea to create another dummy for the effect just to modify its color is good since you could do that in Magos. And since you already have a dummy unit for RoS you could just create one when the spell is casted and attach the effect to the dummy caster just for the sake of easy rescaling of the effect using triggers...

and the effect scaling is much much more useful than a simple recolor...
 
Level 10
Joined
Aug 21, 2010
Messages
316
I've noticed. However, I'm just trying to point out what impact it has on actual gameplay,
Of course basing it off Carrion Swarm would require other types of configuration (essentially making it a level based dummy unit skill), but it could be done just as easily
Again something about dota hmm .... here's the original version.After processing trigger looks just like this. Nothing special.

JASS:
// 'A0HE' = Requiem of Souls (Shadow Fiend : Nevermore)
// 'A0CQ' = Necromastery Effect
// 'e00C' = Stop looking at me swan!!
// 'A0HG' = Requiem of Souls Effect
// 'Aloc' = Locust (Dummy,ItemHolder,Vision Dummy,Dummy Ice,Lion Roar Effect,...)

function Trig_Requiem_of_Souls_Cast_Conditions takes nothing returns boolean
	if(not(GetSpellAbilityId()=='A0HE'))then
		return false
	endif
	return true
endfunction

function Trig_Requiem_of_Souls_Cast_Actions takes nothing returns nothing
	local integer lt5=GetUnitAbilityLevelSwapped('A0CQ',GetTriggerUnit())
	local integer lt6
	local integer lEQ
	local unit lfo=GetTriggerUnit()
	local location liD=GetUnitLoc(GetTriggerUnit())
	local location lng
	set lt5=lt5/2
	set lt6=1
	set lEQ=lt5
	loop
		exitwhen lt6>lEQ
		set lng=PolarProjectionBJ(liD,50.,(I2R(lt6)*(360/lt5)))
		call CreateNUnitsAtLoc(1,'e00C',GetOwningPlayer(lfo),liD,bj_UNIT_FACING)
		call UnitAddAbility(bj_lastCreatedUnit,'A0HG')
		call SetUnitAbilityLevelSwapped('A0HG',bj_lastCreatedUnit,GetUnitAbilityLevelSwapped('A0HE',GetTriggerUnit()))
		call UnitApplyTimedLifeBJ(2.,'BTLF',bj_lastCreatedUnit)
		call IssuePointOrderByIdLoc(bj_lastCreatedUnit,OrderId("carrionswarm"),lng)
		call SetUnitPathing(bj_lastCreatedUnit,false)
		call SetUnitInvulnerable(bj_lastCreatedUnit,true)
		call UnitAddAbility(bj_lastCreatedUnit,'Aloc')
		call RemoveLocation(lng)
		set lt6=lt6+1
	endloop
	call RemoveLocation(liD)
endfunction

function StartTrigger_Requiem_of_Souls_Cast takes nothing returns nothing
	set gg_trg_Requiem_of_Souls_Cast=CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(gg_trg_Requiem_of_Souls_Cast,EVENT_PLAYER_UNIT_SPELL_EFFECT)
	call TriggerAddCondition(gg_trg_Requiem_of_Souls_Cast,Condition(function Trig_Requiem_of_Souls_Cast_Conditions))
	call TriggerAddAction(gg_trg_Requiem_of_Souls_Cast,function Trig_Requiem_of_Souls_Cast_Actions)
endfunction
JASS:
// 'A0HE' = Requiem of Souls (Shadow Fiend : Nevermore)
// 'A04R' = Marker (Nether Ward 4,Lightning Bolter,Nether Ward 3,Nether Ward 2,Vengeance Death caster,...)
// 'o003' = Spin Web
// 'e00C' = Stop looking at me swan!!
// 'A0HH' = Requiem of Souls Cripple Far
// 'Aloc' = Locust (Dummy,ItemHolder,Vision Dummy,Dummy Ice,Lion Roar Effect,...)
// 'A0HJ' = Requiem of Souls Cripple Moderate
// 'A0HI' = Requiem of Souls Cripple Close

function Trig_Requiem_of_Souls_Effect_Conditions takes nothing returns boolean
	if(not(GetSpellAbilityId()=='A0HE'))then
		return false
	endif
	return true
endfunction

function Requiem_of_Souls_Slow_Filter takes nothing returns boolean
	if(IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE))then
		return false
	endif
	if(GetUnitAbilityLevelSwapped('A04R',GetFilterUnit())==1)then
		return false
	endif
	if(IsUnitAliveBJ(GetFilterUnit())==false)then
		return false
	endif
	if(GetUnitTypeId(GetFilterUnit())=='o003')then
		return false
	endif
	if(IsUnitEnemy(GetFilterUnit(),GetTriggerPlayer())==false)then
		return false
	endif
	if(GetTriggerUnit()==GetFilterUnit())then
		return false
	endif
	if(IsUnitVisible(GetFilterUnit(),GetTriggerPlayer())==false)then
		return false
	endif
	return true
endfunction

function Requiem_Range700 takes nothing returns nothing
	local unit lfo=GetTriggerUnit()
	local location liD=GetUnitLoc(lfo)
	call CreateNUnitsAtLoc(1,'e00C',GetOwningPlayer(lfo),liD,bj_UNIT_FACING)
	call UnitAddAbility(bj_lastCreatedUnit,'A0HH')
	call SetUnitAbilityLevelSwapped('A0HH',bj_lastCreatedUnit,GetUnitAbilityLevelSwapped('A0HE',GetTriggerUnit()))
	call UnitApplyTimedLifeBJ(2.,'BTLF',bj_lastCreatedUnit)
	call IssueTargetOrderById(bj_lastCreatedUnit,OrderId("cripple"),GetEnumUnit())
	call SetUnitPathing(bj_lastCreatedUnit,false)
	call SetUnitInvulnerable(bj_lastCreatedUnit,true)
	call UnitAddAbility(bj_lastCreatedUnit,'Aloc')
	call RemoveLocation(liD)
endfunction

function Requiem_Range400 takes nothing returns nothing
	local unit lfo=GetTriggerUnit()
	local location liD=GetUnitLoc(lfo)
	call CreateNUnitsAtLoc(1,'e00C',GetOwningPlayer(lfo),liD,bj_UNIT_FACING)
	call UnitAddAbility(bj_lastCreatedUnit,'A0HH')
	call SetUnitAbilityLevelSwapped('A0HJ',bj_lastCreatedUnit,GetUnitAbilityLevelSwapped('A0HE',GetTriggerUnit()))
	call UnitApplyTimedLifeBJ(2.,'BTLF',bj_lastCreatedUnit)
	call IssueTargetOrderById(bj_lastCreatedUnit,OrderId("cripple"),GetEnumUnit())
	call SetUnitPathing(bj_lastCreatedUnit,false)
	call SetUnitInvulnerable(bj_lastCreatedUnit,true)
	call UnitAddAbility(bj_lastCreatedUnit,'Aloc')
	call RemoveLocation(liD)
endfunction

function Requiem_Range200 takes nothing returns nothing
	local unit lfo=GetTriggerUnit()
	local location liD=GetUnitLoc(lfo)
	call CreateNUnitsAtLoc(1,'e00C',GetOwningPlayer(lfo),liD,bj_UNIT_FACING)
	call UnitAddAbility(bj_lastCreatedUnit,'A0HH')
	call SetUnitAbilityLevelSwapped('A0HI',bj_lastCreatedUnit,GetUnitAbilityLevelSwapped('A0HE',GetTriggerUnit()))
	call UnitApplyTimedLifeBJ(2.,'BTLF',bj_lastCreatedUnit)
	call IssueTargetOrderById(bj_lastCreatedUnit,OrderId("cripple"),GetEnumUnit())
	call SetUnitPathing(bj_lastCreatedUnit,false)
	call SetUnitInvulnerable(bj_lastCreatedUnit,true)
	call UnitAddAbility(bj_lastCreatedUnit,'Aloc')
	call RemoveLocation(liD)
endfunction

function Trig_Requiem_of_Souls_Effect_Actions takes nothing returns nothing
	local location liD=GetUnitLoc(GetTriggerUnit())
	local unit lfo=GetTriggerUnit()
	local group lEw
	set lEw=GetUnitsInRangeOfLocMatching(700,liD,Condition(function Requiem_of_Souls_Slow_Filter))
	call ForGroup(lEw,function Requiem_Range700)
	set lEw=GetUnitsInRangeOfLocMatching(400,liD,Condition(function Requiem_of_Souls_Slow_Filter))
	call ForGroup(lEw,function Requiem_Range400)
	set lEw=GetUnitsInRangeOfLocMatching(200,liD,Condition(function Requiem_of_Souls_Slow_Filter))
	call ForGroup(lEw,function Requiem_Range200)
	call RemoveLocation(liD)
	call DestroyGroup(lEw)
endfunction

function StartTrigger_Requiem_of_Souls_Effect takes nothing returns nothing
	set gg_trg_Requiem_of_Souls_Effect=CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(gg_trg_Requiem_of_Souls_Effect,EVENT_PLAYER_UNIT_SPELL_EFFECT)
	call TriggerAddCondition(gg_trg_Requiem_of_Souls_Effect,Condition(function Trig_Requiem_of_Souls_Effect_Conditions))
	call TriggerAddAction(gg_trg_Requiem_of_Souls_Effect,function Trig_Requiem_of_Souls_Effect_Actions)
endfunction

From version 6.60
When all aspects, it seems the author[ice frog] is not so much bother about whether he be a perfect trigger
 
Last edited:
LOL Someone needs to teach IceFrog about "efficiency"
I think he couldn't care less about efficiency because he's using
Vexorian's Anti-BJ feature.

I finished lining most of the code from v6.72 and it seems that the code hasn't
changed. There are no BJs, but the inefficient Condition functions reveal the lack
of change in his spells from v6.60 to v6.72 :/
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Requiem of Souls is an underpowered version of "Stomp of Corruption". And it's the only memorable spell in the pack.

Things I liked:

- Spells all fit the same theme
- Passive ability can track the number of units killed by the hero

Things I didn't like:

- You need to preload the soul effect because it doesn't display properly when cast the firsrt time
- Passive ability only goes to level 30.
- You use levels to track the passive ability - this slows down map loading time a lot! Perhaps if you clicked on the icon it would display some text which showed you how many units you had killed, this way it loads faster and can be unlimited.
- All-offensive spells. Maybe a summon would give better synergy than what you have.
- Three icons for one spell is overkill, I recommend doing the spell differently: shoot the thing out of the caster, damaging all units on its way, thereby requiring only one icon.
- It's really not original. Stomp of Corruption already does the same effect but with knockback.
 
Level 9
Joined
Dec 3, 2010
Messages
162
Requiem of Souls is an underpowered version of "Stomp of Corruption". And it's the only memorable spell in the pack.

Things I liked:

- Spells all fit the same theme
- Passive ability can track the number of units killed by the hero

Things I didn't like:

- You need to preload the soul effect because it doesn't display properly when cast the firsrt time
- Passive ability only goes to level 30.
- You use levels to track the passive ability - this slows down map loading time a lot! Perhaps if you clicked on the icon it would display some text which showed you how many units you had killed, this way it loads faster and can be unlimited.
- All-offensive spells. Maybe a summon would give better synergy than what you have.
- Three icons for one spell is overkill, I recommend doing the spell differently: shoot the thing out of the caster, damaging all units on its way, thereby requiring only one icon.
- It's really not original. Stomp of Corruption already does the same effect but with knockback.

Well, yeah the spell can't be original. It's a re-made skill from DotA xD So, originally is killed in that aspect. And about the soul effect, which one are you referring to? Necromastery or Requiem of Souls?
 
Top