System BuffStruct

Jesus4Lyf

Good Idea™
BuffStruct​
Version 1.0.4​

Requirements:
- Jass NewGen
- AIDS
- Damage
- TimerUtils (optional)

JASS:
//
//      ___ _   _ ___ ___ ___ _____ ___ _   _  ___ _____ 
//     | _ ) | | | __| __/ __|_   _| _ \ | | |/ __|_   _|
//     | _ \ |_| | _|| _|\__ \ | | |   / |_| | (__  | |
//     |___/\___/|_| |_| |___/ |_| |_|_\\___/ \___| |_|
//                                         By Jesus4Lyf
//                                                                    v 1.0.4
//      What is BuffStruct?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          BuffStruct is a simple buff adding/removal/tracking system designed for
//          rapid map development. It automatically generates all object data and
//          backing code for adding and removing buffs to and from units.
//          
//      How to implement?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          1. Create a new trigger named BuffStructHeader. Go to 'Edit -> Convert
//          to Custom Text', and replace everything that's there with this script.
//
//          2. Create a new trigger immediately after BuffStructHeader, named
//          BuffStructFooter. go to 'Edit -> Convert to Custom Text', and replace
//          everything that's there with: //! endexternalblock
//
//          3. To make a BuffStruct, make a new trigger between BuffStructHeader
//          and BuffStructFooter, and use the template below.
//
//      BuffStruct Template:
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Example:
/*
//! runtextmacro BuffType("Return")
    //! runtextmacro SetBuffName("Return")
    //! runtextmacro SetBuffAlignment("NEUTRAL")
    //! runtextmacro SetBuffTooltip("This unit is being Returned; it will return to its previous location soon.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTNDaggerOfEscape.blp")
//! runtextmacro BuffStruct()
    real x
    real y
    method onCreate takes nothing returns nothing
        set this.x = GetUnitX(this.unit)
        set this.y = GetUnitY(this.unit)
    endmethod
    method preDestroy takes nothing returns nothing
        call SetUnitX(this.unit, this.x)
        call SetUnitY(this.unit, this.y)
    endmethod
//! runtextmacro EndBuff()
*/
//          Documentation:
//
//              //! runtextmacro BuffType("Identifier")
//                  This must contain a 1 word identifier for the buff. This is
//                  used to create new instances with Identifier.create(unit)
//
//              //! runtextmacro SetBuffName("Name")
//                  This is the name that will display in the buff tray.
//
//              //! runtextmacro SetBuffAlignment("NEUTRAL")
//                  This is whether the buff is POSITIVE, NEGATIVE or NEUTRAL.
//
//              //! runtextmacro SetBuffTooltip("Tooltip Missing!")
//                  This is the tooltip that will display in the buff tray.
//
//              //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTN???.blp")
//                  This is the icon used for the buff in the buff tray.
//
//              //! runtextmacro BuffStruct()
//                  This denotes the end of textmacro configuration for a buff,
//                  and the start of the struct that will be instanciated for
//                  each instance of a buff.
//                  You may use the optional event response methods here, which
//                  are listed below.
//
//              //! runtextmacro EndBuff()
//                  This denotes the end of the BuffStruct.
//
//      Event Response Methods:
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          In each BuffStruct, you may optionally implement the following methods:
//
/*              method onApply takes nothing returns nothing
*/              // Fires just after the buff is applied to a unit.
//
/*              method onRemove takes nothing returns nothing
*/              // Fires just before the buff is removed from a unit.
//
/*              method onCreate takes nothing returns nothing
*/              // Fires immediately after the buff is created and applied to
//              // the first unit. onApply will fire immediately after this.
//
/*              method preDestroy takes nothing returns nothing
*/              // Fires just before the buff instance is destroyed. onRemove
//              // will fire just before this.
//
/*              method onDamageReceived takes nothing returns nothing
*/              // Fires when the buffed unit takes damage. Use GetEventDamageSource()
//              // to refer to the damaging unit.
//              // All functions from "Damage" are available here.
//
/*              method onDamageDealt takes nothing returns nothing
*/              // Fires when the buffed unit deals damage. Use GetTriggerUnit()
//              // to refer to the unit taking the damage.
//              // All functions from "Damage" are available here.
//
//      Other:
//     ¯¯¯¯¯¯¯¯
//          All BuffStructs' instances have the ".unit" field, which is the unit
//          the buff is currently on.
//
//          All BuffStructs have the .setUnit(unit) method, which will remove
//          the buff instance from the current unit, and apply it to the given unit.
//          Use .setUnit(null) to unapply a buff without destroying it.
//
//          Use .isOn(unit) --> boolean to see if a buff is on a unit.
//
//          To do something for each buff on a unit, use:
/*          call BuffList[unit].forEachBuff(BUFF_ALIGNMENT_??, myMethod)
*/          // ?? should be substituted for POSITIVE, NEGATIVE or NEUTRAL.
//          // The function used for myMethod must take only a BuffStruct argument.
//
//          You may destroy a buff in x seconds using:
/*          call myBuffInstance.destroyTimed(real)
*/          // "real" is the time to destruction.
//
//      Thanks:
//     ¯¯¯¯¯¯¯¯¯
//          - 13lade619: for isolating a lag issue in the BETA version to do with
//            creating a buff instance for a null unit.
//
library BuffStruct requires AIDS, Damage, optional TimerUtils
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro BuffStruct__StartConfig()

