| 01-01-2011, 04:25 PM | #1 |
The Aura works fine except: When a hero levels the ability, units must leave and re-enter the range for the updated skill level to take effect (and therefore never updates on the hero himself). How do I fix this? Note: I am using AHeroSkill, which I thought corrected this issue. JASS:library BashAura initializer Init requires ABuff, ABuffAura, ABuffHeroSkill, ABuffDisplay globals // BUFF EFFECT private constant integer BUFF_ABILITY = 'A08I' //the bash ability that units under the effect of the aura gain private constant integer BUFF_ABILITY_HOLDER = 'A08J' //The spellbook containing bash // BUFF VISUALS private constant integer BUFF_AURA = 'A09S' //the self-targeting aura that places the buff in the unit's status card private constant integer BUFF = 'B01A' //the buff bestowed upon the unit by the aura // MAIN AURA HERO SKILL private constant integer AURA = 'A09Q' //the dummy aura ability on the hero endglobals private function Range takes integer level returns real // This is the area of effect of the aura. if (level < 6) then return 850.0 + level * 50 else return 1200.0 endif endfunction private function Targets takes unit affected, unit auraGiver returns boolean // This function follows the ABuffAuraTargets function interface // and defines what units can be affected by the aura. return not(IsUnitEnemy(affected, GetOwningPlayer(auraGiver))) and not(IsUnitType(affected, UNIT_TYPE_MECHANICAL)) and not(IsUnitType(affected, UNIT_TYPE_STRUCTURE)) endfunction // ================================================================ // BUFF CODE globals private aBuffType auraBuff endglobals private function BuffApply takes aBuff eventBuff returns nothing //add the bash ability when the unit enters aura range. call UnitAddAbility(eventBuff.target.u, BUFF_ABILITY_HOLDER) call SetUnitAbilityLevel(eventBuff.target.u, BUFF_ABILITY, eventBuff.level) call UnitMakeAbilityPermanent(eventBuff.target.u, true, BUFF_ABILITY_HOLDER) //prevent morphing from removing the ability endfunction private function BuffCleanup takes aBuff eventBuff returns nothing //remove the bash ability when the unit leaves aura range. call UnitRemoveAbility(eventBuff.target.u, BUFF_ABILITY_HOLDER) endfunction // ABILITY CODE globals private aBuffType auraSource endglobals private function AuraSet takes aBuff eventBuff returns nothing call UnitSetABuffAura(eventBuff.target.u, auraBuff, eventBuff.level, Targets, Range(eventBuff.level)) endfunction private function AuraRemove takes aBuff eventBuff returns nothing call UnitRemoveABuffAura(eventBuff.target.u, auraBuff) endfunction // ================================================================ // ABILITY INITIALIZATION private function Init takes nothing returns nothing //this is the aura buff which gives units the bash ability set auraBuff=aBuffType.create() set auraBuff.eventCreate = BuffApply set auraBuff.eventRefresh = BuffApply set auraBuff.eventCleanup = BuffCleanup set auraBuff.countsAsBuff = false set auraBuff.display = aBuffDisplay.create(BUFF_AURA, BUFF) //this is the hero buff which makes the hero a source of the aura //when he learns the AURA ability (thanks to ABuffHeroSkill) set auraSource=aBuffType.create() set auraSource.eventCreate = AuraSet set auraSource.eventRefresh = AuraSet set auraSource.eventCleanup = AuraRemove set auraSource.ignoreAsBuff = true call NewABuffHeroSkill(AURA, auraSource) endfunction endlibrary |
| 01-01-2011, 10:01 PM | #2 |
Ah, I see, I forgot to force an aura refresh if the level changes. Here's the ABuffAura library with the bug fixed: JASS:library ABuffAura requires ABuff //***************************************************************** //* ABUFF AURA SYSTEM 1.7b (quick fix of the level update bug) //* //* written by: Anitarf //* requires: -ABuff //* //* This library allows you to create efficient triggered auras //* using the ABuff system. To use it, you must first define a //* STANDARD aBuffType, then you can add the aura to a unit (or //* update it if the unit already has it) using this function: //* //* function UnitSetABuffAura takes unit u, aBuffType appliedBuff, integer level, ABuffAuraTargets targets, real range returns nothing //* //* The unit argument passed tot he function will be the source of //* the aura, appliedBuff is the buff type used by the aura, level //* and range should be self-explanatory and the targets argument //* is a function that follows the ABuffAuraTargets function //* interface and determines whether a unit should be affected by //* the aura. Note that the buff type used by an aura must be in //* the STANDARD category. //* //* To remove an aura from a unit, use this function: //* //* function UnitRemoveABuffAura takes unit u, aBuffType removedBuff returns boolean //* //* The returned boolean will be true if the aura was removed and //* false if the unit did not have an aura granting that buff. If //* you remove the aura's aBuff from a unit, that buff will not //* be reapplied until the unit exits and re-enters the range of //* the aura, so be careful not to remove aura aBuffs with //* triggered dispel abilities unless that is the effect you want //* to achieve. //* //* When a unit that is already under the effect of the aura from //* one source comes in range of another source, the aBuff on the //* unit will be refreshed to the new source if that source has a //* higher level, otherwise it will not be refreshed. //***************************************************************** globals private constant real AURA_REFRESH_PERIOD = 0.25 private constant real MAXIMUM_COLLISION_SIZE = 55. endglobals // This function interface is included in the calibration section // for user reference only and should not be changed in any way. function interface ABuffAuraTargets takes unit affected, unit auraGiver returns boolean // ================================================================ // AURA UNIT private struct aBuffAuraUnit aBuffAuraUnit next = 0 aBuffAuraUnit prev = 0 unit u = null integer level = 0 real range = 0 group affected ABuffAuraTargets targets = 0 boolean torefresh=false boolean todestroy=false static method create takes unit u, integer level, ABuffAuraTargets targets, real range returns aBuffAuraUnit local aBuffAuraUnit this = aBuffAuraUnit.allocate() set .u = u set .level=level set .range=range set .targets=targets if .affected == null then set .affected = CreateGroup() endif return this endmethod method onDestroy takes nothing returns nothing call GroupClear(.affected) endmethod endstruct // ================================================================ // AURA TYPE private struct aBuffAura aBuffType appliedBuff = 0 aBuffAuraUnit first = 0 private static aBuffAura array table private static aBuffAura array list private static integer count = 0 private integer listIndex = 0 private static method create takes aBuffType abt returns aBuffAura local aBuffAura this=aBuffAura.allocate() set aBuffAura.list[aBuffAura.count] = this set aBuffAura.table[abt] = this set .listIndex = aBuffAura.count set .appliedBuff = abt set aBuffAura.count=aBuffAura.count+1 return this endmethod static method get takes aBuffType abt returns aBuffAura if aBuffAura.table[abt] == 0 then return aBuffAura.create(abt) endif return aBuffAura.table[abt] endmethod method onDestroy takes nothing returns nothing //this is only called if the aura has no units linked so no need to cleanup .first set aBuffAura.count=aBuffAura.count-1 set aBuffAura.table[.appliedBuff] = 0 set aBuffAura.list[.listIndex]=aBuffAura.list[aBuffAura.count] set aBuffAura.list[.listIndex].listIndex = .listIndex endmethod // ================================================================ method getAuraUnit takes unit u returns aBuffAuraUnit local aBuffAuraUnit abau = .first loop exitwhen abau==0 if abau.u==u then return abau endif set abau = abau.next endloop return 0 endmethod private method insertAuraUnit takes aBuffAuraUnit insert returns nothing local aBuffAuraUnit abau = .first if insert.level>=abau.level then set .first=insert set abau.prev=insert set insert.next=abau else loop exitwhen insert.level>=abau.next.level or abau.next==0 set abau=abau.next endloop if abau.next!=0 then set abau.next.prev=insert set insert.next=abau.next endif set insert.prev=abau set abau.next=insert endif endmethod private method removeAuraUnit takes aBuffAuraUnit remove returns nothing if .first==remove then set .first = remove.next else set remove.prev.next = remove.next endif if remove.next != 0 then set remove.next.prev = remove.prev endif endmethod // ================================================================ private static aBuffAuraUnit current private static boolean updating = false private static group inrange = CreateGroup() private static group toremove = CreateGroup() private static group processed = CreateGroup() private static boolexpr enum private static method groupenum takes nothing returns boolean // get eligible targets by picking units in range that: // - are not dead, // - match the target criteria and // - are not already affected by a higher level of the aura. local unit u=GetFilterUnit() local boolean b=(not IsUnitType(u, UNIT_TYPE_DEAD)) and (aBuffAura.current.targets.evaluate(u, current.u)) and (not IsUnitInGroup(u, aBuffAura.processed)) set u=null return b endmethod private static method updateAffectedUnits takes nothing returns nothing local unit u=GetEnumUnit() if IsUnitInGroup(u, aBuffAura.inrange) then call GroupAddUnit(aBuffAura.processed, u) call GroupRemoveUnit(aBuffAura.inrange, u) else if not IsUnitInGroup(u, aBuffAura.processed) then call GroupAddUnit(aBuffAura.toremove, u) endif call GroupRemoveUnit(aBuffAura.current.affected, u) endif set u=null endmethod method update takes nothing returns nothing local aBuffAuraUnit abau=.first local unit u set aBuffAura.updating=true call GroupClear(aBuffAura.inrange) call GroupClear(aBuffAura.processed) call GroupClear(aBuffAura.toremove) loop exitwhen abau==0 set aBuffAura.current=abau if abau.torefresh or abau.todestroy then call ForGroup(abau.affected, function aBuffAura.updateAffectedUnits) set abau.torefresh=false endif if abau.todestroy then call .removeAuraUnit(abau) call abau.destroy() else call GroupEnumUnitsInRange(aBuffAura.inrange, GetUnitX(abau.u), GetUnitY(abau.u), abau.range, aBuffAura.enum) call ForGroup(abau.affected, function aBuffAura.updateAffectedUnits) loop set u=FirstOfGroup(aBuffAura.inrange) exitwhen u==null call ABuffApply(.appliedBuff, u, abau.u, 0.0, abau.level, 0) call GroupAddUnit(abau.affected, u) call GroupAddUnit(aBuffAura.processed, u) call GroupRemoveUnit(aBuffAura.toremove, u) call GroupRemoveUnit(aBuffAura.inrange, u) endloop endif set abau=abau.next endloop loop set u=FirstOfGroup(aBuffAura.toremove) exitwhen u==null call ABuffRemove(GetABuffFromUnitByType(u, .appliedBuff)) call GroupRemoveUnit(aBuffAura.toremove, u) endloop set aBuffAura.updating=false endmethod static method updateAll takes nothing returns nothing local integer i=0 loop exitwhen i>=aBuffAura.count call aBuffAura.list[i].update() if aBuffAura.list[i].first==0 then call aBuffAura.list[i].destroy() else set i=i+1 endif endloop endmethod private static method onInit takes nothing returns nothing call TimerStart(CreateTimer(), AURA_REFRESH_PERIOD, true, function aBuffAura.updateAll) set aBuffAura.enum = Condition(function aBuffAura.groupenum) endmethod // ================================================================ method setUnit takes unit u, integer level, ABuffAuraTargets targets, real range returns nothing local aBuffAuraUnit abau=.getAuraUnit(u) if abau==0 then call .insertAuraUnit(aBuffAuraUnit.create(u, level, targets, range)) else if abau.level != level then call .removeAuraUnit(abau) set abau.level=level call .insertAuraUnit(abau) set abau.torefresh=true endif if abau.targets != targets then set abau.targets=targets set abau.torefresh=true endif set abau.range=range set abau.todestroy=false endif if not aBuffAura.updating then call .update() endif endmethod method removeUnit takes unit u returns boolean local aBuffAuraUnit abau=.getAuraUnit(u) if abau!=0 then set abau.todestroy=true if not aBuffAura.updating then call .update() endif return true endif return false endmethod endstruct // ================================================================ // MAIN USER FUNCTIONS function UnitSetABuffAura takes unit u, aBuffType appliedBuff, integer level, ABuffAuraTargets targets, real range returns nothing if appliedBuff.category==ABuff_STANDARD then call aBuffAura.get(appliedBuff).setUnit(u, level, targets, range) debug else debug call BJDebugMsg("UnitSetABuffAura error: the function only accepts buff types in the STANDARD category.") endif endfunction function UnitRemoveABuffAura takes unit u, aBuffType removedBuff returns boolean return aBuffAura.get(removedBuff).removeUnit(u) endfunction endlibrary |
