System Attack Detection

gref

New Member
Reaction score
33
Attack Detection 1.10
No current versions are stable. Please wait to use this in your map until a stable version has been released.

System Description:
An Attack Detection system is system that triggers, for all units, when they take damage, depending on whether that damage was caused via a spell or an attack, a predefined action. The purpose of the system is to make it as simple as possible to detect and respond to damage events, as it is for all generic events.

Most recent update: January 10th 2008.
GUI: 1.10b: Removed the need for 3 global variables.
Jass: 1.10c: ExecuteFunc use changed to trigger action use. Syntax errors will occur on compile now rather than in game.



Changelog
Version 1.00:
-Changed to PUI from CSCache- More user friendliness/safety as a result
-Added more demo items
-Added shop to get items from in game
-File size is halved

Version 1.01:
-Added support for excluding dummy units from system. Slight performance increase, has no effect on system behaviour as dummy units do not take damage.

Version 1.10
-Removed everyones hands from my library
-Added support for GUI
-Added ExecuteFunc for Jass

Version 1.10b Jass
-Added an important level of data abstraction for Jass users

Version 1.10b GUI
-Removed the need for 3 Global variables, making initialization simpler.

Version 1.10c Jass
-Change ExecuteFunc use to TriggerExecute, allowing syntaxing, and removing multiple-thread abuse.

Screenshots:
ADSystemScreen.jpg

ADSystemScreen2.jpg

System Code:
Jass 1.10c
JASS:
//====================>
// AD by gref.
//====================>
// To add functions scroll down to where it says Add Functions.


library AttackDetection initializer Init_AttackDetection requires PUI

//====================>
// Constants
//====================>
    // AbilCode = the integer id of AD Ability
    // BuffCode = the interger id of AD Buff
    globals
        private constant integer BuffCode = 'B000'
        private constant integer AbilCode = 'A000' 
        
        private trigger array SpellTriggers
        private trigger array AttackTriggers
        private integer SpellNumber = 0
        private integer AttackNumber = 0 
        
        unit AD_Attacker
        unit AD_Defender
        real AD_Damage
        
        private integer array Dummys
        private integer DummyNumber = 0 
    endglobals
//====================>
// Data types
//====================>
    struct AD
        trigger t
        triggeraction ta
        unit u    
        
        private static AD array THIS
                
        static method Get takes unit whichUnit returns AD
            local integer pui = GetUnitIndex(whichUnit)
            if .THIS[pui]==null then
                set .THIS[pui] = AD.allocate()
            endif
            return .THIS[pui]
        endmethod
    endstruct

//====================>
// User Editted Functions
//====================>
    function AD_AddDummy takes integer id returns nothing
        set Dummys[DummyNumber] = id
        set DummyNumber = DummyNumber + 1
    endfunction
    
    function AD_AddFunction takes code userFunc, boolean attack returns nothing
        if(attack == true) then   
            set AttackTriggers[AttackNumber] = CreateTrigger()
            call TriggerAddAction(AttackTriggers[AttackNumber], userFunc)
            set AttackNumber = AttackNumber + 1             
        else            
            set SpellTriggers[SpellNumber] = CreateTrigger()
            call TriggerAddAction(SpellTriggers[SpellNumber], userFunc)
            set SpellNumber = SpellNumber + 1           
        endif    
    endfunction

    private function IsUnitDummy takes integer id returns boolean
        local integer i = 0
    
        loop
            exitwhen i == DummyNumber
            
            if (id == Dummys<i>) then
                return true
            endif
            
            set i = i + 1
        endloop
                
        return false
    endfunction
    
    //Add Functions in the demonstrated spaces below.
    private function UnitDamaged takes nothing returns nothing
        local integer i = 0
        
        set AD_Damage = GetEventDamage()
        set AD_Attacker = GetEventDamageSource()
        set AD_Defender = GetTriggerUnit()
        
        
        if(GetUnitAbilityLevel(GetTriggerUnit(), BuffCode) &gt; 0) then   
            call UnitRemoveAbility(GetTriggerUnit(), BuffCode)  
            
                   
            loop
                exitwhen i == AttackNumber
            
                call TriggerExecute(AttackTriggers<i>)
            
                set i = i+1       
            endloop
                    
        else   
        
            loop
                exitwhen i == SpellNumber
            
                call TriggerExecute(SpellTriggers<i>)
            
                set i = i+1       
            endloop
        
        endif
        
    endfunction     