//===========================================================================
// CONFIG AREA
//
    
    //===========================================================================
    // System Object Editor IDs.
    //
    
    //! runtextmacro BuffStruct__BeginSysIds()
        // Uses:
        //  - 'Bxx&' for buff type.
        //  - 'Axx&' for base ability.
        
        //! runtextmacro BuffStruct__AllowSysId("@a")
        //! runtextmacro BuffStruct__AllowSysId("@b")
        //! runtextmacro BuffStruct__AllowSysId("@c")
        //! runtextmacro BuffStruct__AllowSysId("@d")
        //! runtextmacro BuffStruct__AllowSysId("@e")
        //! runtextmacro BuffStruct__AllowSysId("@f")
        //! runtextmacro BuffStruct__AllowSysId("@g")
        //! runtextmacro BuffStruct__AllowSysId("@h")
        //! runtextmacro BuffStruct__AllowSysId("@i")
        //! runtextmacro BuffStruct__AllowSysId("@j")
        //! runtextmacro BuffStruct__AllowSysId("@k")
        //! runtextmacro BuffStruct__AllowSysId("@l")
        //! runtextmacro BuffStruct__AllowSysId("@m")
        //! runtextmacro BuffStruct__AllowSysId("@n")
        //! runtextmacro BuffStruct__AllowSysId("@o")
        //! runtextmacro BuffStruct__AllowSysId("@p")
        //! runtextmacro BuffStruct__AllowSysId("@q")
        //! runtextmacro BuffStruct__AllowSysId("@r")
        //! runtextmacro BuffStruct__AllowSysId("@s")
        //! runtextmacro BuffStruct__AllowSysId("@t")
        //! runtextmacro BuffStruct__AllowSysId("@u")
        //! runtextmacro BuffStruct__AllowSysId("@v")
        //! runtextmacro BuffStruct__AllowSysId("@w")
        //! runtextmacro BuffStruct__AllowSysId("@x")
        //! runtextmacro BuffStruct__AllowSysId("@y")
        //! runtextmacro BuffStruct__AllowSysId("@z")
        //! runtextmacro BuffStruct__AllowSysId("@A")
        //! runtextmacro BuffStruct__AllowSysId("@B")
        //! runtextmacro BuffStruct__AllowSysId("@C")
        //! runtextmacro BuffStruct__AllowSysId("@D")
        //! runtextmacro BuffStruct__AllowSysId("@E")
        //! runtextmacro BuffStruct__AllowSysId("@F")
        //! runtextmacro BuffStruct__AllowSysId("@G")
        //! runtextmacro BuffStruct__AllowSysId("@H")
        //! runtextmacro BuffStruct__AllowSysId("@I")
        //! runtextmacro BuffStruct__AllowSysId("@J")
        //! runtextmacro BuffStruct__AllowSysId("@K")
        //! runtextmacro BuffStruct__AllowSysId("@L")
        //! runtextmacro BuffStruct__AllowSysId("@M")
        //! runtextmacro BuffStruct__AllowSysId("@N")
        //! runtextmacro BuffStruct__AllowSysId("@O")
        //! runtextmacro BuffStruct__AllowSysId("@P")
        //! runtextmacro BuffStruct__AllowSysId("@Q")
        //! runtextmacro BuffStruct__AllowSysId("@R")
        //! runtextmacro BuffStruct__AllowSysId("@S")
        //! runtextmacro BuffStruct__AllowSysId("@T")
        //! runtextmacro BuffStruct__AllowSysId("@U")
        //! runtextmacro BuffStruct__AllowSysId("@V")
        //! runtextmacro BuffStruct__AllowSysId("@W")
        //! runtextmacro BuffStruct__AllowSysId("@X")
        //! runtextmacro BuffStruct__AllowSysId("@Y")
        //! runtextmacro BuffStruct__AllowSysId("@Z")
        
    //! runtextmacro BuffStruct__EndSysIds()
    
