System BuffStruct

Jesus4Lyf

Good Idea™
Reaction score
397
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

  • BuffStruct.w3x
    117.2 KB · Views: 1,038
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 :)
 
This is awesome. Now I can phase out those wc3c systems and replace them with SpellStruct and BuffStruct.
 
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.
 
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
 
I, for one, am waiting for RacePreferenceStruct.
 
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.
 
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?
 
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?
 
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?
 
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?
 
Does GetEventDamage() work in onDamageDealt (And am I abled to block damage after receiving the amount?)?
 
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.
  • Varine Varine:
    A probate is usually done with a will, yes? If so I am sorry for your loss
    +1
  • The Helper The Helper:
    Yeah Tom, me too sorry for your loss buddy my mom told me she finds out her olds friend died from Google searching them. She had not talked to one of her old friends in a year and found out she died from Google. Also another one in the same session. RIP all of them my sincere condolences Tom
    +1
  • Varine Varine:
    We have some elderly guests that regularly come hang out at the bar at the end of the night, and every once in a while we don't see someone for a few weeks and then someone shows up with their obituary.
  • Varine Varine:
    We usually let them do their memorials there in the morning if they want to and I'll make them some snacks and drinks. There was one guy named Tom that came in like every night and would sit by himself and get a bunch of soup and a glass of wine. idk why but he LOVED our fucking soup, like he would order a fucking quart of it at a time and would always get so sad when we stop doing it for the summer.
    +1
  • Varine Varine:
    But he also loved our calamari, which is another thing I hate but it sells super well so I can't change it. There was one day he came in and was asking me how to make it, because he tried to at home once in the off season when we stop running it and he really wanted it lol
  • Varine Varine:
    I think he's one of the only people I've made recipes for for free because he really wanted a broccoli cheddar, and it was like dude I don't have a recipe, it's just whatever I have, but here, this is how you do it
  • Varine Varine:
    I don't think he ever figured out how to do the calamari in a pan though, like idk how to do that either. He was afraid of the at home deep fryers though and it's like yeah, that's fair, I am too
  • Varine Varine:
    He was just such a sweet old man, we had two servers pregnant and they held a baby shower together, he was soooooo fucking excited to get to see a baby. Unfortunately he died a month or so before they were born
  • The Helper The Helper:
    So I decided to Google some people that I had not seen or heard from in a while and sure enough one of my old best friends, we had a falling out years ago but whatever, find out he died of Pancreatic Cancer in January. I have also lost a few of my closer acquaintances from growing up the last year. Getting old - people die - I kinda thought it was going to be this way a few years ago....
    +2
  • The Helper The Helper:
    Forum running super slow again
  • Ghan Ghan:
    Not really clear from the stats as to what is causing the slowness.
  • Ghan Ghan:
    We get a lot of guest traffic so it may just be the load is getting too high and not from any particular source.
  • Ghan Ghan:
    Looks like the server is maxed out on CPU.
  • Ghan Ghan:
    Oh it looks like a lot of the traffic is Silkroad Forums. That domain isn't protected by Cloudflare.
  • Ghan Ghan:
    But the old Silkroad site is still on its own server. I just had a test site set up on this server for it.
  • Ghan Ghan:
    I just disabled that test site. Let's see if that helps the load.
  • Ghan Ghan:
    Looks much better already.
  • The Helper The Helper:
    I had actually forgot about the Silkroad site. I had asked
  • The Helper The Helper:
    SD Ryoko about it and he said the couple of people left on there really like it, that was a few years ago, maybe I should check back
  • jonas jonas:
    I guess when you're getting old, and the last day of soup season draws near, you start wondering
  • jonas jonas:
    will I make it to the start of the next season? or was this the last time I'll ever have my favorite dish?
  • The Helper The Helper:
    I am doing my first Vibe Coding project. In installed the environment and tools according to instructions but it is all chat doing this for me at my direction. It is fun really and holy shit I might finish in 2 hours what it would have taken a day to in my Access and this would be an electron app complete new
  • Ghan Ghan:
    Good stuff.
  • Ghan Ghan:
    Just make sure it is secure. :)
  • The Helper The Helper:
    It will only be on internal network

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials
      Top