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

Arcania Zero v0.03

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
A new spell of mine, I create the spell for a contest, but there you've need to. But I hadn't the time to finish the second. So I post it here.

Hope you like it. You can read the needed things in the head of the spell code.

Please give credits when you use this.

This spell creates a buff upon the target, which sucks all nearby enemies. When the reached the unit their knocked away. When their are move, they lose some hp and mana. And when they collide with the sucking unit they lose additional hp and mana.

JASS:
scope ArcaniaZero initializer init

//================================================================================================
//                                            Arcania Zero
//                                                by
//                                                cedi
//                                                
//                                            Requires:
//                                                TimerUtils by Vexorian
//                                                Vector by Anitarf
//                                                Heights by cedi
//                                                IsTerrainWalkable by Anitarf
//================================================================================================

private keyword Arcania //System
private keyword Grabbed //System
private keyword ArcKB //System

globals
    private constant integer SPELL_ID           = 'A000'
    //Raw Code of the Spell
    private constant integer BUFF_ID            = 'B000'
    //Raw Code of the Buff, which is applied by the spell
    private constant integer MAX_TARGETS        = 10
    //The max amount of units sucked at the same time
    private constant real    RED                = 1.00
    //Amount of Red color of the lightning ( Between 1 - 0 )
    private constant real    GREEN              = 1.00
    //Amount of Green color of the lightning ( Between 1 - 0 )
    private constant real    BLUE               = 1.00
    //Amount of Blue color of the lightning ( Between 1 - 0 )
    private constant real    ALPHA              = 1.00
    //Amount of Alpha color of the lightning ( Between 1 - 0 )
    private constant real    TIMER_INTERVAL     = 0.035
    //Interval of the moving should be around 0.035
    private constant real    PICK_INTERVAL      = 0.10
    //Each x will the spell search for new targets. Don't use a to small number
    private constant real    DRAG_SFX_INTERVAL  = 0.10
    //Each x the System will create a drag effect
    private constant real    KB_SFX_INTERVAL    = 0.20
    //Each x the System will create a knockback effect
    private constant real    COLLISION_RANGE    = 100.00
    //The range the suckeds unit have to reach to be knocked away
    private constant real    ADD_HEIGHT         = 20.00
    //Bonus Height that the lightning hits the middle of the sucked units
    private constant real    START_SPEED        = 300.00 
    //The sucking speed in ms
    private constant real    ACCELERATION       = 20.00 
    //The acceleration of the sucking speed in ms
    private constant real    INSTA_KILL_SPEED   = 2000.00 
    //The needed speed to insta kill a unit in ms
    private constant real    START_KB_SPEED     = 600.00 
    //The start speed of the knockback in ms
    private constant real    KB_SLOW_DOWN       = 60.00 
    //Friction in ms
    private constant real    KB_MIN_SPEED       = 20.00
    //The knockback ends when the knockback speed is equal or smaller then this in ms
    private constant string  CANCEL_SFX         = "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"
    //The effect when the connection is canceled
    private constant string  COLLISION_SFX      = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
    //The effect when the unit collides
    private constant string  DRAG_SFX           = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCaster.mdl"
    //The effect when the units are sliding
    private constant string  GRAB_SFX           = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
    //The effect attached to sucked units
    private constant string  LIGHTNING_STRING   = "DRAM"
    //String code of the lightning
    private constant string  KB_SFX             = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
    //Slide effect on the knockback
    private constant string  INSTA_KILL_SFX     = "Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl"
    //Damage dealt only to enemies?
    private constant boolean DAMAGE_ONLY_ENEMY  = true
    //The Attacktyp which is used to deal damage.
    private constant attacktype ATTACK          = ATTACK_TYPE_MAGIC
    
    //System Variables
    
    private          Arcania TEMPDATA
    private          ArcKB   TEMPKB
    private          integer TEMPINT  = 0
    private          real    REAL_START_SPEED = START_SPEED * TIMER_INTERVAL
    private          real    REAL_ACCELERATION = ACCELERATION * TIMER_INTERVAL
    private          real    REAL_INSTA_KILL_SPEED = INSTA_KILL_SPEED * TIMER_INTERVAL
    private          real    REAL_START_KB_SPEED = START_KB_SPEED * TIMER_INTERVAL
    private          real    REAL_KB_SLOW_DOWN = KB_SLOW_DOWN * TIMER_INTERVAL
    private          real    REAL_KB_MIN_SPEED = KB_MIN_SPEED * TIMER_INTERVAL
    private          real    TEMPREAL = 0.00
    private          vector  TEMPVEC
    private          group   TEMPGROUP = CreateGroup()
    
    private real     array   DURATION
    private real     array   AOE
    private real     array   DAMAGE_COLLISION
    private real     array   DAMAGE
    private real     array   MANALOSE_COLLISION
    private real     array   MANALOSE
