| 12-09-2008, 01:46 PM | #1 |
I'm writing a simple damage detection system for a map I'm making and am looking to optimize it a bit. Basically I'm wondering how I could reduce unnecessary iterations on attack, the current way I'm doing it was just a placeholder to get the system up and running, which it does. What I was thinking of doing was attaching a linked list of abilities that the unit currently has and only iterate through those each attack and would probably drastically increase performance. I think that this might over complicate things for such a simple damage detection system and I was wondering what other possibilities there are out there that would help solve this problem. Here's what is being used currently (not exact, don't have my map on this hd) JASS://base attack shielding loop exitwhen shields.end() set shield = shields.next() if (unit has shield.abilityID) then //this is the user defined function, where response is a struct containing the damage modifier and a boolean to continue set response = shields.funcInterface.evaluate() set Damage = Damage - r.damage if (not(r.continue)) then //blahblah clean up and end, we don't care about any more damage/shields endif endif endloop //ability attack shielding loop exitwhen swords.end() set sword = swords.next() if (unit has sword.abilityID) then set BonusDamage = swords.funcInterface.evaluate() loop exitwhen shields.end() set shield = shields.next() if (unit has shield.abilityID) then //this is the user defined function, where response is a struct containing the damage modifier and a boolean to continue set response = shields.funcInterface.evaluate() set BonusDamage = BonusDamage - r.damage if (not(r.continue)) then //blahblah clean up and end, we don't care about any more damage/shields endif endif endloop endif endloop |
| 12-09-2008, 02:20 PM | #2 |
Can't really comment on it without seeing the whole code. I guess you're trying to make something like ADamage? |
| 12-09-2008, 05:05 PM | #3 |
Hmm, odd I didn't see that in the Resources when I was looking before I started this, I've only skimmed over it a bit but yeah something like that although not nearly as complex. It looks like you used linked lists, do you attach them to units and retrieve them when that unit is involved in the damage event, and how did it work out? Anyways, I need to run I'm already late as it is, QQ. JASS:library Zodiac initializer Init requires PUI//, Dictionary globals public constant integer ATK_BUFF = 'B000' endglobals //You can use this to exclude certain units from the system entirely (buildings, undeads, whatever) private function RegisterFilter takes unit u returns boolean if (IsUnitType(u, UNIT_TYPE_STRUCTURE)) then return false endif return true endfunction //******************************************************************************************************************** //! runtextmacro DICTIONARY("Sword", "private") //! runtextmacro DICTIONARY("Shield", "private") public function interface SwordResponse takes unit Attacker, unit Attacked, real Damage returns real public function interface ShieldResponse takes unit Attacker, unit Attacked, real Damage returns integer //i don't understand why declaring this as public or private breaks compile? struct Comeback real damage boolean continue static method create takes real r, boolean b returns Comeback local Comeback x = Comeback.allocate() set x.damage = r set x.continue = b return x endmethod endstruct //contains the function to run and the ability id to trigger from private struct Sword SwordResponse sr integer aid static method create takes integer aid, SwordResponse sr returns Sword local Sword s = Sword.allocate() set s.aid = aid set s.sr = sr return s endmethod endstruct //contains the function to run and the ability id to trigger from private struct Shield ShieldResponse sr integer aid static method create takes integer aid, ShieldResponse sr returns Shield local Shield s = Shield.allocate() set s.aid = aid set s.sr = sr return s endmethod endstruct globals private trigger array UnitEventTrigger endglobals public function RegisterSword takes integer priority, integer aid, SwordResponse s returns nothing set DictionarySword[priority] = Sword.create(aid, s) endfunction public function RegisterShield takes integer priority, integer aid, ShieldResponse s returns nothing set DictionaryShield[priority] = Shield.create(aid, s) endfunction //the 'core' of the system, its fired every time a registered unit is attacked private function UnitDamageEvent takes nothing returns boolean local unit Attacked = GetTriggerUnit() local unit Attacker = GetEventDamageSource() local real Damage = GetEventDamage() local real BonusDamage = 0 local real TotalDamage local real Life = GetWidgetLife(Attacked) local real MaxLife = GetUnitState(Attacked, UNIT_STATE_MAX_LIFE) local Sword sw local Shield sh local Comeback r = -1 //we don't care about 0 damage attacks if (Damage <= 0.0) then set Attacked = null set Attacker = null return false endif //need: check if base damage should be reduced by unit shields //if the unit was attacked by a regular attack (not spell) if (GetUnitAbilityLevel(Attacked, ATK_BUFF) > 0) then call UnitRemoveAbility(Attacked, ATK_BUFF) //iterate through the sword abilities and calculate bonuses call DictionarySwordIterator.reset() loop exitwhen DictionarySwordIterator.end() set sw = DictionarySwordIterator.next() if (GetUnitAbilityLevel(Attacker, sw.aid) > 0) then set BonusDamage = sw.sr.evaluate(Attacker, Attacked, Damage) //now that we have the bonuses calculated, check shields to see if they get reduced at all call DictionaryShieldIterator.reset() loop exitwhen DictionaryShieldIterator.end() set sh = DictionaryShieldIterator.next() if (GetUnitAbilityLevel(Attacked, sh.aid) > 0) then set r = sh.sr.evaluate(Attacker, Attacked, BonusDamage) set BonusDamage = BonusDamage - r.damage //allows shields to cancel calculations (currently used only for life saving ability) if (not(r.continue)) then //this needs some reworking maybe include in the response what to set life at //if we cancel calculations or something call SetWidgetLife(Attacked, 1 + Damage) set Attacker = null set Attacked = null call r.destroy() return false endif endif endloop //needs tweaking, we need to factor in reductions to base damage //something like ((Life + BaseDamage) - (Damage + BonusDamage)) might work call SetWidgetLife(Attacked, GetWidgetLife(Attacked) - BonusDamage) endif endloop endif set Attacker = null set Attacked = null if (r != -1) then call r.destroy() endif return false endfunction //this function creates a trigger tied to unit's EVENT_UNIT_DAMAGED and indexes it to trigger array with PUI //and fires the UnitDamageEvent function which is the 'core' of the system private function RegisterUnit takes unit u returns nothing local integer index = GetUnitIndex(u) if (UnitEventTrigger[index] != null) then //If we've grabbed a recycled index from PUI, destroy the existing trigger call DestroyTrigger(UnitEventTrigger[index]) endif set UnitEventTrigger[index] = CreateTrigger() call TriggerRegisterUnitEvent(UnitEventTrigger[index], u, EVENT_UNIT_DAMAGED) call TriggerAddCondition(UnitEventTrigger[index], Condition(function UnitDamageEvent)) endfunction //obvious: registers a new unit that's created private function RegisterNewUnit takes nothing returns nothing if (RegisterFilter(GetTriggerUnit())) then call RegisterUnit(GetTriggerUnit()) endif endfunction //obvious: registers a unit that's placed on the map private function RegisterExistingUnitsEnum takes nothing returns nothing if (RegisterFilter(GetEnumUnit())) then call RegisterUnit(GetEnumUnit()) endif endfunction private function RegisterExistingUnits takes nothing returns nothing set bj_lastCreatedGroup = CreateGroup() call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, null) call ForGroup(bj_lastCreatedGroup, function RegisterExistingUnitsEnum) call DestroyGroup(bj_lastCreatedGroup) set bj_lastCreatedGroup = null endfunction private function Init takes nothing returns nothing local trigger t //register existing units set t = CreateTrigger() call TriggerRegisterTimerEvent(t, 0.0, false) call TriggerAddAction(t, function RegisterExistingUnits) //register new units that are spawned during game set t = CreateTrigger() call TriggerRegisterEnterRectSimple(t, bj_mapInitialPlayableArea) call TriggerAddAction(t, function RegisterNewUnit) set t = null endfunction endlibrary |
