• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Damage units ONCE

Status
Not open for further replies.
Level 8
Joined
Jun 18, 2007
Messages
214
JASS:
constant function Swing_Slash_Rawcode takes nothing returns integer
    return 'A000'
endfunction

constant function Swing_Slash_DOT_Code takes nothing returns integer
    return 'A001'
endfunction

constant function Swing_Slash_DOT_Buff_Code takes nothing returns integer
    return 'B000'
endfunction

constant function Dummy_Unit_Code takes nothing returns integer
    return 'h003'
endfunction

constant function Nova_SFX takes nothing returns string
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction

constant function Hit_SFX takes nothing returns string
    return "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
endfunction

constant function Slash_Distance takes nothing returns real
    return 250.0
endfunction

constant function Damage_Radius takes nothing returns real
    return 90.0
endfunction

constant function Slash_Damage takes integer i returns real
    return 50.0*i
endfunction    

constant function Slash_Number takes nothing returns integer
    return 10
endfunction

constant function Nova_Spawn_Speed takes nothing returns real
    return 0.1
endfunction
//==========================================================================================================================================================================================================
//Condition trigger.
function Trig_Swing_Slash_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Swing_Slash_Rawcode()
endfunction

//Filter for picking enemies in group.
function Swing_Slash_Filter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and (GetWidgetLife(GetFilterUnit())>0.405)
endfunction
//==========================================================================================================================================================================================================


//===========EXECUTE NOVA===============================================================================
function Slash_Nova takes nothing returns nothing
 local timer novatimer = GetExpiredTimer()
 local unit damager    = LoadUnitHandle(udg_Hash, GetHandleId(novatimer), 1)
 local unit ug         = null
 local unit dummy      = null
 local integer count   = LoadInteger(udg_Hash, GetHandleId(novatimer), 6)
 local integer angle   = 180/Slash_Number()
 local integer level   = LoadInteger(udg_Hash, GetHandleId(novatimer), 7)
 local real x          = LoadReal(udg_Hash, GetHandleId(novatimer), 3)
 local real y          = LoadReal(udg_Hash, GetHandleId(novatimer), 4)
 local real start      = LoadReal(udg_Hash, GetHandleId(novatimer), 5)
 local group g         = null
 local group hit       = LoadGroupHandle(udg_Hash, GetHandleId(novatimer), 8)
 local boolexpr b      = null
 local real newX
 local real newY 
 
 if count < Slash_Number() then
 
  set newX = x + Slash_Distance() * Cos((start + angle * count) * bj_DEGTORAD)
  set newY = y + Slash_Distance() * Sin((start + angle * count) * bj_DEGTORAD)
  call DestroyEffect(AddSpecialEffect(Nova_SFX(), newX, newY)) 
  call SaveInteger  (udg_Hash, GetHandleId(novatimer), 6, count + 1)
  
  set g                        = CreateGroup()
  set b                        = Condition(function Swing_Slash_Filter)
  set bj_groupEnumOwningPlayer = GetOwningPlayer(damager)
  call GroupEnumUnitsInRange(g, newX, newY, Damage_Radius(), b)
  call DestroyBoolExpr(b)
        
        loop   
            set ug = FirstOfGroup(g)
            exitwhen ug == null
            call GroupRemoveUnit(g, ug)
            call DestroyEffect(AddSpecialEffect(Hit_SFX(), GetUnitX(ug), GetUnitY(ug)))
   
            
               if IsUnitInGroup(ug, hit) == true then
               else
                call UnitDamageTarget(damager, ug, Slash_Damage(level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
                set dummy = CreateUnit      (GetOwningPlayer(damager), Dummy_Unit_Code(), GetUnitX(ug), GetUnitY(ug), 0.0)
                call UnitAddAbility         (dummy, Swing_Slash_DOT_Code())
                call SetUnitAbilityLevel    (dummy, Swing_Slash_DOT_Code(), level)
                call IssueTargetOrder       (dummy, "shadowstrike", ug)
                call UnitApplyTimedLife     (dummy, 'BTLF', 2.0)    
               endif
            call GroupAddUnit    (hit, ug)  
        endloop
   call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, hit) 
   call DestroyGroup(g)
   call DestroyGroup(hit)
   set g = null
   set hit = null
   set b = null
   set novatimer = null
   set damager = null
   set ug = null
   
 else
    
    call FlushChildHashtable(udg_Hash, GetHandleId(novatimer))
    call PauseTimer(novatimer)
    call DestroyTimer(novatimer)
    set novatimer = null
    set b = null
    set g = null
    set damager = null
    set ug = null
  endif
endfunction       


//===============SETTINGS FOR 180 % NOVA==============================================================================
function Trig_Swing_Slash_Actions takes nothing returns nothing
 local timer novatimer = CreateTimer()
 local unit cast       = GetTriggerUnit()
 local integer level   = GetUnitAbilityLevel(cast, Swing_Slash_Rawcode()) 
 local real start      = GetUnitFacing(cast) - 90.0
 local real cX         = GetUnitX(cast)
 local real cY         = GetUnitY(cast)
 local group hit       = CreateGroup()

        call SaveUnitHandle  (udg_Hash, GetHandleId(novatimer), 1, cast)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 3, cX)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 4, cY)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 5, start)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 6, 1)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 7, level)
        call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, hit)
        call TimerStart(novatimer, Nova_Spawn_Speed(), true, function Slash_Nova)
    call DestroyGroup(hit)
    set hit = null   
    set novatimer = null
    set cast      = null