//===========================================================================
// END CONFIG AREA
//
    //! runtextmacro BuffStruct__EndConfig()
    
    
    //===========================================================================
    // SYSTEM AREA
    //
    
    globals
        constant integer BUFF_ALIGNMENT_POSITIVE=1
        constant integer BUFF_ALIGNMENT_NEGATIVE=2
        constant integer BUFF_ALIGNMENT_NEUTRAL=3
    endglobals
    
    private function interface Method takes integer this returns nothing
    
    //! textmacro BuffStruct__StartConfig
    //! endtextmacro
    //! textmacro BuffStruct__EndConfig
    //! endtextmacro
    
    
    //===========================================================================
    // Id Declaration
    //
    //  Exposes a module which implements the system ids, as per the system
    // configuration, automatically filling structs starting from struct ID #1.
    // 
    
    //! textmacro BuffStruct__BeginSysIds
        private keyword abilType
        private keyword buffType
        private keyword idMax
        
        private module SysIds
            /*libprivate*/ integer abilType
            /*libprivate*/ integer buffType
            /*libprivate*/ static integer idMax=0
            private static method onInit takes nothing returns nothing
                //! i sysIds={}
                //! i maxSysIds=0
    //! endtextmacro
    //! textmacro BuffStruct__EndSysIds
            endmethod
        endmodule
        //! i sysIdsUsed=0
    //! endtextmacro
    
    //! textmacro BuffStruct__AllowSysId takes SYSID
        set thistype.idMax=thistype.idMax+1
        //! i maxSysIds=maxSysIds+1
        
        set thistype(thistype.idMax).abilType='A$SYSID$&'
        set thistype(thistype.idMax).buffType='B$SYSID$&'
        //! i sysIds[maxSysIds]={abilType="A$SYSID$&", buffType="B$SYSID$&"}
    //! endtextmacro
    
    //===========================================================================
    // BuffType Struct
    //
    
    private struct BuffType
        implement SysIds // supplies abilType, buffType, preloaded.
    endstruct
    
    //===========================================================================
    // BuffStruct
    //
    private keyword buffUnit
    private keyword next
    private keyword prev
    private keyword temp
    
    private interface DEFAULTS
        static BuffStruct temp
        
        unit buffUnit
        BuffStruct next
        BuffStruct prev
        
        // User implementable
        method onCreate takes nothing returns nothing defaults nothing
        method onApply takes nothing returns nothing defaults nothing
        method onRemove takes nothing returns nothing defaults nothing
        method preDestroy takes nothing returns nothing defaults nothing
        method onDamageReceived takes nothing returns nothing defaults nothing
        method onDamageDealt takes nothing returns nothing defaults nothing
        
        // Module
        method setUnit takes unit whichUnit returns nothing defaults nothing
    endinterface
    
    struct BuffStruct extends DEFAULTS
        private static method timedDestroyCallback takes nothing returns nothing
            static if LIBRARY_TimerUtils then
                local timer t=GetExpiredTimer()
                call thistype(GetTimerData(t)).destroy()
                call ReleaseTimer(t)
            endif
        endmethod
        method destroyTimed takes real time returns nothing
            static if LIBRARY_TimerUtils then
                local timer t=NewTimer()
                call SetTimerData(t,this)
                call TimerStart(t,time,false,function thistype.timedDestroyCallback)
            else
                call BJDebugMsg("BuffStruct Error: Must import TimerUtils in order to use .timedDestroy method.")
            endif
        endmethod
    endstruct
    
    module BuffStruct
        static integer ALIGNMENT=BUFF_ALIGNMENT_NEUTRAL
        //! textmacro BuffStruct__AttachToWhichUnit
            set BuffStruct.temp=BuffList[whichUnit][thistype.ALIGNMENT]
            set BuffStruct.temp.prev.next=this
            set this.prev=BuffStruct.temp.prev
            set BuffStruct.temp.prev=this
            set this.next=BuffStruct.temp
        //! endtextmacro
        
        private static BuffType typeStruct=0
        static method isOn takes unit whichUnit returns boolean
            return GetUnitAbilityLevel(whichUnit,thistype.typeStruct.abilType)>0
        endmethod
        private static method onInit takes nothing returns nothing
            set thistype.typeStruct=BuffType.create()
        endmethod
        
        method operator unit takes nothing returns unit
            return this.buffUnit
        endmethod
        
        method setUnit takes unit whichUnit returns nothing
            if this.buffUnit!=null then
                call this.onRemove()
                set this.next.prev=this.prev
                set this.prev.next=this.next
                call UnitMakeAbilityPermanent(this.buffUnit,false,thistype.typeStruct.abilType)
                call UnitRemoveAbility(this.buffUnit,thistype.typeStruct.abilType)
                call UnitRemoveAbility(this.buffUnit,thistype.typeStruct.buffType)
            endif
            set this.buffUnit=whichUnit
            if whichUnit!=null then
                call UnitAddAbility(whichUnit,thistype.typeStruct.abilType)
                call UnitMakeAbilityPermanent(whichUnit,true,thistype.typeStruct.abilType)
                //! runtextmacro BuffStruct__AttachToWhichUnit()
                call this.onApply()
            endif
        endmethod
        
        private method onDestroy takes nothing returns nothing
            if this.buffUnit!=null then
                call this.onRemove()
                call this.preDestroy()
                set this.next.prev=this.prev
                set this.prev.next=this.next
                call UnitMakeAbilityPermanent(this.buffUnit,false,thistype.typeStruct.abilType)
                call UnitRemoveAbility(this.buffUnit,thistype.typeStruct.abilType)
                call UnitRemoveAbility(this.buffUnit,thistype.typeStruct.buffType)
            else
                call this.preDestroy()
            endif
        endmethod
        
        static method create takes unit whichUnit returns thistype
            local thistype this=thistype.allocate()
            set this.buffUnit=whichUnit
            if whichUnit==null then
                call this.onCreate()
            else
                call UnitAddAbility(whichUnit,thistype.typeStruct.abilType)
                call UnitMakeAbilityPermanent(whichUnit,true,thistype.typeStruct.abilType)
                //! runtextmacro BuffStruct__AttachToWhichUnit()
                call this.onCreate()
                call this.onApply()
            endif
            return this
        endmethod
    endmodule
    
    //! textmacro BuffType takes IDENTIFIER
        struct $IDENTIFIER$ extends BuffStruct
            implement BuffStruct
            //! i itemIdentifier="$IDENTIFIER$"
            private static method onInit takes nothing returns nothing
                //! i sysIdsUsed=sysIdsUsed+1
                // Defaults.
                //! i buffName="$IDENTIFIER$"
                //! i buffIcon=""
                //! i buffDescription=""
                //! i buffAlignment="NEUTRAL"
    //! endtextmacro
    
    //! textmacro SetBuffName takes VAL
        //! i buffName="$VAL$"
    //! endtextmacro
    //! textmacro SetBuffIcon takes VAL
        //! i buffIcon="$VAL$"
    //! endtextmacro
    //! textmacro SetBuffTooltip takes VAL
        //! i buffDescription="$VAL$"
    //! endtextmacro
    //! textmacro SetBuffAlignment takes VAL
        set thistype.ALIGNMENT=BUFF_ALIGNMENT_$VAL$
        //! i buffAlignment="$VAL$"
    //! endtextmacro
    
    //! textmacro BuffStruct
            endmethod
    //! endtextmacro
    //! textmacro EndBuff
        endstruct
        // Make object data.
        // Actual buff
        //! i setobjecttype("buffs")
        //! i createobject("Basl",sysIds[sysIdsUsed].buffType)
        //! i makechange(current,"ftat","")
        //! i makechange(current,"fnsf","(BuffStruct)")
        //! i makechange(current,"fart",buffIcon)
        //! i makechange(current,"fube",buffDescription)
        //! i if buffAlignment=="POSITIVE" then
            //! i makechange(current,"ftip","|cff00FF00"..buffName.."|r")
        //! i elseif buffAlignment=="NEUTRAL" then
            //! i makechange(current,"ftip","|cff00FFFF"..buffName.."|r")
        //! i else
            //! i makechange(current,"ftip",buffName)
        //! i end
        
        // Slow aura
        //! i setobjecttype("abilities")
        //! i createobject("Aasl",sysIds[sysIdsUsed].abilType)
        //! i makechange(current,"ansf","(BuffStruct)")
        //! i makechange(current,"Slo1",1,0)
        //! i makechange(current,"aare",1,0)
        //! i makechange(current,"abuf",1,sysIds[sysIdsUsed].buffType)
        //! i makechange(current,"arac","other")
        //! i makechange(current,"atar",1,"self")
        //! i makechange(current,"anam",buffName)
    //! endtextmacro
    
    //===========================================================================
    // On Damage
    //
    
    private module DamageEvent
        private static method onDamage takes nothing returns boolean
            // Attacked
            local thistype u=thistype[GetTriggerUnit()]
            local BuffStruct base=u[BUFF_ALIGNMENT_POSITIVE]
            local BuffStruct this=base.next
            loop
                exitwhen this==base
                call this.onDamageReceived()
                set this=this.next
            endloop
            set base=u[BUFF_ALIGNMENT_NEUTRAL]
            set this=base.next
            loop
                exitwhen this==base
                call this.onDamageReceived()
                set this=this.next
            endloop
            set base=u[BUFF_ALIGNMENT_NEGATIVE]
            set this=base.next
            loop
                exitwhen this==base
                call this.onDamageReceived()
                set this=this.next
            endloop
            // Attacker
            if GetEventDamageSource()!=null then
                set u=thistype[GetEventDamageSource()]
                set base=u[BUFF_ALIGNMENT_POSITIVE]
                set this=base.next
                loop
                    exitwhen this==base
                    call this.onDamageDealt()
                    set this=this.next
                endloop
                set base=u[BUFF_ALIGNMENT_NEUTRAL]
                set this=base.next
                loop
                    exitwhen this==base
                    call this.onDamageDealt()
                    set this=this.next
                endloop
                set base=u[BUFF_ALIGNMENT_NEGATIVE]
                set this=base.next
                loop
                    exitwhen this==base
                    call this.onDamageDealt()
                    set this=this.next
                endloop
            endif
            return false
        endmethod
        private static method onInit takes nothing returns nothing
            local trigger t=CreateTrigger()
            call Damage_RegisterEvent(t)
            call TriggerAddCondition(t,Filter(function thistype.onDamage))
            set t=null
        endmethod
    endmodule
    
    //===========================================================================
    // Buff Listing
    //
    
    private struct LinkNode extends BuffStruct
    endstruct
    
    struct BuffList extends array
        private static LinkNode array linkNode
        method operator [] takes integer alignment returns LinkNode
            return thistype.linkNode[this*3+alignment]
        endmethod
        private method operator []= takes integer alignment, LinkNode node returns nothing
            set thistype.linkNode[this*3+alignment]=node
        endmethod
        
        private method AIDS_onCreate takes nothing returns nothing
            set BuffStruct.temp=LinkNode.create()
            set BuffStruct.temp.next=BuffStruct.temp
            set BuffStruct.temp.prev=BuffStruct.temp
            set this[BUFF_ALIGNMENT_POSITIVE]=BuffStruct.temp
            set BuffStruct.temp=LinkNode.create()
            set BuffStruct.temp.next=BuffStruct.temp
            set BuffStruct.temp.prev=BuffStruct.temp
            set this[BUFF_ALIGNMENT_NEGATIVE]=BuffStruct.temp
            set BuffStruct.temp=LinkNode.create()
            set BuffStruct.temp.next=BuffStruct.temp
            set BuffStruct.temp.prev=BuffStruct.temp
            set this[BUFF_ALIGNMENT_NEUTRAL]=BuffStruct.temp
        endmethod
        private method AIDS_onDestroy takes nothing returns nothing
            call this[BUFF_ALIGNMENT_POSITIVE].destroy()
            call this[BUFF_ALIGNMENT_NEGATIVE].destroy()
            call this[BUFF_ALIGNMENT_NEUTRAL].destroy()
        endmethod
        //! runtextmacro AIDS()
        
        implement DamageEvent
        
        method forEachBuff takes integer alignment, Method func returns nothing
            local LinkNode base=this[alignment]
            set this=thistype(base.next)
            loop
                exitwhen this==base
                call func.evaluate(this)
                set this=thistype(LinkNode(this).next)
            endloop
        endmethod
    endstruct
