System UAC - Unit Aura Control

Romek

Super Moderator
Reaction score
963
Unit Aura Control
By Romek
Version 3.1
Introduction:
UAC is a system that was originally designed to make creating Aura-type spells much easier than it currently is, although it can be used for anything which requires "Unit In Range" type events. See the documentation (in the map) and the example spell for more information!

The Documentation:
JASS:
.
   _   _  _   ___                                         
  | | | |/_\ / __|     U N I T   A U R A   C O N T R O L                                  Last Update: 22nd Nov 2009
  | |_| / _ \ (__             B y   R o m e k
   \___/_/ \_\___|              Version 3.1

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    Contact Information:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        My Profile:
          <a href="http://www.thehelper.net/forums/member.php?u=7807" class="link link--internal">www.thehelper.net/forums/member.php?u=7807</a>
          
        UAC Thread:
          <a href="http://www.thehelper.net/forums/showthread.php?t=112374" class="link link--internal">www.thehelper.net/forums/showthread.php?t=112374</a>
          
    What is UAC?
    ¯¯¯¯¯¯¯¯¯¯¯¯
        UAC is a system which allows the creation of aura-type abilities in an efficient, user-friendly way.
        Think of it as the aura equivalent of the caster system.
        
        Although UAC alone can be used to create incredible auras very easily, optional modules are also 
        available, which can provide extra options and methods.
        
        UAC requires vJASS knowledge.
        
    How to Implement:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        - Open your map, open the trigger editor (F4)
        - Create a new trigger object (CTRL + T), and name it whatever you want (preferably UAC).
        - Go to Edit -&gt; Convert to Custom Text
        - Delete all the text that appears
        - Copy everything in the UAC trigger, and paste it into the trigger you created
        - You may want to change the configurable, though this isn&#039;t recommended.
        - Save, and enjoy!
        
    How to Use:
    ¯¯¯¯¯¯¯¯¯¯¯
        - Create a new JASS trigger.
        - Create a struct, and make it extend UAC. (struct Name extends UAC)
        - Then you can use all the methods, members and interface methods listed below 
          on (and in) this new struct you created.
        - See the example spell(s) for real usage.
        
    Methods:
    ¯¯¯¯¯¯¯¯
        _______________________________________________________________________
         static method create takes unit mainUnit, real range returns thistype
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This creates an instance for you to use. &#039;mainUnit&#039; is the unit which
            has the aura spell. &#039;range&#039; is the range of the aura. Units within this range
            of &#039;mainUnit&#039; will be affected. See &#039;main&#039; and &#039;range&#039; members for more detail.
            If your struct has a custom create method, you will need to call &#039;allocate&#039; instead
            of create. The arguments will be exactly the same though.
            Remember to use &lt;YourStructName&gt;.create(...), not UAC.create(...).
            
            local Aura data = Aura.create(GetTriggerUnit(), 600.)
            
        ________________________________________________________
         static method get takes unit mainUnit returns thistype
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This returns the aura instance which &#039;mainUnit&#039; is the main unit for.
            This is most useful when you need to check if a unit leveled up the aura, or learned it, 
            as it&#039;d be bad to create a new instance everytime a unit levels a spell.
            This will return 0 if there is no data.
            This will only return a struct of the type that the method is used from. So if a unit has two
            auras, X and Y; X.get(u) and Y.get(u) will return different structs. Similarly, Z.get(u) will
            return 0.
            
            if Aura.get(u) == 0 then
                set data = Aura.create(...)
            else
                call BJDebugMsg(&quot;Aura already learned. Levelling up!&quot;)
            endif
            
        ________________________________________________________
         method isAffected takes unit whichUnit returns boolean
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is used to check if &#039;whichUnit&#039; is affected by the aura.
            It will return true if the unit is, and false if it isn&#039;t.
            This will only return true if the unit is affected by the current instance.
            So even if the unit is affected by an aura of the same type as the current instance,
            this&#039;ll return false if it&#039;s not affected by this exact instance.
            
            This is useful for auras such as &#039;double damage&#039; auras. It&#039;s impossible to give a unit
            double the damage when it enters or leaves the auras range; nor is it possible to do so
            every 0.03125 (by default) seconds. However, if using damage detection, you could check if
            the damage source is affected by the aura. If it is, then deal the damage again.
            
            if data.isAffected(GetEventDamageSource()) then
                call KillUnit(GetTriggerUnit())
            endif
            
            
    Members:
    ¯¯¯¯¯¯¯¯
        ________________    
         unit main          &#039;main&#039; can be used to retrieve the main unit for the aura. The main unit is the unit
         unit mainUnit      that has the aura ability, and units come within range of this unit to become affected.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This can be used in all the interface methods (more below).
            &#039;main&#039; is a readonly member, meaning it cannot be set. Only retrieved.
            &#039;mainUnit&#039; can also be used instead of &#039;main&#039;. It does exactly the same thing, just with a different name.
            
            call SetWidgetLife(data.main, 500.)
            call SetWidgetLife(data.mainUnit, 500.)
            
        ________________   
         real range         &#039;range&#039; is the range of the aura. Units that come within this range of the main unit
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    become affected. If this is set to 0 or less, the instance will be paused, and the      
            range will need to be reset to a higher number to resume the aura.
            
            set data.range = data.range + 100
            
        ________________
         boolean pause      &#039;pause&#039; determines whether or not a struct instance is paused. When an instance is
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    paused, no units are affected by the aura, and no effects happen. The struct is 
            virtually destroyed during the time it&#039;s paused.
            When a struct is paused, all affected units will become unaffected.
            
            if data.pause then
                set data.pause = false
            endif
            
        ________________
         boolean single     &#039;single&#039; determines whether or not the struct will be destroyed when the main unit dies.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    If single is true, then the struct will be destroyed when the main unit dies. Otherwise, 
            the struct will be paused until the unit is revived (or it&#039;ll just remain paused forever).
            &#039;single&#039; is automatically set to true if the main unit is not a hero. Otherwise, it stays false.
            
            if IsUnitType(u, UNIT_TYPE_HERO) == true then
                set data.single = false
            endif
            
        ________________
         integer count      &#039;count&#039; simply returns the amount of units that are currently affected by an aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This is useful if you want certain effects to happen depending on the amount of units
            within range. For example, divide some damage between all targets, or heal the caster for targets * 100.
            &#039;count&#039; is a readonly member, meaning it cannot be set. Only retrieved.
            
            call SetWidgetLife(data.main, 1000 / data.count)
            
        ________________
         real ticker        &#039;ticker&#039; is, in seconds, how often the periodic functions of UAC are called for the
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    particular instance. This includes the frequency at which units can become affected
            or unaffected, and how often unitPeriodic and timerLoop are called. This is automatically rounded down
            to a multiple of TIMEOUT. This is TIMEOUT by default. 
            
            set data.ticker = data.ticker + TIMEOUT
            
            
    Interface Methods:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        - All of these methods must be declared in your struct. They aren&#039;t used like normal methods are,
          but are simply created within the struct, then automagically called when appropriate.
        - All of these methods are optional.
        - The arguments do not have to be named the same as they are in the codes below.
        ________________________________________________________
         method unitEnter takes unit whichUnit returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is called when a unit comes within range of the mainunit. &#039;whichUnit&#039; is the unit
            that came within range, and is now affected by the aura.
            
            method unitEnter takes unit u returns nothing
                call SetUnitMoveSpeed(u, 100.)
            endmethod
            
        ________________________________________________________
         method unitLeave takes unit whichUnit returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method goes hand-in-hand with unitEnter. It does the complete opposite.
            This method is called when a unit that was affected by the aura stops being affected.
            &#039;whichUnit&#039; is the unit that left the range of the aura.
            This method is often used to remove any effects that were created in unitEnter.
            
            method unitLeave takes unit u returns nothing
                call SetUnitMoveSpeed(u, GetUnitDefaultMoveSpeed(u))
            endmethod   
            
        __________________________________________________________
         method unitPeriodic takes unit whichUnit returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is called every 0.03125 (by default) seconds, for every unit that is affected
            by the aura. Useful for continous effects which need to be updated constantly for as long 
            as the unit is affected.
            
            method unitPeriodic takes unit u returns nothing
                call SetUnitMoveSpeed(u, GetUnitMoveSpeed(u) - 1)
            endmethod
            
        ________________________________________________
         method mainDeath takes nothing returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is called when the main unit dies. Useful for removing any aura effects attached
            to the main unit, or undoing any main-unit only effects. unitLeave is automatically called for
            every unit affected.
            
            method mainDeath takes nothing returns nothing
                call DestroyEffect(this.effect)
            endmethod
            
        _________________________________________________
         method mainRevive takes nothing returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is called when the main unit is revived. This method will never be called if
            &#039;single&#039; was true. This is useful for recreating anything that was removed in mainDeath.
            All units that would be affected become affected automatically.
            
            method mainRevive takes nothing returns nothing
                set this.effect = AddSpecialEffectTarget(&quot;model&quot;, .main, &quot;origin&quot;)
            endmethod
            
        ________________________________________________
         method timerLoop takes nothing returns nothing
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            This method is called every 0.03125 seconds (by default). Unlike unitPeriodic, it doesn&#039;t take
            a unit argument. It&#039;s simply called regardless of any conditions, units, etc.
            Can save you a timer. Useable as a &#039;unitPeriodic&#039; for the mainUnit only, as unitPeriodic isn&#039;t
            suitable for this (it could be called any amount of times, depending on the amount of units affected).
            This method is called only once every 0.03125 seconds.
            
            method timerLoop takes nothing returns nothing
                call SetUnitPosition(.dummy, GetUnitX(.mainUnit), GetUnitX(.main))
            endmethod
            
            
    Filter Methods:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
         - These are similar to Interface Methods, in the sense that they also have to be declared manually
           in the struct.
         - These are used to prevent unwanted units from being affected by the aura.
         - If these return true, then the unit that was passed is a valid target.
         - All of these are optional.

         ________________________________________________________
          method andFilterA takes unit whichUnit returns boolean
          method andFilterB takes unit whichUnit returns boolean
          method andFilterC takes unit whichUnit returns boolean
         ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
         - All of the declared and filters must be true for the unit to be a valid taget
         
         _______________________________________________________
          method orFilterA takes unit whichUnit returns boolean
          method orFilterB takes unit whichUnit returns boolean
          method orFilterC takes unit whichUnit returns boolean
         ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
         - At least one of the declared or filters must be true for the unit to be a valid target.
         
    
    Changelog:
    ¯¯¯¯¯¯¯¯¯¯
        3.1
        - Readded Tickers
    
        3.0
        - Complete rewrite of script. It&#039;s now more efficient, stable and virtually limitless. 
        - Code is also littered with comments.
        - Renamed most methods:
            - UnitEnter -&gt; unitEnter
            - UnitLeave -&gt; unitLeave
            - unitPeriodic -&gt; unitPeriodic
            - OrFilter% -&gt; orFilter%
            - AndFilter% -&gt; andFilter%
            - MainDeath -&gt; mainDeath
            - MainRevive -&gt; mainRevive
            - TimerLoop -&gt; timerLoop
            - MainUnit -&gt; main            
        - Added optional use of mainUnit instead of main
        - Some additional features have been removed (such as effects)
        - Added support for optional extensions
            - Created UAC Effects
            - Created UAC Filters
        - Created new readme
        - Added more safety and debugging options
        - pausing now works as it should
        - This should be the last major update. (Enough with the interface changes (sorry!))
        
        2.2                                                                                                        
        - Added the TimerLoop method                                                                               
        - Now works with the new 1.23b patch. (And is more stable as a result!)                                    
                                                                                                                    
        2.1                                                                                                        
        - Fixed a minor coding error in the create method                                                          
        - Added &quot;count&quot; method operator                                                                            
        - Fixed a bug which involved leaking an instance with heroes which had more than one aura                  
        - Lots of changes related to multiple auras per unit.                                                      
        - Added &#039;effect&#039; and &#039;attachpoint&#039; operators, for the newly added Effects.                                 
        - TIMEOUT is now public. It can be accessed by using UAC_TIMEOUT.                                          
                                                                                                                    
        2.0b                                                                                                       
        - Removed the limitation of 1 aura ability per unit.                                                       
                                                                                                                    
        2.0                                                                                                        
        - Re-wrote the entire system to meet my standards                                                          
        - Added MainDeath and MainRevive methods                                                                   
        - Changed most of the current methods                                                                      
        - Added internal attachment, so the system no longer depends on PUI                                        
        - Added IsAffected Method                                                                                  
        - Added &#039;Single&#039; operator                                                                                  
                                                                                                                    
        1.8                                                                                                        
        - Changed the SetRange method to an operator                                                               
        - Implemented Pausing                                                                                      
                                                                                                                    
        1.7                                                                                                        
        - Added Tickers                                                                                            
                                                                                                                    
        1.6                                                                                                        
        - Fixed some small coding errors                                                                           
        - Fixed a bug which continously called &quot;UnitLeave&quot; for the main unit. (Silly me <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />)                        
                                                                                                                    
        1.5                                                                                                        
        - Added the .Destroy method. When &#039;set data.Destroy = true&#039; is used; when the main                         
          unit dies, the struct will be destroyed automatically.                                                   
                                                                                                                    
        1.4                                                                                                        
        - Recoded the entire system to improve on efficiency and fix some sloppy coding.                           
        - The main functions now take 2 arguments. (enumerated unit, and main unit)                                
        - Renamed UnitInRange to UnitPeriodic                                                                      
        - Renamed UnitEntersRange to UnitEnter                                                                     
        - Renamed UnitLeavesRange to UnitLeave                                                                     
        - Filters have been completely revamped. They are now optional functions, and there are &#039;And&#039; and &#039;Or&#039;      
          filters. At least one of the &#039;Or&#039; ones has to be true, and all of the &#039;And&#039;s have to be true.            
          They are all optional.                                                                                   
        - As a result of the filters being remade, the filter library is now removed. (Didn&#039;t last long!)          
                                                                                                                    
        1.3                                                                                                        
        - Fixed a bug which occured when the &#039;main&#039; unit died.                                                     
        - Added a library of common filters, so the user doesn&#039;t have to create identical functions                
          for most auras.                                                                                          
        - Fixed a bug which kept calling UnitInRange for units which where enumerated at least                     
          once, but then should&#039;ve been filtered. (Maybe the unit became flying, etc)                              
          been filtered.                                                                                           
                                                                                                                    
        1.2                                                                                                        
        - Changed another small coding error                                                                       
        - Made TrueGroup non-static to avoid bugs involving units in range of                                      
          multiple &#039;aura units&#039;                                                                                    
        - Removed a useless variable from a function                                                               
                                                                                                                    
        1.1                                                                                                        
        - Fixed a coding error involving index recycling                                                           
                                                                                                                     
        1.0:                                                                                                       
        - Initial Release

The Code:
JASS:
library UAC
globals
//           _______________________________________________________________
//          +---------------------------------------------------------------+
//          ||     _   _  _   ___                                          ||
//          ||    | | | |/_\ / __|     U N I T   A U R A   C O N T R O L   ||
//          ||    | |_| / _ \ (__             B y   R o m e k              ||
//          ||     \___/_/ \_\___|              Version 3.1                ||
//   _______||_____________________________________________________________||_______
//  ||¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||
//  ||  U A C allows users to create aura-type spells in a simple, user-friendly   ||
//  ||  way, with the use of 3 main methods, and numerous members, giving maximum  ||
//  ||  flexibility and efficieny. For more information, -= see the READ ME =-     ||
//  |+-----------------------------------------------------------------------------+|
//  ||  The newer versions (3.0 and above) also allow optional extensions, which   ||
//  ||  enhance UAC with additional members and methods if they&#039;re present.        ||
//  |+-----------------------------------------------------------------------------+|
//  ||  This controls how often units are checked to see if they are affected by   ||
public constant real TIMEOUT = 0.03125 // The auras. timerLoop and unitPeriodic    ||
//  ||  are called at this frequency. .03125 is recommended.                       ||
//  |+-----------------------------------------------------------------------------+|
//   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// =======================================================================================


        // if debug mode is enabled AND this is true, then error/warning messages will be
        // displayed when something goes wrong or could potentially go wrong.
        debug constant boolean UAC__DEBUG = true
    
    endglobals
    
    // Optional Modules:
    // ------------------
    
        // At top of struct
        private module MainModules 
            implement optional UACEffects
            implement optional UACFilters
        endmodule
        
        // When instance is created
        private module CreateModules
            implement optional UACEffects_Create
        endmodule
        
        // When a unit leaves
        private module LeaveModules
            implement optional UACEffects_Leave
        endmodule
        
        // When a unit enters
        private module EnterModules
            implement optional UACEffects_Enter
        endmodule
        
        // Every TIMEOUT seconds.
        private module PeriodicModules
        
        endmodule
        
        // During the filter stage
        private module FilterModules
            implement optional UACFilters_Filter
        endmodule
    
    // ---------------------

    // Interface for optional methods
    private interface UACInterface
        method unitEnter    takes unit whichUnit returns nothing defaults nothing
        method unitLeave    takes unit whichUnit returns nothing defaults nothing
        method unitPeriodic takes unit whichUnit returns nothing defaults nothing
        
        method mainDeath    takes nothing        returns nothing defaults nothing
        method mainRevive   takes nothing        returns nothing defaults nothing
        method timerLoop    takes nothing        returns nothing defaults nothing
        
        // It&#039;s a shame that &#039;.exists&#039; can&#039;t be used with stub methods.
        method orFilterA    takes unit whichUnit returns boolean defaults false
        method orFilterB    takes unit whichUnit returns boolean defaults false
        method orFilterC    takes unit whichUnit returns boolean defaults false
    endinterface
    
    // Filter methods.
    //! textmacro UAC__Filter takes X
        stub method andFilter$X$ takes unit whichUnit returns boolean
            return true
        endmethod
    //! endtextmacro    
    
    struct UAC extends UACInterface
        // Main unit:
        readonly unit main
        
        // mainUnit can be used instead of main. =)
        method operator mainUnit takes nothing returns unit
            return .main
        endmethod
        
        // &#039;u&#039; prefix because the names would be taken for safer method operators.
        private real urange     // aura range
        private boolean upause  // is the unit paused?
        private group affected  // holds the affected units
        
        boolean single // should it be destroyed when the mainunit dies?
        readonly integer count = 0 // the amount of units affected by an aura.
        
        // Tickers
        private real uticker = TIMEOUT
        private real ticks = 0.
        
        // struct stack
        private static timer T = CreateTimer() 
        private static integer N = 0
        private static thistype array D
        private integer index
        
        // temporary group filled with all units in range
        private static group fill = CreateGroup()
        
        // code variables used so I can order the methods in the struct as I please.
        // (As long as these are at the top, and onInit is at the bottom)
        private static code funcexpire
        private static code callbacka
        private static code callbackb
        private static code unaffect
        private static boolexpr mainfilt
        
        // Temporary globals
        private static unit tempunit
        private static boolean tempbool
        private static thistype temp
        
        private static hashtable allUACs = InitHashtable() // .typeid, handleId
        
        // Optional Modules:
        implement MainModules
        // -----------------
        
        static method create takes unit mainUnit, real range returns thistype
            local thistype this
            
            // What&#039;s the point in creating the struct if the unit could be null?
            if mainUnit == null then
                debug if UAC__DEBUG then
                debug   call BJDebugMsg(&quot;|cFFFF0000UAC Error:|r Attempt to create aura on null unit.&quot;)
                debug endif
                return thistype(0)
            endif   
            
            set this = .allocate()
            
            // Setting basic members
            set .main = mainUnit
            set .urange = range
            
            // If the range is &lt;= 0, then we pause the struct. It&#039;d be pointless to be constantly calling functions
            // if no units are going to be affected anyway.
            set .upause = range &lt;= 0
            
            debug if UAC__DEBUG and range &lt;= 0 then
            debug   call BJDebugMsg(&quot;|cffffcc00UAC Warning:|r Instance created with 0 range. It has been automatically paused.&quot;)
            debug endif
            
            // By default, the struct will be automatically destroyed if mainunit isn&#039;t a hero.
            // Otherwise, it&#039;ll remain, but be paused.
            set .single = IsUnitType(mainUnit, UNIT_TYPE_HERO) == false
            
            if .affected == null then
                set .affected = CreateGroup()
            else
                call GroupClear(.affected)
            endif
            
            // Optional Modules:
            implement CreateModules
            // -----------------
            
            // &#039;Attaching&#039; the struct to the main unit for use with .get method.
            call SaveInteger(.allUACs, .typeid, GetHandleId(mainUnit), this)
            set .D[.N] = this
            set .index = .N
            set .N = .N + 1
            if .N == 1 then
                call TimerStart(.T, TIMEOUT, true, .funcexpire)
            endif
            
            return this
        endmethod
        
        // Returns the struct for the aura for a main unit.
        static method get takes unit mainUnit returns thistype
            debug if UAC__DEBUG and mainUnit == null then
            debug   call BJDebugMsg(&quot;|cFFFF0000UAC Error:|r Attempt to get a struct attached to a null unit.&quot;)
            debug endif
            return LoadInteger(.allUACs, .typeid, GetHandleId(mainUnit))
        endmethod
        
        // If the unit is affected by the aura, this&#039;ll return true. 
        method isAffected takes unit whichUnit returns boolean
            debug if UAC__DEBUG and whichUnit == null then
            debug   call BJDebugMsg(&quot;|cFFFF0000UAC Error:|r Attempt to check if null unit is affected&quot;)
            debug endif
            return IsUnitInGroup(whichUnit, .affected)
        endmethod
        
        // Pause/unpause the struct. If it&#039;s being paused, then un-affect all units.
        method operator pause= takes boolean shouldPause returns nothing
            if not .upause and shouldPause then
                set .temp = this
                call ForGroup(.affected, .unaffect)
            endif
            
            // Attempting to unpause a struct with 0 range?
            if .urange &lt;= 0 and shouldPause == false then
            
                debug if UAC__DEBUG then
                debug    call BJDebugMsg(&quot;|cffffcc00UAC Warning:|r Attempt to unpause struct with 0 range - unpause failed.&quot;)
                debug endif
                
                set .upause = true
                return
            else
                set .upause = shouldPause
            endif
        endmethod
        
        // Is the struct paused?
        method operator pause takes nothing returns boolean
            return .upause
        endmethod
        
        // Set how often the periodic functions should be called.
        method operator ticker= takes real timeout returns nothing
            // Below TIMEOUT?
            if timeout &lt; TIMEOUT then
                debug if UAC__DEBUG then
                debug    call BJDebugMsg(&quot;|cffffcc00UAC Warning:|r Attempt to set a ticker to below TIMEOUT seconds.&quot;)
                debug endif
                set .uticker = TIMEOUT
            else
                // Must be a multiple of TIMEOUT
                set .uticker = I2R(R2I(timeout / TIMEOUT)) * TIMEOUT
            endif
            set .ticks = 0.
        endmethod
        
        // How often does it expire?
        method operator ticker takes nothing returns real
            return .uticker
        endmethod
        
        // Sets the range of the aura
        method operator range= takes real range returns nothing
            if range &lt;= 0 then // Fool! Setting range to &lt;= 0
                
                debug if UAC__DEBUG then
                debug    call BJDebugMsg(&quot;|cffffcc00UAC Warning:|r Attempt to set a structs range to 0. Instance paused.&quot;)
                debug endif
                
                // We&#039;ll need to pause it.
                set .pause = true
            endif
            
            // If it was paused previously due to invalid range, and the range is valid,
            // now would be the time to unpause it.
            if .urange &lt;= 0 and .upause then
                set .pause = false
            endif
            
            set .urange = range
        endmethod
        
        // What&#039;s my range again?
        method operator range takes nothing returns real
            return .urange
        endmethod
        
        static method expire takes nothing returns nothing
            local integer i = 0
            local thistype this
            loop
                exitwhen i == .N
                    set this = .D<i>
                    
                    set .ticks = .ticks + TIMEOUT // Increasing the ticker
                    
                    // Is it time to expire?
                    if .ticks &gt;= .uticker then
                    
                        set .ticks = 0. // Resetting the ticks.
                    
                        if not .upause then // We don&#039;t want to fill paused instances.
                            set .temp = this
                            
                            // Fill is first filled with all units in range, matching the condition.
                            // Then the units that are affected, and the units in fill are compared;
                            // if there are units in fill that aren&#039;t affected, they become affected.
                            // If there are units that are affected, but aren&#039;t in fill, they stop being affected.
                            call GroupEnumUnitsInRange(.fill, GetUnitX(.main), GetUnitY(.main), .urange, .mainfilt)
                            call ForGroup(.fill, .callbacka)
                            call ForGroup(.affected, .callbackb)
                            
                        endif
                        
                        // timerLoop is just a time-saving method which is called every TIMEOUT, regardless of any conditions.
                        if .timerLoop.exists then
                            call .timerLoop()
                        endif
                        
                    endif
                    
                set i = i + 1
            endloop
        endmethod
        
        static method callbackA takes nothing returns nothing
            set .tempunit = GetEnumUnit()
            
            // Every unit here is a valid target for the aura. If the unit
            // is not affected, it means it recently came within range, or 
            // is now meeting the conditions. We need to affect the unit with
            // the aura.
            
            if not IsUnitInGroup(.tempunit, .temp.affected) then
                
                // Optional Modules:
                implement EnterModules
                // -----------------
                
                set .temp.count = .temp.count + 1
                
                if .temp.unitEnter.exists then
                    call .temp.unitEnter(.tempunit)
                endif
                
                call GroupAddUnit(.temp.affected, .tempunit)
                
            endif
        endmethod
        
        static method callbackB takes nothing returns nothing
            set .tempunit = GetEnumUnit()
            
            // Every unit here is affected by the aura, though some of which
            // may no longer be valid targets. We compare the units here to 
            // the ones that were valid targets. If it&#039;s not a valid target, 
            // then the unit becomes no longer affected.
            
            if not IsUnitInGroup(.tempunit, .fill) then
            
                // Optional Modules:
                implement LeaveModules
                // -----------------
                
                set .temp.count = .temp.count - 1
                
                if .temp.unitLeave.exists then
                    call .temp.unitLeave(.tempunit)
                endif
                
                call GroupRemoveUnit(.temp.affected, .tempunit)
                
            else
                
                // Optional Modules:
                implement PeriodicModules
                // -----------------
            
                // If the unit is a valid target, then we need to call the
                // periodic function (called for every valid target).
                // This wasn&#039;t called previously as some targets might&#039;ve been invalid.
                if .temp.unitPeriodic.exists then
                    call .temp.unitPeriodic(.tempunit)
                endif
                
            endif
        endmethod
        
        private static method clearAffected takes nothing returns nothing
            set .tempunit = GetEnumUnit()
            
            // Optional Modules:
            implement LeaveModules
            // -----------------
            
            set .temp.count = .temp.count - 1
            
            if .temp.unitLeave.exists then
                call .temp.unitLeave(.tempunit)
            endif
            
            call GroupRemoveUnit(.temp.affected, .tempunit)
        endmethod
        
        // Filters:
        //! runtextmacro UAC__Filter(&quot;A&quot;)
        //! runtextmacro UAC__Filter(&quot;B&quot;)
        //! runtextmacro UAC__Filter(&quot;C&quot;)
        
        private static method unitFilter takes nothing returns boolean
            // Checking if units in range can be affected by the aura
            set .tempunit = GetFilterUnit()
            if not .temp.orFilterA.exists and not .temp.orFilterB.exists and not .temp.orFilterC.exists then
                set .tempbool = (.temp.andFilterA(.tempunit) and .temp.andFilterB(.tempunit) and .temp.andFilterC(.tempunit))
            else
                set .tempbool = (.temp.andFilterA(.tempunit) and .temp.andFilterB(.tempunit) and .temp.andFilterC(.tempunit)) and (.temp.orFilterA(.tempunit) or .temp.orFilterB(.tempunit) or .temp.orFilterC(.tempunit))
            endif
            
            // Optional Module:
            implement FilterModules
            // ----------------
            
            return .tempbool
        endmethod
        
        // This method is called when a unit dies.
        private static method deathCond takes nothing returns boolean
            set .tempunit = GetTriggerUnit()
            set .temp = .get(.tempunit)
            
            // The dying unit didn&#039;t have an aura. =(
            if .temp == 0 then
                return false
            endif
            
            if .temp.mainDeath.exists then
                call .temp.mainDeath()
            endif
            
            // Both of these actions clear the affected units.
            if .temp.single then
                // The main unit died. Destroy the struct if it&#039;s meant to only last for one &#039;life&#039;
                call .destroy(.temp)
            else
                // Else, pause it.
                set .temp.pause = true
            endif
            
            return false
        endmethod
        
        // This method is called when a hero revives
        private static method awakenCond takes nothing returns boolean
            set .tempunit = GetRevivingUnit()
            set .temp = .get(.tempunit)
            
            // The reviving hero didn&#039;t have an aura. =(
            if .temp == 0 then
                return false
            endif
            
            if .temp.mainRevive.exists then
                call .temp.mainRevive()
            endif
            
            // Unpause it.. If possible.
            set .temp.pause = false
            
            return false
        endmethod
        
        method onDestroy takes nothing returns nothing
            // Clearing the struct &#039;attachment&#039;
            
            // call RemoveSavedInteger(.allUACs, .typeid, GetHandleId(.main))
            // Apparently, RemoveSavedInteger doesn&#039;t work.
            call SaveInteger(.allUACs, .typeid, GetHandleId(.main), 0)
            call ForGroup(.affected, .unaffect) // And unaffecting the units
            
            set .N = .N - 1
            set .D[.index] = .D[.N]
            set .D[.index].index = .index
            if .N == 0 then
                call PauseTimer(.T)
            endif
        endmethod
        
        private static method onInit takes nothing returns nothing
            // Trigger created so that the struct can be appropriately handled when the mainunit dies.
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
            call TriggerAddCondition(t, Filter(function thistype.deathCond))
            
            // Trigger created so that the struct can be resumed if the mainunit is revived.
            set t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_REVIVE_FINISH)
            call TriggerAddCondition(t, Filter(function thistype.awakenCond))
            
            // Using variables so that the code can be arranged in any order.
            set .funcexpire = function thistype.expire
            set .mainfilt = Filter(function thistype.unitFilter)
            set .callbacka = function thistype.callbackA
            set .callbackb = function thistype.callbackB
            set .unaffect = function thistype.clearAffected
        endmethod
        
    endstruct

endlibrary</i>


Note that this requires Jasshelper 0.9.G.0 or newer, and Patch 1.23b or newer!

The Extensions and an Example are in the [POST=912022]next post![/POST]
 

Attachments

  • UAC.w3x
    52.8 KB · Views: 627

Romek

Super Moderator
Reaction score
963
Effects Extension:
JASS:
.
   _   _  _   ___                                         
  | | | |/_\ / __|     U N I T   A U R A   C O N T R O L
  | |_| / _ \ (__             B y   R o m e k
   \___/_/ \_\___|              

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            -- == E F F E C T S   E X T E N S I O N == --
                           Version 1.1
_________________________________________________________________

    UAC Effects?
    ¯¯¯¯¯¯¯¯¯¯¯¯
        UAC Effects is an optional extension made for UAC. It adds some new members
        which allow the user to easily add effects for every unit affected.
        This is generally used to add a little indicator that the unit is affected, such as the
        general aura target (The little blue glow).
        
    How to Implement:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        - Copy the UAC Effects trigger into your map
        - Change the constants at the top if you want
        - All the members are automatically added to UAC if the extension is present.
        
    Members:
    ¯¯¯¯¯¯¯¯
        ______________________    
         boolean enableeffect     If enableeffect is true, then a special effect will be added to 
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    every affected unit. Otherwise, the effects will not be added.
                This can be changed for every instance of every type of aura.
                
                set data.enableeffect = true
                
        ______________________
         string effectpath        This is the path of the model that will be attached to the unit.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    &#039;effectpath&#039; is DEFAULT_PATH by default (see the configurable
                at the top of the scope). If this is set to &quot;&quot; or null, then the effect is disabled.
                
                set data.effectpath = &quot;SomeModel.mdl&quot;
                
        ______________________
         string effectpoint       This is the point on the affected unit to which the special effect
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    is attached. This is DEFAULT_POINT by default, and I recommend using 
                the default value whenever possible. If this is set to &quot;&quot; or null, then the effect is 
                disabled.
                
                set data.effecpoint = &quot;origin&quot;
            
        
        
    Changelog:
    ¯¯¯¯¯¯¯¯¯¯
        1.1
        - Fixed a minor bug which made units recieve effects when enableeffect was false.
    
        1.0
        - Initial Release

JASS:
scope UACEffects
globals
//           _______________________________________________________________
//          +---------------------------------------------------------------+
//          ||     _   _  _   ___                                          ||
//          ||    | | | |/_\ / __|     U N I T   A U R A   C O N T R O L   ||
//          ||    | |_| / _ \ (__             B y   R o m e k              ||
//          ||     \___/_/ \_\___|                                         ||
//   _______||_____________________________________________________________||_______
//  ||¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||
//  ||               -- ==  E F F E C T S   E X T E N S I O N  == --               ||
//  ||                                Version 1.1                                  ||
//  ||               ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯               ||
//  ||  This extension allows the user to easily add an effect to every unit that  ||
//  ||  is affected by the aura. For more information, see the READ ME.            ||
//  |+-----------------------------------------------------------------------------+|
//  ||  The default effect that will be attached to the affected units.            ||__________________________
private constant string DEFAULT_PATH = &quot;Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl&quot; // |
//  ||                                                                             ||¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//  ||  The default attachment point of the effect:                                ||
private constant string DEFAULT_POINT = &quot;origin&quot;                       //          ||
//  |+-----------------------------------------------------------------------------+|
//   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

endglobals
    
    module UACEffects
        string uaceffects_path = DEFAULT_PATH
        string uaceffects_point = DEFAULT_POINT
        boolean uaceffects_enable = false
        group uaceffects_affected
        static hashtable uaceffects_table = InitHashtable()
        static thistype uaceffects_temp
        
        private static method uaceffectsCallback takes nothing returns nothing
            local unit u = GetEnumUnit()
            call GroupRemoveUnit(.uaceffects_temp.uaceffects_affected, u)
            call DestroyEffect(LoadEffectHandle(.uaceffects_table, .uaceffects_temp, GetHandleId(u)))
        endmethod
        
        method operator enableeffect= takes boolean enable returns nothing
            if .uaceffects_enable and not enable then
                set .uaceffects_temp = this
                call ForGroup(.uaceffects_affected, function thistype.uaceffectsCallback)
            endif   
            set .uaceffects_enable = enable
        endmethod
        method operator enableeffect takes nothing returns boolean
            return .uaceffects_enable
        endmethod
        
        method operator effectpath= takes string newPath returns nothing
            if newPath == &quot;&quot; or newPath == null then
                set .enableeffect = false
                set .uaceffects_path = DEFAULT_PATH
                return
            endif
            set .uaceffects_path = newPath
            set .enableeffect = .uaceffects_point != &quot;&quot;
        endmethod
        method operator effectpath takes nothing returns string
            return .uaceffects_path
        endmethod
        
        method operator effectpoint= takes string newPoint returns nothing
            if newPoint == &quot;&quot; or newPoint == null then
                set .enableeffect = false
                set .uaceffects_point = DEFAULT_POINT
                return
            endif
            set .uaceffects_point = newPoint
            set .enableeffect = .uaceffects_path != &quot;&quot;
        endmethod
        method operator effectpoint takes nothing returns string
            return .uaceffects_point
        endmethod
    endmodule
    
    module UACEffects_Enter
        if .temp.uaceffects_enable and not IsUnitInGroup(.tempunit, .temp.uaceffects_affected) then
            call GroupAddUnit(.temp.uaceffects_affected, .tempunit)
            call SaveEffectHandle(.uaceffects_table, .temp, GetHandleId(.tempunit), AddSpecialEffectTarget(.temp.uaceffects_path, .tempunit, .temp.uaceffects_point))
        endif
    endmodule
    
    module UACEffects_Leave
        if .temp.uaceffects_enable and IsUnitInGroup(.tempunit, .temp.uaceffects_affected) then
            call GroupRemoveUnit(.temp.uaceffects_affected, .tempunit)
            call DestroyEffect(LoadEffectHandle(.uaceffects_table, .temp, GetHandleId(.tempunit)))
        endif   
    endmodule
    
    module UACEffects_Create
        if .uaceffects_affected == null then
            set .uaceffects_affected = CreateGroup()
        else
            call GroupClear(.uaceffects_affected)
        endif
    endmodule

endscope

Filters Extension:
JASS:
.
   _   _  _   ___                                         
  | | | |/_\ / __|     U N I T   A U R A   C O N T R O L
  | |_| / _ \ (__             B y   R o m e k
   \___/_/ \_\___|              

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
            -- == F I L T E R S   E X T E N S I O N == --
                           Version 1.2
_________________________________________________________________

    UAC Filters?
    ¯¯¯¯¯¯¯¯¯¯¯¯
        UAC Filters is an optional extension for UAC, which allows the user to easily
        change which units can be affected by the aura, in a user-friendly way without using
        any filter methods.
        
    How to Implement:
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        - Copy the UAC Filters trigger into your map
        - All the members are automatically added to UAC if the extension is present.
        
    Members:
    ¯¯¯¯¯¯¯¯
        ______________________    
         boolean allies           If this is true, allies of the main unit can be affected by the aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This is true by default.
                
                set data.allies = false
             
        ______________________    
         boolean enemies          If this is true, enemies of the main unit can be affected by the aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This is true by default.
                
                set data.enemies = false
             
        ______________________    
         boolean neutral          If this is true, units neutral to the mainunit can be affected by the aura
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This is false by default.
                
                set data.neutral = true
                
        ______________________    
         boolean visible          If this is true, only units that are visible to the mainunit will be affected
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    by the aura. Otherwise, invisible units can be affected too.
                This is false by default.
                
                set data.visible = true
                
        ______________________    
         boolean self             If this is false, the mainunit cannot be affected by the aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This is true by default. This has no effect if allies is false.
                
                set data.self = false
                
        ______________________    
         boolean dead             If this is false, dead units cannot be affected.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    This will probably always be false, unless UAC is being used to
                give some sort of bonuses depending on dead units within range.
                If this is true, ONLY dead units will be affected.
                This is false by default.
                
                set data.dead = true
                
        ______________________    
         unittype requirement     Units MUST be this unittype to be affected by the aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    Set this to null if you do not want any requirement.
                
                set data.requirement = UNIT_TYPE_GROUND
                
        ______________________    
         unittype exception       Units that are this unittype will not be affected by the aura.
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    Set this to null if you do not want any exception.
                
                set data.exception = UNIT_TYPE_STRUCTURE
        
        
    Changelog:
    ¯¯¯¯¯¯¯¯¯¯
        1.2
        - Fixed neutral again.
        
        1.1
        - Fixed a bug which stopped allied units being affected when .neutral was false. 
    
        1.0
        - Initial Release

JASS:
scope UACFilters
//           _______________________________________________________________
//          +---------------------------------------------------------------+
//          ||     _   _  _   ___                                          ||
//          ||    | | | |/_\ / __|     U N I T   A U R A   C O N T R O L   ||
//          ||    | |_| / _ \ (__             B y   R o m e k              ||
//          ||     \___/_/ \_\___|                                         ||
//   _______||_____________________________________________________________||_______
//  ||¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||
//  ||                 -- ==  F I L T E R S  E X T E N S I O N  == --              ||
//  ||                                Version 1.2                                  ||
//  ||               ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯               ||
//  ||  This extension allows the user to modify the targets allowed for auras in  ||
//  ||  a more user-friendly way than using or/andFilters. It introduces a set of  ||
//  ||  members which can be set to allow different targets.                       ||
//  |+-----------------------------------------------------------------------------+|
//   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

    module UACFilters
        boolean allies = true
        boolean enemies = true
        boolean neutral = false
        boolean visible = false
        boolean self = true
        boolean dead = false
        
        unittype requirement = null
        unittype exception = null
        
        static player uacfilters_player
    endmodule


    module UACFilters_Filter
        if .tempbool == false then
            return false
        endif
        
        set .uacfilters_player = GetOwningPlayer(.temp.main)
        
        set .tempbool = IsUnitAlly(.tempunit, .uacfilters_player) and GetPlayerAlliance(.uacfilters_player, GetOwningPlayer(.tempunit), ALLIANCE_HELP_REQUEST)
        
        if not .temp.allies and .tempbool then
            return false
        elseif not .temp.enemies and IsUnitEnemy(.tempunit, .uacfilters_player) then
            return false
        elseif not .temp.neutral and IsUnitAlly(.tempunit, .uacfilters_player) and not .tempbool then
            return false
        elseif .temp.visible and not IsUnitVisible(.tempunit, .uacfilters_player) then
            return false
        elseif not .temp.self and .tempunit == .temp.main then
            return false
        elseif .temp.dead != (GetWidgetLife(.tempunit) &lt;= 0.405 or IsUnitType(.tempunit, UNIT_TYPE_DEAD) == true) then
            return false
        elseif .temp.exception != null and IsUnitType(.tempunit, .temp.exception) == true then
            return false
        elseif .temp.requirement != null and IsUnitType(.tempunit, .temp.requirement) == false then
            return false
        else
            return true
        endif
        
    endmodule
    
endscope
 

Grundy

Ultra Cool Member
Reaction score
35
Cool. That does look pretty easy to use.

Can you set the TIMEOUT for each aura? Like what if i have a spell similar to your example that does something every 0.1 seconds but i have another aura that casts Raise Dead on a random corpse within x range every 5 seconds

-edit-

Well, I just looked over the code and i see TIMEOUT is a global constant so every aura uses the same TIMEOUT. What if you put a variable in your struct called timeout and it initializes to what the global is set to but the you can change it inside of each struct that extends UAC


---------------

I wrote some code to do projectiles for me... The way I'm doing it, it works but it kind of annoys me. I think I'm going to rewrite it to work more like how your auras work. Thanks for giving me this idea.
 

Flare

Stops copies me!
Reaction score
662
JASS:
            if .FAmount == 5 then
                debug call BJDebugMsg(&quot;UAC Error: Too many Filters added to instance&quot;)
                return
            elseif .FAmount == 0 then
                set .F1 = wf
            elseif .FAmount == 1 then
                set .F2 = wf
            elseif .FAmount == 2 then
                set .F3 = wf
            elseif .FAmount == 3 then
                set .F4 = wf
            elseif .FAmount == 4 then
                set .F5 = wf
            endif

(and everything else to do with the filters)

Why not use arrays? Would be far simpler, and would allow for a configurable number of filter functions (some people may not want/need 5, and others may want alot :p)

Also, in your example, why not just do:
JASS:
local Data d = Data[GetTriggerUnit ()]
if d == 0 then
//create new
else
//retrieve from unit
endif

:D
 

Romek

Super Moderator
Reaction score
963
Why not use arrays? Would be far simpler, and would allow for a configurable number of filter functions (some people may not want/need 5, and others may want alot :p)
That would decrease the instance limit on the structs.
And there would be a limit either way. (You need to specifiy the array size).
5 is too much anyway, as you can have mulitple 'conditions' in a single filter. (Is unit not a structure, flying and ally, for example)

Also, in your example, why not just do:
JASS:
local Data d = Data[GetTriggerUnit ()]
if d == 0 then
//create new
else
//retrieve from unit
endif

:D
It doesn't make much difference.
Although I do admit it's easier to read.

I'll probably fix it up later.
 

Flare

Stops copies me!
Reaction score
662
That would decrease the instance limit on the structs.
1638 (by default) auras using this system, in existence, without any unused? That's quite an unlikely situation (you'd need a huge amount of units, or a number of auras on each unit, both of which are quite unlikely)

Anyway, you can always reduce the value if needs be (since 5 filters probably won't be needed anyway, which makes the above situation even less likely)
 

Romek

Super Moderator
Reaction score
963
1638 (by default) auras using this system, in existence, without any unused? That's quite an unlikely situation (you'd need a huge amount of units, or a number of auras on each unit, both of which are quite unlikely)

Anyway, you can always reduce the value if needs be (since 5 filters probably won't be needed anyway, which makes the above situation even less likely)
I don't think there's a point in making it an array. It works fine the way it is.
And anyway, I feel the system is better with 8191 possible instances than 1638. Even if the latter is near-impossible to reach :p

Edit:

Grundy said:
-edit-

Well, I just looked over the code and i see TIMEOUT is a global constant so every aura uses the same TIMEOUT. What if you put a variable in your struct called timeout and it initializes to what the global is set to but the you can change it inside of each struct that extends UAC


---------------

I wrote some code to do projectiles for me... The way I'm doing it, it works but it kind of annoys me. I think I'm going to rewrite it to work more like how your auras work. Thanks for giving me this idea.
Ever heard of "xecollider"?
 

Furby

Current occupation: News poster
Reaction score
144
Well, this is really useful. :thup: It is making auras like Crtitical Strike Aura much easier to make. :)
+rep :thup:
 

Romek

Super Moderator
Reaction score
963
Well, this is really useful. :thup: It is making auras like Crtitical Strike Aura much easier to make. :)
+rep :thup:
Thanks.
And yes it is.
Just use the UnitEnterRange method, and give the units the critical strike ability.
And then the UnitLeaveRange method, to remove the ability. :D
 

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
Nevermind, I re-read. Looks like it triggers when a unit enters range of a unit and such...
 

Romek

Super Moderator
Reaction score
963
Nevermind, I re-read. Looks like it triggers when a unit enters range of a unit and such...
Yeah. That's exactly what it does.
Although it doesn't really 'trigger'.
The appropriate function is simply called.
 

Romek

Super Moderator
Reaction score
963
Updated!
  • v1.4
    • Recoded the entire system to improve on efficiency and fix some sloppy coding.
    • The main functions now take 2 arguments. (enumerated unit, and main unit)
    • Renamed UnitInRange to UnitPeriodic
    • Renamed UnitEntersRange to UnitEnter
    • Renamed UnitLeavesRange to UnitLeave
    • Filters have been completely revamped. They are now optional functions, and there are 'And' and 'Or' filters. At least one of the 'Or' ones has to be true, and all of the 'And's have to be true. They are all optional.
    • As a result of the filters being remade, the filter library is now removed. (Didn't last long!)

Have fun! :D

~23 Hour bump. I guess that's not too early.
 

Romek

Super Moderator
Reaction score
963
Is there a way to remove an aura from a unit? Any potential leaks when I do? Or when the unit dies?
JASS:
call data.Destroy()


Clears the instance. No leaks, no hassle. (There is an onDestroy method :))
It doesn't remove it automatically when the unit dies, although the effects stop.

You could easily make a trigger which destroys the struct when the 'caster' dies.
 

Romek

Super Moderator
Reaction score
963
> You could easily make a trigger which destroys the struct when the 'caster' dies.

Does the doc say so somewhere? :p
It does now. :thup:
Under 'usage'.

You've also given me a useful idea, which I will add in the next version (Automatically destroying the struct when the main unit dies. Will be disabled by default, but can be enabled with a single function call).
 

ronaldo

New Member
Reaction score
0
I will try to use it on my map, but im not good at jass yet, so i will probably just change effect of your demo spell.
Looks nice.
Thanks.
 
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