endglobals

//Duration of the ability, should be the same for the spell
private function SET_DURATION takes nothing returns nothing
    set DURATION[1] = 5.00
    set DURATION[2] = 6.00
    set DURATION[3] = 7.00
    set DURATION[4] = 8.00
    set DURATION[5] = 9.00
endfunction

//Suck AoE
private function SET_AOE takes nothing returns nothing
    set AOE[1] = 500.00
    set AOE[2] = 600.00
    set AOE[3] = 700.00
    set AOE[4] = 800.00
    set AOE[5] = 900.00
endfunction

//Damage on collision
private function SET_DAMAGE_COLLISION takes nothing returns nothing
    set DAMAGE_COLLISION[1] = 50.00
    set DAMAGE_COLLISION[2] = 60.00
    set DAMAGE_COLLISION[3] = 70.00
    set DAMAGE_COLLISION[4] = 80.00
    set DAMAGE_COLLISION[5] = 90.00
endfunction

//Damage per second ( when the unit is sucked )
private function SET_DAMAGE takes nothing returns nothing
    set DAMAGE[1] = 50.00 * TIMER_INTERVAL
    set DAMAGE[2] = 60.00 * TIMER_INTERVAL
    set DAMAGE[3] = 70.00 * TIMER_INTERVAL
    set DAMAGE[4] = 80.00 * TIMER_INTERVAL
    set DAMAGE[5] = 90.00 * TIMER_INTERVAL
endfunction

//Mana lose on collision
private function SET_MANALOSE_COLLISION takes nothing returns nothing
    set MANALOSE_COLLISION[1] = 50.00
    set MANALOSE_COLLISION[2] = 60.00
    set MANALOSE_COLLISION[3] = 70.00
    set MANALOSE_COLLISION[4] = 80.00
    set MANALOSE_COLLISION[5] = 90.00
endfunction

//Mana lose on suck, per second
private function SET_MANA takes nothing returns nothing
    set MANALOSE[1] = 50.00 * TIMER_INTERVAL
    set MANALOSE[2] = 60.00 * TIMER_INTERVAL
    set MANALOSE[3] = 70.00 * TIMER_INTERVAL
    set MANALOSE[4] = 80.00 * TIMER_INTERVAL
    set MANALOSE[5] = 90.00 * TIMER_INTERVAL
endfunction

//================================================================================================
//                                              SYSTEM
//================================================================================================

private function KBOuterControl takes nothing returns nothing
    set TEMPKB = GetTimerData( GetExpiredTimer() )
    call TEMPKB.InnerControl()
endfunction

private function GetNewAngle takes real angle returns real
    if(angle<=45 and angle>=-45) then
        set angle=angle*-1
    elseif(angle>45 and angle<=135) then
        set angle=180-angle
    elseif(angle>135 and angle>=-135) then
        set angle=360-angle
    else
        set angle=-180-angle
    endif
    return angle
endfunction

