Spellpack Nevermore, the Shadowfiend

Ayanami

칼리
Introduction
Decided to make Shadowfiend's spell in vJASS for fun.

Requirements
- Timer32
- GroupUtils

The spells:
  • 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.2                       
//                            BY Ayanami                            
//==============================================================================

//==============================================================================
//                            REQUIREMENTS                                      
//==============================================================================
//
// - vJASS Compiler (NewGen)
// - Timer32                                                              
// - GroupUtils                                                                  
//                                                            
//==============================================================================

//==============================================================================
//                           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
//
//==============================================================================



Spells

Shadowraze

Description:
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

Screenshot:


Code:
JASS:

scope Shadowraze initializer OnInit // requires GroupUtils

//===========================================================================
//                           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 PRELOADID = 'prel' // raw code of unit "Preloader"
    
    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 attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
    private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
    private constant weapontype WEP = WEAPON_TYPE_WHOKNOWS // weapon type of damage
endglobals

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

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

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

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

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

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

native UnitAlive takes unit id returns boolean

globals
    private unit Caster
    private real Damage
endglobals

private function OnRemove takes nothing returns boolean
    local trigger t = GetTriggeringTrigger()
    
    call RemoveUnit(GetTriggerUnit())
    call TriggerClearConditions(t)
    call DestroyTrigger(t)
    set t = null
    return false
endfunction

private function FilterFunc takes nothing returns boolean
    local unit u = GetFilterUnit()
    
    if IsUnitEnemy(u, GetOwningPlayer(Caster)) and UnitAlive(u) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
        call UnitDamageTarget(Caster, u, Damage, true, false, ATK, DMG, WEP)
    endif
    set u = null
    return false
endfunction

private function Actions takes nothing returns boolean
    local trigger t
    local unit u
    local integer spellid = GetSpellAbilityId()
    local integer level
    local real range
    local real a
    local real x
    local real y
    
    if spellid == ABILIDZ or spellid == ABILIDX or spellid == ABILIDC then
        set Caster = GetTriggerUnit()
        set level = GetUnitAbilityLevel(Caster, ABILID)
        set Damage = GetDamage(level)
        
        if spellid == ABILIDZ then
            set range = GetRangeZ(level)
        elseif spellid == ABILIDX then
            set range = GetRangeX(level)
        else
            set range = GetRangeC(level)
        endif
        
        set a = GetUnitFacing(Caster) * bj_DEGTORAD
        set x = GetUnitX(Caster) + range * Cos(a)
        set y = GetUnitY(Caster) + range * Sin(a)
        set u = CreateUnit(GetOwningPlayer(Caster), DUMMYID, x, y, a * bj_RADTODEG)
        call SetUnitVertexColor(u, RED, GREEN, BLUE, TRANS)
        call SetUnitScale(u, SCALE, SCALE, SCALE)
        call UnitApplyTimedLife(u, 'BTLF', ANIMDUR)
        set t = CreateTrigger()
        call TriggerRegisterDeathEvent(t, u)
        call TriggerAddCondition(t, Condition(function OnRemove))
        call GroupEnumUnitsInArea(ENUM_GROUP, x, y, GetArea(level), Filter(function FilterFunc))
    endif
    set t = null
    set u = null
    return false
endfunction

private function Learn takes nothing returns boolean
    local unit u
    local integer level
    
    if GetLearnedSkill() == ABILID 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
endfunction

private function OnInit takes nothing returns nothing
    local trigger t = CreateTrigger()
    local unit u = CreateUnit(Player(13), PRELOADID, 0, 0, 0)
    
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Actions))
    set t = null
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(t, Condition(function Learn))
    set t = null
    
    //preload
    call UnitAddAbility(u, ABILIDZ)
    call UnitAddAbility(u, ABILIDX)
    call UnitAddAbility(u, ABILIDC)
    call RemoveUnit(CreateUnit(Player(13), DUMMYID, 0, 0, 0))
    call RemoveUnit(u)
    set u = null
endfunction

endscope


Necromastery

Description:
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 souls (black projectile) must reach the hero in before providing its bonus damage.

Screenshot:

Code:
JASS:

