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. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  5. Dismiss Notice
  6. The Highway to Hell has been laid open. Come along and participate in the 5th Special Effect Contest.
    Dismiss Notice
  7. 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.

Luck Aura v1.3

Submitted by mckill2009
This bundle is marked as approved. It works and satisfies the submission rules.
Luck Aura v1.3
Once activated, it brings good luck to the caster and his allies, giving a chance to drop random items from kills depending on the level of the spell.

|cffffcc00Level 1|r - 15% of Level 1 items,
|cffffcc00Level 2|r - 20% of Level 1-3 items.
|cffffcc00Level 3|r - 25% of Level 1-4 items.
|cffffcc00Level 4|r - 30% of Level 1-5 items.

Code (vJASS):

/*
===Luck Aura v1.3
===By Mckill2009

INSTALLATION:
- Copy the custom dummy unit/buff/abilities to your map
- You MUST input or change the correct rawID's (see below)
- To view rawID, press CTRL+D in the object editor
- Copy ALL the required libraries and the LuckAura trigger to your map (SimError is optional)
- Change the CONFIGURABLES and AOE if needed
- DONE!

REQUIRED LIBRARIES:
- RegisterPlayerUnitEvent by Magtheridon96
- Table by Bribe
- SpellEffectEvent by Bribe
- *SimError (Optional)

FULL DESCRIPTION:
Once activated, it brings good luck to the caster and his allies, giving a chance to drop random items from kills depending on the level of the spell.

|cffffcc00Level 1|r - 15% of Level 1 items,
|cffffcc00Level 2|r - 20% of Level 1-3 items.
|cffffcc00Level 3|r - 25% of Level 1-4 items.
|cffffcc00Level 4|r - 30% of Level 1-5 items.

|cffffcc00Spell lasts 30 seconds.|r
*/


scope LuckAura

globals
    private Table lu //NEVER TOUCH THIS!
    private constant itemtype          ITEMID = ITEM_TYPE_ANY
    private constant real                 AOE = 600 //Buff Effect or range, make sure that this matches the AOE of DUMMY_SPELL_ID
    private constant integer         SPELL_ID = 'A001' //Hero ability rawID
    private constant integer   DUMMY_SPELL_ID = 'A000' //Buff Aura rawID
    private constant integer         DUMMY_ID = 'h000' //Dummy Unit rawID
    private constant integer             BUFF = 'B000' //Buff Aura rawID    
endglobals

//===CONFIGURABLES:
private function GetDuration takes integer i returns real
    return 30.
endfunction

private function GetChance takes integer i returns integer
    return 10 + i * 5
endfunction
//===END OF CONFIGURABLES

private function EnemyDies takes unit u, unit k returns nothing
    local unit first
    local integer level
    call GroupEnumUnitsInRange(bj_lastCreatedGroup,GetUnitX(k),GetUnitY(k),AOE,null)
    loop
        set first = FirstOfGroup(bj_lastCreatedGroup)
        exitwhen first==null
        if UnitAlive(first) and lu.has(GetHandleId(first)) then
            set level = lu[GetHandleId(first)]
            if GetRandomInt(1,100) <= GetChance(level) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                if level==1 then
                    call CreateItem(ChooseRandomItemEx(ITEMID, 1), GetUnitX(u), GetUnitY(u))
                else
                    call CreateItem(ChooseRandomItemEx(ITEMID, GetRandomInt(1,level+1)), GetUnitX(u), GetUnitY(u))
                endif
            endif
        endif
        call GroupRemoveUnit(bj_lastCreatedGroup,first)
    endloop
endfunction

private function EnemyDiesCond takes nothing returns nothing
    if (GetUnitAbilityLevel(GetKillingUnit(), BUFF) > 0) and IsUnitEnemy(GetKillingUnit(),GetTriggerPlayer()) then  
        call EnemyDies(GetTriggerUnit(), GetKillingUnit())
    endif
endfunction