endlibrary
This system allows rapid buff development, and will be extended with additional features in the future. In combination with Status, this system holds some pretty awesome power (such as moving all positive/negative/neutral buffs from one unit to another).

In using this system, the user requires to make no object editor data for buff placement whatsoever.

Here's an example:
JASS:
//! runtextmacro BuffType("Return")
    //! runtextmacro SetBuffName("Return")
    //! runtextmacro SetBuffAlignment("NEUTRAL")
    //! runtextmacro SetBuffTooltip("This unit is being Returned; it will return to its previous location soon.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTNDaggerOfEscape.blp")
//! runtextmacro BuffStruct()
    real x
    real y
    method onCreate takes nothing returns nothing
        set this.x=GetUnitX(this.unit)
        set this.y=GetUnitY(this.unit)
    endmethod
    method preDestroy takes nothing returns nothing
        call SetUnitX(this.unit,this.x)
        call SetUnitY(this.unit,this.y)
    endmethod
//! runtextmacro EndBuff()
This example gives a simple Return style buff. It is created with Return.create(unit). At any point you can use instance.setUnit(otherUnit) to make a different unit return to the location instead. When the buff is destroyed using .destroy, the current unit the buff is on will be returned to the location the original unit was at when it was buffed.

Updates:
- Version 1.0.4 (BETA): Fixed a bug to do with lag issues when a buff is created for a null unit (thanks 13lade619).
- Version 1.0.3 (BETA): Fixed a bug where an AIDS struct was retrieved for null units when damage came from a null source.
- Version 1.0.2 (BETA): Added static .isOn(unit) method.
- Version 1.0.1 (BETA): Added .destroyTimed(time) method.
- Version 1.0.0 (BETA): Release.
 