private struct ArcKB
    unit target    = null
    Arcania data   = 0
    real cos       = 0.00
    real sin       = 0.00
    real speed     = REAL_START_KB_SPEED
    real interval  = KB_SFX_INTERVAL
    timer time     = null
    
    method onDestroy takes nothing returns nothing
        call ReleaseTimer( .time )
        if .data.mytargets != null and .data != 0 then
            call GroupRemoveUnit( .data.mytargets, .target )
        endif
    endmethod
    
    method InnerControl takes nothing returns nothing
        local real x
        local real y
        set .speed = .speed - REAL_KB_SLOW_DOWN
        if .speed <= REAL_KB_MIN_SPEED then
            call .destroy()
        endif
        set x = GetUnitX( .target ) + .cos * .speed
        set y = GetUnitY( .target ) + .sin * .speed
        if IsTerrainWalkable( x, y ) then
            call SetUnitX( .target, x )
            call SetUnitY( .target, y )
        else
            call .destroy()
        endif
        set .interval = .interval - TIMER_INTERVAL
        if .interval <= 0.00 then
            set .interval = KB_SFX_INTERVAL
            call DestroyEffect( AddSpecialEffect( KB_SFX, x, y ) )
        endif
    endmethod
    
    static method createEx takes unit caster, unit buffed, unit target, Arcania data returns thistype
        local thistype this = thistype.allocate()
        set TEMPREAL = Atan2(GetUnitY( buffed ) - GetUnitY( target ), GetUnitX( buffed ) - GetUnitX( target ))
        set TEMPREAL = GetNewAngle( TEMPREAL )
        set .target = target
        set .cos = Cos( TEMPREAL )
        set .sin = Sin( TEMPREAL )
        set .time = NewTimer()
        set .data = data
        call SetTimerData( .time, this )
        call TimerStart( .time, TIMER_INTERVAL, true, function KBOuterControl )
        return this
    endmethod
    
    static method create takes unit caster, unit buffed, unit target, Arcania data returns thistype
        local thistype this = thistype.allocate()
        set TEMPREAL = Atan2(GetUnitY( target ) - GetUnitY( buffed ), GetUnitX( target ) - GetUnitX( buffed ))
        set .target = target
        set .cos = Cos( TEMPREAL )
        set .sin = Sin( TEMPREAL )
        set .time = NewTimer()
        set .data = data
        call SetTimerData( .time, this )
        call TimerStart( .time, TIMER_INTERVAL, true, function KBOuterControl )
        return this
    endmethod
    
endstruct

private function OuterControl takes nothing returns nothing
    set TEMPDATA = GetTimerData( GetExpiredTimer() )
    call TEMPDATA.InnerControl()
endfunction

private function IsTarget takes nothing returns boolean
    return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitEnemy( GetFilterUnit(), GetOwningPlayer( TEMPDATA.caster ) ) and not IsUnitInGroup( GetFilterUnit(), TEMPDATA.mytargets ) and GetFilterUnit() != TEMPDATA.buffed and GetUnitAbilityLevel( GetFilterUnit(), BUFF_ID ) <= 0
endfunction