endfunction
     


//=============INIT TRIGG===================================================================
function InitTrig_Swing_Slash takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer guza

    set guza = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(guza), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set guza = guza + 1
        exitwhen guza == 16
    endloop

    call TriggerAddCondition(trig, Condition(function Trig_Swing_Slash_Conditions))
    call TriggerAddAction(trig, function Trig_Swing_Slash_Actions)
    
    call Preload(Nova_SFX())
    call Preload(Hit_SFX())
    call PreloadStart()
    
    
    set udg_Hash = InitHashtable()
    set trig = null
endfunction

Hello again. I'm sorry for bothering everyone with more questions. But I've been working on this spell the whole day. And I always have some problems.

Now the problem that I couldn't fix for the last 2 hours, is damage units.
This spell should create novas in front of caster in 180 %, that's working, actually everything is working, except damage. I want the novas to damage each caught unit once. If one nova dealt damage to the unit, next one shouldn't. I've tried everything, saving hit unit in a hash. Saving a group of hit units in hash, but I failed every time, they always get hit 2 or 3 times. Tried with damage radius, if I set it to 50 it's to small, if I set it to 6 they again get hit twice. So I really need someone's help again. Thank in advance. :sad::sad::sad:

EDIT: Damage action is in Slash_Nova function
 