Attachments

Executor

I see you
Hehe, more and more functions I ever missed in wc3 come to life :p

Didn't read the whole code, but the interface seems very good to me :)
 

Narks

Vastly intelligent whale-like being from the stars
This is awesome. Now I can phase out those wc3c systems and replace them with SpellStruct and BuffStruct.
 

Kenny

Back for now.
Interesting..

To tired to read through it all now, but one thing caught my attention.

Can the [ljass]preDestroy method[/ljass] be renamed to [ljass]onDestroy[/ljass]?

I know it is technically more correct the other way, but I find it more intuitive. Plus if it is named preDestroy, then shouldn't onApply be named postApply? :p

Edit:

Textmacro interfaces are fugly, but you did a really good job at making them usable and readable. Major props for that.

It would look cool if there was some type of macro keyword that replaced [ljass]//! runtextmacro[/ljass], so that it looked a bit more structured, but that isn't your area.
 

Jesus4Lyf

Good Idea™
Another demonstration, for cool factor:
JASS:
//! runtextmacro BuffType("Knockback")
    //! runtextmacro SetBuffName("Knocked")
    //! runtextmacro SetBuffAlignment("NEGATIVE")
    //! runtextmacro SetBuffTooltip("This unit is being Knocked Back; it is stunned and sliding backwards.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTNBash.blp")