private struct Grabbed
    unit       grabbed      = null
    Arcania    root         = 0
    lightning  light        = null
    real       speed        = REAL_START_SPEED
    real       sfxinterval  = DRAG_SFX_INTERVAL
    effect     grabbedsfx   = null
    vector     vec
    
    method End takes nothing returns nothing
        debug call BJDebugMsg( "END" )
        call DestroyEffect( AddSpecialEffectTarget( CANCEL_SFX, .grabbed, "origin" ) )
        call .destroy()
    endmethod
    
    private method Collision takes nothing returns nothing
        if not DAMAGE_ONLY_ENEMY or IsUnitEnemy( .root.buffed, GetOwningPlayer( .root.caster ) ) then
            call UnitDamageTarget( .root.caster, .root.buffed, DAMAGE_COLLISION[.root.level], true, false, ATTACK, DAMAGE_TYPE_NORMAL, null )
            call SetUnitState( .root.buffed, UNIT_STATE_MANA, GetUnitState( .grabbed, UNIT_STATE_MANA ) - MANALOSE_COLLISION[.root.level] )
        endif
        call UnitDamageTarget( .root.caster, .grabbed, DAMAGE_COLLISION[.root.level], true, false, ATTACK, DAMAGE_TYPE_NORMAL, null )
        call SetUnitState( .grabbed, UNIT_STATE_MANA, GetUnitState( .grabbed, UNIT_STATE_MANA ) - MANALOSE_COLLISION[.root.level] )
        call DestroyEffect( AddSpecialEffectTarget( COLLISION_SFX, .grabbed, "origin" ) )
        call ArcKB.create( .root.caster, .root.buffed, .grabbed, .root )
        //Lets do some damage and knock away
    endmethod
    
    method Control takes nothing returns boolean
        local real x
        local real y
        //Death?
        if GetWidgetLife( .grabbed ) <= 0.405 or IsUnitType( .grabbed, UNIT_TYPE_DEAD) == true or .grabbed == null or GetUnitAbilityLevel( .grabbed, BUFF_ID ) >= 1 then
            call GroupRemoveUnit( .root.mytargets, .grabbed )
            return false
        endif
        //New Direction
        set TEMPREAL = Atan2(GetUnitY( .root.buffed ) - GetUnitY( .grabbed ), GetUnitX( .root.buffed ) - GetUnitX( .grabbed ))
        //New Speed
        set .speed = .speed + REAL_ACCELERATION
        //Jep Insta kill ( could only happen when the unit is sucked by two buffs ).
        if .speed >= REAL_INSTA_KILL_SPEED then
            debug call BJDebugMsg( "insta kill" )
            debug call BJDebugMsg( R2S( .speed ) )
            call SetWidgetLife( .grabbed, 1.00 )
            call UnitDamageTarget( .root.caster, .grabbed, 10.00, true, false, ATTACK, DAMAGE_TYPE_NORMAL, null )
            call GroupRemoveUnit( .root.mytargets, .grabbed )
            call DestroyEffect( AddSpecialEffectTarget( INSTA_KILL_SFX, .grabbed, "origin" ) )
            return false
        endif
        //New Position
        set TEMPVEC.x = Cos( TEMPREAL ) * .speed
        set TEMPVEC.y = Sin( TEMPREAL ) * .speed
        call .vec.add( TEMPVEC )
        call .vec.scale( 0.5 )
        call SetUnitX( .grabbed, GetUnitX( .grabbed ) + .vec.x )
        call SetUnitY( .grabbed, GetUnitY( .grabbed ) + .vec.y )
        call UnitDamageTarget( .root.caster, .grabbed, DAMAGE[.root.level], true, false, ATTACK, DAMAGE_TYPE_NORMAL, null )
        call SetUnitState( .grabbed, UNIT_STATE_MANA, GetUnitState( .grabbed, UNIT_STATE_MANA ) - MANALOSE[.root.level] )
        if not IsTerrainWalkable( GetUnitX( .grabbed ), GetUnitY( .grabbed ) ) then
            debug call BJDebugMsg( "not walkable" )
            call ArcKB.createEx( .root.caster, .root.buffed, .grabbed, .root )
            return false
        endif
        //Collision?
        set x = GetUnitX( .root.buffed ) - GetUnitX( .grabbed )
        set y = GetUnitY( .root.buffed ) - GetUnitY( .grabbed )
        set TEMPREAL = SquareRoot( x * x + y * y )
        if TEMPREAL <= COLLISION_RANGE then
            //Jep it's a collision
            call .Collision()
            return false
        else
            //Move light and create some nice effects
            if .light != null then
                call MoveLightningEx( .light, true, GetUnitX( .root.buffed ), GetUnitY( .root.buffed ), GetUnitZ( .root.buffed ) + ADD_HEIGHT, GetUnitX( .grabbed ), GetUnitY( .grabbed ), GetUnitZ( .grabbed ) + ADD_HEIGHT )
            endif
            //Some cool effects
            set .sfxinterval = .sfxinterval - TIMER_INTERVAL
            if .sfxinterval <= 0.00 then
                set .sfxinterval = DRAG_SFX_INTERVAL
                call DestroyEffect( AddSpecialEffect( DRAG_SFX, GetUnitX( .grabbed ), GetUnitY( .grabbed ) ) )
            endif
        endif
        //Lets leave this
        return true
    endmethod
    
    static method create takes Arcania root, unit target returns thistype
        local thistype this = thistype.allocate()
        local real angle = Atan2(GetUnitY( .root.buffed ) - GetUnitY( target ), GetUnitX( .root.buffed ) - GetUnitX( target ))
        set .root = root
        set .grabbed = target
        set .light = AddLightningEx( LIGHTNING_STRING, true, GetUnitX( root.buffed ), GetUnitY( root.buffed ), GetUnitZ( root.buffed ) + ADD_HEIGHT, GetUnitX( target ), GetUnitY( target ), GetUnitZ( target ) + ADD_HEIGHT ) 
        call SetLightningColor( .light, RED, GREEN, BLUE, ALPHA )
        set .grabbedsfx = AddSpecialEffectTarget( GRAB_SFX, target, "chest" )
        set .vec = vector.create( Cos( angle ) * REAL_START_SPEED, Sin( angle ) * REAL_START_SPEED, 0.00 )
        return this
    endmethod
    
    method onDestroy takes nothing returns nothing
        call DestroyEffect( .grabbedsfx )
        set .grabbedsfx = null
        call DestroyLightning( .light )
        set .light = null
    endmethod
    