//====================&gt;
// Initialization
//====================&gt;

    private function UnitEntersWorld takes nothing returns nothing
        local unit  u = GetEnteringUnit()
        local AD a = AD.Get(u) 
        
        if(IsUnitDummy(GetUnitTypeId(u)) != true) then
        
            //Clear the previous units triggers
            if(a.u != null) then
                call TriggerRemoveAction(a.t, a.ta)
                call DestroyTrigger(a.t)  
            endif                 
                
            //Add the new ones.                                         
            set a.u = u
            set a.t = CreateTrigger()
            call TriggerRegisterUnitEvent(a.t, u, EVENT_UNIT_DAMAGED) 
            call UnitAddAbility(u, AbilCode)  
            set a.ta = TriggerAddAction(a.t, function UnitDamaged)  
        endif
                       
        set u = null
    endfunction

    private function Init_AttackDetection takes nothing returns nothing
    // Adds all units on the map at initilization to damage detection triggers.
        local unit u
        local group g = CreateGroup()
        local AD a
        local trigger t = CreateTrigger() //Add a trigger to make all units entering the map added.
        
        call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            
            set a = AD.Get(u)
            //Clear the previous units triggers
            if(a.u != null) then
                call TriggerRemoveAction(a.t, a.ta)
                call DestroyTrigger(a.t)  
            endif                 
                
            //Add the new ones.                                         
            set a.u = u
            set a.t = CreateTrigger()
            call TriggerRegisterUnitEvent(a.t, u, EVENT_UNIT_DAMAGED) 
            call UnitAddAbility(u, AbilCode)  
            set a.ta = TriggerAddAction(a.t, function UnitDamaged)   
             
        
            call GroupRemoveUnit(g, u)
        endloop    
        
        //Add units entering world trigger.
        call TriggerRegisterEnterRectSimple(t, GetWorldBounds())
        call TriggerAddAction(t, function UnitEntersWorld)
                     
        
        set u = null
        set g = null
        set t = null
    endfunction

endlibrary</i></i></i>

GUI 1.10b
JASS:
//====================&gt;
// AD by gref.
//====================&gt;
// To add functions scroll down to where it says Add Functions.


library AttackDetection initializer Init_AttackDetection requires PUI

//====================&gt;
// Constants
//====================&gt;
    // AbilCode = the integer id of AD Ability
    // BuffCode = the interger id of AD Buff
    globals
        private constant integer BuffCode = &#039;B000&#039;
        private constant integer AbilCode = &#039;A000&#039; 
    endglobals
//====================&gt;
// Data types
//====================&gt;
    struct AD
        trigger t
        triggeraction ta
        unit u    
        
        private static AD array THIS
                
        static method Get takes unit whichUnit returns AD
            local integer pui = GetUnitIndex(whichUnit)
            if .THIS[pui]==null then
                set .THIS[pui] = AD.allocate()
            endif
            return .THIS[pui]
        endmethod
    endstruct