scope Necromastery initializer SetUp // requires Timer32

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 PRELOADID = 'prel' // raw code of unit "Preloader"
    
    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 SetUp takes nothing returns nothing
    local integer i = 0
    local unit u = CreateUnit(Player(13), PRELOADID, 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(CreateUnit(Player(13), DUMMYID, 0, 0, 0))
    call RemoveUnit(u)
    set u = null
endfunction

private function GetMaxSoul takes integer level returns integer // maximum number of souls
    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

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

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

private struct Data
    unit killer
    unit dummy

    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 &gt; 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 = SquareRoot(dx * dx + dy * dy)
        
        if dist &lt;= 50.0 then
            set level = GetUnitAbilityLevel(this.killer, DUMABILID)
            if level &lt; 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 RemoveUnit(this.dummy)
            call this.stopPeriodic()
            call this.deallocate()
        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 actions 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 &gt; 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 thistype.setDamage(u)
        elseif klevel &gt; 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 learn takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer i
        
        if GetLearnedSkill() == ABILID and GetUnitAbilityLevel(u, DUMABILID) == 0 then
            call UnitAddAbility(u, DUMABILID)
            
            set i = 0
            loop
                exitwhen i &gt; 4
                call UnitAddAbility(u, DAMAGEID<i>)
                set i = i + 1
            endloop
        endif
        set u = null
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(t, Condition(function thistype.actions))
        set t = null
        
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
        call TriggerAddCondition(t, Condition(function thistype.learn))
        set t = null
    endmethod
endstruct

endscope
</i></i></i>




Presence of the Dark Lord

Description:
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

Screenshot:


Requiem of Souls

Description:
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.

Screenshot:

Code:
JASS:

scope RequiemOfSouls // requires Timer32, GroupUtils

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

globals
    private constant integer ABILID = 'ABRS' // raw code of ability &quot;Requiem of Souls&quot;
    private constant integer DUMABILID = 'ARS0' // raw code of ability &quot;Requiem of Souls (Reduction)&quot;
    private constant integer DUMMYID = 'rOSD' // raw code of unit &quot;Requiem of Souls Dummy&quot;
    private constant integer CASTERID = 'cAST' // raw code of unit &quot;Caster Dummy&quot;
    
    private constant integer SOULCOUNT = 2 // number of souls required to create a &quot;line&quot;
    private constant real SOULAOE = 150.0 // area of effect of each &quot;line&quot;
    private constant real SPEED = 1000.0 // distance travelled by &quot;line&quot; per second
    private constant real TRUESPEED = SPEED * T32_PERIOD // distance travelled by &quot;line&quot; 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 = &quot;Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl&quot; // effect spawned every interval
    
    private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
    private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
    private constant weapontype WEP = WEAPON_TYPE_WHOKNOWS // weapon 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

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

native UnitAlive takes unit id returns boolean

private struct Data
    unit caster
    unit dummy
    group damagedgroup
    real damage
    real dist
    real angle
    real interval = INTERVAL
    static thistype tempData
    static unit tempUnit
    
    private static method reductionFilter takes nothing returns boolean
        local unit u = GetFilterUnit()
        
        if IsUnitEnemy(u, GetOwningPlayer(tempUnit)) and UnitAlive(u) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
            call IssueTargetOrder(tempUnit, &quot;cripple&quot;, u)
        endif
        set u = null
        return false
    endmethod
    
    private static method filterFunc takes nothing returns boolean
        local thistype this = tempData
        local unit u = GetFilterUnit()
        
        if IsUnitEnemy(u, GetOwningPlayer(this.caster)) and UnitAlive(u) and not IsUnitInGroup(u, this.damagedgroup) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
            call UnitDamageTarget(this.caster, u, this.damage, true, false, ATK, DMG, WEP)
            call GroupAddUnit(this.damagedgroup, u)
        endif
        set u = null
        return false
    endmethod
    
    private method periodic takes nothing returns nothing
        local real x = GetUnitX(this.dummy)
        local real y = GetUnitY(this.dummy)
        
        if this.dist &lt;= 0 then
            call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
            call RemoveUnit(this.dummy)
            call ReleaseGroup(this.damagedgroup)
            call this.stopPeriodic()
            call this.deallocate()
        else
            if this.interval &lt;= 0 then
                call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
                set this.interval = INTERVAL
            else
                set this.interval = this.interval - TRUESPEED
            endif
            call SetUnitPosition(this.dummy, x + TRUESPEED * Cos(this.angle), y + TRUESPEED * Sin(this.angle))
            set tempData = this
            call GroupEnumUnitsInArea(ENUM_GROUP, x, y, SOULAOE, Filter(function thistype.filterFunc))
            set this.dist = this.dist - TRUESPEED
        endif
    endmethod
    implement T32x
    
    private static method actions takes nothing returns boolean
        local thistype this
        local unit u
        local integer level
        local integer i
        local real angle
        local real anglerate
        local real x
        local real y
    
        if GetSpellAbilityId() == ABILID then
            set u = GetTriggerUnit()
            set level = GetUnitAbilityLevel(u, ABILID)
            set i = (GetUnitAbilityLevel(u, Necromastery_DUMABILID) - 1) / SOULCOUNT
            set angle = 0
            if i != 0 then
                set anglerate = (2 * bj_PI) / i
            endif
            set x = GetUnitX(u)
            set y = GetUnitY(u)
            
            loop
                exitwhen i == 0
                set this = thistype.allocate()
                set this.caster = u
                set this.damagedgroup = NewGroup()
                set this.damage = GetDamage(level)
                set this.dist = GetArea(level)
                set this.angle = angle
                set this.dummy = CreateUnit(GetOwningPlayer(this.caster), DUMMYID, x, y, angle)
                
                call this.startPeriodic()
                set angle = angle + anglerate
                set i = i - 1
            endloop
            
            set tempUnit = CreateUnit(GetOwningPlayer(u), CASTERID, x, y, 0)
            call UnitAddAbility(tempUnit, DUMABILID)
            call SetUnitAbilityLevel(tempUnit, DUMABILID, level)
            call GroupEnumUnitsInArea(ENUM_GROUP, x, y, REDUCTIONAOE, Filter(function thistype.reductionFilter))
            call RemoveUnit(tempUnit)
        endif
        set u = null
        return false
    endmethod

    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function thistype.actions))
        set t = null
    endmethod