private struct Luck
    unit caster
    unit dummy
    real duration
   
    private static timer tim
    private static integer index = 0
    private static integer array indexAR  
    private static thistype DATA
   
    private static method looper takes nothing returns nothing
        local thistype this
        local integer i = 0
        loop
            set i = i+1
            set this = indexAR[i]
            if .duration > 0 and UnitAlive(.caster) then
                set .duration = .duration - 0.5
                call SetUnitX(.dummy, GetUnitX(.caster))
                call SetUnitY(.dummy, GetUnitY(.caster))
            else
                call KillUnit(.dummy)
                call lu.remove(GetHandleId(.caster))
                set .caster = null
                set .dummy = null
                call .destroy()
                set indexAR[i] = indexAR[index]
                set indexAR[index] = this
                set i = i-1
                set index = index - 1
                if index==0 then
                    call PauseTimer(tim)
                    call DestroyTimer(tim)
                endif    
            endif            
            exitwhen i==index
        endloop
    endmethod
                                             
    private static method cast takes nothing returns nothing
        local thistype this
        local unit u = GetTriggerUnit()
        local timer t
        local integer timerID
        local integer casterID = GetHandleId(u)
        local integer level  
        local player p = GetTriggerPlayer()
        if not lu.has(casterID) then
            set this = allocate()
            set level = GetUnitAbilityLevel(u, SPELL_ID)
            set lu[casterID] = level
            set .caster = GetTriggerUnit()
            set .dummy = CreateUnit(p, DUMMY_ID, GetUnitX(u), GetUnitY(u), 0)            
            set .duration = GetDuration(level)
            if index==0 then
                set tim = CreateTimer()
                call TimerStart(tim, 0.5, true, function thistype.looper)
            endif
            set index = index + 1
            set indexAR[index] = this
            call UnitAddAbility(dummy, DUMMY_SPELL_ID)
            call SetUnitAbilityLevel(dummy, DUMMY_SPELL_ID, level)
        else
            call IssueImmediateOrder(u, "stop")
            static if LIBRARY_SimError then
                call SimError(p, "Can't be used yet!")
            endif
        endif
        set u = null
        set p = null
    endmethod
   
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(SPELL_ID, function thistype.cast)
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function EnemyDiesCond)
        set lu = Table.create()
    endmethod
endstruct

endscope
 


Changelogs

v1.3
- Changed to structs
- Uses only 1 timer
- Uses 2 additional libraries

v1.2
- 6 Lines reduced.
- "u" is nulled from FilterThem.
- Ability level reduced to 4, as suggested by Bribe (I dont really understand why).
- Description changed.

v1.1
- Converted to vJass with optimized coding.
- Uses known libraries.
- Description changed.


Keywords:
aura, active, passive, item, enemy, powerup
Contents

Luck Aura (Map)