endstruct

private struct Arcania
    unit     buffed                 = null
    unit     caster                 = null
    integer  count                  = 0
    timer    time                   = null
    integer  level                  = 1
    boolean  buffon                 = false
    real     duration               = 0.00
    real     pickinterval           = PICK_INTERVAL
    real     thereissomethingwrong  = 5.00
    group    mytargets              = CreateGroup()
    boolean  end                    = false
    
    Grabbed array grabbeds[MAX_TARGETS]
    
    private method PickThem takes nothing returns nothing
        local unit u
        if .count <= MAX_TARGETS then
            set TEMPDATA = this
            call GroupEnumUnitsInRange( TEMPGROUP, GetUnitX( .buffed ), GetUnitY( .buffed ), AOE[.level], Condition( function IsTarget ) )
            loop
                set u = FirstOfGroup( TEMPGROUP )
                exitwhen u == null or .count > MAX_TARGETS
                set .grabbeds[.count] = Grabbed.create( this, u )
                call GroupAddUnit( .mytargets, u )
                call GroupRemoveUnit( TEMPGROUP, u )
                set .count = .count + 1
            endloop
            call GroupClear( TEMPGROUP )
        endif
        //Lets pick'em and don't forget to add them to your group
    endmethod
    
    private method SuckThem takes nothing returns nothing
        local integer i = 0
        //Should work
        loop
            exitwhen i >= .count //Exitwhen i reached free place
            if .grabbeds[i] != 0 then //Is Grabbeds set?
                if not .grabbeds[i].Control() then //Returns false when it should be destroyed
                    set .count = .count - 1 //Set count == last needed place
                    call .grabbeds[i].destroy() //Destroys light and sfx
                    set .grabbeds[i] = 0 //Clear the place of the destroyed struct
                    if i != .count then //If last place == destroyed struct
                        set .grabbeds[i] = .grabbeds[.count] //Set cleared place == last struct
                        set .grabbeds[.count] = 0 //Clear that place
                    endif
                endif
            endif
            set i = i + 1 //Next
        endloop
        //Jep I remove them of the group when the knockback is done
        debug call BJDebugMsg( "Count: " + I2S( .count ) )
    endmethod
    
    method InnerControl takes nothing returns nothing
        set TEMPINT = GetUnitAbilityLevel( .buffed, BUFF_ID ) //Level wird gesetzt
        if .end then //DIE DIE DIE DIE
            call .destroy()
            return
        endif
        if not .buffon then //Buff applayed?
            if TEMPINT > 0 then
                set .buffon = true //Jep
            else
                set .thereissomethingwrong = .thereissomethingwrong - TIMER_INTERVAL
                if .thereissomethingwrong <= 0.00 then
                    debug call BJDebugMsg( "CRITICAL ERROR, BUFF IS NOT APPLIED" )
                    set .end = true
                    call .destroy()
                    return
                endif
            endif
        else
            //All Actions
            if TEMPINT <= 0 then //Buff away == destroy
                set .end = true
                call .destroy()
                return
            endif
            //Time's up
            set .duration = .duration - TIMER_INTERVAL
            if .duration <= 0.00 then
                set .end = true
                call .destroy()
                return
            endif
            //Picking
            set .pickinterval = .pickinterval - PICK_INTERVAL
            if .pickinterval <= 0.00 and .end == false then
                set .pickinterval = PICK_INTERVAL
                call .PickThem()
            endif
            //Sucking
            if .end == false then
                call .SuckThem()
            endif
        endif
    endmethod
    
    method onDestroy takes nothing returns nothing
        local integer i = 0
        call ReleaseTimer( .time )
        debug call BJDebugMsg( "Endcount: " + I2S( .count ) )
        loop
            exitwhen i == .count //Go through and destroy them
            if .grabbeds[i] != 0 then //If that struct exists
                debug call BJDebugMsg( I2S( i ) )
                call .grabbeds[i].End() //Destroy it in a special way
            endif
            set i = i + 1
        endloop
        call GroupClear( .mytargets )
        call DestroyGroup( .mytargets )
        set .mytargets = null
    endmethod
    
    static method create takes unit caster, unit target returns thistype
        local thistype this = thistype.allocate()
        set .buffed = target
        set .caster = caster
        set .time = NewTimer()
        set .level = GetUnitAbilityLevel( caster, SPELL_ID )
        set .duration = DURATION[.level]
        call SetTimerData( .time, this )
        call TimerStart( .time, TIMER_INTERVAL, true, function OuterControl )
        return this
    endmethod
    