//! runtextmacro BuffStruct()
    real speed=400*T32_PERIOD // can be changed dynamically for an instance.
    private effect e
    private method periodic takes nothing returns nothing
        local real r=GetUnitFacing(this.unit)*bj_DEGTORAD
        call SetUnitX(this.unit,GetUnitX(this.unit)-Cos(r)*this.speed)
        call SetUnitY(this.unit,GetUnitY(this.unit)-Sin(r)*this.speed)
    endmethod
    implement T32x
    method onApply takes nothing returns nothing
        call Status[this.unit].addStun()
        call this.startPeriodic()
        set this.e=AddSpecialEffectTarget("Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl",this.unit,"overhead")
    endmethod
    method onRemove takes nothing returns nothing
        call Status[this.unit].removeStun()
        call this.stopPeriodic()
        call DestroyEffect(this.e)
    endmethod
//! runtextmacro EndBuff()

Epic knockback. At any point, calling instance.setUnit(unit) will change the unit being knocked back (and .setUnit(null) will dispel it, naturally). :D
Can the [ljass]preDestroy method[/ljass] be renamed to [ljass]onDestroy[/ljass]?
I wish. JassHelper wouldn't let me, but I shall keep seeing if there's a way... :(
Textmacro interfaces are fugly, but you did a really good job at making them usable and readable. Major props for that.
Thanks. I try. :)