endstruct

endscope


Credits
Code:
Jesus4Lyf - [URL="http://www.thehelper.net/forums/showthread.php/132538-Timer32?highlight=Timer32"]Timer32[/URL]
Rising_Dusk - [URL="http://www.wc3c.net/showthread.php?t=104464"]GroupUtils[/URL]

Changelogs
Code:
Version 1.0
- Initial relase
Version 1.1
- Optimized code
- Made Attack Type, Weapon Type and Damage Type configurable for Shadowraze and Requiem of Souls
Version 1.2
- Rewrote codes using Timer32 and GroupUtils, instead of KT2 and Recycle
Feedback will be appreciated.
 

Attachments

BlackRose

Forum User
Shadowraze
  • I like how you name the variables relative to their hotkey in DotA. It's easy for people to modify.
  1. In the Learn function, variable u should be set after the if GetLearnedSkill() == ABILID then. Why? Incase the learned skill was not ABILID, then you save one GetTriggerUnit call.
  2. In the Actions function, variable a can be set as a = GetUnitFacing( u ) * bj_DEGTORAD to save one multiplication.
  3. In the GroupFunc function, you should make the attacktype, damagetype, and weapontypes configurable at the top.
 

Ayanami

칼리
Shadowraze
  • I like how you name the variables relative to their hotkey in DotA. It's easy for people to modify.
  1. In the Learn function, variable u should be set after the if GetLearnedSkill() == ABILID then. Why? Incase the learned skill was not ABILID, then you save one GetTriggerUnit call.
  2. In the Actions function, variable a can be set as a = GetUnitFacing( u ) * bj_DEGTORAD to save one multiplication.
  3. In the GroupFunc function, you should make the attacktype, damagetype, and weapontypes configurable at the top.
Thanks for the feedback. Will make the necessary changes.

EDIT
Done.
 

BlackRose

Forum User
Doesn't DotA use purge for Requiem of Souls?