Level 4
Joined
Apr 16, 2009
Messages
85
a group is the way to go (you'll have to save the group like you save all the other values)
1. create a group for the spell instance and save it in a hashtable
2. before the GroupEnumUnitsInRange set a global group to your loaded group (lets name it temp_group)
3. in the filter of your GroupEnumUnitsInRange just add IsUnitInGroup(GetFilterUnit(), temp_group)

4. every time you do damage save that unit in the group with GroupAddUnit
 
Level 8
Joined
Jun 18, 2007
Messages
214
a group is the way to go (you'll have to save the group like you save all the other values)
1. create a group for the spell instance and save it in a hashtable
2. before the GroupEnumUnitsInRange set a global group to your loaded group (lets name it temp_group)
3. in the filter of your GroupEnumUnitsInRange just add IsUnitInGroup(GetFilterUnit(), temp_group)

4. every time you do damage save that unit in the group with GroupAddUnit

Tried it, either it's not working or I failed. They again get damaged 2 or 3 times. Here's what I did:

JASS:
//
//Filter for picking enemies in group.
function Swing_Slash_Filter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and (GetWidgetLife(GetFilterUnit())>0.405) and IsUnitInGroup(GetFilterUnit(), udg_temp_group) == false
endfunction
//==========================================================================================================================================================================================================
===========EXECUTE NOVA===============================================================================
function Slash_Nova takes nothing returns nothing
 local timer novatimer = GetExpiredTimer()
 local unit damager    = LoadUnitHandle(udg_Hash, GetHandleId(novatimer), 1)
 local unit ug         = null
 local unit dummy      = null
 local integer count   = LoadInteger(udg_Hash, GetHandleId(novatimer), 6)
 local integer angle   = 180/Slash_Number()
 local integer level   = LoadInteger(udg_Hash, GetHandleId(novatimer), 7)
 local real x          = LoadReal(udg_Hash, GetHandleId(novatimer), 3)
 local real y          = LoadReal(udg_Hash, GetHandleId(novatimer), 4)
 local real start      = LoadReal(udg_Hash, GetHandleId(novatimer), 5)
 local group g         = null
 local group hit       = LoadGroupHandle(udg_Hash, GetHandleId(novatimer), 8)
 local boolexpr b      = null
 local real newX
 local real newY 
 
 if count < Slash_Number() then
 
  set newX = x + Slash_Distance() * Cos((start + angle * count) * bj_DEGTORAD)
  set newY = y + Slash_Distance() * Sin((start + angle * count) * bj_DEGTORAD)
  call DestroyEffect(AddSpecialEffect(Nova_SFX(), newX, newY)) 
  call SaveInteger  (udg_Hash, GetHandleId(novatimer), 6, count + 1)

  set udg_temp_group           = hit
  set g                        = CreateGroup()
  set b                        = Condition(function Swing_Slash_Filter)
  set bj_groupEnumOwningPlayer = GetOwningPlayer(damager)
  call GroupEnumUnitsInRange(g, newX, newY, Damage_Radius(), b)
  call DestroyBoolExpr(b)

        
        loop   
            set ug = FirstOfGroup(g)
            exitwhen ug == null
            call GroupRemoveUnit        (g, ug)
            call DestroyEffect          (AddSpecialEffect(Hit_SFX(), GetUnitX(ug), GetUnitY(ug)))
            call UnitDamageTarget       (damager, ug, Slash_Damage(level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            set dummy = CreateUnit      (GetOwningPlayer(damager), Dummy_Unit_Code(), GetUnitX(ug), GetUnitY(ug), 0.0)
            call UnitAddAbility         (dummy, Swing_Slash_DOT_Code())
            call SetUnitAbilityLevel    (dummy, Swing_Slash_DOT_Code(), level)
            call IssueTargetOrder       (dummy, "shadowstrike", ug)
            call UnitApplyTimedLife     (dummy, 'BTLF', 2.0)    
            call GroupAddUnit           (hit, ug)  
        endloop
   call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, hit)
   call DestroyGroup(udg_temp_group) 
   call DestroyGroup(g)
   call DestroyGroup(hit)
   set g = null
   set hit = null
   set b = null
   set novatimer = null
   set damager = null
   set ug = null
   
 else
    
    call FlushChildHashtable(udg_Hash, GetHandleId(novatimer))
    call PauseTimer(novatimer)
    call DestroyTimer(novatimer)
    set novatimer = null
    set b = null
    set g = null
    set damager = null
    set ug = null
  endif
endfunction       


//===============SETTINGS FOR 180 % NOVA==============================================================================
function Trig_Swing_Slash_Actions takes nothing returns nothing
 local timer novatimer = CreateTimer()
 local unit cast       = GetTriggerUnit()
 local integer level   = GetUnitAbilityLevel(cast, Swing_Slash_Rawcode()) 
 local real start      = GetUnitFacing(cast) - 90.0
 local real cX         = GetUnitX(cast)
 local real cY         = GetUnitY(cast)
 local group hit       = CreateGroup()

        call SaveUnitHandle  (udg_Hash, GetHandleId(novatimer), 1, cast)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 3, cX)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 4, cY)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 5, start)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 6, 1)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 7, level)
        call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, hit)
        call TimerStart(novatimer, Nova_Spawn_Speed(), true, function Slash_Nova)
    call DestroyGroup(hit)
    set hit = null   
    set novatimer = null
    set cast      = null
endfunction
 
Level 8
Joined
Jun 18, 2007
Messages
214
call GroupAddUnit( LoadGroupHandle(udg_Hash, GetHandleId(novatimer), 8), ug )
Try that in the FoG loop rather than the local group hit.

If that doesn't work I have no idea what.


By the way, you coding is very inefficient.