Edit: Hm! I could make a buff where if it is dispelled, it will find another unit near by and settle on it... XD

Edit2: This requires the above buff.
JASS:
//! runtextmacro BuffType("LightHeaded")
    //! runtextmacro SetBuffName("Light Headed")
    //! runtextmacro SetBuffAlignment("NEGATIVE")
    //! runtextmacro SetBuffTooltip("This unit is feeling Light Headed; if it is attacked, it will be knocked back.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTNDizzy.blp")
//! runtextmacro BuffStruct()
    method onDamageReceived takes nothing returns nothing
        if Damage_IsAttack() then
            call Knockback.create(this.unit).destroyTimed(0.3)
        endif
    endmethod
//! runtextmacro EndBuff()

Readable? Cool? Released Version 1.0.1. :p
 

Viikuna

No Marlo no game.
Nice, a buff system.

Time to request some features.



-Possibility to make BuffClasses, such as Positive Buffs, Negative Buffs, Fire Buffs, Frost Buffs, Imba Buffs, etc.

This is cool when you want for example to extend duration of all Fire Buffs or all Positive Buffs. ( With some ForEachBuff -function, or BuffList[ unit ].forEachBuff -method ) Buff that belongs both Fire and Positive class, naturally gets both of these.


- Possibility to check if applied buff instance is the first or the last of the list.

This way you can make some stacking buff that reduces armor by X each time its applied to unit, but the special effect is only created/destroyed when first buff in the list is created/destroyed.

Also allows you to make semi and non stackable buffs. When list gets its second buff, you can destroy that first one, and maybe extend the duration of that new buff to make only duration stack.

- Global events for those OnBuffCreate and OnBuffDestroy and others, so you can for example make some stuff for all buffs in Fire or Positive -class.

For example, if unit gets buff that belongs to Hold class, and is currently being knockbacked, the knockback is stopped, and all buffs of Knockback -class get removed. Unit with active Hold class buffs can not receive Knockback class buffs. This way you can make some ensnare buff to prevent knockbacks.


End of my list for now. It contains lot of Bluff Class stuff, which is because the interaction between triggered buffs is what makes them so cool, and thats why things like Buff Classes are cool too.

I try to think some other kind of stuff too later. Anyways, stuff looks good, good luck with it.

edit.

And yea, make some example trigger, which removes all buffs from unit when it dies. Make sure that this triggers after other death events, so people can still use buff stuff in their death event triggers.
 

Grundy

Ultra Cool Member
If you want to loop through all buffs would you have to call BuffList[unit].forEachBuff(BUFF_ALIGNMENT_POSITIVE, myMethod), BuffList[unit].forEachBuff(BUFF_ALIGNMENT_NEGATIVE, myMethod), and BuffList[unit].forEachBuff(BUFF_ALIGNMENT_NEUTRAL, myMethod) or is there a way to loop through all buffs at once?

Sorry if I'm just missing it (I looked for it and I'm not seeing it) but is there a way to see how many buffs a unit has? Or would I have to loop through all the buffs and increment a counter?
 

Jesus4Lyf