Reviews
Moderator
13 Dec 2011 Bribe: Approved.
  1. 13 Dec 2011
    Bribe: Approved.
     
  2. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
    Nice to see you stepping up your coding knowledge. So here we go.

    -Don't use actions, merge them with the conditions.

    -Trigger t2 shouldn't have actions either, just add condition and make the actions there.

    And remember to return false afterwards.

    -Instead of creating your own hashtable, use this: Link to Bribe's New Table

    -Please use TimerUtils, you never destroy timers in vJASS.

    -These are unneeded. What are you trying to do? Shadow globals?

    -No need to use this local or shadowed global in the filter, it's only used once anyway.
    set targetID = GetHandleId(u)

    -GetOwningPlayer(u) -> GetTriggerPlayer() in the cast trigger.

    -In the loop function, the GetUnitX(u), GetUnitY(u) should be stored into locals, saving two additional calls.

    -Should be a local integer
    set level = LoadInteger(HASH, timerID, 5)// This is a global variable

    That's what I could find for now. You should really learn to use the ability to use libraries in vJASS. Will save ya lots of work. Example that could make this even better is to use Axarion's advanced aura module.
     
  3. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Code (vJASS):
    private function LUCK_DEATHS takes nothing returns nothing
        local unit k = GetTriggerUnit()
        local unit u = GetKillingUnit()
        local real x = GetUnitX(k)
        local real y = GetUnitY(k)
        local integer targetID = GetHandleId(u) // This is a global variable
        local integer level = LoadInteger(HASH, targetID, 1)
        if IsUnitEnemy(u, GetOwningPlayer(k)) and GetRandomInt(1,100) <= LUCK_CHANCE(level) and IsUnitType(k, UNIT_TYPE_STRUCTURE)==false then
            if GetUnitAbilityLevel(u, BUFF) > 0 then
                call CreateItem(ChooseRandomItemEx(ITEMID, level), x, y)
            endif
        endif
        set k = null
        set u = null
    endfunction
     


    Since you only used x and y once, it's better to just use the functions :)
    You don't need locals if you're only going to use them once :)

    Code (vJASS):
    private function LUCK_FILTER takes nothing returns boolean
        local unit u = GetFilterUnit()
        local integer targetID
        if IsUnitAlly(u, GetOwningPlayer(u)) and GetUnitAbilityLevel(u, BUFF) > 0 then
            set targetID = GetHandleId(u)
            call SaveInteger(HASH, targetID, 1, level)
        endif
        return true
    endfunction
     


    Since it would make no difference, I think it's better to just set the targetID to the handle id
    of the unit on local declaration :)

    Code (vJASS):
    private function LUCK_LOOP takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer timerID = GetHandleId(t)
        local unit u = LoadUnitHandle(HASH, timerID, 1)
        local unit dummy = LoadUnitHandle(HASH, timerID, 2)
        local real duration = LoadReal(HASH, timerID, 3)
        local real AoE = LoadReal(HASH, timerID, 4)
        local integer casterID = GetHandleId(u)
        set level = LoadInteger(HASH, timerID, 5)// This is a global variable
        if duration >0 and GetWidgetLife(u) >= 0.405 then
            call SetUnitX(dummy, GetUnitX(u))
            call SetUnitY(dummy, GetUnitY(u))
            call SaveReal(HASH, timerID, 3, duration - TIMERSPEED)
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(u), GetUnitY(u), AoE, Filter(function LUCK_FILTER))
        else
            call UnitApplyTimedLife(dummy, 'BTLF', 0.01)
            call SetUnitExploded(dummy, true)
            call FlushChildHashtable(HASH, timerID)      
            call FlushChildHashtable(HASH, casterID)
            call PauseTimer(t)
            call DestroyTimer(t)
        endif
        set t = null
        set u = null
        set dummy = null
    endfunction
     


    This would be a good place to declare 2 local real variables for the units
    x and y since you're using the functions more than once.

    Also,
    Filter(function LUCK_FILTER))

    You don't really need to use the "Filter".
    Without it, it would still function similarly :]
    Using it in this case is a waste of efficiency :/

    Code (vJASS):
    private function LUCK_CAST takes nothing returns nothing
        local timer t = CreateTimer()
        local unit u = GetTriggerUnit()
        local unit dummy
        local integer timerID = GetHandleId(t)
        local integer casterID = GetHandleId(u)
        local integer level = GetUnitAbilityLevel(u, ABILITY_ID)
        local real duration = LUCK_DURATION(level)
        local real AoE = LUCK_AOE(level)
        local texttag tag = CreateTextTag()
        if HaveSavedReal(HASH, casterID, 1)==false then
            set dummy = CreateUnit(GetOwningPlayer(u), DUMMY_ID, GetUnitX(u), GetUnitY(u), 0)    
            call UnitAddAbility(dummy, DUMMYABILITY_ID)
            call SetUnitAbilityLevel(dummy, DUMMYABILITY_ID, level)
           
            //SAVE FOR THE CASTER ID
            call SaveReal(HASH, casterID, 1, duration)
           
            //SAVE FOR THE TIMER ID
            call SaveUnitHandle(HASH, timerID, 1, u)
            call SaveUnitHandle(HASH, timerID, 2, dummy)
            call SaveReal(HASH, timerID, 3, duration)
            call SaveReal(HASH, timerID, 4, AoE)
            call SaveInteger(HASH, timerID, 5, level)
            call TimerStart(t, TIMERSPEED, true, function LUCK_LOOP)
        else
            call IssueImmediateOrder(u, "stop")
            call SetTextTagPosUnit(tag, u, 0.)
            call SetTextTagText(tag, "You can't use this yet!", 0.025)
            call SetTextTagPermanent(tag, false)
            call SetTextTagVelocity(tag, 0.03, 0.03)
            call SetTextTagLifespan(tag, 3)
            call SetTextTagFadepoint(tag, 0.01)        
        endif
        set t = null
        set u = null
        set dummy = null
        set tag = null
    endfunction
     


    This function looks good :)


    I think that almost ANY spell that happens to be efficient and original
    deserves a 5/5 :) (In 90% of all cases that is ;P)
     
  4. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
    Does it? As it seems to inline a filter without the "Filter" infront of it.
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    You're most probably right ;)
     
  6. Marcos DAB

    Marcos DAB

    Joined:
    Mar 26, 2011
    Messages:
    1,042
    Resources:
    218
    Models:
    1
    Icons:
    214
    Spells:
    2
    Tutorials:
    1
    Resources:
    218
    Its too imba for an balanced Map.
     
  7. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    thanks for all your suggestion guys, however, I just started to make vJASS spells since my JNGP fucked up before...So I may need time to learn libraries and structs...

    I really need to use filter since I dont want to pick up every unit, but I think I will change it to "GetUnitAbilityLevel(u, BUFF) > 0" only...

    As for merging actions, Ima excercise that next update...

    @Marcos DAB
    The configurations are there for a reason :)...
     
  8. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
    What he meant was that without typing keyword Filter it will inline and add a filter by default and do not give a syntax error as long as the function returns a boolean.
     
  9. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,083
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Currently your system will cause errors - what if RemoveUnit is called? The death event won't fire and you're stuck with unused space in your hashtable that will probably never be clear thus filling up unnecessary memory.

    If you use a unit-indexing system, you will not have to worry about this as the indexer takes care of the deindexing portion and the arrays' data will be replaced with other data at some point.
     
  10. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    RemoveUnit meaning globally or the FlushChildHandle?...from what I see, the Flushing of targetID is not there so maybe it will cause error or leak...I assume that unit-indexing system is a library but idk it yet, so I better stick to hashtables first...

    @baassee
    my bad...
     
  11. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,083
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
  12. SpectreD

    SpectreD

    Joined:
    Apr 4, 2011
    Messages:
    548
    Resources:
    0
    Resources:
    0
    i love the idea of this spell. thank you for the share
     
  13. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    Changed most of it however I really dont know why I'd be using FirstOfGroup coz
    TimerLoop is meant to Filter 'all' those who gets near the hero, not the FirstOfGroup...
     
  14. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,083
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    A FirstOfGroup loop is the same thing as doing a group filter if you only use the group for that one moment. I don't know what you're talking about because it seems like you think that FirstOfGroup only picks one unit, but if you do the FirstOfGroup loop it picks all the units, the same as the filter.
     
  15. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    you mean something like this?...
    I'm surprised, its faster :)...
    Code (vJASS):

    function Actions takes nothing returns nothing
        local unit u
        call GroupEnumUnitsInRange(bj_lastCreatedGroup,0,0,5000,null)  
        loop
            set u = FirstOfGroup(bj_lastCreatedGroup)
            exitwhen u==null
            if not IsUnitType(u, UNIT_TYPE_DEAD) then
                call KillUnit(u)
                set I = I+1
                call BJDebugMsg(I2S(I))
            endif
            call GroupRemoveUnit(bj_lastCreatedGroup, u)
        endloop
    endfunction
     
     
  16. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,083
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    People used to do all their loops via FirstOfGroup, but years ago the null filter leaked so everyone just did everything via the filter, because it didn't leak that way. But now that null filter can be used safely the FirstOfGroup loop is the best of the best.
     
  17. baassee

    baassee

    Joined:
    Nov 14, 2008
    Messages:
    3,220
    Resources:
    17
    Spells:
    14
    Tutorials:
    3
    Resources:
    17
    Don't use UnitAlive, it's the same as IsUnitType(unit, UNIT_TYPE_DEAD).
     
  18. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    I know that but the native is easier for me to write :)...