Will try, and why is it inefficient? I didn't use a single BJs or locations?

EDIT: It's still not working, again they get hit multiple times.
 
Level 4
Joined
Apr 16, 2009
Messages
85
By the way, you coding is very inefficient.

true but that will come with time i wasn't better when is started - but back to your problem: you destroy the group way to early: you have to move call DestroyGroup(hit) from where it is below the else


oh and: don't do
call GroupAddUnit( LoadGroupHandle(udg_Hash, GetHandleId(novatimer), 8), ug )
(its a total waste of speed and does the same as yours)
 
Level 8
Joined
Jun 18, 2007
Messages
214
true but that will come with time i wasn't better when is started - but back to your problem: you destroy the group way to early: you have to move call DestroyGroup(hit) from where it is below the else


oh and: don't do
(its a total waste of speed and does the same as yours)

Tested, not working. But I don't understand how would this suppose to help me. If I remove DestroyGroup(hit) from then, it would leak then. 'cause I'm only destroying it in else.
And, can anyone explain why is this code Inefficient?
 
Level 4
Joined
Apr 16, 2009
Messages
85
oh i just saw you have to remove that line: DestroyGroup(hit) in the Trig_Swing_Slash_Actions function (in addition to moving the other DestroyGroup thing down)(and now that doesn't leak as you only have to destroy things when you don't use them anymore not earlier)

(btw with vJass this thing would only take like 1/4 off the function calls i think thats what i meant with its inefficient)
 
Level 8
Joined
Jun 18, 2007
Messages
214
oh i just saw you have to remove that line: DestroyGroup(hit) in the Trig_Swing_Slash_Actions function (in addition to moving the other DestroyGroup thing down)(and now that doesn't leak as you only have to destroy things when you don't use them anymore not earlier)

(btw with vJass this thing would only take like 1/4 off the function calls i think thats what i meant with its inefficient)

But that will do the same thing. Alright, testing.

JASS:
constant function Swing_Slash_Rawcode takes nothing returns integer
    return 'A000'
endfunction

constant function Swing_Slash_DOT_Code takes nothing returns integer
    return 'A001'
endfunction

constant function Swing_Slash_DOT_Buff_Code takes nothing returns integer
    return 'B000'
endfunction

constant function Dummy_Unit_Code takes nothing returns integer
    return 'h003'
endfunction

constant function Nova_SFX takes nothing returns string
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction

constant function Hit_SFX takes nothing returns string
    return "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
endfunction

constant function Slash_Distance takes nothing returns real
    return 250.0
endfunction

constant function Damage_Radius takes nothing returns real
    return 90.0
endfunction

constant function Slash_Damage takes integer i returns real
    return 50.0*i
endfunction    

constant function Slash_Number takes nothing returns integer
    return 10
endfunction

constant function Nova_Spawn_Speed takes nothing returns real
    return 0.1
endfunction
//==========================================================================================================================================================================================================
//Condition trigger.
function Trig_Swing_Slash_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Swing_Slash_Rawcode()
endfunction

//Filter for picking enemies in group.
function Swing_Slash_Filter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and (GetWidgetLife(GetFilterUnit())>0.405) and IsUnitInGroup(GetFilterUnit(), udg_temp_group) == false
endfunction
//==========================================================================================================================================================================================================


