1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  5. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  6. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  7. The results are out! Check them out.
    Dismiss Notice
  8. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  9. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  10. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Omega Wave v1.04

Submitted by Maker
This bundle is marked as approved. It works and satisfies the submission rules.
Omega Wave v1.04 by Maker


Icon Description
[​IMG] [​IMG]


A spell request from Aeroblyctos to be used as a boss ability in his great campaign, The Chosen Ones.

The cool thing with this ability is that you can turn it into a game of trying to evade the green parts and go through the blue parts so that you take no damage. There's a mini-game for that in the test map.

http://www.youtube.com/watch?v=q7piX85DY24

The code uses recycling indexing in hashtables, so it only loops through active cicles.

Code (vJASS):

/*~~~~~~~~~~~~~~~~~ OMEGA WAVE v1.04 by Maker ~~~~~~~~~~~~~~~~~~~~~*/  
/*                                                                 |
| Creates rotating circles around the caster. Part of the circle   |
| damages and part destroys mana.                                  |
|                                                                 */

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/          


scope OmegaWave initializer Omega_Wave

    globals
        private constant integer    ABILCODE            = 'A000'
        private constant integer    DUMMY_TYPE          = 'h000'
        private constant integer    ORDERID             = 852600
        // Of how many lightnings the circle consist
        private constant integer    LIGHTNINGS          = 16
        // How many of the lightnings do not cause damage
        // They drain mana instead
        private constant integer    MANA_LIGHTNINGS     = 6
        // How many circle waves there are
        private constant integer    WAVES               = 3
        // How many more waves per ability level. Does not apply at lvl 1
        private constant integer    WAVES_BONUS         = 1
        // How often a new circle is spawned
        // Match this with Data - Art duration
        // in object editor
        private constant real       INTERVAL            = 2.0
        // Height offset from ground
        private constant real       HEIGHT              = 60.
        // How fast the circle expands
        private constant real       SPEED               = 3.
        // Initial radius of the circle
        private constant real       INIT_DIST           = 32.
        // Circle position update interval
        private constant real       TIMEOUT             = 0.03
        // How far the circle expands
        private constant real       MAX_OFFSET          = 400.
        // Base damage per second
        private constant real       DMG_BASE            = 100.  * TIMEOUT
        // Bonus damage per ability level per second.
        // Does not apply at level 1
        private constant real       DMG_BONUS           = 30.   * TIMEOUT
        // How much mana is destroyed per second
        private constant real       MANA_BASE           = 40.   * TIMEOUT
        // BOnus mana destroyed per ability level per second.
        // Does not apply at level 1
        private constant real       MANA_BONUS          = 20.   * TIMEOUT
        // How wide the lightning is. Used for detecting
        // collision with units
        private constant real       LIGHTNING_WIDTH     = 28.
        // Does the circle rotate
        private constant boolean    ROTATES             = TRUE
        // Min and max speed for the rotation
        private constant real       MIN_ROT_SPD         = 15    * TIMEOUT * bj_DEGTORAD
        private constant real       MAX_ROT_SPD         = 30    * TIMEOUT * bj_DEGTORAD
        // Lightning types
        private constant string   TYPESAFE            = "DRAM"
        private constant string   TYPEDANGER          = "DRAL"
       
        // RGB values of the mana lightnings, adjusts colour
        // Adjust the first 255 between 0 and 255
        private constant real       MRED                = 255.  / 255.
        private constant real       MGREEN              = 255.  / 255.
        private constant real       MBLUE               = 255.  / 255.
       
        // RGB values of the health lightnings, adjusts colour
        private constant real       HRED                = 255.  / 255.
        private constant real       HGREEN              = 255.  / 255.
        private constant real       HBLUE               = 255.  / 255.
       
        // Transparency of the lightnings
        private constant real       MALPHA              = 1.
        private constant real       HALPHA              = 1.
        // Effect when damaging lightning hits
        private constant string     DMG_EFFECT          = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl"
        // Effect when mana destroying lightning hits
        private constant string     MANA_EFFECT         = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
       
        // Attack- and damage types
        private constant attacktype ATKTYPE             = ATTACK_TYPE_NORMAL
        private constant damagetype DMGTYPE             = DAMAGE_TYPE_NORMAL
       
        /*~~~~~~~~~~~~~ Global variables, don't change these ~~~~~~~~~~~~~*/
        private real r1
        private real r2
        private real r3
        private real r4
        private real r5
        private real r6
        private real r7
       
        private player plr
        private unit un
        private integer casts = 0
       
        private location l1 = Location(0,0)
        private location l2 = Location(0,0)
       
        private group grp1 = CreateGroup()
        private group grp2 = CreateGroup()
        private group casters = CreateGroup()
       
        private timer tmr = CreateTimer()
       
        private hashtable hash = InitHashtable()
        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    endglobals
   
   
    /*~The hash functions return the child hash integer for hashtable~*/
    private constant function HashCircles takes nothing returns integer
        return 1
    endfunction
   
    private constant function HashActiveCircles takes nothing returns integer
        return 2
    endfunction
   
    private constant function HashTime takes nothing returns integer
        return 3
    endfunction
   
    private constant function HashInterval takes nothing returns integer
        return 4
    endfunction
   
    private constant function HashDamage takes nothing returns integer
        return 5
    endfunction
   
    private constant function HashSafeWidth takes nothing returns integer
        return 6
    endfunction
   
    private constant function HashWaves takes nothing returns integer
        return 7
    endfunction
   
    private constant function HashFirstFree takes nothing returns integer
        return 8
    endfunction
   
    private constant function HashFirst takes nothing returns integer
        return 9
    endfunction
   
    private constant function HashLast takes nothing returns integer
        return 10
    endfunction
   
    private constant function HashMana takes nothing returns integer
        return 11
    endfunction
   
    private function HashAngle takes integer value returns integer
        return 10 * LIGHTNINGS + value
    endfunction
   
    private function HashDist takes integer value returns integer
        return 20 * LIGHTNINGS + value
    endfunction

    private function HashDestroyed takes integer value returns integer
        return 30 * LIGHTNINGS + value
    endfunction
   
    private function HashSafeAngle takes integer value returns integer
        return 40 * LIGHTNINGS + value
    endfunction
   
    private function HashRotSpeed takes integer value returns integer
        return 50 * LIGHTNINGS + value
    endfunction
   
    private function HashRotDir takes integer value returns integer
        return 60 * LIGHTNINGS + value
    endfunction
   
    private function HashDummy takes integer value1, integer value2 returns integer
        return 1000 * LIGHTNINGS + value1 * 100 + value2
    endfunction
   
    private function HashLightning takes integer value1, integer value2 returns integer
        return 5000 * LIGHTNINGS + value1 * 100 + value2
    endfunction
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   
   
    /*~~~~~~~~~~~~~~~~~~~~~~Deals damage to units~~~~~~~~~~~~~~~~~~~~~*/
    private function Pick_Filter_2 takes nothing returns boolean
        local unit u = GetFilterUnit()
        if not(IsUnitInGroup(u, grp1))                                      and /*
        */
