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=039;A$SYSID$&039;
set thistype(thistype.idMax).buffType=039;B$SYSID$&039;
//! 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
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()
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.