//====================&gt;
// User Editted Functions
//====================&gt;

    private function IsUnitDummy takes integer id returns boolean
        local integer i = 0
    
        loop
            exitwhen udg_AD_Dummys<i> == null
        
            if (id == udg_AD_Dummys<i>) then
                return true
            endif
            
            set i = i + 1
        endloop
                
        return false
    endfunction
    
    //Add Functions in the demonstrated spaces below.
    private function UnitDamaged takes nothing returns nothing
        local integer i = 0
        
        set udg_AD_Damage = GetEventDamage()
        set udg_AD_Attacker = GetEventDamageSource()
        set udg_AD_Defender = GetTriggerUnit()
        
        
        if(GetUnitAbilityLevel(GetTriggerUnit(), BuffCode) &gt; 0) then   
            call UnitRemoveAbility(GetTriggerUnit(), BuffCode)  
            
                   
            loop
                exitwhen udg_AD_AttackTriggers<i> == null
            
                if(TriggerEvaluate(udg_AD_AttackTriggers<i>)) then
                    call TriggerExecute(udg_AD_AttackTriggers<i>)            
                endif           
            
                set i = i+1       
            endloop
                    
        else   
        
            loop
                exitwhen udg_AD_SpellTriggers<i> == null
            
                if(TriggerEvaluate(udg_AD_SpellTriggers<i>)) then
                    call TriggerExecute(udg_AD_SpellTriggers<i>)            
                endif           
            
                set i = i+1       
            endloop
        
        endif
        
        if(i == 0) then
            call BJDebugMsg(&quot;Error: No AD triggers defined. Start at 0 array index.&quot;)
        endif
        
    endfunction     

//====================&gt;
// Initialization
//====================&gt;

    private function UnitEntersWorld takes nothing returns nothing
        local unit  u = GetEnteringUnit()
        local AD a = AD.Get(u) 
        
        if(IsUnitDummy(GetUnitTypeId(u)) != true) then
        
            //Clear the previous units triggers
            if(a.u != null) then
                call TriggerRemoveAction(a.t, a.ta)
                call DestroyTrigger(a.t)  
            endif                 
                
            //Add the new ones.                                         
            set a.u = u
            set a.t = CreateTrigger()
            call TriggerRegisterUnitEvent(a.t, u, EVENT_UNIT_DAMAGED) 
            call UnitAddAbility(u, AbilCode)  
            set a.ta = TriggerAddAction(a.t, function UnitDamaged)  
        endif
                       
        set u = null
    endfunction

    private function Init_AttackDetection takes nothing returns nothing
    // Adds all units on the map at initilization to damage detection triggers.
        local unit u
        local group g = CreateGroup()
        local AD a
        local trigger t = CreateTrigger() //Add a trigger to make all units entering the map added.
        
        call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            
            set a = AD.Get(u)
            //Clear the previous units triggers
            if(a.u != null) then
                call TriggerRemoveAction(a.t, a.ta)
                call DestroyTrigger(a.t)  
            endif                 
                
            //Add the new ones.                                         
            set a.u = u
            set a.t = CreateTrigger()
            call TriggerRegisterUnitEvent(a.t, u, EVENT_UNIT_DAMAGED) 
            call UnitAddAbility(u, AbilCode)  
            set a.ta = TriggerAddAction(a.t, function UnitDamaged)   
             
        
            call GroupRemoveUnit(g, u)
        endloop    
        
        //Add units entering world trigger.
        call TriggerRegisterEnterRectSimple(t, GetWorldBounds())
        call TriggerAddAction(t, function UnitEntersWorld)
                     
        
        set u = null
        set g = null
        set t = null
    endfunction

endlibrary</i></i></i></i></i></i></i></i>

 

Attachments

  • AD System 1.10b GUI.w3x
    96.6 KB · Views: 387
  • AD System 1.10c Jass.w3x
    81.7 KB · Views: 313

Cohadar

master of fugue
Reaction score
209
Any Attack Detection engine that uses CSCashe fails - Instantly
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
Want me to share my system?
Although it is abit lame, but it works well on me.
JASS:
//&lt;-- Damaged Main Engine --&gt;//
globals
    private trigger p = null
    private trigger time = CreateTrigger()
endglobals