endstruct

private function IsSpell takes nothing returns boolean
    if GetSpellAbilityId() == SPELL_ID then
        call Arcania.create( GetTriggerUnit(), GetSpellTargetUnit() )
    endif
    return false
endfunction

private function HasBuff takes nothing returns boolean
    if GetSpellAbilityId() == SPELL_ID and GetUnitAbilityLevel( GetSpellTargetUnit(), BUFF_ID ) >= 1 then
        call IssueImmediateOrder( GetTriggerUnit(), "stop" )
        call DisplayTextToPlayer( GetOwningPlayer( GetTriggerUnit() ), 0.5, -0.50, "|cffffcc00Target has buff already|r" )
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local trigger t2 = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
    call TriggerAddCondition( t2, Condition( function HasBuff ) )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function IsSpell ) )
    set TEMPVEC = vector.create( 0.00, 0.00, 0.00 )
    call SET_DURATION()
    call SET_AOE()
    call SET_DAMAGE_COLLISION()
    call SET_DAMAGE()
    call SET_MANALOSE_COLLISION()
    call SET_MANA()
endfunction

endscope

Keywords:
Arcan, Magic, Sucking, Knockback, Manadrain, lightning, Mana, Damage, collision, Buff
Contents

Arcania Zero v0.03 (Map)

Reviews
KILLCIDE
Spell currently has syntax errors, and the author has not been on since Sept. 2014. Resource is moved to Substandard.

Moderator

M

Moderator

19:14, 4th Oct 2009
TriggerHappy187:

Review.

The spell is good enough without those improvements, but they are improvements nonetheless, so please consider using them.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Ok I always like that your spells have an extra something :)
Anyways:
JASS:
//Duration of the ability, should be the same for the spell
private function SET_DURATION takes nothing returns nothing
    set DURATION[1] = 5.00
    set DURATION[2] = 6.00
    set DURATION[3] = 7.00
    set DURATION[4] = 8.00
    set DURATION[5] = 9.00
endfunction

//Suck AoE
private function SET_AOE takes nothing returns nothing
    set AOE[1] = 500.00
    set AOE[2] = 600.00
    set AOE[3] = 700.00
    set AOE[4] = 800.00
    set AOE[5] = 900.00