(By the way, it's DotA: Defence of the Ancients, not DoTA: Defence of The Ancients.)
 

BlackRose

Forum User
I was wrong, I checked myself, it's all Cripple. Thinking from memory, I thought it used Purge :p

Does your Requiem of Souls follow this though: The closer the units are the greater the effect.? The Cripple that is, I noticed DotA uses three Cripple abilities: "Far", "Moderate", and "Close".
 

Ayanami

칼리
I was wrong, I checked myself, it's all Cripple. Thinking from memory, I thought it used Purge :p

Does your Requiem of Souls follow this though: The closer the units are the greater the effect.? The Cripple that is, I noticed DotA uses three Cripple abilities: "Far", "Moderate", and "Close".
Well, nope. I guess I should do that though. Lol.
 

Ayanami

칼리
Updated to version 1.2

Code:
[B]Version 1.2[/B]
- Rewrote codes using Timer32 and GroupUtils, instead of KT2 and Recycle
 

Sevion

The DIY Ninja
Weird. I thought I posted this yesterday. Anyways. I think Recycle would be a better system to use than GroupUtils. Less overhead.
 

chobibo

Level 1 Crypt Lord
Weird. I thought I posted this yesterday. Anyways. I think Recycle would be a better system to use than GroupUtils. Less overhead.
You did. Dunno why it's not there anymore though.
 

tooltiperror

Super Moderator
Why are you even using groups? I thought dynamic groups were considered bad now.

>It is MUI, meaning can be cast many times at the same instance
8190 to be precise.

>function GetMaxSoul
That could be [LJASS]I2R(R2I(- 0.333 * level * level * level + 2.5 * level * level + 1.75 * level + 4.083))[/LJASS] and comment in the values. The I2R/R2I should round it up (untested).
 

tooltiperror

Super Moderator
GetMaxSoul change would probably slow down for more than it's worth.

Approved.
 

super_nova

Member
Excuse me, i want to ask some question
I'm trying to copy the necromastery skill you made here, and modify its name
But it doesnt work and error when i save it to my map, i did what you said to copy step by step...
Can you help me?
lorokabeh.jpg
I dont know how to upload a picture, so i just attach it..
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    Friday Yay!
  • mgarcia mgarcia:
    did you guys catch Carl's interview? https://www.youtube.com/watch?v=kuHiMXABkGs
  • mgarcia mgarcia:
    he's the one that informed me about the DVD's working!
  • mgarcia mgarcia:
    he also mentioned the progress on the controllers!
  • The Helper The Helper:
    I did actually it was cool to see the NUON mention
  • The Helper The Helper:
    https://discord.com/channels/985377399338332202/985377399950696481 you can still use this chat too we are two fisted now :)
  • thewrongvine thewrongvine:
    costs me $80 to fill gas tank sad face
  • Ghan Ghan:
    Oof
  • The Helper The Helper:
    Yeah that gas is some expensive stuff :)
  • The Helper The Helper:
    ghan does not have to worry about it he has a tesla and I have a small tank so it does not cost me usually more than 50
  • The Helper The Helper:
    fyi Ghan we are getting an error trying to access stats or world editor tutorials Error 526 Ray ID: 72128c6bf99f6707 • 2022-06-26 02:35:15 UTCInvalid SSL certificate
  • Ghan Ghan:
    An artifact of switching to Cloudflare... the Let's Encrypt certs can't autorenew through Cloudflare.
  • Ghan Ghan:
    I got the forum updated before things expired but there were some other casualties.
  • Ghan Ghan:
    Everything should be fixed now....
  • The Helper The Helper:
    Thank you Ghan!
  • The Helper The Helper:
    Happy Monday!
  • The Helper The Helper:
    new NUON forum mod cubanral!
    +1
  • The Helper The Helper:
  • tom_mai78101 tom_mai78101:
    Started learning how to make tools-assisted speedruns, so I'm lately busy.
  • tom_mai78101 tom_mai78101:
    Here's my current project.
    +3
  • O Old Mountain Shadow:
    that was pretty good!
  • jonas jonas:
    really cool! I saw the game before but always thought it's just a half as good double dragon. Now I realize it actually has a lot of depth!
  • The Helper The Helper:
    I just saw a bunch of running and jumping past all the enemies look like it was scripted as he said I guess I should have watched the whole thing. I only got a couple of minutes in. You should post that video in the forum Tom
  • Darthfett Darthfett:
    "Hi in the chat!"
    +2
  • tom_mai78101 tom_mai78101:
    Currently busy with making the run even better, so I'll post that new one once I'm done. Right now, I had to modify the emulator itself, the tools that makes this video, and some RAM address disassembling / reverse-engineering to get the right values, and such.
    +1

    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