- Joined
- Jul 10, 2007
- Messages
- 6,306
implement CTQ
local boolean wasActive
local real x1
local real x2
local real y1
local real y2
local integer lev
// forgotten lines??
local thistype time
local UnitIndex entering
implement CTQExpire
// ...
library TestAura uses AuraStruct, Bonus
struct tester extends array
private static constant real TIMEOUT = .3
private static constant boolean STACKS = false
private static constant integer ABILITY_ID = 'AHad' // Devotion Aura
private static method onLevel takes UnitIndex source, integer level returns nothing
endmethod
private method onEndEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
call AddUnitBonus(GetUnitById(affected),BONUS_DAMAGE,100)
endmethod
private method onEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
call AddUnitBonus(GetUnitById(affected),BONUS_DAMAGE,100)
endmethod
private static method getRange takes UnitIndex source, integer level returns real
return 900.
endmethod
implement AuraStruct
endstruct
endlibrary
struct testers extends array
private static unit u
private static unit u2
private static unit u3
private static method onInit takes nothing returns nothing
set u=CreateUnit(Player(0),'Hmkg',GetStartLocationX(0),GetStartLocationY(0),270)
set u2=CreateUnit(Player(0),'Hpal',GetStartLocationX(0),GetStartLocationY(0)-250,270)
set u3=CreateUnit(Player(0),'hbar',GetStartLocationX(0),GetStartLocationY(0)-500,270)
call SetHeroLevel(u2,10,false)
endmethod
endstruct
struct tester extends array
private static constant real TIMEOUT = .3
private static constant boolean STACKS = false
private static constant integer ABILITY_ID = 'AHad'
private static method onLevel takes UnitIndex source, integer level returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,GetUnitName(GetUnitById(source))+" has learned devotion aura")
endmethod
private method onEndEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,GetUnitName(GetUnitById(affected))+" has lost devotion aura")
endmethod
private method onEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,GetUnitName(GetUnitById(affected))+" has gotten devotion aura")
endmethod
private method onPeriodicEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
call SetWidgetLife(GetUnitById(affected), GetWidgetLife(GetUnitById(affected))+5*.3)
endmethod
private static method absFilter takes UnitIndex source, UnitIndex entering returns boolean
return not IsUnitType(GetUnitById(entering), UNIT_TYPE_STRUCTURE)
endmethod
private method filter takes UnitIndex source, UnitIndex affected, integer level returns boolean
return IsUnitAlly(GetUnitById(source), GetOwningPlayer(GetUnitById(affected)))
endmethod
private static method getRange takes UnitIndex source, integer level returns real
return 900.
endmethod
implement AuraStruct
endstruct
library AuraStruct /* v1.1.0.1
*************************************************************************************
*
* An efficient and easy to use module for aura design.
*
*************************************************************************************
*
* */uses/*
*
* */ UnitEvent /* hiveworkshop.com/forums/jass-functions-413/extension-unit-event-172365/
* */ UnitInRangeEvent /* hiveworkshop.com/forums/submissions-414/unitinrangeevent-205036/
* */ Tt /* hiveworkshop.com/forums/jass-functions-413/system-timer-tools-201165/
*
************************************************************************************
*
* Interface
*
* private static constant real TIMEOUT
* (required) - How often the aura effect runs
*
* private static constant boolean STACKS
* (required) - Does the aura stack?
*
* private static constant integer ABILITY_ID
* (required) - The aura ability id
*
* private static method onLevel takes UnitIndex source, integer level returns nothing
* (optional) - Runs when aura levels up
*
* private static method getRange takes UnitIndex source, integer level returns real
* (required) - Should return the range of the aura
*
* private method onEndEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
* (optional) - Runs when the aura effect ends (aura no longer on unit)
*
* private method onEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
* (optional) - Runs when aura effect starts (aura just went on to unit)
*
* private method onPeriodicEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
* (optional) - Runs every period of the aura. First run is right after onEffect
*
* private static method absFilter takes UnitIndex source, UnitIndex entering returns boolean
* (optional) - Runs when the unit initially enters in the range of the aura. If this returns false, the
* - unit is ignored as if it doesn't exist and it will never be able to get the aura
*
* private method filter takes UnitIndex source, UnitIndex affected, integer level returns boolean
* (optional) - Runs whenever the aura cycles (every TIMEOUT seconds). This helps determine if the
* - aura is active or not for the unit.
*
* private static method removeBuff takes unit whichUnit, integer level returns nothing
* (optional) - Runs when the buff icon should be removed from the unit
*
* private static method addBuff takes unit whichUnit, integer level returns nothing
* (optional) - Runs when the buff icon should be added to the unit
*
************************************************************************************/
module AuraStruct
static if not thistype.STACKS then
private static integer array auraLevel
endif
private integer affectedLevel
private static hashtable affecting = InitHashtable()
static if thistype.removeBuff.exists then
private static integer array buffCount
elseif thistype.addBuff.exists then
private static integer array buffCount
endif
private static integer array level
private static triggercondition array onEnterT
private static triggercondition array onEnterT2
private boolean ran
private boolean active
private UnitIndex source
private UnitIndex affected
private method isActive takes nothing returns boolean
static if not thistype.STACKS then
static if thistype.filter.exists then
return filter(source, affected, level[source]) and (level[source] > auraLevel[affected] or affectedLevel == auraLevel[affected])
else
return (level[source] > auraLevel[affected]) or affectedLevel == auraLevel[affected]
endif
else
static if thistype.filter.exists then
return filter(source, affected, level[source])
endif
endif
endmethod
private method doEffect takes nothing returns nothing
if (not ran) then
set ran = true
static if thistype.onEffect.exists then
call onEffect(source, affected, level[source])
endif
endif
static if thistype.onPeriodicEffect.exists then
call onPeriodicEffect(source, affected, level[source])
endif
endmethod
implement CTQ
local boolean wasActive
local real x
local real y
implement CTQExpire
set x = GetWidgetX(GetUnitById(source))-GetWidgetX(GetUnitById(affected))
set y = GetWidgetY(GetUnitById(source))-GetWidgetY(GetUnitById(affected))
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"----------------------------------\n"+/*
*/"ability("+I2S(GetUnitAbilityLevel(GetUnitById(source), ABILITY_ID))+") != "+"stored("+I2S(affectedLevel)+") or "/*
*/+R2S(SquareRoot(x*x+y*y))+" > "+R2S(getRange(source, level[source]))/*
*/)
if (/*
*/GetUnitAbilityLevel(GetUnitById(source), ABILITY_ID) != affectedLevel or /*
*/IsUnitDead(source) or /*
*/IsUnitReincarnating(source) or /*
*/IsUnitDead(affected) or /*
*/IsUnitReincarnating(affected) or /*
*/SquareRoot(x*x+y*y) > getRange(source, level[source]) /*
*/) then
if (active) then
static if thistype.removeBuff.exists then
set buffCount[affected] = buffCount[affected] - 1
if (0 == buffCount[affected]) then
call removeBuff(GetUnitById(affected), auraLevel[affected])
endif
elseif thistype.addBuff.exists then
set buffCount[affected] = buffCount[affected] - 1
endif
static if not thistype.STACKS then
if (affectedLevel == auraLevel[affected]) then
set auraLevel[affected] = 0
endif
endif
static if thistype.onEndEffect.exists then
call onEndEffect(source, affected, level[source])
endif
endif
if (LoadInteger(affecting, source, affected) == affectedLevel) then
call RemoveSavedInteger(affecting, source, affected)
endif
call destroy()
if (source == affected) then
call source.unlock()
endif
call affected.unlock()
else
set wasActive = active
set active = isActive()
if (active) then
static if not thistype.STACKS then
if (level[source]>auraLevel[affected]) then
static if thistype.addBuff.exists then
if (not wasActive) then
set buffCount[affected] = buffCount[affected] + 1
endif
static if thistype.removeBuff.exists then
call removeBuff(GetUnitById(affected), auraLevel[affected])
endif
call addBuff(GetUnitById(affected), level[source])
elseif thistype.removeBuff.exists then
if (not wasActive) then
set buffCount[affected] = buffCount[affected] + 1
endif
endif
set auraLevel[affected] = level[source]
set ran = false
else
call doEffect()
endif
else
call doEffect()
endif
elseif (wasActive) then
static if thistype.removeBuff.exists then
set buffCount[affected] = buffCount[affected] - 1
if (0 == buffCount[affected]) then
call removeBuff(GetUnitById(affected), auraLevel[affected])
endif
elseif thistype.addBuff.exists then
set buffCount[affected] = buffCount[affected] - 1
endif
static if not thistype.STACKS then
if (affectedLevel == auraLevel[affected]) then
set auraLevel[affected] = 0
endif
endif
set ran = false
static if thistype.onEndEffect.exists then
call onEndEffect(source, affected, level[source])
endif
endif
endif
implement CTQNull
implement CTQEnd
private static method doEnter takes thistype this, UnitIndex entering returns nothing
local thistype time
local boolean canEnter = true
static if thistype.absFilter.exists then
set canEnter = absFilter(this, entering)
endif
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Entered")
if (canEnter and LoadInteger(affecting, this, entering) != level[this]) then
call entering.lock()
call SaveInteger(affecting, this, entering, level[this])
set time = create()
set time.source = this
set time.affected = entering
set time.ran = false
set time.affectedLevel = level[this]
set time.active = time.isActive()
static if not thistype.STACKS then
if (time.active) then
static if thistype.addBuff.exists then
set buffCount[entering] = buffCount[entering] + 1
if (0 != level[this]) then
call addBuff(GetUnitById(entering), level[this])
endif
elseif thistype.removeBuff.exists then
set buffCount[entering] = buffCount[entering] + 1
endif
set auraLevel[entering] = level[this]
endif
endif
endif
endmethod
private static method onEnter takes nothing returns boolean
call doEnter(GetEventSourceUnitId(), GetUnitUserData(GetTriggerUnit()))
return false
endmethod
private static method onLearn takes nothing returns boolean
local thistype this
local unit u
if (GetLearnedSkill()==ABILITY_ID) then
set u = GetTriggerUnit()
set this = GetUnitUserData(u)
call UnitIndex(this).lock()
if (null!=onEnterT[this]) then
call UnregisterUnitInRangeEvent(onEnterT2[this], u, getRange(this, level[this])-64)
call UnregisterUnitInRangeEvent(onEnterT[this], u, getRange(this, level[this]))
endif
set level[this] = GetUnitAbilityLevel(u, ABILITY_ID)
static if thistype.onLevel.exists then
call onLevel(this, level[this])
endif
call doEnter(this, this)
set onEnterT2[this] = RegisterUnitInRangeEvent(function thistype.onEnter, u, getRange(this, level[this])-64)
set onEnterT[this] = RegisterUnitInRangeEvent(function thistype.onEnter, u, getRange(this, level[this]))
set u = null
endif
return false
endmethod
static if thistype.addBuff.exists then
private static method onIndex takes nothing returns boolean
set buffCount[GetIndexedUnitId()] = 0
return false
endmethod
elseif thistype.removeBuff.exists then
private static method onIndex takes nothing returns boolean
set buffCount[GetIndexedUnitId()] = 0
return false
endmethod
endif
private static method onInit takes nothing returns nothing
local integer i = 15
local trigger t = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_HERO_SKILL, null)
exitwhen 0 == i
set i = i - 1
endloop
call TriggerAddCondition(t, Condition(function thistype.onLearn))
static if thistype.addBuff.exists then
call RegisterUnitIndexEvent(Condition(function thistype.onIndex), UnitIndexer.INDEX)
elseif thistype.removeBuff.exists then
call RegisterUnitIndexEvent(Condition(function thistype.onIndex), UnitIndexer.INDEX)
endif
set t = null
endmethod
endmodule
endlibrary
local integer i = 15
local trigger t = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_HERO_SKILL, null)
exitwhen 0 == i
set i = i - 1
endloop
call TriggerAddCondition(t, Condition(function thistype.onLearn))
set t = null
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL,function thistype.onLearn)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
this bug still exists.A high value on TIMEOUT is doing the aura be removed twice.
I am testing with TIMEOUT = 1.
this bug still exists.
Creating a local to store an array index works out much better on
FPS than letting an array index be referenced so many times. Arrays
are quite slower than locals.
GetUnitX/Y was benchmarked faster than GetWidgetX/Y by multiple
people including myself with the RTC benchmarks and D4RK_G4ND4LF
with his crazy GUI benchmarks, and some others.
If the unit finishes reincarnating, or gets ressurrected or reanimated,
it looks like the aura doesn't re-register for that unit.
private static method unregisterRange takes integer sourceId, unit sourceUnit, real range returns nothing
if (null!=onEnterT[sourceId]) then
call UnregisterUnitInRangeEvent(onEnterT2[sourceId], sourceUnit, range-96)
call UnregisterUnitInRangeEvent(onEnterT[sourceId], sourceUnit, range-32)
endif
endmethod
private static method registerRange takes integer sourceId, unit sourceUnit, real range returns nothing
call doEnter(sourceId, sourceId)
set learning[sourceId] = true
set onEnterT2[sourceId] = RegisterUnitInRangeEvent(function thistype.onEnter, sourceUnit, range-96)
set onEnterT[sourceId] = RegisterUnitInRangeEvent(function thistype.onEnter, sourceUnit, range-32)
endmethod
Perhaps just throw out those living/dead checks and let the user decide
under what special conditions to remove the aura, and make it up to them
to decide when the aura should be re-added.
I checked for the source unit only so that revive etc would work with it.And I am not sure why you are still checking if the "affected" unit is alive periodically but checking if the source unit is alive by events. Or maybe I am missing something.
but the way you have it doesn't have to be the same
Still using the "Condition" native and I don't know why. "Filter" is better.
filterfunc extends boolexpr
filterfunc extends boolexpr
conditionfunc extends boolexpr
AuraStruct don't compiles with UnitInRangeEvent 2.0
I know. I'm still updating AuraStruct >.>.
Read the note in the first post ; P
Also, the new code will be extremely readable ; P.
However, this update could take me up to a week to finish. Sry about that : |
I figured out a way to reduce the module size by A TON ; )