1. 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
  2. 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
  3. 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
  4. Dismiss Notice
  5. The Highway to Hell has been laid open. Come along and participate in the 5th Special Effect Contest.
    Dismiss Notice
  6. 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.

"evasion aura"

Discussion in 'World Editor Help Zone' started by Fingolfin, Mar 16, 2012.

  1. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    Hi everyone!
    I want to make a smoke grenade-type spell that gives all friendly units in area of effect the ability to dodge x percent of enemy attacks. My idea was to give evasion to all those units within the AoE, and then somehow remove it when they get outside of it. I just can't come up with how to do the removing part.
    Feel free to suggest other methods to achieve the same effect, as long as they don't involve a damage detection system, i have way too many units for that and they die way to fast for that to be reasonable.

    Please note that giving miss chance to enemies will NOT have the same effect, the idea is that units inside the smoke would be able to dodge bullets even from units outside of it!

    Thanks in advance!
     
  2. Ezekiel12

    Ezekiel12

    Joined:
    Mar 13, 2012
    Messages:
    1,053
    Resources:
    0
    Resources:
    0
    Okay, whats the problem about adding and removing an evasion ability?

    Unit - Add Ability
    Unit - Remove Ability

    Please specify so I can help you better..
     
  3. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    You could create a dummy unit at the center of the smoke. Periodically (every 0.2 seconds or whatever) pick units in range. If the picked unit doesn't have the ability, give it that. Add the unit into a group x. Also pick all units in group x and if the distance between the dummy and picked units is too great, remove the ability.

    The thing to keep in mind is that there can be more than one smokes, so if a unit that has the ability is not in range of any smoke, remove the ability.
     
  4. Mechanical Man

    Mechanical Man

    Joined:
    Jan 18, 2005
    Messages:
    5,385
    Resources:
    39
    Models:
    30
    Icons:
    3
    Packs:
    1
    Maps:
    4
    Tutorials:
    1
    Resources:
    39
    But that would be very inefficient :/
     
  5. Lembidi

    Lembidi

    Joined:
    Jul 30, 2011
    Messages:
    236
    Resources:
    0
    Resources:
    0
    How about x - x %
    Randomlized Blinded or Evasion!!
     
  6. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    Because i can't cycle through all units on the map to see if they are close to a smoke. Once i have added it, it should be removed once they get outside of the AoE again, and then i need to detect that.

    @Maker, that sounds like a reasonable idea. I could have a global group for all affected units, and a linked list of structs for the dummies that i loop though periodically. I am gonna tinker a bit with this and see what i get, but please, come with more ideas if you got any on how to make it in the slimmest way possible.

    EDIT: this is what i got after a couple of minutes:

    Code
    Code (vJASS):

    library SmokeGrenade requires ListModule

        globals
            private constant real    RANGE       = 300.
            private constant integer EVASION_ID  = 'A02O'
            private constant integer DUMMY_ID    = 'h013'
        endglobals
       
        private function filter takes nothing returns boolean
            return (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false)
        endfunction
       
        private struct dummy
            static group units
            static group temp
            static timer tick
            unit u
            real x
            real y
            implement List //for ListModule
           
            private static method EnumGiveAbil takes nothing returns nothing
                call UnitAddAbility(GetEnumUnit(), EVASION_ID)
                call GroupAddUnit(.units, GetEnumUnit())
            endmethod
           
            private static method GiveAbil takes nothing returns nothing
                local thistype this = .first
               
                loop
                    exitwhen this == 0
                   
                    call GroupEnumUnitsInRange(.temp, .x, .y, RANGE, Filter(function filter))
                    call ForGroup(.temp, function thistype.EnumGiveAbil)
                   
                    if .count < 1 then
                        call PauseTimer(.tick)
                    endif
                   
                    set this = .next
                endloop
            endmethod
           
            private static method hasAbil takes nothing returns nothing
                local thistype this = .first //ListModule helps me browse through every instance of the struct
                local unit target = GetEnumUnit()
                local real x = GetUnitX(target)
                local real y = GetUnitY(target)
                local real dx
                local real dy
               
                loop
                    exitwhen this == 0
                    set dx = .x - x
                    set dy = .y - y
                    //Remove evasion from all units that aren't close to a dummy
                    if SquareRoot(dx * dx + dy * dy) > RANGE then
                        call UnitRemoveAbility(target, EVASION_ID)
                        call GroupRemoveUnit(.units, target)
                    endif
                   
                    set this = .next
                endloop
               
                call thistype.GiveAbil() //and then we add them again to those who are
            endmethod
           
            private static method onExpire takes nothing returns nothing
                call ForGroup(.units, function thistype.hasAbil)
            endmethod
           
            static method Create takes real x, real y, player owner returns dummy
                local thistype this = thistype.allocate()
                set .u = CreateUnit(owner, DUMMY_ID, x, y, 0.)
                set .x = x
                set .y = y
               
                call listAdd()
               
                if .count == 1 then
                    call TimerStart(.tick, 0.6, true, function thistype.onExpire)
                endif
               
                return this
            endmethod
           
            method onDestroy takes nothing returns nothing
                call listRemove()
            endmethod
           
            private static method onInit takes nothing returns nothing
                set .tick   = CreateTimer()
                set .units  = CreateGroup()
                set .temp   = CreateGroup()
            endmethod
           
        endstruct

    endlibrary
     


    I had to do it in a backwards kind of fashion since i would otherwise have problems with overlapping auras, but i hope you understand how it is supposed to work. How do you think this looks?
     
    Last edited: Mar 16, 2012
  7. Ezekiel12

    Ezekiel12

    Joined:
    Mar 13, 2012
    Messages:
    1,053
    Resources:
    0
    Resources:
    0
    Well the event 'Unit - Unit Within Range' and then adding this unit to the group x as Maker said and so on should be quite efficient, no?
     
  8. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    I hade a code library that i added to my post above, check that out.

    The way i made it is like this:

    1. Browse through the global group and compare each units location to each dummy unit. If it is outside of range, remove evasion. This will fire when the unit is away from ANY dummy on the map, hence i have to do it before i add them again.

    2. Browse through all dummies, pick all organic units near them, give them the ability and add them to the global group. It picks all units intentionally, i don't care about ownership.

    EDIT: I just realized, my code doesn't work. Since i compare all units to all dummies, and remove evasion when the unit is away from at least ONE of all the dummies, it will always remove it unless the dummies are all infact in the same spot. Duh. Gonna do a quick fix for this...

    EDIT2: this should work better:

    Code
    Code (vJASS):

    library SmokeGrenade requires ListModule

        globals
            private constant real    RANGE       = 300.
            private constant integer EVASION_ID  = 'A02O'
            private constant integer DUMMY_ID    = 'h013'
        endglobals
       
        private function filter takes nothing returns boolean
            return (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false)
        endfunction
       
        private struct dummy
            static group units
            static group temp
            static timer tick
            unit u
            real x
            real y
            implement List //for ListModule
           
            private static method EnumGiveAbil takes nothing returns nothing
                call UnitAddAbility(GetEnumUnit(), EVASION_ID)
                call GroupAddUnit(.units, GetEnumUnit())
            endmethod
           
            private static method GiveAbil takes nothing returns nothing
                local thistype this = .first
               
                loop
                    exitwhen this == 0
                   
                    call GroupEnumUnitsInRange(.temp, .x, .y, RANGE, Filter(function filter))
                    call ForGroup(.temp, function thistype.EnumGiveAbil)
                   
                    if .count < 1 then
                        call PauseTimer(.tick)
                    endif
                   
                    set this = .next
                endloop
            endmethod
           
            private static method hasAbil takes nothing returns nothing
                local thistype this = .first
                local unit target = GetEnumUnit()
                local real x = GetUnitX(target)
                local real y = GetUnitY(target)
                local real dx
                local real dy
                local integer count = 0
               
                loop
                    exitwhen this == 0
                    set dx = .x - x
                    set dy = .y - y
                   
                    if SquareRoot(dx * dx + dy * dy) < RANGE then
                        set count = count+1
                    endif
                   
                    set this = .next
                endloop
               
                if count == 0 then
                    call UnitRemoveAbility(target, EVASION_ID)
                    call GroupRemoveUnit(.units, target)
                endif
               
                call thistype.GiveAbil()
            endmethod
           
            private static method onExpire takes nothing returns nothing
                call ForGroup(.units, function thistype.hasAbil)
            endmethod
           
            static method Create takes real x, real y, player owner returns dummy
                local thistype this = thistype.allocate()
                set .u = CreateUnit(owner, DUMMY_ID, x, y, 0.)
                set .x = x
                set .y = y
               
                call listAdd()
               
                if .count == 1 then
                    call TimerStart(.tick, 0.6, true, function thistype.onExpire)
                endif
               
                return this
            endmethod
           
            method onDestroy takes nothing returns nothing
                call listRemove()
            endmethod
           
            private static method onInit takes nothing returns nothing
                set .tick   = CreateTimer()
                set .units  = CreateGroup()
                set .temp   = CreateGroup()
            endmethod
           
        endstruct

    endlibrary
     
     
  9. shadowvzs

    shadowvzs

    Joined:
    Nov 13, 2006
    Messages:
    1,803
    Resources:
    2
    Spells:
    2
    Resources:
    2
    just a question, why dont make a normal dummy aura(example endurance aura with 0 attack & move speed with different buff icon and description) and with damage detection system u check if DagameEventTarget got this aura buff then with random u make x% chance for Damage = 0 and write out miss :p

    ok maker way is better if u want customize the eva chance, but if i remember Nest also made snip about aura things :) http://www.hiveworkshop.com/forums/jass-resources-412/snippet-auralevel-212146/
     
  10. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    Because of the reason i already stated, i have too many units in my map that spawn and die too frequently to justify a damage detection system for all units. It requires you to create and destroy triggers everytime a unit dies and spawns, and the more often you do this the more likely it is to bug since destroying triggers on runtime is never very safe.
     
  11. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Actually, the easiest solution is this

    http://www.hiveworkshop.com/forums/jass-resources-412/snippet-aurastruct-205061/

    Create dummy, create aura for dummy. On enter range, add ability of level. On leave range, remove ability of level. Done.

    Take you 5 minutes to code and it's efficient >.>.


    The only problem is that all of your standard auras would then need to be custom auras as it does not work with wc3 standard auras : |. Wc3 standard auras break unit in range event ;p.
     
  12. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    That looks cool, i might try it out! Sucks that it breaks normal auras though.
     
  13. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Well, no, it's the other way around

    Meaning that standard wc3 auras break AuraStruct ; )
     
  14. Arhowk

    Arhowk

    Joined:
    Aug 8, 2007
    Messages:
    2,752
    Resources:
    0
    Resources:
    0
    You're overcomplicating this.

    Make an aura, base it whatever and give it a buff.

    Import DamageEvent (your choice) into your map

    do something like this in dmg modify evnet

    If (DamageEventTarget has buff YourAuraBuff and Random Integer between 1 and 100 is less than or equal to YourChance (15% would be 15) then
    Set DamageAmount = 0
    ? - Create nessecary text tags to show "Dodged!"

    e/ read the sentence about damage detection systems and i have to completely disagree with this. No map should have so many units that a damage detection system is not a choice
     
  15. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    Well, i just want to achieve this without having to implement a shitload of code in the process.. DamageEvent requires me to get DamageModifiers and Table, while nestharus system requires me to get UnitEvent, UnitInRangeEvent, Tt, and RegisterPlayerUnitEvent (this being said, i already have Jesus4Lyf's Event library in the map!). That is thousands of extra lines of code just for a single shitty ability, and i don't feel like it is worth it.

    EDIT: when i think of it, i might consider DamageEvent, just because i already have a damage detection system in my map reserved for just mechanicals, which is a bit more crude and skinned down than Anitarf's. It still kinda feels like building a nuclear powerplant to power a light bulb though.
     
  16. shadowvzs

    shadowvzs

    Joined:
    Nov 13, 2006
    Messages:
    1,803
    Resources:
    2
    Spells:
    2
    Resources:
    2
    i do similiar aura thing, just with channeling, i mean till a unit channel then in 600 range all friendly unit got x% damage reduction
    basically mine a bit complicated maybe but if u need only for few aura then u can try it too this buff thing


    normal jass

    Map header functions
    Code (vJASS):



    function RemoveUnitBuff takes integer id, integer index, boolean check returns nothing
        local integer cv = GetUnitUserData( udg_Buff_Unit[id] )
        local integer pl = GetPlayerId(GetOwningPlayer(udg_Buff_Unit[id])) + 1
        local integer buffid
        local real spd
        local integer amount
        local integer t
        local integer i = 1
        local integer times
        local unit u = udg_Buff_Unit[id]
        local integer diff
        if not check then
            set buffid = LoadInteger( udg_Buff_Index_Table, cv, index )
            set amount = LoadInteger( udg_Buff_Amount, cv, buffid ) * - 1
            set diff = amount
            set t = LoadInteger( udg_Buff_Index_Table, cv, buffid )
            if index != udg_Buff_Unit_Index[cv] then
                call SaveInteger( udg_Buff_Index_Table, cv, index, LoadInteger( udg_Buff_Index_Table, cv, udg_Buff_Unit_Index[cv] ) )
            endif
       
            set udg_Buff_Unit_Index[cv] = udg_Buff_Unit_Index[cv] - 1
            call DestroyEffect ( LoadEffectHandle(udg_Buff_EffectTable, cv, buffid))

            call DisplayTextToPlayer( Player(0), 0, 0, "|cff00000ff2nd Remove:|r" + GetUnitName(udg_Buff_Unit[id]) + " id" + I2S(id) + " index" + I2S(index))

            call SaveInteger( udg_Buff_Timer, cv, buffid, 0 )
            call SaveInteger( udg_Buff_Amount, cv, buffid, 0 )
            if buffid==1 then
                call AddHPMP( true, amount, udg_Buff_Unit[id] )
            elseif buffid==2 then
                call AddHPMP( false, amount, udg_Buff_Unit[id] )
            elseif buffid == 3 then
                set udg_B_Crit[cv] = udg_B_Crit[cv] + diff
            elseif buffid == 4 then
                set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + diff
            elseif buffid == 5 then
                set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
            elseif buffid == 6 then
                set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
            elseif buffid == 7 then
                set udg_B_AttLv[cv] = udg_B_AttLv[cv] + diff
            elseif buffid == 8 then
                set udg_B_DefLv[cv] = udg_B_DefLv[cv] + diff
            elseif buffid == 9 then
                set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
            elseif buffid == 10 then
                set udg_B_Eva[cv] = udg_B_Eva[cv] + diff
            elseif buffid == 14 then
                call UnitRemoveAbility( u, 'A01R' )
            elseif buffid == 15 then
                set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
            elseif buffid == 16 then
                set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
            elseif buffid == 17 then
                set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
            elseif buffid == 18 then
                set udg_B_Ref[cv] = udg_B_Ref[cv] + diff
            elseif buffid == 19 then
                set udg_Global_MattackAddon[cv] = udg_Global_MattackAddon[cv] + diff
            elseif buffid == 20 then
                set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
            elseif buffid == 21 then
                set udg_Global_ArmorBreak[cv] = udg_Global_ArmorBreak[cv] + diff
            elseif buffid == 22 then
                set udg_Global_LifeSteal[cv] = udg_Global_LifeSteal[cv] + diff
            elseif buffid == 23 then
                set udg_B_Crit[cv] = udg_B_Crit[cv] + diff
            elseif buffid == 24 then
                set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + diff
            elseif buffid == 25 then
                set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
            elseif buffid == 26 then
                set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
            elseif buffid == 27 then
                set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
            elseif buffid == 28 then
                set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
            elseif buffid == 29 then
                set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
            elseif buffid == 31 then
                set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
            elseif buffid == 32 then
                set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
            elseif buffid == 33 then
                set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
            elseif buffid == 34 then
                set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
            elseif buffid == 35 then
                set udg_Global_MattackAddon[cv] = udg_Global_MattackAddon[cv] + diff
            elseif buffid == 36 then
                set udg_B_LS[cv] = udg_B_LS[cv] + diff
            elseif buffid == 37 then
                set udg_B_LS[cv] = udg_B_LS[cv] + diff
            elseif buffid == 36 then
                set spd = GetUnitMoveSpeed( u )
                call SetUnitMoveSpeed( u, spd + diff )
            elseif buffid == 37 then
                set spd = GetUnitMoveSpeed( u )
                call SetUnitMoveSpeed( u, spd + diff )
            elseif buffid == 38 then
                set spd = GetUnitMoveSpeed( u )
                call SetUnitMoveSpeed( u, spd + diff )
            elseif buffid == 39 then
                set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
            elseif buffid == 40 then
                set udg_Global_Shield[cv] = 0
            elseif buffid == 41 then
                set udg_Soulburn_Caster[cv] = null
                set udg_Soulburn_Damage[cv] = 0
            elseif buffid == 42 then
                set udg_Global_Exp_Buff[pl] = 0
            elseif buffid == 43 then
                set udg_Global_Exp_Red[pl] = udg_Global_Exp_Red[pl] + diff
            elseif buffid == 44 then
                set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
            elseif buffid == 45 then
                set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
            elseif buffid == 59 then
                set udg_Stat_AttackSpeed[pl] = udg_Stat_AttackSpeed[pl] + diff
                call AddDMG(false, u)
            endif

            call SaveInteger( udg_Buff_Amount, cv, buffid, 0 )

            if udg_Buff_Unit_Index[cv] == 0 then
                set udg_Buff_Unit_Id[cv] = 0
                if id != udg_Buff_Index then
                    set udg_Buff_Unit[id] = udg_Buff_Unit[udg_Buff_Index]
                    set udg_Buff_Unit_Id[GetUnitUserData(udg_Buff_Unit[id])] = id
                    call RemoveUnitBuff (id, 0, true)
                else

                endif
                set udg_Buff_Index = udg_Buff_Index - 1
                call FlushChildHashtable(udg_Buff_Index_Table, cv)
                call FlushChildHashtable(udg_Buff_EffectTable, cv)
                call FlushChildHashtable(udg_Buff_Timer, cv)
                call FlushChildHashtable(udg_Buff_Amount, cv)
            endif
        else
            loop
                exitwhen id > udg_Buff_Index
                set cv = GetUnitUserData( udg_Buff_Unit[id] )
                loop
                    exitwhen i > udg_Buff_Unit_Index[cv]
                    set buffid = LoadInteger(udg_Buff_Index_Table, cv, i)
                    set times = LoadInteger(udg_Buff_Timer, cv, buffid)
                    call DisplayTextToPlayer( Player(0), 0, 0, "|cffffff00New unit:|r" + GetUnitName(udg_Buff_Unit[id]) + " index=" + I2S(id) + " buff id" + I2S(buffid) + " time" + I2S(times))

                    if times == 0 then
                        call DisplayTextToPlayer( Player(0), 0, 0, "|cffff00ffRemove:|r" + GetUnitName(udg_Buff_Unit[id]) + " index" + I2S(i))

                        call RemoveUnitBuff (id, i, false)
                    endif
                    set i = i + 1
                endloop
                set id = id + 1
            endloop
        endif
    //    call DisplayTextToPlayer( Player(0), 0, 0, "|cffffff00Remove buff a="+I2S(amount)+" array index" + I2S(udg_Buff_Index+1)+" C.Index" + I2S(id) +" buff index"+I2S(udg_Buff_Unit_Index[cv]) + " time" +I2S(t)+GetUnitName(u)+"|r")
        set u = null
    endfunction

    function ClearUnitBuff takes integer id returns nothing
        local unit u = udg_Buff_Unit[id]
        local integer e
        local integer v
        local integer i = 0
        local integer cv = GetUnitUserData(u)
        local integer buffid
        local integer po
        local integer amount
        local real spd

        loop
            exitwhen i > udg_Buff_Unit_Index[cv]
            set buffid = LoadInteger(udg_Buff_Index_Table, cv, i)
            call DisplayTextToPlayer( Player(0), 0, 0, "clearbuff from " + GetUnitName(u) + "unit index in unit array" + I2S(id) + " unit buff index" + I2S(i))
            call RemoveUnitBuff (id, i, false)
            set i = i + 1
        endloop
    endfunction

    function UnitDeBuff takes unit u, boolean debuff returns nothing
        local integer cv = GetUnitUserData(u)
        local integer index = udg_Buff_Unit_Id[cv]
        local integer i = 0
        local integer buffid
        local integer amount

        loop
            exitwhen i > udg_Buff_Unit_Index[cv]
            set buffid = LoadInteger(udg_Buff_Index_Table, cv, i)
            set amount = LoadInteger( udg_Buff_Amount, cv, buffid )
            if debuff and amount > 0 then
                call DestroyEffect(AddSpecialEffectTarget ("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", u, "overhead" ))
                call RemoveUnitBuff (index, i, false)
            elseif not debuff and amount < 0 then
                call DestroyEffect(AddSpecialEffectTarget ("Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl", u, "overhead" ))
                call RemoveUnitBuff (index, i, false)
            endif
            set i = i + 1
        endloop
    endfunction

    function AddUnitBuff takes unit u, integer buffid, integer amount, integer dur, integer effectid, string apoint returns nothing
        local integer cv = GetUnitUserData(u)
        local integer times = LoadInteger( udg_Buff_Timer, cv, buffid )
        local integer oldv = LoadInteger( udg_Buff_Amount, cv, buffid )
        local integer diff = amount - oldv
        local integer pl = GetPlayerId(GetOwningPlayer(u)) + 1
        local real spd

        if udg_Buff_Unit_Id[cv] == 0 then
            set udg_Buff_Index = udg_Buff_Index + 1
            set udg_Buff_Unit[udg_Buff_Index] = u
            set udg_Buff_Unit_Id[cv] = udg_Buff_Index
       
        endif

        if times == 0 and LoadInteger( udg_Buff_Amount, cv, buffid ) == 0 then
            set udg_Buff_Unit_Index[cv] = udg_Buff_Unit_Index[cv] + 1
            call SaveInteger( udg_Buff_Index_Table, cv, udg_Buff_Unit_Index[cv], buffid )
           
            if effectid > - 1 then
                call SaveEffectHandle(udg_Buff_EffectTable, cv, buffid, AddSpecialEffectTarget( udg_Effects[effectid], u, apoint ))
            endif
        endif
       
        call SaveInteger( udg_Buff_Amount, cv, buffid, amount )
        call SaveInteger( udg_Buff_Timer, cv, buffid, dur )

    //    call DisplayTextToPlayer( Player(0), 0, 0, "dur=" + I2S(dur) + " amount="+I2S(amount)+" unit index in unit array" + I2S(udg_Buff_Index) +" unit buff index"+I2S(udg_Buff_Unit_Index[cv]))

        if buffid == 1 and oldv == 0 then
            call AddHPMP(true, amount, u)
        elseif buffid == 2 and oldv == 0 then
            call AddHPMP(false, amount, u)
        elseif buffid == 3 then
            set udg_B_Crit[cv] = udg_B_Crit[cv] + diff
        elseif buffid == 4 then
            set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + diff
        elseif buffid == 5 then
            set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
        elseif buffid == 6 then
            set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
        elseif buffid == 7 then
            set udg_B_AttLv[cv] = udg_B_AttLv[cv] + diff
        elseif buffid == 8 then
            set udg_B_DefLv[cv] = udg_B_DefLv[cv] + diff
        elseif buffid == 9 then
            set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
        elseif buffid == 10 then
            set udg_B_Eva[cv] = udg_B_Eva[cv] + diff
        elseif buffid == 14 then
            if oldv == 0 then
                call UnitAddAbility( u, 'A01R' )
            endif
        elseif buffid == 15 then
            set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
        elseif buffid == 16 then
            set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
        elseif buffid == 17 then
            set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
        elseif buffid == 18 then
            set udg_B_Ref[cv] = udg_B_Ref[cv] + diff
        elseif buffid == 19 then
            set udg_Global_MattackAddon[cv] = udg_Global_MattackAddon[cv] + diff
        elseif buffid == 20 then
            set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
        elseif buffid == 21 then
            set udg_Global_ArmorBreak[cv] = udg_Global_ArmorBreak[cv] + diff
        elseif buffid == 22 then
            set udg_Global_LifeSteal[cv] = udg_Global_LifeSteal[cv] + diff
        elseif buffid == 23 then
            set udg_B_Crit[cv] = udg_B_Crit[cv] + diff
        elseif buffid == 24 then
            set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + diff
        elseif buffid == 25 then
            set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
        elseif buffid == 26 then
            set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
        elseif buffid == 27 then
            set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
        elseif buffid == 28 then
            set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
        elseif buffid == 29 then
            set udg_Global_IncDmg[cv] = udg_Global_IncDmg[cv] + diff
        elseif buffid == 31 then
            set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
        elseif buffid == 32 then
            set udg_Global_DmgInc[cv] = udg_Global_DmgInc[cv] + diff
        elseif buffid == 33 then
            set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
        elseif buffid == 34 then
            set udg_Global_DmgRed[cv] = udg_Global_DmgRed[cv] + diff
        elseif buffid == 35 then
            set udg_Global_MattackAddon[cv] = udg_Global_MattackAddon[cv] + diff
        elseif buffid == 36 then
            set udg_B_LS[cv] = udg_B_LS[cv] + diff
        elseif buffid == 37 then
            set udg_B_LS[cv] = udg_B_LS[cv] + diff
        elseif buffid == 36 then
            set spd = GetUnitMoveSpeed( u )
            call SetUnitMoveSpeed( u, spd + diff )
        elseif buffid == 37 then
            set spd = GetUnitMoveSpeed( u )
            call SetUnitMoveSpeed( u, spd + diff )
        elseif buffid == 38 then
            set spd = GetUnitMoveSpeed( u )
            call SetUnitMoveSpeed( u, spd + diff )
        elseif buffid == 39 then
            set udg_B_Acc[cv] = udg_B_Acc[cv] + diff
        elseif buffid == 40 then
            //set udg_Global_Shield[cv] = 0
        elseif buffid == 41 then
            //set udg_Soulburn_Caster[cv] = null
            //set udg_Soulburn_Damage[cv] = 0
        elseif buffid == 42 then
            set udg_Global_Exp_Buff[pl] = udg_Global_Exp_Buff[pl] + diff
        elseif buffid == 43 then
            set udg_Global_Exp_Red[pl] = udg_Global_Exp_Red[pl] + diff
        elseif buffid == 44 then
            set udg_B_Pdef[cv] = udg_B_Pdef[cv] + diff
        elseif buffid == 45 then
            set udg_B_Mdef[cv] = udg_B_Mdef[cv] + diff
        elseif buffid == 59 then
            set udg_Stat_AttackSpeed[pl] = udg_Stat_AttackSpeed[pl] + diff
            call AddDMG(false, u)
        endif
        call DisplayTextToPlayer( Player(0), 0, 0, "|cffff0000b.id=" + I2S(buffid) + " diff=" + I2S(diff) + " array index" + I2S(udg_Buff_Index) + " b amount" + I2S(udg_Buff_Unit_Id[cv]) + "|r")

    endfunction
     


    all buff checking with 1 timer

    Code (vJASS):

    function Trig_Timer_Actions takes nothing returns nothing
        local integer i = 1
        local integer ii = 1
        local integer pv = 0
        local integer cc
        local integer po = 0
        local integer cv
        local integer buffid = 0
        local integer times = 0
        local integer vigor = 0
        loop
            exitwhen i > udg_Buff_Index
            set cv = GetUnitUserData(udg_Buff_Unit[i])
            if IsUnitType(udg_Buff_Unit[i], UNIT_TYPE_DEAD) or udg_Buff_Purge[cv] then
                call ClearUnitBuff (i)
            else
                loop
                    exitwhen ii > udg_Buff_Unit_Index[cv]
                    set buffid = LoadInteger(udg_Buff_Index_Table, cv, ii)
                    set times = LoadInteger(udg_Buff_Timer, cv, buffid)
                    call DisplayTextToPlayer( Player(0), 0, 0, GetUnitName(udg_Buff_Unit[i]) + " timer=" + I2S(times) + " unit index in unit array" + I2S(i) + " unit buff index" + I2S(ii))
                    if times == 0 then
                        call RemoveUnitBuff (i, ii, false)
                    else
                        call SaveInteger(udg_Buff_Timer, cv, buffid, times - 1)
                    endif
                    set ii = ii + 1
                endloop
                set ii = 1
                set udg_Buff_Purge[cv] = false
            endif
            set i = i + 1
        endloop
    endfunction
     


    healing rain with damage reduction

    Code (vJASS):

    function Trig_Tranquility_Conditions takes nothing returns boolean
        return GetSpellAbilityId() == 'A03M'
    endfunction


    function TranquilityTimer takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit u = LoadUnitHandle(udg_Channel_Table, id, 1)
        local integer cv = GetUnitUserData(u)
        local unit pu
        local real x = udg_Channel_X[cv]
        local real y = udg_Channel_Y[cv]
        local real mana = GetUnitState(u, UNIT_STATE_MANA)
        local integer i = 0
       
        if mana >= udg_Channel_ManaCost[cv] and udg_Channel_Boolean[cv] then
            call SetUnitState (u, UNIT_STATE_MANA, (mana - udg_Channel_ManaCost[cv]))

                call GroupEnumUnitsInRange(udg_UG, x, y, 600.00, null)
                loop
                    set pu = FirstOfGroup(udg_UG)
                    exitwhen (pu==null)
    if IsAlly(u, pu)  then
                        call SetWidgetLife(pu, GetWidgetLife(pu)+udg_Channel_Dmg[cv])
    //-------------------------------------------
    // here i add friendly  unit to linked list
                        call AddUnitBuff (pu, 34, 33, 5, -1, "chest")
    //-------------------------------------------
                        call DestroyEffect(AddSpecialEffect ("Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl", GetUnitX(pu) , GetUnitY(pu)))
                    endif
                    call GroupRemoveUnit(udg_UG, pu)
               endloop
       
            call TimerStart(t, 5, false, function TranquilityTimer)
        else
            call PauseTimer(t)
            call DestroyTimer(t)
            call FlushChildHashtable(udg_Channel_Table, id)
            if udg_Channel_CasterSF[cv] != null then
                call IssueImmediateOrder( u, "stop" )
                call DestroyEffect(udg_Channel_CasterSF[cv])
            endif
        endif
       
        set t = null
        set u = null
    endfunction

    function Trig_Tranquility_Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real radius = 300.00
        local real dmg = GetUnitAbilityLevel(u, 'A03M') * 100 + udg_TotalSpellPower[GetPlayerId(GetTriggerPlayer())+1]
        local timer t = CreateTimer()
        local integer id = GetHandleId(t)
        local integer cv = GetUnitUserData(u)
        set udg_Channel_Boolean[cv] = true
        set udg_Channel_X[cv] = x
        set udg_Channel_Y[cv] = y
        set udg_Channel_ManaCost[cv] = GetUnitAbilityLevel(u, 'A03M') * 10
        set udg_Channel_Dmg[cv] = dmg
        if GetUnitState(u, UNIT_STATE_MANA) >= 10 then
            set udg_Channel_Count[cv] = 0
            set udg_Channel_Dur[cv] = 0
            call SaveUnitHandle(udg_Channel_Table, id, 1, u)
            call TimerStart(t, 0.5, false, function TranquilityTimer)
            set udg_Channel_CasterSF[cv] = AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Tranquility\\Tranquility.mdl", u, "origin")
        endif
        set t = null
        set u = null
    endfunction

    //===========================================================================
    function InitTrig_Tranquility takes nothing returns nothing
        set gg_trg_Tranquility = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( gg_trg_Tranquility, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( gg_trg_Tranquility, Condition( function Trig_Tranquility_Conditions ) )
        call TriggerAddAction( gg_trg_Tranquility, function Trig_Tranquility_Actions )
    endfunction

     



    basically indifferent u do it with ability or with gui damage engine, then main thing is periodical add unit to a linked list for short time, that your choose u use a variable+damagedetectionsystem or u add passive ability with dummy hidden spellbook for a short time.

    (when u add unit then u add ability or change variable amount[unit custom value] and if timer expired/unit die then simple remove that ability or decrease that variable)

    i also use add passive ability for a time, this way i made buff from reincarnation :)
     
  17. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    I managed to finalize my system and make it work, although i noticed i'm getting some framerate drops in occasions, especially in the first few moments when i launch a bunch of smoke grenades into a large number of units. I am gessing this is as good as it is gonna get with this solution though, so i might indeed be better off getting a damage detection system after all.

    Here is the final code for those who are interrested:

    Code
    Code (vJASS):

    library SmokeGrenade requires ListModule

        globals
            private constant real    RANGE       = 180.
            private constant integer EVASION_ID  = 'svsb'
            private constant integer DUMMY_ID    = 'smdu'
        endglobals
       
        private function filter takes nothing returns boolean
            return (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false and GetUnitTypeId(GetFilterUnit()) != DUMMY_ID and GetUnitTypeId(GetFilterUnit()) != 'h013')
        endfunction
       
        struct Smoke
            static group units
            static group temp
            static timer tick
            unit u
            real x
            real y
            timer t
            implement List //for ListModule
           
            private static method EnumGiveAbil takes nothing returns nothing
                call UnitAddAbility(GetEnumUnit(), EVASION_ID)
                call GroupAddUnit(.units, GetEnumUnit())
            endmethod
           
            private static method GiveAbil takes nothing returns nothing
                local thistype this = .first
               
                loop
                    exitwhen this == 0
                   
                    call GroupEnumUnitsInRange(.temp, .x, .y, RANGE, Filter(function filter))
                    call ForGroup(.temp, function thistype.EnumGiveAbil)
                    call GroupClear(.temp)
                   
                    set this = .next
                endloop
               
                if .count < 1 then
                    call PauseTimer(.tick)
                endif
            endmethod
           
            private static method hasAbil takes nothing returns nothing
                local thistype this = .first
                local unit target = GetEnumUnit()
                local real x = GetUnitX(target)
                local real y = GetUnitY(target)
                local real dx
                local real dy
                local integer count = 0
               
                loop
                    exitwhen this == 0
                    set dx = .x - x
                    set dy = .y - y
                   
                    if SquareRoot(dx * dx + dy * dy) < RANGE then
                        set count = count+1
                    endif
                   
                    set this = .next
                endloop
               
                if count == 0 then
                    call UnitRemoveAbility(target, EVASION_ID)
                    call GroupRemoveUnit(.units, target)
                endif
               
                set target = null
            endmethod
           
            private static method onExpire takes nothing returns nothing
                call ForGroup(.units, function thistype.hasAbil)
                call thistype.GiveAbil()
            endmethod
           
            private static method KillSmoke takes nothing returns nothing
                local thistype this = LoadInteger(Hashtbl, 2, GetHandleId(GetExpiredTimer()))
                call .destroy()
            endmethod
           
            static method create takes real x, real y, player owner returns Smoke
                local thistype this = thistype.allocate()
                set .u = CreateUnit(owner, DUMMY_ID, x, y, 0.)
                set .x = x
                set .y = y
                set .t = CreateTimer()
               
                call listAdd()
               
                if .count == 1 then
                    call TimerStart(.tick, 1.2, true, function thistype.onExpire)
                endif
               
                call SaveInteger(Hashtbl, 2, GetHandleId(.t), this)
                call TimerStart(.t, 20., false, function thistype.KillSmoke)
               
                return this
            endmethod
           
            method onDestroy takes nothing returns nothing
                call listRemove()
                call RemoveSavedInteger(Hashtbl, 2, GetHandleId(.t))
                call KillUnit(.u)
                call DestroyTimer(.t)
            endmethod
           
            private static method onInit takes nothing returns nothing
                set .tick   = CreateTimer()
                set .units  = CreateGroup()
                set .temp   = CreateGroup()
            endmethod
           
        endstruct

    endlibrary
     
     
  18. shadowvzs

    shadowvzs

    Joined:
    Nov 13, 2006
    Messages:
    1,803
    Resources:
    2
    Spells:
    2
    Resources:
    2
    i can ask something? why u use for loop and create group each time instead loop?

    u can declare group like global
    Code (vJASS):

                call GroupEnumUnitsInRange(udg_UG, x, y, RANGE, null)
                loop
                    set pu = FirstOfGroup(udg_UG)
                    exitwhen (pu==null)
                        if not IsUnitType(pu, UNIT_TYPE_MECHANICAL) and GetUnitTypeId(pu) != DUMMY_ID and GetUnitTypeId(pu) != 'h013'  then
                     //do action
                        endif
                    call GroupRemoveUnit(udg_UG, pu)
               endloop
     


    anyway linked list not faster than timer for each unit?

    (just a notice about damage detection engine, between enable-disableing floating text = really visible difference when alot unit attack same time, atleast on my pc drastically droped the fps after i put 700 paladin on same part of the map and all attacked eachother and still i use floating text too, without it really better)
     
    Last edited: Mar 17, 2012
  19. Fingolfin

    Fingolfin

    Joined:
    Jan 11, 2009
    Messages:
    3,205
    Resources:
    153
    Models:
    143
    Icons:
    1
    Packs:
    4
    Skins:
    2
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    153
    I don't create groups every loop, and all my groups are alreaady global (static struct members are the same as private globals!). Groups are created on initialization and never destroyed. Also, in your suloution, you pick ALL nearby untis first and then do the check, it is much more efficient to only pick the ones you want using a filter and then loop through them. As for why i use ForGroup... i could ofcourse go with your method just to get less function calls, but i just thought this was more readable since i would otherwise be forced to put a loop inside a loop.
     
  20. shadowvzs

    shadowvzs

    Joined:
    Nov 13, 2006
    Messages:
    1,803
    Resources:
    2
    Spells:
    2
    Resources:
    2
    ah i see, i never use structs because i allways used normal we. then seems ok.

    something i dont got, ofc u filter with forloop but that is also a loop, then another loop when u do action, correct me if i am wrong but forloop also check every unit, just remove the group what dosnt fit with condition.