Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
//: CustomAura
//: by Anachron
//:
//: This system is thought to provide a basic aura system that can be used
//: to create auras with buffs and unit stat modifiers.
//:
//: What this is:
//: This is a very fast and flexible way to create an AOE aura.
//:
//: Functionality:
//: - Use buffs
//: - Use bonuses
//: - Highly customizeable ([Don't] use whatever you want)
//: - Highly flexible (You are allowed to change values at any time)
//: - Fast
//: - Easy understandable (Examples to bring the system closer to you)
//: - Well written (Code is non-redundant, cathegorized)
//:
//: Credits:
//: Rising_Dusk for GroupUtils [http://www.wc3c.net/showthread.php?t=104464]
//:
//: Thanks to:
//: Axarion for the idea.
//:
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
I would really like to get some feedback.
[Credits, comments, testing, critique etc are all welcome!]
Requires JNGP 5d and JassHelper 0.A.2.B.
Added "method activeCond takes nothing returns boolean defaults true" to allow players to create a custom condition for the spell being active
Added a magic immunity aura around a soldier that makes all alive units around magic immune, in an area of 500, even enemy units.
Fixed all the stuff trigger mentioned.
Added 2nd spell, sadly the buffs do not stack yet.
I tested the system and it seems okay.
I just wanted to say that I don't think CABuff should depend on an ability to give a buff. (It's limited and doesn't stack if you had multiple auras)
I think it's a better idea to depend on Slow Aura(Tornado) for the buff giver as it stacks with different buffs and doesn't need to be cast with a dummy unit.
One dummy unit for all buffs isn't a big deal imho.
But buffs can stack too. (Btw, slow aura is FREAKING laggy on mutliple units)
(Same with all auras)
I don't think so. I made another aura with your example and kept everything the same. The result was that only one of the buffs was shown on the enemy units. Unless you have a different stacking in mind?
(Btw, slow aura is FREAKING laggy on mutliple units)
Edit: I suppose I should also add that aura buffs won't get dispelled normally by spells like Purge or Dispel Magic. Though your system does do a good job of reapplying the buff again, it's nicer to see a unit's status card not changing suddenly when a dispel ability is performed on it.
Tested it and you're right; the fps keeps fluctuating.
Unfortunately, I don't think there are any spells with buffs that stack so you'll either have to rely on having auras that depend on one buff or aura buffs that make performance drop. You should at least make CABuff able to use different spells than Slow for its buffs.
Struct methods don't rearrange. It is still compiled top to bottom, so they create a dummy trigger and function to execute your function. Basically, it is the same as using .evaluate().
Thus, it will create a trigger and add a condition, which is basically some wasted handles. That's why I posted that improved method arrangement. That way, it creates 0 triggers (aside from onDestroy) opposed to its current state which creates a trigger and a condition (or maybe two of each, I don't remember).
When you call a method that is not above the current method, it will create a trigger global. Then it will add a condition, in which the condition function is the copy of the method to be called (with a return true). Then it will create a dummy function at the top of the map script, to evaluate that trigger. This is avoidable by reordering your methods.
Actually I know that I am using this but by this I am able to put create in the top of the struct where (for me at least) it belongs programming wise. I don't want to scroll to bottom just to check its constructor.
Efficiency > Organization. 3 extra handles (more memory), more code (== greater file size), and less speed than a direct function call makes it less efficient.
But, I guess it is up to you. Overall, this system is nice.
Changelog:
- Auras now notice unlearning and are destroyed automatically
- A new aura template has been added (AuraTemplate)
- The system now works a little bit faster
- The old auras have been completely rescripted in order to use the new Template.
Example:
JASS:
library HolyDevotion requires CustomAura
globals
private constant integer BUFF_ID = 'buf1'
private constant integer BUFF_SPELL = 'spl1'
endglobals
private struct HolyDevotionAura extends CustomAura
implement CABuff
implement CABonus
implement TableMacros
private static method new takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer i = GetHandleId(u)
local integer s = GetLearnedSkill()
local integer l = GetUnitAbilityLevel(u, s)
local thistype this = thistype.load(i)
//: Check whether the aura spell ID is valid
if s != 'hldv' then
set u = null
return false
endif
if this == 0 then
set this = thistype.create(u)
set .ID = i
call .save()
else
//: If we can load the data unaffect all so they get the
//: new bonuses
call .unaffectAll()
endif
//: Update the buff and bonus data
//: PLEASE DO NOT PUT THIS BEFORE .unaffectAll() !
call .setBuff(BUFF_SPELL, l, BUFF_ID, true)
set .dmg = - l * 2
set u = null
return false
endmethod
method getRadius takes nothing returns real
return 500.
endmethod
method unitFilter takes unit theUnit returns boolean
//: Do some checks whether the unit is a valid target
return IsUnitEnemy(theUnit, GetOwningPlayer(.theUnit)) and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.40
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local trigger t = CreateTrigger()
call TriggerAddCondition(t, Condition(function thistype.new))
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_HERO_SKILL, null)
set i = i +1
endloop
endmethod
endstruct
endlibrary
Became
JASS:
library HolyDevotion requires AuraTemplate
globals
private constant integer BUFF_ID = 'buf1'
private constant integer BUFF_SPELL = 'spl1'
private constant string BUFF_ORDER = "slow"
private constant integer SPELL_ID = 'hldv'
endglobals
private struct HolyDevotionAura extends AuraTemplate
//! runtextmacro AuraTemplateMethods()
method onLevelup takes integer theLevel returns nothing
set .dmg = - theLevel * 2
endmethod
method getRadius takes nothing returns real
return 500.
endmethod
method unitFilter takes unit theUnit returns boolean
//: Do some checks whether the unit is a valid target
return IsUnitEnemy(theUnit, GetOwningPlayer(.theUnit)) and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.40
endmethod
endstruct
endlibrary
Lol, you're names are very similar and you both worked on making the same thing and then you saw each others' projects... Creepy... I'll check this out later and rate after, for now you can just read this off-topic post until I edit it.
Ex: 10 Units have the aura, so the caster has a 10% chance to do something...
i'll update the amount of units in the onLoop()
So, how to get this integer?
Edit: I added a public integer var and count it in the 2 methods "public method affectUnit takes unit theUnit returns nothing" and "public method unaffectUnit takes unit theUnit returns nothing". It works and as long as u dont have a better idea i dont need to change it...
Could you please upload the code ?
My internet is slow and when it is fast I hate managing all the maps I download (I don't have that much space left on this computer ...)
[JASS="CustomAura"]
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
//: CustomAura
//: by Anachron
//:
//: This system is thought to provide a basic aura system that can be used
//: to create auras with buffs and unit stat modifiers.
//:
//: What this is:
//: This is a very fast and flexible way to create an AOE aura.
//:
//: Functionality:
//: - Use buffs
//: - Use bonuses
//: - Highly customizeable ([Don't] use whatever you want)
//: - Highly flexible (You are allowed to change values at any time)
//: - Fast
//: - Easy understandable (Examples to bring the system closer to you)
//: - Well written (Code is non-redundant, cathegorized)
//:
//: Credits:
//: Rising_Dusk for GroupUtils [http://www.wc3c.net/showthread.php?t=104464]
//:
//: Thanks to:
//: Axarion for the idea.
//:
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
library CustomAura requires GroupUtils, Table
globals
private constant real PERIOD = 0.0375
endglobals
method addBuff takes unit theUnit returns nothing defaults nothing
method removeBuff takes unit theUnit returns nothing defaults nothing
method checkBuff takes unit theUnit returns nothing defaults nothing
method addBonus takes unit theUnit returns nothing defaults nothing
method removeBonus takes unit theUnit returns nothing defaults nothing
endinterface
struct CustomAura extends eventHandler
public unit theUnit = null
private group affect = null
private group last = null
public boolean isAlive = true
public boolean isPaused = false
private boolean hasStarted = false
public integer spellId = 0
public static method create takes unit theUnit returns thistype
local thistype this = thistype.allocate()
set .affect = NewGroup()
set .last = NewGroup()
set .theUnit = theUnit
set .index = thistype.a
set thistype.i[.index] = this
set thistype.a = thistype.a +1
if thistype.a == 1 then
call TimerStart(thistype.t, PERIOD, true, function thistype.run)
endif
public method isUnitAffected takes unit theUnit returns boolean
return IsUnitInGroup(theUnit, .affect)
endmethod
public method affectUnit takes unit theUnit returns nothing
call GroupAddUnit(.affect, theUnit)
if not IsUnitInGroup(theUnit, .last) then
call .addBuff(theUnit)
call .addBonus(theUnit)
call .onRegister(theUnit)
else
call .checkBuff(theUnit)
endif
endmethod
public method unaffectUnit takes unit theUnit returns nothing
if not IsUnitInGroup(theUnit, .affect) then
call GroupRemoveUnit(.last, theUnit)
call .removeBuff(theUnit)
call .removeBonus(theUnit)
call .onUnregister(theUnit)
endif
endmethod
public method unaffectAll takes nothing returns nothing
set thistype.curInstance = this
call GroupClear(.affect)
call ForGroup(.last, function thistype.unaffectAllEnum)
endmethod
private static method tryRegister takes nothing returns boolean
local thistype this = thistype.curInstance
local unit u = GetFilterUnit()
public static method run takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= thistype.a
if thistype.i.isAlive and thistype.i != 0 then
set thistype.curInstance = thistype.i
call thistype.i.move()
else
if thistype.i != 0 then
call thistype.i.destroy()
endif
set thistype.a = thistype.a -1
set thistype.i = thistype.i[thistype.a]
set thistype.i.index = i
set i = i -1
endif
set i = i +1
endloop
if thistype.a == 0 then
call PauseTimer(thistype.t)
endif
endmethod
//! textmacro AuraTemplateMethods
private static method new takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer i = GetHandleId(u)
local integer s = GetLearnedSkill()
local integer l = GetUnitAbilityLevel(u, s)
local thistype this = thistype.load(i)
//: Check whether the aura spell ID is valid
if s != SPELL_ID then
set u = null
return false
endif
if this == 0 then
set this = thistype.create(u)
set this.spellId = SPELL_ID
set .ID = i
call .save()
else
//: If we can load the data unaffect all so they get the
//: new bonuses
call .unaffectAll()
endif
//: Update the buff and bonus data
//: PLEASE DO NOT PUT THIS BEFORE .unaffectAll() !
if BUFF_SPELL != 0 and BUFF_ID != 0 and BUFF_ORDER != null then
call .setBuff(BUFF_SPELL, l, BUFF_ID, BUFF_ORDER, true)
endif
call .onLevelup(l)
set u = null
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local trigger t = null
//call BJDebugMsg(GetObjectName(SPELL_ID))
if SPELL_ID == 0 then
return
endif
set t = CreateTrigger()
call TriggerAddCondition(t, Condition(function thistype.new))
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_HERO_SKILL, null)
set i = i +1
endloop
endmethod
//! endtextmacro
[/code]
method getRadius takes nothing returns real
return 500.
endmethod
method unitFilter takes unit theUnit returns boolean
//: Do some checks whether the unit is a valid target
return IsUnitEnemy(theUnit, GetOwningPlayer(.theUnit)) and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.40
endmethod
endstruct
method getRadius takes nothing returns real
return 500.
endmethod
method unitFilter takes unit theUnit returns boolean
//: Do some checks whether the unit is a valid target
return IsUnitEnemy(theUnit, GetOwningPlayer(.theUnit)) and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.40
endmethod
endstruct
method getRadius takes nothing returns real
return 500.
endmethod
method unitFilter takes unit theUnit returns boolean
//: Only for alive, non-reincarnating units
return GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.40
endmethod
endstruct
This system is being rescripted for the 1.0 version.
Please DO not use this system excessive, 10 auras are still non-laggy, but more can become a problem.
In order to fix the problem, I have decided to remove some Major flaws:
Remove function interfaces, they are damn sloowwwwww.
Add module API, makes it much faster with static function checks.
Rework internal structure.
Remove the crappy old libraries I made myself before, use the new Stack that is approved here.
Give a better naming, add better Test-Auras, create some actual documentation.
Provide a good public API.
I will post WIPs as the progress happens, and would encourage everyone to try and give me feedback for creating the best aura system possible.
This system is being rescripted for the 1.0 version.
Please DO not use this system excessive, 10 auras are still non-laggy, but more can become a problem.
In order to fix the problem, I have decided to remove some Major flaws:
Remove function interfaces, they are damn sloowwwwww.
Add module API, makes it much faster with static function checks.
Rework internal structure.
Remove the crappy old libraries I made myself before, use the new Stack that is approved here.
Give a better naming, add better Test-Auras, create some actual documentation.
Provide a good public API.
I will post WIPs as the progress happens, and would encourage everyone to try and give me feedback for creating the best aura system possible.
Update:
I just wanna let you know that the biggest parts of the system (70%) have been redesigned and rewritten. There was no test yet, however, I am happy to announce that with the next version it's all modular.
There will be events fired for the following situations:
[JASS="AuraEvents"]
public static Event onStart = 0
public static Event onLoop = 0
public static Event onStop = 0
public static Event onEnd = 0
[/code]
[JASS="AuraHeroEvents"]
public static Event onLearn = 0
public static Event onLevelup = 0
public static Event onUnlearn = 0
[/code]
[JASS="AuraGroup"]
public static Event onAffect = 0
public static Event onUnaffect = 0
[/code]
The modules AuraBuff and AuraBoni are not written yet.
The first thing you will notice that I actually use real events, written by Nestrasus. Second thing is, with adding modules to the systems you actually add new events that are getting fired.
The system is smart enough to find out whether the events should be fired or not, as this extraction shows:
[JASS="codeSnippet"]
public method activate takes nothing returns nothing
if not .isStarted then
call .start()
static if thistype.onStart then
set thistype.myself = this
call FireEvent(thistype.onStart)
endif
set .isStarted = true
endif
endmethod
[/code]
Also, events are getting registered now like this:
[JASS="ExampleOfEventAdding"]
call RegisterEvent(Condition(function UnitAura.myCustomCleanup), UnitAura.onEnd)
[/code]
There is still a lot to do, like helper functions/methods/values and demo spells. But I can already tell, the Testmap will be improved a lot too!
Btw, this is what my test-script looks like right now:
[JASS="Test"]
struct UnitAura
implement IsAura
Mhm, looks cool, okay... But I'm still trying to figure out how a terrain screenshot of a demo map is going to give us an idea of how the aura system works.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.