endfunction

//Damage on collision
private function SET_DAMAGE_COLLISION takes nothing returns nothing
    set DAMAGE_COLLISION[1] = 50.00
    set DAMAGE_COLLISION[2] = 60.00
    set DAMAGE_COLLISION[3] = 70.00
    set DAMAGE_COLLISION[4] = 80.00
    set DAMAGE_COLLISION[5] = 90.00
endfunction

//Damage per second ( when the unit is sucked )
private function SET_DAMAGE takes nothing returns nothing
    set DAMAGE[1] = 50.00 * TIMER_INTERVAL
    set DAMAGE[2] = 60.00 * TIMER_INTERVAL
    set DAMAGE[3] = 70.00 * TIMER_INTERVAL
    set DAMAGE[4] = 80.00 * TIMER_INTERVAL
    set DAMAGE[5] = 90.00 * TIMER_INTERVAL
endfunction

//Mana lose on collision
private function SET_MANALOSE_COLLISION takes nothing returns nothing
    set MANALOSE_COLLISION[1] = 50.00
    set MANALOSE_COLLISION[2] = 60.00
    set MANALOSE_COLLISION[3] = 70.00
    set MANALOSE_COLLISION[4] = 80.00
    set MANALOSE_COLLISION[5] = 90.00
endfunction

//Mana lose on suck, per second
private function SET_MANA takes nothing returns nothing
    set MANALOSE[1] = 50.00 * TIMER_INTERVAL
    set MANALOSE[2] = 60.00 * TIMER_INTERVAL
    set MANALOSE[3] = 70.00 * TIMER_INTERVAL
    set MANALOSE[4] = 80.00 * TIMER_INTERVAL
    set MANALOSE[5] = 90.00 * TIMER_INTERVAL
endfunction
Make it a one SETUP function, rather than all these...

Also, the coding is decent as always :) and debugged too ;)
One more thing, well maybe you'd like to make an option to set how many units could be picked in total when there are already other picked. Get what I mean? =)

Nice one!
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
I was SO F***ING impressed by your spell that I wasted my afternoon and made a GUI version for my map out of it

however I did not ask you for permission and would like to do it now :grin:

there are still some things which are not perfect like the lightning height and the special effect on units but I think I can handle it

but there is ONE thing I don't know how to fix
your movement is so smooth and mine is crappy
how did you do it?
(I could try to understand the JASS code but my JASS knowledge is limited to making functions)

5/5 + rep of course

edit:
thanks cedi :D

edit2:
just tested your spell again and noticed some things
-I created the lightning at both the knockback and the repulsion and not the knockback only (which is much better)
-the repulsion sfx is much easier to create then I thought xD
-and I forgot the dmg oO
edit3:
changed some things and it seems like everything is kinda bugged
will take some time to fix

edit4:
Update0.2:
-fixed angle bug
-removed lightning for knockback
-found new bug: the pullback does not vanish until the spell is over

Update0.3:
-fixed typo and added better effects

Update0.4:
-stupid debugg groups don't work :cry:
however it works fine this way too