//===========EXECUTE NOVA===============================================================================
function Slash_Nova takes nothing returns nothing
 local timer novatimer = GetExpiredTimer()
 local unit damager    = LoadUnitHandle(udg_Hash, GetHandleId(novatimer), 1)
 local unit ug         = null
 local unit dummy      = null
 local integer count   = LoadInteger(udg_Hash, GetHandleId(novatimer), 6)
 local integer angle   = 180/Slash_Number()
 local integer level   = LoadInteger(udg_Hash, GetHandleId(novatimer), 7)
 local real x          = LoadReal(udg_Hash, GetHandleId(novatimer), 3)
 local real y          = LoadReal(udg_Hash, GetHandleId(novatimer), 4)
 local real start      = LoadReal(udg_Hash, GetHandleId(novatimer), 5)
 local group g         = null
 local group hit       = LoadGroupHandle(udg_Hash, GetHandleId(novatimer), 8)
 local boolexpr b      = null
 local real newX
 local real newY 
 
 if count < Slash_Number() then
 
  set newX = x + Slash_Distance() * Cos((start + angle * count) * bj_DEGTORAD)
  set newY = y + Slash_Distance() * Sin((start + angle * count) * bj_DEGTORAD)
  call DestroyEffect(AddSpecialEffect(Nova_SFX(), newX, newY)) 
  call SaveInteger  (udg_Hash, GetHandleId(novatimer), 6, count + 1)

  set udg_temp_group           = hit
  set g                        = CreateGroup()
  set b                        = Condition(function Swing_Slash_Filter)
  set bj_groupEnumOwningPlayer = GetOwningPlayer(damager)
  call GroupEnumUnitsInRange(g, newX, newY, Damage_Radius(), b)
  call DestroyBoolExpr(b)

        
        loop   
            set ug = FirstOfGroup(g)
            exitwhen ug == null
            call GroupRemoveUnit        (g, ug)
            call DestroyEffect          (AddSpecialEffect(Hit_SFX(), GetUnitX(ug), GetUnitY(ug)))
            call UnitDamageTarget       (damager, ug, Slash_Damage(level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            set dummy = CreateUnit      (GetOwningPlayer(damager), Dummy_Unit_Code(), GetUnitX(ug), GetUnitY(ug), 0.0)
            call UnitAddAbility         (dummy, Swing_Slash_DOT_Code())
            call SetUnitAbilityLevel    (dummy, Swing_Slash_DOT_Code(), level)
            call IssueTargetOrder       (dummy, "shadowstrike", ug)
            call UnitApplyTimedLife     (dummy, 'BTLF', 2.0)    
            call GroupAddUnit           (hit, ug)  
        endloop
   call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, hit)
   call DestroyGroup(g)
   set g = null
   set b = null
   set novatimer = null
   set damager = null
   set ug = null
   
 else
    
    call FlushChildHashtable(udg_Hash, GetHandleId(novatimer))
    call PauseTimer(novatimer)
    call DestroyTimer(novatimer)
    call DestroyGroup(hit)
    call DestroyGroup(udg_temp_group)
    set hit = null
    set novatimer = null
    set b = null
    set g = null
    set damager = null
    set ug = null
  endif
endfunction       


//===============SETTINGS FOR 180 % NOVA==============================================================================
function Trig_Swing_Slash_Actions takes nothing returns nothing
 local timer novatimer = CreateTimer()
 local unit cast       = GetTriggerUnit()
 local integer level   = GetUnitAbilityLevel(cast, Swing_Slash_Rawcode()) 
 local real start      = GetUnitFacing(cast) - 90.0
 local real cX         = GetUnitX(cast)
 local real cY         = GetUnitY(cast)

        call SaveUnitHandle  (udg_Hash, GetHandleId(novatimer), 1, cast)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 3, cX)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 4, cY)
        call SaveReal        (udg_Hash, GetHandleId(novatimer), 5, start)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 6, 1)
        call SaveInteger     (udg_Hash, GetHandleId(novatimer), 7, level)
        call SaveGroupHandle (udg_Hash, GetHandleId(novatimer), 8, CreateGroup())
        call TimerStart(novatimer, Nova_Spawn_Speed(), true, function Slash_Nova)  
    set novatimer = null
    set cast      = null
endfunction
     


//=============INIT TRIGG===================================================================
function InitTrig_Swing_Slash takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer guza

    set guza = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(guza), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set guza = guza + 1
        exitwhen guza == 16
    endloop

    call TriggerAddCondition(trig, Condition(function Trig_Swing_Slash_Conditions))
    call TriggerAddAction(trig, function Trig_Swing_Slash_Actions)
    
    call Preload(Nova_SFX())
    call Preload(Hit_SFX())
    call PreloadStart()
    
    
    set trig = null
endfunction

Well it's working only if I remove DestroyGroup(udg_temp_group) and DestroyGroup(hit), from then actions. But I guess now it's leaking 2 groups?
 
Level 4
Joined
Apr 16, 2009
Messages
85
Well it's working only if I remove DestroyGroup(udg_temp_group) and DestroyGroup(hit), from then actions. But I guess now it's leaking 2 groups?