private function pickedCond takes nothing returns boolean
    return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)&gt;0 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction

private function pickedAct takes nothing returns nothing
local unit e = GetEnumUnit()
    call TriggerRegisterUnitEvent(p,e,EVENT_UNIT_DAMAGED)
set e = null
endfunction

private function TimeAct takes nothing returns nothing
local group picked = CreateGroup()

    //Setting Trigger
    if p != null then
        call DestroyTrigger(p)
    endif
    set p = CreateTrigger()
    call TriggerAddCondition(p,Condition(function GTCond))
    call TriggerAddAction(p, function GTAct )
    //End
    

    call GroupEnumUnitsInRect(picked, bj_mapInitialPlayableArea,Condition(function pickedCond))
    call ForGroup(picked, function pickedAct)
    
call DestroyGroup(picked)
set picked = null
endfunction
//&lt;-- Damaged Main Engine End --&gt;//
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Any Attack Detection engine that uses CSCashe fails - Instantly

Code:
  Extreme amount of attacks during one game
+ Every attack uses CACHE
+ Cache is slow, especially in great amounts
====================================
= Fail (read: lag or slow system)

Am I about right on your thoughts?



Gals: you have a damage detection system, we need an attack detection system
 

gref

New Member
Reaction score
33
Oh I'm sorry Mr. IFlamePandasBecauseMySystemIsSoSLow.
Isn't your system only 9% faster than gamecache anyway? A.
And B. simple integer attachment really doesn't take very long on ANY system.
OH NOES! Everytime a unit is damaged it has to make 0 CSCache calls. GG LAG!!1!
There are only CSCache calls when a unit is added or removed.

And Gals is right...it is a damage detection system. It just makes sure the damage is from an attack or spell.

My system has negatives Cohadar, which is why I put the whole Negatives bit in the readme, and linked to 2 other systems that do the same thing. Performance however, really isn't one of them.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Oh I'm sorry Mr. IFlamePandasBecauseMySystemIsSoSLow.
Isn't your system only 9% faster than gamecache anyway? A.
And B. simple integer attachment really doesn't take very long on ANY system.

What 'my system'? I don't have a system.
What I'm saying is using game cache at all is kinda outdated, but using game cache for every attack made during an entire game is completely absurd.

I had a spell once which moved 84 dummy units at once and I first used KaTTaNa's handle vars (game cache) for the struct attaching (struct = integer!).

My spell lagged and was even game ruiningly slow during multiple casts due to this flawed game cache speed.

When I used Cohadar's ABC (no cache) afterwards, it didn't lag at all anymore.

Go figure.
 

gref

New Member
Reaction score
33
Wasn't talking to you Magentix :)

There is no gamecache on any attacks at all.
There are in fact no timers either. So ABC really isn't very relevant.

That is all.
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
>>Gals: you have a damage detection system, we need an attack detection system
Sry ya, I am noob.

Main Topic
It is a basic knowledge to every advance mapper, gamecache is slow and quite unstable.
Take another try, use struct attachment system. They don't use gamecache but global arrays.