IsUnitEnemy(u, plr)                                              and /*
        */
GetWidgetLife(u) > 0.405                                         and /*
        */
GetUnitFlyHeight(u) < HEIGHT                                     then
            if Cos(r1 - Atan2(GetUnitY(u) - r4, GetUnitX(u) - r3)) < r7 then
                call UnitDamageTarget(un, u, r5, false, true, ATKTYPE, DMGTYPE, null)
                call DestroyEffect(AddSpecialEffectTarget(DMG_EFFECT, u, "chest"))
            elseif GetUnitState(u, UNIT_STATE_MANA) > 0 then
                call DestroyEffect(AddSpecialEffectTarget(MANA_EFFECT, u, "chest"))
                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - r6)
            endif
        endif
        set u = null
        return FALSE
    endfunction

    private function Pick_Filter_1 takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(), plr)
    endfunction
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

   
    /*~~~~~~~~~~~~~Adds an expanding circle for the caster~~~~~~~~~~~~*/
    private function Add_Circle takes unit u, integer ID returns nothing
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real angle = GetRandomReal(-bj_PI, bj_PI)
        local real x1
        local real y1
        local real x2
        local real y2
        local integer i = 0
        local integer first = LoadInteger(hash, ID, HashFirst())
        local integer last = LoadInteger(hash, ID, HashLast())
        local integer free = LoadInteger(hash, ID, HashFirstFree())
        local integer circles = LoadInteger(hash, ID, HashCircles())
        local integer waves = LoadInteger(hash, ID, HashWaves())
        local lightning l
       
        // Saves the angle where the first lightning starts from
        call SaveReal(hash, ID, HashAngle(free), angle)
        // Saves the angle at the center of the safe lightnings
        call SaveReal(hash, ID, HashSafeAngle(free), angle + (I2R(MANA_LIGHTNINGS) / I2R(LIGHTNINGS))* bj_PI)
         
        // Randomizes the rotation angle
        if ROTATES then
            if GetRandomInt(1,2) == 1 then
                call SaveReal(hash, ID, HashRotDir(free), 1)
            else
                call SaveReal(hash, ID, HashRotDir(free), -1)
            endif
        endif
       
        // The loop creates a circle of lightnings and
        // dummies around the caster
        loop
            set x1 = x + INIT_DIST * Cos(angle)
            set y1 = y + INIT_DIST * Sin(angle)
            set angle = angle + 2 * bj_PI / LIGHTNINGS
            set x2 = x + INIT_DIST * Cos(angle)
            set y2 = y + INIT_DIST * Sin(angle)
               
            if i < MANA_LIGHTNINGS then
                set l = AddLightningEx(TYPESAFE , true , x1 , y1 , HEIGHT , x2 , y2 , HEIGHT)
                call SetLightningColor(l, MRED, MGREEN, MBLUE, MALPHA)
            else
                set l = AddLightningEx(TYPEDANGER , true , x1 , y1 , HEIGHT , x2 , y2 , HEIGHT)
                call SetLightningColor(l, HRED, HGREEN, HBLUE, HALPHA)
            endif
           
            set bj_lastCreatedUnit = CreateUnit(Player(15), DUMMY_TYPE, x1, y1, angle*bj_RADTODEG)
            call SetUnitFlyHeight(bj_lastCreatedUnit, HEIGHT, 0)
            // Remove Move ability from dummy so it won't try to return
            // to the pointwhere it was created at
            call UnitRemoveAbility(bj_lastCreatedUnit, 'Amov')
               
            call SaveUnitHandle(hash, ID, HashDummy(free,i), bj_lastCreatedUnit)
            call SaveLightningHandle(hash, ID, HashLightning(free,i), l)
               
            set i = i + 1
            exitwhen i >= LIGHTNINGS
        endloop
       
        // Saves the distance of the circle from the caster
        call SaveReal(hash, ID, HashDist(free), INIT_DIST)
        call SaveBoolean(hash, ID, HashDestroyed(free), false)
        call SaveInteger(hash, ID, HashCircles(), circles + 1)
        call SaveInteger(hash, ID, HashFirstFree(), free + 1)
        call SaveInteger(hash, ID, HashActiveCircles(), LoadInteger(hash, ID, HashActiveCircles()) + 1)
        call SaveReal(hash, ID, HashRotSpeed(free), GetRandomReal(MIN_ROT_SPD, MAX_ROT_SPD))
       
        // Update the smallest index to loop through
        if free < first then
            call SaveInteger(hash, ID, HashFirst(), free + 1)
        endif
       
        // Update the largest index to loop through
        if free > last then
            call SaveInteger(hash, ID, HashLast(), free)
        endif
           
        set l = null
    endfunction
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


    private function Loop takes nothing returns nothing
        local unit u = GetEnumUnit()
        local integer ID = GetHandleId(u)
        local integer i = 0
        local integer j = LoadInteger(hash, ID, HashFirst())
        local integer k = 1
        local integer oid = GetUnitCurrentOrder(u)
        local integer free = LoadInteger(hash, ID, HashFirstFree())
        local integer circles = LoadInteger(hash, ID, HashCircles())
        local integer activeCircles = LoadInteger(hash, ID, HashActiveCircles())
        local integer maxloop = LoadInteger(hash, ID, HashLast())
        local real time = LoadReal(hash, ID, HashTime())+ TIMEOUT
        local real interv = LoadReal(hash, ID, HashInterval()) + TIMEOUT
        local real rotdir
        local real offset
        local real angle
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real x1
        local real x2
        local real y1
        local real y2
        local unit dummy
        local lightning l
       
       
        // Caster must be alive, waves left to cast and at least one active circle
        if not(IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0) and (circles < LoadInteger(hash, ID, HashWaves()) or activeCircles != 0) and oid == ORDERID then
            loop
                set rotdir = LoadReal(hash, ID, HashRotDir(j))
                set angle = LoadReal(hash, ID, HashAngle(j))
                set offset = LoadReal(hash, ID, HashDist(j)) + SPEED
                // Has the circle not reached max dist
                if offset < MAX_OFFSET then
                    set i = 0
                    loop
                        set x1 = x + offset * Cos(angle)
                        set y1 = y + offset * Sin(angle)
                        set angle = angle + 2 * bj_PI / LIGHTNINGS
                        set x2 = x + offset * Cos(angle)
                        set y2 = y + offset * Sin(angle)
                       
                        call MoveLocation(l1, x1, y1)
                        call MoveLocation(l2, x2, y2)
                       
                        set l = LoadLightningHandle(hash, ID, HashLightning(j,i))
                       
                        // Makes the lightnings to "flow" the right direction
                        if rotdir == 1 then
                            call MoveLightningEx(l, false, x2, y2, HEIGHT + GetLocationZ(l2), x1, y1, HEIGHT + GetLocationZ(l1))
                        else
                            call MoveLightningEx(l, false, x1, y1, HEIGHT + GetLocationZ(l1), x2, y2, HEIGHT + GetLocationZ(l2))
                        endif
                       
                        set dummy = LoadUnitHandle(hash, ID, HashDummy(j,i))
                        call SetUnitX(dummy, x1)
                        call SetUnitY(dummy, y1)
                       
                        set i = i + 1
                        exitwhen i > LIGHTNINGS
                    endloop
                   
                    set l = null
                    set dummy = null
                   
                    set un = u
                    set plr = GetOwningPlayer(u)
                    set r1 = LoadReal(hash, ID, HashSafeAngle(j))
                    set r2 = LoadReal(hash, ID, HashSafeWidth())
                    set r7 = Cos(r2)
                    set r3 = x
                    set r4 = y
                    set r5 = LoadReal(hash, ID, HashDamage())
                    set r6 = LoadReal(hash, ID, HashMana())
                   
                    call GroupEnumUnitsInRange(grp1, x, y, offset - LIGHTNING_WIDTH, function Pick_Filter_1)
                    call GroupEnumUnitsInRange(grp2, x, y, offset + LIGHTNING_WIDTH, function Pick_Filter_2)
                   
                    call SaveReal(hash, ID, HashDist(j), offset)
                   
                    // Updates the rotation angle and the safe angle
                    static if ROTATES then
                        call SaveReal(hash, ID, HashAngle(j), LoadReal(hash, ID, HashAngle(j)) + LoadReal(hash, ID, HashRotSpeed(j)) * LoadReal(hash, ID, HashRotDir(j)))
                        call SaveReal(hash, ID, HashSafeAngle(j), LoadReal(hash, ID, HashAngle(j)) + r2)
                    endif
                else
                    // Checks whether the circle has been destroyed already or not
                    if LoadBoolean(hash, ID, HashDestroyed(j)) != true then
                        // The loop destroys all dummies and lightnings of the circle
                        set k = 0
                        loop
                            // Checks that the lightning exists, can produce fatal error without this check
                            if HaveSavedHandle(hash, ID, HashLightning(j,k)) then
                                call DestroyLightning(LoadLightningHandle(hash, ID, HashLightning(j,k)))
                                call UnitApplyTimedLife(LoadUnitHandle(hash, ID, HashDummy(j,k)), 1 , 0.01)
                                call RemoveSavedHandle(hash, ID, HashLightning(j,k))
                            endif
                            set k = k + 1
                            exitwhen k > LIGHTNINGS
                        endloop
                        // Marks the circle as been destroyed
                        call SaveBoolean(hash, ID, HashDestroyed(j), true)
                        // Reduces the number of active circles for the caster
                        call SaveInteger(hash, ID, HashActiveCircles(), activeCircles - 1)
                        // Updates the first free index
                        if j < free then
                            call SaveInteger(hash, ID, HashFirstFree(), j)
                        endif
                    endif
                endif
                set j = j + 1
                exitwhen j > maxloop
            endloop
            // Updates the interval time used for creating a new circle
            call SaveReal(hash, ID, HashTime(), interv)
            if circles < LoadInteger(hash, ID, HashWaves()) then
                if interv >= INTERVAL then
                    call Add_Circle(u, ID)
                    call SaveReal(hash, ID, HashInterval(), 0)
                else
                    call SaveReal(hash, ID, HashInterval(), interv)
                endif
            endif
        else
            loop
                set k = 0
                loop
                    if HaveSavedHandle(hash, ID, HashLightning(j,k)) then
                        call DestroyLightning(LoadLightningHandle(hash, ID, HashLightning(j,k)))
                        call UnitApplyTimedLife(LoadUnitHandle(hash, ID, HashDummy(j,k)), 1 , 0.01)
                    endif
                    set k = k + 1
                    exitwhen k > LIGHTNINGS
                endloop
                set j = j + 1
                exitwhen j > maxloop
            endloop
            call GroupRemoveUnit(casters, u)
            if oid == ORDERID then
                call IssueImmediateOrder(u, "stop")
            endif
            call FlushChildHashtable(hash, ID)
           
            set casts = casts - 1
            if casts == 0 then
                call PauseTimer(tmr)
            endif
        endif
       
        set u = null
    endfunction


    private function Timer_Expire takes nothing returns nothing
        call ForGroup(casters, function Loop)
    endfunction


    private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer ID = GetHandleId(u)
        local integer level = GetUnitAbilityLevel(u, ABILCODE) - 1
       
        /*~~~ 0 value doesn't need to be saved but I do it to remember ~~~*/
        /*~~~~~~~~~~~~~~~ the things that need to be saved ~~~~~~~~~~~~~~~*/
       
        // call SaveReal(hash, ID, HashTime(), 0)
        // call SaveReal(hash, ID, HashInterval(), 0)
        // call SaveInteger(hash, ID, HashLast(), 0)
        // call SaveInteger(hash, ID, HashFirst(), 0)
        // call SaveInteger(hash, ID, HashCircles(), 0)
        // call SaveInteger(hash, ID, HashFirstFree(), 0)
        // call SaveInteger(hash, ID, HashActiveCircles(), 0)
       
        call SaveInteger(hash, ID, HashWaves(), WAVES + WAVES_BONUS * level)
        call SaveReal(hash, ID, HashDamage(), DMG_BASE + DMG_BONUS * level)
        call SaveReal(hash, ID, HashMana(), MANA_BASE + MANA_BONUS * level)
        call SaveReal(hash, ID, HashSafeWidth(), I2R(MANA_LIGHTNINGS) / I2R(LIGHTNINGS)* bj_PI)
       
        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

        call Add_Circle(u, ID)
       
        call GroupAddUnit(casters, u)
        if casts == 0 then
            call TimerStart(tmr , TIMEOUT , true , function Timer_Expire)
        endif
        set casts = casts + 1
       
        set u = null
    endfunction

   
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABILCODE
    endfunction


    private function Omega_Wave takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(t, function Conditions )
        call TriggerAddAction(t, function Actions )
    endfunction