no you are not (and you can remove call DestroyGroup(udg_temp_group) as hit and udg_temp_group are the same group and you can't destroy the same group twice)
 
Level 15
Joined
Jul 6, 2009
Messages
889
1. You are creating a dummy unit every time a target is hit, just have 1 dummy cast every Shadow Strike. More efficient.
2. Condition( function Swing_Slash_Filter ) is called every callback. If you could, set it to a global boolexpr.
3. First of Group loops are inefficient, use the filter as the direct function that does things to it. http://wiki.thehelper.net/wc3/Group_API#boolexpr_as_callback
4. call TimerStart(novatimer, Nova_Spawn_Speed(), true, function Slash_Nova) Can just be call TimerStart( CreateTimer(), bblah blah blah )

5. In the init trigger, guza can just be local integer guza = 0.
6. Dynamic group in the callback! Use only one global group for GroupEnum, because they are used instantly.
 
Level 4
Joined
Apr 16, 2009
Messages
85
agree with anything but 4. (4. would leak a timer gogo timer recycling systems :D)
 
Level 8
Joined
Jun 18, 2007
Messages
214
1. You are creating a dummy unit every time a target is hit, just have 1 dummy cast every Shadow Strike. More efficient.
2. Condition( function Swing_Slash_Filter ) is called every callback. If you could, set it to a global boolexpr.
3. First of Group loops are inefficient, use the filter as the direct function that does things to it. http://wiki.thehelper.net/wc3/Group_API#boolexpr_as_callback
4. call TimerStart(novatimer, Nova_Spawn_Speed(), true, function Slash_Nova) Can just be call TimerStart( CreateTimer(), bblah blah blah )

5. In the init trigger, guza can just be local integer guza = 0.
6. Dynamic group in the callback! Use only one global group for GroupEnum, because they are used instantly.

1. Changed to a single dummy.
2. Isn't it same, since I'm destroying it right after use?
3. In Group API, they didn't say First of Group is bad, they said it can be used, but using as boolexpr as callback it's faster.
4. Now it can't be, I need to tie handles, reals and integers to a timer so I can use hashtable.
5. Set to that. I forgot about that.
6. Now using only one global group.

Thank you for you comments.
 
Level 4
Joined
Apr 16, 2009
Messages
85
look at this this is a vJass rewrite of the spell and i guess its almost as efficient as it could be (could be run on a single timer instead of 1 per instance but i was to lazy to do that ^^)

(2 things: no id doesn't leak (the groups/timers get recycled and you can't really "leak" globals (or struct members)) and it requires Jasshelper, TimerUtils, GroupUtils, xebasic, xecast, xepreload)