If you were pro enough, invent your own global array attaching system.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Ah well, I'm still waiting for the attack system out there that doesn't require an orb :(
 

gref

New Member
Reaction score
33
@ Gals

*sigh*
Your damage detection code was fine but I couldn't actually see what it did because the GTAct function wasn't in what you showed us. --

Change from CSCache: But there's no need? It's only called when a unit enters the map, leaves the map and map initialization. It's not something that happens so frequently I need a super fast attachment system that people have to copy into their map.

If I was pro enough etc: I don't want to make another standard that people have to copy into their map.

CSCache is pretty much a standard that almost everyone has, or has used, and a lot of people have in their maps. Hence I use that. I could use KaTtAnA's system. I could use ABC. I could use PandaMine's system. I could invent my own retarded system then speedtest it to boost my epeen. But I won't, because then more users would have to copy more useless crap into their map.



Ah well, I'm still waiting for the attack system out there that doesn't require an orb :(

There is actually one.
It's the first link in I put in the first post.

But it's flawed because you can attack, cancel to make actions occur when they wouldn't etc.
It's still useful for some purposes.

My main reason for using one with an orb, is because the basic orb effects are damned easy to make, so I don't see a reason not to.
 

gref

New Member
Reaction score
33
@ onDestroy: In the end...I just removed it.

I'll assume that people won't be foolish enough to alter the system and implode their maps. Probably a foolish assumption

@ Exclude unit, yeah that is a good idea.

Updated.

================================>
Updated: I just made this extremely simple to use in GUI, completely reworked the calling of the On Damage functions, and made an entire second seperate version, complete with demonstration Items.

*Tired sigh*

================================>
Updated further: Another level of data abstraction and ease of use for Jass users has been added.
As for GUI users, advice on whether I should do similar and get them to use custom script, or keep it using GUI variables would be nice...

Bump for all the effort I put in yesterday to make this usable by anyone.

I'd like everyone who'd care to give it's opinion on both the Jass and GUI version, and how to make implementation easier for both sets of people.

Should I make it so that GUI users call a custom script function or leave it as it is with the arrays?
Should I keep the executeFunc version for jass users, or make it take an actualy function? Is being able to use wait's occasionally in damage events worth the possible performance impact of using them to often?

That's fair enough.
I consider this easier to use, but I understand the other viewpoint which is why I added the other systems that approach it the other way.

All I need to make a map use this and not leak:
-One more trigger, that cleans units when they die.
-Replace RemoveUnit with my RemoveUnitClean function
-Add a AD_AddUnit(whichUnit) in where heroes are revived, or animate dead is cast.

Bump for major update.

Ok...Since it now uses PUI which should take care of the fact that all units die eventually, this is now actually user friendly.

Read the first post for details.
http://www.thehelper.net/forums/showthread.php?p=650345#post650345
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Hmm, I' just got an idea for an Attack Detection System without orbs :eek:

Damn, now I can't wait till my exams are over, so I can start on it :(
 

0zaru

Learning vJASS ;)
Reaction score
60
An attachment system is not useless crap.

And those calls (When you call the attach int) are a lot, remember that when you create a spell that requires dummy unit, the unit enters in the playable map area. And if you call a barrier for example that needs 36 units...
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
I'll be interested to see it. Check to make sure it isn't the same as this http://www.wc3campaigns.net/showthread.php?t=91354
And remember that autocast attack abilities always override orbs.

No, it's an idea for something that doesn't need any ability, nor check for buffs, but that's all I'm going to say right now, I need to design and test it first before I get people's hopes up
 

gref

New Member
Reaction score
33
An attachment system is not useless crap.

And those calls (When you call the attach int) are a lot, remember that when you create a spell that requires dummy unit, the unit enters in the playable map area. And if you call a barrier for example that needs 36 units...

Yup. It's alot. But CSCache will do it fine. :)

You guys all seem to forget that Stacking Orbs by Vexorian used CSCache, was much more attachment intensive, and yet is used by many many people.
 

Cohadar

master of fugue
Reaction score
209
The issues is not speed.
Attaching to units is not safe.

I think I repeated that line like 100 times by now.
You want to know why is it not safe?
Use the search button.
 

gref

New Member
Reaction score
33
It's not safe because units die and get removed I know.

Do you know why I don't care? Read the readme.

It might have something to do with the fact that I'm already requiring all users of this system to call AD_CleanUnit(whichUnit) before every unit is removed.
This includes units that die and are then removed.
Why? Because it means that I can have much simpler and faster execution and code. I did say this was not for Jass users that couldn't cover their own tracks.
 

Cohadar

master of fugue
Reaction score
209
Yeah fine.
I just don't like stuff that are harder to use that they need to be.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top