Update0.5:
-0.4 got lost oO
-however now it should work fine (the units don't get knocked back everytime but mostly :p)
-there is no cliff/building detection and it'll take me some time to invent some good method (items are buggy and units are more buggy but have more options..need to slep/do homework/read some books...will make the rest tomorrow or later if it takes more time)
 

Attachments

  • Arcane Bubble.w3x
    28.4 KB · Views: 87
  • Arcane Bubble 0.2.w3x
    28.3 KB · Views: 91
  • Arcane Bubble 0.3.w3x
    28.8 KB · Views: 90
  • Arcane Bubble 0.5.w3x
    28.8 KB · Views: 86
Last edited:
Level 12
Joined
Jul 27, 2008
Messages
1,181
Nice spell, but you still use many setup triggers. Merge them to:

JASS:
private function SETUP takes nothing returns nothing
//Duration of the ability, should be the same for the spell
    set DURATION[1] = 5.00
    set DURATION[2] = 6.00
    set DURATION[3] = 7.00
    set DURATION[4] = 8.00
    set DURATION[5] = 9.00

//Suck AoE
    set AOE[1] = 500.00
    set AOE[2] = 600.00
    set AOE[3] = 700.00
    set AOE[4] = 800.00
    set AOE[5] = 900.00

//Damage on collision
    set DAMAGE_COLLISION[1] = 50.00
    set DAMAGE_COLLISION[2] = 60.00
    set DAMAGE_COLLISION[3] = 70.00
    set DAMAGE_COLLISION[4] = 80.00
    set DAMAGE_COLLISION[5] = 90.00

//Damage per second ( when the unit is sucked )
    set DAMAGE[1] = 50.00 * TIMER_INTERVAL
    set DAMAGE[2] = 60.00 * TIMER_INTERVAL
    set DAMAGE[3] = 70.00 * TIMER_INTERVAL
    set DAMAGE[4] = 80.00 * TIMER_INTERVAL
    set DAMAGE[5] = 90.00 * TIMER_INTERVAL

//Mana lose on collision
    set MANALOSE_COLLISION[1] = 50.00
    set MANALOSE_COLLISION[2] = 60.00
    set MANALOSE_COLLISION[3] = 70.00
    set MANALOSE_COLLISION[4] = 80.00
    set MANALOSE_COLLISION[5] = 90.00

//Mana lose on suck, per second
    set MANALOSE[1] = 50.00 * TIMER_INTERVAL
    set MANALOSE[2] = 60.00 * TIMER_INTERVAL
    set MANALOSE[3] = 70.00 * TIMER_INTERVAL
    set MANALOSE[4] = 80.00 * TIMER_INTERVAL
    set MANALOSE[5] = 90.00 * TIMER_INTERVAL
endfunction
It is better and as easy to modify (Plus, a few lines shorter).
 
Long code -_-

  • You don't need to null your triggers.
  • You seem to be nulling all of the arguments passed through functions when it's not needed. You only need to null local variables, not arguments
  • Wouldn't it be wise to store the buff's level inside the struct, you seem to be calling the GetUnitAbilityLevel function alot.
  • call GroupClear( TEMPGROUP ) is not needed, groups are cleared once they are re-enumerated.
  • ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null should all be configurable.
  • Calling GetUnitState when referencing a units life should be replaced with GetWidgetLife, it's faster.
  • Same goes for SetUnitState (SetWidgetLife).
  • Your constant functions are a little wierd, setting the data inside arrays. You should be using an algorithm that would work for all levels and return the value. Something like this, though not exactly this;
    JASS:
    private constant function Damage takes integer level returns real
        return 100*level
    endfunction
 
Last edited:
Level 17
Joined
Mar 17, 2009
Messages
1,349
You sure about the state vs. widgetlife thing?

Also, the usage of arrayed globals as adjustable values is more user friendly as you just set the value you want (ie you don't have to think of an equation)... what's more, not everything can be an equation, and so your method won't work for all values :p
 
You sure about the state vs. widgetlife thing?

Also, the usage of arrayed globals as adjustable values is more user friendly as you just set the value you want (ie you don't have to think of an equation)... what's more, not everything can be an equation, and so your method won't work for all values :p

Apparently these benchmarks confirm it.
 
Level 2
Joined
Jul 21, 2009
Messages
21
Your spell is very nice :grin:

But:
-When i copy the scripts and copy to my Map it doesnt works the script says:
The ...Installer script with the name... doesnt exist and than the trigger
turns off pls need help.
 
Level 2
Joined
Jun 8, 2014
Messages
11
Guys, help me please, WE giving error to these triggers when i try to save the map, i don't know what to do :(
 
Level 2
Joined
Jun 8, 2014
Messages
11
Look, I wanted to import some spells wich use triggers, but usual WE don't accept these , so i downloaded JNGP latest version . Here I imported the spell , copied the triggers and when i try to save the map a syntax error appears . I am a newbie so I don't understand what and how to make it work ((
 
Top