JASS:
scope SwingSlash initializer init
    private keyword SwingSlash
    
    globals
        private constant integer RawCode = 'A000'
        private constant integer DOTCode = 'A001'
        private constant string NovaSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
        private constant string HitSFX = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
        private constant real Distance = 250.0
        private constant real DamageRadius = 90.0
        private constant integer SlashNumber = 10
        private constant real SpawnSpeed = 0.1
        private real Angle = bj_PI/SlashNumber
        private SwingSlash FilterSlash
        private real FilterX
        private real FilterY
        private boolexpr filter
    endglobals

    private function SlashDamage takes integer l returns real
        return 50.0*l
    endfunction
    
    //Filter for picking enemies in group.
    private function FILTER takes nothing returns boolean
        local unit u = GetFilterUnit()
        if IsUnitEnemy(u, FilterSlash.owningplayer) and IsUnitInRangeXY(u, FilterX, FilterY, DamageRadius)  and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitInGroup(u, FilterSlash.hit) and GetUnitState(u, UNIT_STATE_LIFE) > 0.405 then
            if FilterSlash.caster != null then
                call UnitDamageTarget(FilterSlash.caster, u, SlashDamage(FilterSlash.level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            endif
            call DestroyEffect(AddSpecialEffect(HitSFX, GetUnitX(u), GetUnitY(u)))
            call FilterSlash.castOnTarget(u)
            call GroupAddUnit(FilterSlash.hit, u)
        endif
        set u = null
        return false
    endfunction
    
    private struct SwingSlash extends xecast
        private unit c
        private real start
        private group h
        private timer t
        private integer slashes = 0
        
        method operator caster takes nothing returns unit
            return this.c
        endmethod
        
        method operator hit takes nothing returns group
            return this.h
        endmethod
        
        static method periodic takes nothing returns nothing
            local thistype this = thistype(GetTimerData(GetExpiredTimer()))
            local real x = this.sourcex + Distance * Cos(this.start + Angle * this.slashes)
            local real y = this.sourcey + Distance * Sin(this.start + Angle * this.slashes)
            call DestroyEffect(AddSpecialEffect(NovaSFX, x, y))
            set FilterSlash = this
            set FilterX = x
            set FilterY = y
            call GroupEnumUnitsInRange(ENUM_GROUP, x, y, DamageRadius+XE_MAX_COLLISION_SIZE, filter)
            call GroupClear(ENUM_GROUP)
            set this.slashes = this.slashes + 1
            if this.slashes > SlashNumber then
                call this.destroy()
            endif
        endmethod
        
        static method create takes unit caster returns thistype
            local thistype this = thistype.allocate()
            set this.h = NewGroup()
            set this.t = NewTimer()
            call SetTimerData(this.t, integer(this))
            set this.c = caster
            set this.abilityid = DOTCode
            set this.orderid = 852527 //thats the same as doing this.orderstring = "shadowstrike"
            set this.owningplayer = GetOwningPlayer(caster)
            set this.recycledelay = 16.0
            set this.sourcex = GetUnitX(caster)
            set this.sourcey = GetUnitY(caster)
            set this.start = (GetUnitFacing(caster)-90.0)*bj_DEGTORAD
            set this.level = GetUnitAbilityLevel(caster, RawCode)
            call TimerStart(this.t, SpawnSpeed, true, function thistype.periodic)
            return this
        endmethod
        
        private method onDestroy takes nothing returns nothing
            call ReleaseGroup(.h)
            call ReleaseTimer(.t)
        endmethod
    endstruct


    //===============SETTINGS FOR 180 % NOVA==============================================================================
    private function ConditionsActions takes nothing returns boolean
        if GetSpellAbilityId() == RawCode then
            call SwingSlash.create(GetSpellAbilityUnit())
        endif
        return false
    endfunction


    //=============INIT TRIGG===================================================================
    private function init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        local integer i = 0
        set filter = Filter(function FILTER)
        loop
            exitwhen i == 16
            call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
        endloop

        call TriggerAddCondition(trig, Condition(function ConditionsActions))

        call Preload(NovaSFX)
        call Preload(HitSFX)
        call XE_PreloadAbility(DOTCode)
        set trig = null
    endfunction
endscope

edit: btw this spell looks quite cool ^^
 
Level 8
Joined
Jun 18, 2007
Messages
214
look at this this is a vJass rewrite of the spell and i guess its almost as efficient as it could be (could be run on a single timer instead of 1 per instance but i was to lazy to do that ^^)

(2 things: no id doesn't leak (the groups/timers get recycled and you can't really "leak" globals (or struct members)) and it requires Jasshelper, TimerUtils, GroupUtils, xebasic, xecast, xepreload)

JASS:
scope SwingSlash initializer init
    private keyword SwingSlash
    
    globals
        private constant integer RawCode = 'A000'
        private constant integer DOTCode = 'A001'
        private constant string NovaSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
        private constant string HitSFX = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
        private constant real Distance = 250.0
        private constant real DamageRadius = 90.0
        private constant integer SlashNumber = 10
        private constant real SpawnSpeed = 0.1
        private real Angle = bj_PI/SlashNumber
        private SwingSlash FilterSlash
        private real FilterX
        private real FilterY
        private boolexpr filter
    endglobals

    private function SlashDamage takes integer l returns real
        return 50.0*l
    endfunction
    
    //Filter for picking enemies in group.
    private function FILTER takes nothing returns boolean
        local unit u = GetFilterUnit()
        if IsUnitEnemy(u, FilterSlash.owningplayer) and IsUnitInRangeXY(u, FilterX, FilterY, DamageRadius)  and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitInGroup(u, FilterSlash.hit) and GetUnitState(u, UNIT_STATE_LIFE) > 0.405 then
            if FilterSlash.caster != null then
                call UnitDamageTarget(FilterSlash.caster, u, SlashDamage(FilterSlash.level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            endif
            call DestroyEffect(AddSpecialEffect(HitSFX, GetUnitX(u), GetUnitY(u)))
            call FilterSlash.castOnTarget(u)
            call GroupAddUnit(FilterSlash.hit, u)
        endif
        set u = null
        return false
    endfunction
    
    private struct SwingSlash extends xecast
        private unit c
        private real start
        private group h
        private timer t
        private integer slashes = 0
        
        method operator caster takes nothing returns unit
            return this.c
        endmethod
        
        method operator hit takes nothing returns group
            return this.h
        endmethod
        
        static method periodic takes nothing returns nothing
            local thistype this = thistype(GetTimerData(GetExpiredTimer()))
            local real x = this.sourcex + Distance * Cos(this.start + Angle * this.slashes)
            local real y = this.sourcey + Distance * Sin(this.start + Angle * this.slashes)
            call DestroyEffect(AddSpecialEffect(NovaSFX, x, y))
            set FilterSlash = this
            set FilterX = x
            set FilterY = y
            call GroupEnumUnitsInRange(ENUM_GROUP, x, y, DamageRadius+XE_MAX_COLLISION_SIZE, filter)
            call GroupClear(ENUM_GROUP)
            set this.slashes = this.slashes + 1
            if this.slashes > SlashNumber then
                call this.destroy()
            endif
        endmethod
        
        static method create takes unit caster returns thistype
            local thistype this = thistype.allocate()
            set this.h = NewGroup()
            set this.t = NewTimer()
            call SetTimerData(this.t, integer(this))
            set this.c = caster
            set this.abilityid = DOTCode
            set this.orderid = 852527 //thats the same as doing this.orderstring = "shadowstrike"
            set this.owningplayer = GetOwningPlayer(caster)
            set this.recycledelay = 16.0
            set this.sourcex = GetUnitX(caster)
            set this.sourcey = GetUnitY(caster)
            set this.start = (GetUnitFacing(caster)-90.0)*bj_DEGTORAD
            set this.level = GetUnitAbilityLevel(caster, RawCode)
            call TimerStart(this.t, SpawnSpeed, true, function thistype.periodic)
            return this
        endmethod
        
        private method onDestroy takes nothing returns nothing
            call ReleaseGroup(.h)
            call ReleaseTimer(.t)
        endmethod
    endstruct


    //===============SETTINGS FOR 180 % NOVA==============================================================================
    private function ConditionsActions takes nothing returns boolean
        if GetSpellAbilityId() == RawCode then
            call SwingSlash.create(GetSpellAbilityUnit())
        endif
        return false
    endfunction


    //=============INIT TRIGG===================================================================
    private function init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        local integer i = 0
        set filter = Filter(function FILTER)
        loop
            exitwhen i == 16
            call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
        endloop

        call TriggerAddCondition(trig, Condition(function ConditionsActions))

        call Preload(NovaSFX)
        call Preload(HitSFX)
        call XE_PreloadAbility(DOTCode)
        set trig = null
    endfunction
endscope

edit: btw this spell looks quite cool ^^

Uh, nice, but I really need to learn vJASS, first I have problems with installing it and second I really hate this in vJASS: Jasshelper, TimerUtils, GroupUtils, xebasic, xecast, xepreload. Requires so many things, and it really annoys me.

I'm still going to use JASS, until I get bored of it, then I start learning vJASS.
Thank you so much for helping me, to bad I can't rep you again xD.
 
Level 8
Joined
Jun 18, 2007
Messages
214
I have a question if I'm using
JASS:
function EnumAction takes nothing returns boolean
    local unit u = GetFilterUnit()
    if someCondition(u) then
        // do something with the unit
    endif
    return false
endfunction
 
function Actions takes nothing returns nothing
    call GroupEnumUnits*(DUMMYGROUP, ..., Condition(function EnumAction))
endfunction

as a loop for a group, how will I know who damages it. How to transfer a damaging unit in that function?

EDIT: Will it be MUI if I use a global variable?
 
Status
Not open for further replies.
Top