endscope
 



Change log

v1.00 Uploaded 20.04.2011
v1.01 Uploaded 21.04.2011
Changed the name of one variable
Made some hash functions constant
Small code improvements
v1.02 Uploaded 21.04.2011
Code improved
v1.03 Uploaded 22.04.2011
Code improved
v1.04
Added configurable lightning colour



Credits

Aeroblyctos for spell idea


Keywords:
omega, wave, lightning, laser, maker, aeroblyctos, circle
Contents

Omega Wave v1.04 (Map)

Reviews
Moderator
Bribe: This is a very inspiring spell for me. The effects are very creative. Technically speaking, the biggest improvement I see you don't have to init hashtable values to 0 - you can remove those lines as hashtables will return 0 if they aren't...
  1. Bribe:

    This is a very inspiring spell for me. The effects are very creative.

    Technically speaking, the biggest improvement I see you don't have to init hashtable values to 0 - you can remove those lines as hashtables will return 0 if they aren't set - it's not like using an un-initialized global. Arrays work the same as this (auto-init to 0). This won't affect the speed too tremendously but would decrease the map size a bit.

    At the people worried that the constant functions don't inline - JassHelper does inline them. This ends up being very efficient.
     
  2. Marsal

    Marsal

    Joined:
    Jun 24, 2009
    Messages:
    1,345
    Resources:
    15
    Maps:
    1
    Spells:
    14
    Resources:
    15
    looks nice but there are more green lightings than blue ones ~.~
     
  3. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,190
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    You can configure that in the variables.

    Personally I want it to have more greens than blues, green ones deal damage, blues drain mana. Not all units have mana.
     
  4. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    VERY ORIGINAL!
    Excellent work mate :)

    Just a few things:
    Code (vJASS):

        private function HashCircles takes nothing returns integer
            return 1
        endfunction
       
        private function HashActiveCircles takes nothing returns integer
            return 2
        endfunction
       
        private function HashTime takes nothing returns integer
            return 3
        endfunction
       
        private function HashInterval takes nothing returns integer
            return 4
        endfunction
       
        private function HashDamage takes nothing returns integer
            return 5
        endfunction
       
        private function HashSafeWidth takes nothing returns integer
            return 6
        endfunction
       
        private function HashWaves takes nothing returns integer
            return 7
        endfunction
       
        private function HashFirstFree takes nothing returns integer
            return 8
        endfunction
       
        private function HashFirst takes nothing returns integer
            return 9
        endfunction
       
        private function HashLast takes nothing returns integer
            return 10
        endfunction
       
        private function HashMana takes nothing returns integer
            return 11
        endfunction
     


    I know these functions help readability, but I think it's best (for efficiency) if you just use
    the values in your code instead of calling these functions.

    If you don't like my suggestion, then I guess the least you could do is call them "constant"
    functions. This way, they'd be faster.
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    *Whisper*: He's on to us.. Get him! ;p (I don't get it too xD)

    *looks for any reason to make a post so it doesn't count as spam* ... ...

    FOUND ONE:

    Code (vJASS):
    local unit u = GetFilterUnit()
            if not(IsUnitInGroup(u, grp1))                                      and /*
            */
    IsUnitEnemy(GetFilterUnit(), plr)                                and /*


    Instead of GetFilterUnit(), use the local u

    Another thing, I don't know if this will make any difference to the efficiency, but over here:
    (IsUnitType(u, UNIT_TYPE_DEAD)
    , you could use
    GetWidgetLife(u) <= 0.405
     
  6. Marcos DAB

    Marcos DAB

    Joined:
    Mar 26, 2011
    Messages:
    1,041
    Resources:
    218
    Models:
    1
    Icons:
    214
    Spells:
    2
    Tutorials:
    1
    Resources:
    218
    Very impressive. Nice work.
     
  7. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,190
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Thanks for the comments!

    They will remain functions :) But I will make the functions constant.

    Yeah.

    Apparently GetWidgetLife, while being faster, can bug in some rare cases.
     
  8. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    SOLD! ;P

    One last thing to make this as efficient as possible:
    Store the level of the ability in an integer instead of repeating the function call here:

    Code (vJASS):
    local unit u = GetTriggerUnit()
            local integer ID = GetHandleId(u)
           
            /*~~~ 0 value doesn't need to be saved but I do it to remember ~~~*/
            /*~~~~~~~~~~~~~~~ the things that need to be saved ~~~~~~~~~~~~~~~*/
            call SaveInteger(hash, ID, HashLast(), 0)
            call SaveInteger(hash, ID, HashFirst(), 0)
            call SaveInteger(hash, ID, HashCircles(), 0)
            call SaveInteger(hash, ID, HashFirstFree(), 0)
            call SaveInteger(hash, ID, HashActiveCircles(), 0)
            call SaveInteger(hash, ID, HashWaves(), WAVES + WAVES_BONUS * (GetUnitAbilityLevel(u, ABILCODE)) - 1)
            call SaveReal(hash, ID, HashTime(), 0)
            call SaveReal(hash, ID, HashInterval(), 0)
            call SaveReal(hash, ID, HashSafeWidth(), I2R(SAFE_LIGHTNINGS) / I2R(LIGHTNINGS)* bj_PI)
            call SaveReal(hash, ID, HashDamage(), DMG_BASE + DMG_BONUS * (GetUnitAbilityLevel(u, ABILCODE)) - 1)
            call SaveReal(hash, ID, HashMana(), MANA_BASE + MANA_BONUS * (GetUnitAbilityLevel(u, ABILCODE)) - 1)
     


    That should do it :)
    The spell is now as efficient as possible .. at least i hope so :p
     
  9. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,190
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    I spesifically didn't declare a variable for that since I'm calling the function only twice. Not worth it IMO :)

    Thanks for the suggestion though.

    There's still room for improving efficiency. Like storing the Cos(r2) into hashtable. But I will take a look at things when I have more time.
     
  10. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Look Again ;)
    3 times.

    Btw, I gave it a 5/5 due to its originality, lack of leaks and bugs, and its efficiency :)
     
  11. Adiktuz

    Adiktuz

    Joined:
    Oct 16, 2008
    Messages:
    9,674
    Resources:
    23
    Models:
    2
    Packs:
    1
    Maps:
    1
    Spells:
    16
    Tutorials:
    1
    JASS:
    2
    Resources:
    23
    Wow, really original and awesome spell. ^_^
     
  12. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Hmm... now to take this and turn it into JASS...
     
  13. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
    Alright haven't reviewed a spell in a while so don't blame me.

    -private functions doesn't need to be prefixed, they're private?

    -merge the conditions and the actions

    return GetSpellAbilityId() == ABILCODE


    will be an if instead and below that you put all your actions

    and remember to always return false afterwards

    -I don't get why you aren't using structs, your life could have been much more easier but as you are using hashtables, use Bribe's New Table library no buts

    -these calls are unnecessary as GroupEnumUnitsInRange clears a group before it enums
    call GroupClear(grp1)
    call GroupClear(grp2)

    -you should be ashamed (no offense :p), using globals and yet arent using global locations
    Code (vJASS):
            local location l1 = null
            local location l2 = null


    create two global locations and call the native "MoveLocation" to your newx and newy and then you can play with GetLocationZ and don't have to remove them

    -I don't get this, in the filter function, you are only using GetWidgetLife as death check yet in the loop you use IsUnitType and GetUnitTypeId. Combine atleast GWL and IUT at both places.

    This is a great spell though no question about it.
     
  14. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,190
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Thank you for the suggestions baassee.

    The spell was originally coded in plain JASS since it was for a campaign. That's why no structs and prefixed functions :)
     
  15. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
  16. Vercas

    Vercas

    Joined:
    Dec 9, 2007
    Messages:
    2,604
    Resources:
    1
    Spells:
    1
    Resources:
    1
    This is so cool! Good job!
     
  17. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    My feedback:

    • Code (vJASS):
      /*~~~ 0 value doesn't need to be saved but I do it to remember ~~~*/
              /*~~~~~~~~~~~~~~~ the things that need to be saved ~~~~~~~~~~~~~~~*/

      Now that you are done remembering and saving, you can feel free to remove them, unless I'm mistaken. :p
    • In the loop function, not all of the variables need to be initialized. (eg: x1, x2, y1, y2... etc)
    • For this:
      Code (vJASS):
                              if rotdir == 1 then
                                  call MoveLightningEx(l, false, x2, y2, HEIGHT + GetLocationZ(l2), x1, y1, HEIGHT + GetLocationZ(l1))
                              else
                                  call MoveLightningEx(l, false, x1, y1, HEIGHT + GetLocationZ(l1), x2, y2, HEIGHT + GetLocationZ(l2))
                              endif

      You can just move one location (and only use one). It will either be moved to (x2,y2) or (x1,y1), so you don't need two separate locations unless you are doing it for both. So it can be:
      Code (vJASS):
                              if rotdir == 1 then
                                  call MoveLocation(l1,x2,y2)
                                  call MoveLightningEx(l, false, x2, y2, HEIGHT + GetLocationZ(l1), x1, y1, HEIGHT + GetLocationZ(l1))
                              else
                                  call MoveLocation(l1,x1,y1)
                                  call MoveLightningEx(l, false, x1, y1, HEIGHT + GetLocationZ(l1), x2, y2, HEIGHT + GetLocationZ(l1))
                              endif
    • "l" and "dummy" don't need to be nulled per loop, just nulled when they are done being used in general. (at the bottom of the function or after the loop..)
    • Instead of using r1, r2, r3... You should make it an array.
    • Instead of using grp1, you might be able to just use
      not IsUnitInRangeXY
      .
    • Possibly merge the conditions and actions.

    Otherwise, really cool spell. :)

    Afaik, it is the same speed. Someone did benchmarks a long time ago, and they ended up being the same in terms of speed. However, I still recommend keeping the
    constant
    there so that the people will know that they can modify those values. =)
     
  18. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    =D Thanks for that information =D
    I guess I should remove those "constant" keywords from my map's functions
    (I'll save 8 bytes per keyword :D :D)
     
  19. yurneric

    yurneric

    Joined:
    Jul 16, 2009
    Messages:
    92
    Resources:
    0
    Resources:
    0
    Instead of having a semi-circle of green and a semi-circle of blue, why not alternate them between green and blue lightning?

    In other words: green lightning, then blue lightning, then green again, followed by blue, etc.

    It makes dodging more challenging when the dodger has to "slip" through a small gap.