Good Idea™
If you want to loop through all buffs would you have to call BuffList[unit].forEachBuff(BUFF_ALIGNMENT_POSITIVE, myMethod), BuffList[unit].forEachBuff(BUFF_ALIGNMENT_NEGATIVE, myMethod), and BuffList[unit].forEachBuff(BUFF_ALIGNMENT_NEUTRAL, myMethod) or is there a way to loop through all buffs at once?

Sorry if I'm just missing it (I looked for it and I'm not seeing it) but is there a way to see how many buffs a unit has? Or would I have to loop through all the buffs and increment a counter?
At the moment, both of what you suggested is correct, but I'm planning to add features to this system. In what sort of situation did you want to loop through all buffs?
 

Renendaru

(Evol)ution is nothing without love.
Get all negative buffs, all positive buffs, buffs with a certain type, etc. My uses. I had a thought of using this and implementing a map with this alone for buffs, then use State to control how long someone is stunned, shorten the stun based on a value, purge a stun, etc. Would make it really fun, don't you think?
 

Grundy

Ultra Cool Member
Well there are some spells, like mirror image for example, that will remove all buffs from your hero, positive or negative. Same thing with cyclone. I might want to make a spell that removes all buffs; positive, neutral, and negative. Maybe there is (or will be) an easy way to remove all the buffs on a unit, if not then I guess I'd have to loop through all the buffs to remove them.

Another one might a hero that has mad respect for all spell effects, and even more for stronger spell effects. So he regenerates X mana per second for each buff applied to him whether they are good or bad, with higher level buffs restoring a little more. Or he gets X bonus movement speed for each buff, or he regenerates a certain amount of hit points for each buff, or his attack damage is increased for each buff, lots of possibilities. Maybe he has 1 ability that randomly changes what bonus he gets from having a lot of buffs and his ultimate would make him get all of the different bonuses at the same time. In that case just getting the number of buffs wouldn't be enough you would actually have to loop through all the buffs to see what level they each are.

-edit-
Does BuffStruct even support levels for buffs? It doesn't look like it to me...am I missing something?
 

Lehona

New Member
Does GetEventDamage() work in onDamageDealt (And am I abled to block damage after receiving the amount?)?
 

Jesus4Lyf

Good Idea™
Does GetEventDamage() work in onDamageDealt (And am I abled to block damage after receiving the amount?)?
Yep.
Does BuffStruct even support levels for buffs? It doesn't look like it to me...am I missing something?
Depends what you mean by levels. Can you give an example?
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    they got a server engineer job opening :)
  • Ghan Ghan:
    I really do not want to move to California otherwise I might consider it.
  • The Helper The Helper:
    yeah California is not anywhere you really want to live
  • The Helper The Helper:
    That is why I did not take the job Blizzard offered me back in the day, there is no way I could have moved my family there on what they were offering, not even close and that was like 20 years ago
  • The Helper The Helper:
    yeah they wanted me on the tech support team when they did not get me they got one of the next MVPs in Dinobot
  • The Helper The Helper:
    Dinobot was one of the youngest of the MVPs tkron probably could have worked for Blizzard but he had a good job in Chicago doing business programming already
  • The Helper The Helper:
    Dinobot probably still works for Blizzard would love to reconnect with that guy
  • The Helper The Helper:
    I wonder what ever happened to Wargasm?
  • The Helper The Helper:
    This new version of Xenforo really is awesome
  • Ghan Ghan:
    Wargasm is still around. He works for the domain registrar where thehelper.net is kept.
  • Varine Varine:
    Is sqrage still around?
  • The Helper The Helper:
    I have not seen him on lately the forum says he was last on 2 years ago
  • The Helper The Helper:
    How are you doing Varine have not seen you around in a minute
  • thewrongvine thewrongvine:
    lol I live in CA
  • thewrongvine thewrongvine:
    I've got some friends in animation department who have been applying for Blizzard, doing interviews and such. They said the workplace seems nice, though now it'd be all remote work I suppose
  • The Helper The Helper:
    good for them I live close to Austin and am trying to get my kids interested in getting into Games but not having much luck. I would never let them move to Cali.
  • The Helper The Helper:
    unless it was huge money
  • The Helper The Helper:
    and even then with the taxes I really could never let them move there

    Members online

    No members online now.

    Affiliates

    Hive Workshop
    Top