| 03-05-2011, 04:01 PM | #1 |
I have a global trigger that would call a function and in this function, there are code that check and do things. Example like below: JASS:function TrigAct takes nothing returns nothing local unit c// = ... local unit a// = ... local integer lvl// = ... set lvl = GetUnitAbilityLevel(c,'A000') if lvl > 0 and GetRandomInt(1,100) <= 10+5*lvl then // other things endif set lvl = GetUnitAbilityLevel(c,'A001') if lvl > 0 and not IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) then // other things endif //... and there are about 20 of other similar "if" (this will increase in the future) endfunction the trigger is global means that function will run with every unit so, obviously, those if will be ran and if there are too many ifs, the performance will be reduced, right? now I think of an alternate way: use function interface all the ifs are in seperate functions and when the ability is learned, add the consistant functions to the "functions to be called" (I cant think of the right word at the moment, sorry) like so: JASS:function interface TrigActEvent takes unit c, unit a returns nothing globals TrigActEvent array eventCheck [100] // these are "functions to be called" integer eventCheckCount = 0 endglobals function TrigAct takes nothing returns nothing local unit c// = ... local unit a// = ... local integer i = 0 loop exitwhen i == eventCheckCount call eventCheck[i].evaluate(c,a) set i = i + 1 endloop endfunction function EventCheckA000 takes unit c, unit a returns nothing local integer lvl = GetUnitAbilityLevel(c,'A000') if lvl > 0 and GetRandomInt(1,100) <= 10+5*lvl then // other things endif endfunction function EventCheckA001 takes unit c, unit a returns nothing local integer lvl = GetUnitAbilityLevel(c,'A001') if lvl > 0 and not IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) then // other things endif endfunction // other functions for other "if" (and yea, about 20 of them, the number will increase in the future) // this is the action of "hero learn skill" trigger function HeroLearnSkillAct takes nothing returns nothing local unit c// = ... local integer abi// = ... local integer lvl// = ... if abi=='A000' and lvl==1 then set eventCheck[eventCheckCount] = EventCheckA000 set eventCheckCount = eventCheckCount + 1 elseif abi=='A000' and lvl==1 then set eventCheck[eventCheckCount] = EventCheckA001 set eventCheckCount = eventCheckCount + 1 // and more endif endfunction those "EventCheck" functions are normal functions and static method (of struct) so, with the above way, the "ifs" are only ran when the ability is learned so I think it's more efficient but am I abusing the function interface? is this way as efficient as I think? thanks for reading p.s: sorry that I dont have a better title for the thread |
| 03-06-2011, 02:56 AM | #2 |
I would personally use the first method. The second method is a bit more odd and it also internally creates a trigger and evaluates it. It won't be that much of a difference, especially since you are not doing anything resource heavy. What you are doing should be perfectly fine, it should work very well whether it be 20, 50, 100, or maybe even 1000 if-blocks. |
| 03-06-2011, 04:32 AM | #3 |
I forgot to mention that the if-block could be... complex, I'm talking about it checks many conditions but they're only around "IsUnitType". also, I don't know if the number of if-block could get to 100 or not, probably it could but since it's not that heavy so I guess it's fine. I will wait for other opinion :) |
| 03-06-2011, 06:42 PM | #4 |
The ifs are likely a lot faster than doing a trigger evaluate, so the first approach would likely be faster, unless the ratio between the total number of checks and the number of checks you would actually activate with the second approach is something absurd like 1:100. Neither of these two approaches seem particularly good, though. There is likely a better way to do this, but I'd need to know what exactly you are trying to do before I can suggest anything more specific. The first thing I thought of when I saw the code was SpellEvent, but it seems you are doing something slightly different. |
| 03-08-2011, 12:24 AM | #5 |
oh... ok, I will be more specific now: this is the shortened code: JASS:library CustomAttack initializer Init struct CustomAttack unit attacker unit defender boolean isReflect=false boolean isRange boolean checkOnAttack=true integer missed=0 boolean evaded=false boolean interrupted=false real minDamage real maxDamage real modify=1. real criticalHit=1. integer damageType=1 string attackerBonus="" string defenderBonus="" string onHitAbilities="" string onSwingBonus="" integer weaponSound=0 integer bounceCount=0 string bounceTargets="01100000002000002110" real bounceRange=400. real bounceDamageLess=0. boolean firstImpact=true destructable targDest=null item targItem=null real attackerX real attackerY real swingDuration real swingDurationPercent real animationAttack integer indexOfAttack real debug_time //--- attack abilities --- boolean deadeye_barrage = false boolean pass_ChillingTouch = false boolean auto_ManaShatter = false boolean auto_SearingArrow = false boolean auto_ScarletTouch = false boolean pass_OrbVenom = false boolean pass_OrbFire = false boolean pass_OrbStatic = false boolean pass_OrbCorruption = false boolean pass_OrbFrost = false boolean pass_OrbDisruption = false boolean pass_OrbLife = false integer chrono_walk_damage = 0 integer phantom_walk_damage = 0 boolean buff_FreezingArrow = false boolean buff_ShadowGauntlet = false boolean buff_FlamingArrow = false boolean buff_ShadowWalk = false boolean pass_FrostCannon = false boolean pass_LichFrostCannon = false boolean pass_SparklingSlam = false boolean pass_StunningBlow = false boolean pass_SlumberingCane = false static method UpdateAttackerPos takes unit c, real cx, real cy, boolean new returns nothing local integer inx = GetUnitId(c) local thistype this if UnitData[inx].atkData!=0 then set this = UnitData[inx].atkData if new then set .attackerX = GetUnitX(c) set .attackerY = GetUnitY(c) else set .attackerX = cx set .attackerY = cy endif endif endmethod method Reflect takes nothing returns nothing set .isReflect=true set bj_lastCreatedUnit = .attacker set .attacker = .defender set .defender = bj_lastCreatedUnit set bj_lastCreatedUnit = null endmethod method CheckReflect takes nothing returns boolean local integer inx = GetUnitId(.defender) local boolean ok = false local integer lvl return ok endmethod static method EvadeAttacks takes unit u returns nothing local integer inx = GetUnitId(u) local integer i = 1 local thistype this loop exitwhen i > UnitData[inx].attacksCount set this = UnitData[inx].data[StringHash("AttackerNumber"+I2S(UnitData[inx].attacksCount))] set this.evaded = true set i = i + 1 endloop endmethod private method IncomingAttackRegister takes nothing returns nothing local integer inx=GetUnitId(.defender) set UnitData[inx].attacksCount = UnitData[inx].attacksCount+1 set .indexOfAttack=UnitData[inx].attacksCount set UnitData[inx].data[StringHash("AttackerNumber"+I2S(UnitData[inx].attacksCount))]=this endmethod private method IncomingAttackUnRegister takes nothing returns nothing local integer inx=GetUnitId(.defender) local thistype d = UnitData[inx].data[StringHash("AttackerNumber"+I2S(UnitData[inx].attacksCount))] set d.indexOfAttack=.indexOfAttack set UnitData[inx].data[StringHash("AttackerNumber"+I2S(.indexOfAttack))]=UnitData[inx].data[StringHash("AttackerNumber"+I2S(UnitData[inx].attacksCount))] call UnitData[inx].data.flush(StringHash("AttackerNumber"+I2S(UnitData[inx].attacksCount))) set UnitData[inx].attacksCount=UnitData[inx].attacksCount-1 endmethod static method onInterrupt takes unit u returns nothing local integer inx=GetUnitId(u) local thistype this if UnitData[inx].atkData!=0 then //call BJDebugMsg(GetUnitName(u)+" attack is interrupted") set this=UnitData[inx].atkData call S2UB(.attacker,.onSwingBonus,-1) call .destroy() if UnitData[inx].atkSwinging then call ReleaseTimer( UnitData[inx].atkSwing ) endif set UnitData[inx].atkSwinging=false set UnitData[inx].atkAttacking=false set UnitData[inx].atkData=0 if UnitData[inx].spellData.auto_ability != 0 then set UnitData[inx].spellData.auto_manualcast = false endif endif if UnitData[inx].spellData.ShowDamageDeal then set UnitData[inx].spellData.ShowDamageDeal = false endif if UnitData[inx].spellData.dualSwing==1 then set UnitData[inx].spellData.dualSwing = 0 call SetUnitTimeScaleEx(u,1.) endif if UnitData[inx].spellData.volleyFire>0 then set UnitData[inx].spellData.volleyFire = 0 call SetUnitTimeScaleEx(u,1.) endif if UnitData[inx].spellData.doubleThrow==1 then set UnitData[inx].spellData.doubleThrow = 0 call SetUnitTimeScaleEx(u,1.) endif endmethod private method IsAttackInterrupted takes nothing returns boolean local integer inx1=GetUnitId(.attacker) local integer inx2=GetUnitId(.defender) return .evaded or IsUnitInRange(.attacker,.defender, UnitData[inx1].unitConst.atkRange+250+64 )==false or/* */ GetWidgetLife(.attacker)<=0.405 or GetWidgetLife(.defender)<=0.405 or /* */ (IsUnitType(.defender,UNIT_TYPE_ETHEREAL) and UnitData[inx1].unitConst.atkType!="magic" and UnitData[inx1].spellData.allowAttackEthereal==0) or/* */ (IsUnitType(.defender,UNIT_TYPE_MAGIC_IMMUNE) and UnitData[inx1].unitConst.atkType=="magic") or/* */ IsUnitInvisibleEx(.defender,GetOwningPlayer(.attacker)) or/* */ IsUnitHidden(.attacker) or IsUnitHidden(.defender) or/* */ (UnitData[inx1].isPaused>0 and GetUnitX(.attacker)!=.attackerX and GetUnitY(.attacker)!=.attackerY ) endmethod private method onAttackCheck takes nothing returns nothing local integer inx=GetUnitId(.attacker) local boolean ally = IsUnitAlly(.defender, GetOwningPlayer(.attacker)) local boolean structure = IsUnitType(.defender, UNIT_TYPE_STRUCTURE) local boolean elite = IsUnitTypeElite(.defender) local boolean champ = IsUnitTypeChampion(.defender) local boolean cast = false local real cmp local real chp local integer lvl local integer i local unit p local integer dbthr = 0 local real x local real y local real angle //---------- set lvl = GetUnitAbilityLevel(.attacker,'A019') if lvl > 0 then if UnitData[inx].spellData.targFocusFire==.defender then set i = UnitData[inx].spellData.focusFireSpeed set UnitData[inx].spellData.focusFireSpeed = UnitData[inx].spellData.focusFireSpeed + 6+3*lvl if UnitData[inx].spellData.focusFireSpeed > (6+3*lvl)*5 then set UnitData[inx].spellData.focusFireSpeed = (6+3*lvl)*5 endif call GetBonus(.attacker, "atsp", UnitData[inx].spellData.focusFireSpeed - i, 0,0, 1) else set UnitData[inx].spellData.targFocusFire = .defender endif endif set lvl = GetUnitAbilityLevel(.attacker,'A032') if lvl > 0 and UnitMatch(.attacker,.defender,"00000000200000200000") and GetRandomInt(1,100)<=7+7*lvl then set .onHitAbilities = .onHitAbilities + I2S('A032')+":"+I2S(lvl)+";" endif if GetUnitAbilityLevel(.attacker,'B00B')>0 then set UnitData[inx].spellData.rapidFireCount = UnitData[inx].spellData.rapidFireCount - 1 if UnitData[inx].spellData.rapidFireCount == 0 then call UnitBuff.RemoveSpecific(null,.attacker,'B00B') endif endif if GetUnitAbilityLevel(.attacker,'B011')>0 then set .damageType = 3 set UnitData[inx].spellData.chillingTweakCount = UnitData[inx].spellData.chillingTweakCount - 1 if UnitData[inx].spellData.chillingTweakCount==0 then call UnitBuff.RemoveSpecific(null,.attacker,'B011') endif endif if GetUnitAbilityLevel(.attacker,'AD0B')>0 then set .onHitAbilities = .onHitAbilities + I2S('AD0B')+":"+I2S(UnitBuff.GetBuffLevel(.attacker,'AD0B'))+";" call UnitBuff.RemoveSpecific(null,.attacker,'AD0B') endif set lvl = GetUnitAbilityLevel(.attacker,'A02M') if lvl > 0 and GetRandomInt(1,100)<=8+2*lvl then call CustomSpells2_BloodScarab.execute(.attacker,lvl) endif if GetUnitAbilityLevel(.attacker,'B00X')>0 then set lvl = UnitBuff.GetBuffLevel(.attacker,'B00X') set .onHitAbilities = .onHitAbilities + I2S('B00X')+":"+I2S(lvl)+";" set .buff_FreezingArrow = true call UnitBuff.RemoveSpecific(null,.attacker,'B00X') endif set lvl = GetUnitAbilityLevel(.attacker,'A033') if lvl > 0 and UnitMatch( .attacker, .defender, "00000002220000200000" ) then call CustomSpells3_SpeedTranscend.execute( .attacker, .defender, lvl ) endif set lvl = GetUnitAbilityLevel(.attacker,'A05C') if lvl > 0 and UnitMatch( .attacker, .defender, "00000002220000200000" ) then call CustomSpells4_UltimateWeapon.execute( .attacker, .defender, lvl ) endif if GetUnitAbilityLevel(.attacker,'B013')>0 then set lvl = UnitBuff.GetBuffLevel(.attacker,'B013') set UnitData[inx].spellData.shadowGauntletCount = UnitData[inx].spellData.shadowGauntletCount - 1 call GetBonus( .attacker, "atbn", 30*lvl, 0,0, 1 ) set .onSwingBonus = .onSwingBonus+"atbn_"+I2S(30*lvl)+"_0_0;" set .buff_ShadowGauntlet = true call CustomSpells3_ShadowGauntlet.Pull( .attacker, .defender, lvl ) if UnitData[inx].spellData.shadowGauntletCount==0 then call UnitBuff.RemoveSpecific( null,.attacker, 'B013' ) endif endif if GetUnitAbilityLevel(.attacker,'AD0H')>0 then set lvl = GetUnitAbilityLevel(.attacker,'A03A') call UnitRemoveAbility(.attacker,'AD0H') call UnitAddAbilityDelay.Do( .attacker, 'AD0H', 1, 16. - 2 * lvl , false ) set .onHitAbilities = .onHitAbilities + I2S('A03A')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel( .defender, 'A03B' ) if lvl > 0 and not .isRange and UnitMatch(.defender,.attacker,"0010000222000020200" ) and GetRandomInt(1,100) <= 5 + 5 *lvl then set x = GetUnitX(.attacker) set y = GetUnitY(.attacker) call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl",x,y)) set angle = AngleUnitsR(.defender,.attacker) set x = GetPPXR( x, 175+25*lvl , angle ) set y = GetPPYR( y, 175+25*lvl , angle ) call DestroyTreesInCircle( x, y, 100. ) if IsTerrainWalkable(x,y) then call SetUnitX(.attacker,x) call SetUnitY(.attacker,y) else call SetUnitX(.attacker,TerrainPathability_X) call SetUnitY(.attacker,TerrainPathability_Y) endif call UnitDamageUnit(.defender, .attacker, 10+10*lvl, tj_DAMAGE_TYPE_PHYSIC, false, true ) call UnitBuff.ApplySimple( .defender, .attacker, tj_BuffId_Stun, 1, "", 0.25 ) set .interrupted = true endif if GetUnitAbilityLevel(.attacker,'AD0M')>0 then set .onHitAbilities = .onHitAbilities + I2S('AI1M')+":1;" call UnitRemoveAbility(.attacker,'AD0M') call UnitAddAbilityTimed.Do(.attacker,'AD0Q',1,12.,false) set .pass_SparklingSlam = true endif if GetUnitAbilityLevel(.attacker,'AD0L')>0 then call UnitRemoveAbility(.attacker,'AD0L') endif if GetUnitAbilityLevel(.attacker,'B017')>0 then call UnitBuff.RemoveSpecific(null,.attacker,'B017') endif if GetUnitAbilityLevel(.attacker,'B019')>0 then set .onHitAbilities = .onHitAbilities + I2S('B019')+":1;" endif if GetUnitAbilityLevel(.attacker,'AD0Y')>0 then call UnitRemoveAbility(.attacker,'AD0Y') set .pass_LichFrostCannon = true set lvl = GetUnitAbilityLevel(.attacker,'A04D') set .onHitAbilities = .onHitAbilities + I2S('A04D')+":"+I2S(lvl)+";" call CustomCooldown.Start( .attacker, 'A04D',lvl,'AD0R',lvl,30-6*lvl,CustomSpells3_FrostCannon.CooldownDone) endif set lvl = GetUnitAbilityLevel(.attacker,'A04U') if lvl > 0 and GetUnitAbilityLevel(.attacker,'AD1A')==0 then set .pass_SlumberingCane = true set .onHitAbilities = .onHitAbilities + I2S('A04U')+":"+I2S(lvl)+";" call CustomCooldown.Start( .attacker, 'A04U',lvl,'AD1A',lvl,32-6*lvl,0) endif if GetUnitAbilityLevel(.attacker,'AD0V')>0 then call UnitRemoveAbility(.attacker,'AD0V') set .buff_FlamingArrow = true set lvl = GetUnitAbilityLevel(.attacker,'A01R') set .onHitAbilities = .onHitAbilities + I2S('A01R')+":"+I2S(lvl)+";" call UnitAddAbilityDelay.Do(.attacker,'AD0V',1,20-4*lvl,false) endif if GetUnitAbilityLevel(.attacker,'B010')>0 then if UnitMatch(.attacker,.defender,"00000000220000200000") then set .onHitAbilities = .onHitAbilities + I2S('A02X')+":"+I2S(UnitBuff.GetBuffLevel(.attacker,'B010'))+";" set .damageType = 3 endif call UnitBuff.RemoveSpecific(null,.attacker,'B010') endif set lvl = GetUnitAbilityLevel(.attacker,'A03P') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000220000") and GetRandomInt(1,100)<=16 then set .onHitAbilities = .onHitAbilities + I2S('A03P')+":"+I2S(lvl)+";" endif if GetUnitAbilityLevel(.attacker,'B01C')>0 then set UnitData[inx].spellData.crestOfValorAttackCount = UnitData[inx].spellData.crestOfValorAttackCount - 1 if UnitData[inx].spellData.crestOfValorAttackCount==0 then call UnitBuff.RemoveSpecific(null,.attacker,'B01C') endif endif set lvl = GetUnitAbilityLevel(.attacker,'A04O') if lvl > 0 and UnitMatch(.attacker,.defender,"00100002220000200001") and GetRandomInt(1,100)<=5+5*lvl then call CustomSpells3_MindDisruption.execute(.attacker,.defender,lvl) endif if GetUnitAbilityLevel(.attacker,'B01G')>0 then set .onHitAbilities = .onHitAbilities + I2S('A056')+":"+I2S(UnitBuff.GetBuffLevel(.attacker,'B01G'))+";" set UnitData[inx].spellData.earthenEnchantCount = UnitData[inx].spellData.earthenEnchantCount - 1 if UnitData[inx].spellData.earthenEnchantCount==0 then call UnitBuff.RemoveSpecific(null,.attacker,'B01G') endif endif endmethod private method missCheck takes nothing returns nothing local integer inx1=GetUnitId(.attacker) local integer inx2=GetUnitId(.defender) local integer lvl local real evade =0. local real accuracy = UnitData[inx1].atkAccuracy + UnitData[inx1].atkAccuracyNeg local real h = GetLocZ(GetUnitX(.defender),GetUnitY(.defender)) - GetLocZ(GetUnitX(.attacker),GetUnitY(.attacker)) set accuracy = accuracy - RealCond( tj_AttackMissHeight , 0. , (UnitData[inx1].unitConst.atkWeapon == 1 or UnitData[inx1].unitConst.atkWeapon == 2) and h >= 75. ) // evasion abilities check here if GetRandomInt(1,100) <= R2I(100-accuracy) then set .missed=1 else if GetRandomInt(1,100) <= R2I(evade) then set .missed=2 endif endif endmethod static method onDamagePoint takes nothing returns nothing local thistype this = GetTimerData(GetExpiredTimer()) local integer inx=GetUnitId(.attacker) local real x local real y call ReleaseTimer( UnitData[inx].atkSwing ) set UnitData[inx].atkSwinging=false //call BJDebugMsg("hit") if .IsAttackInterrupted() then set UnitData[inx].atkTarget=null set UnitData[inx].atkAttacking=false set UnitData[inx].atkData=0 call .onInterrupt(.attacker) call .destroy() return endif set UnitData[inx].atkData=0 set UnitData[inx].inCombat = tj_InCombatTime set UnitData[GetUnitId(.defender)].inCombat = tj_InCombatTime call .missCheck() call .onAttackCheck() //set .minDamage=GetInflictDamage( .attacker, .defender, false ) //set .maxDamage=GetInflictDamage( .attacker, .defender, true ) //set .weaponSound = UnitData[inx].unitConst.atkWeaponType //call S2UB(.attacker,.onSwingBonus,-1) if .interrupted then call .destroy() return endif if .missed>0 then if .missed==1 then set x = GetUnitX(.attacker) set y = GetUnitY(.attacker) call NewTextTag( "|c00FF0303miss|r",10, x, y,GetUnitFlyHeight(.attacker), 60, 90,3,1,true ) elseif .missed==2 then set x = GetUnitX(.defender) set y = GetUnitY(.defender) call NewTextTag( "|c00007FFFdodge|r",10, x, y,GetUnitFlyHeight(.defender), 60, 90,3,1, true) elseif .missed==3 then if not .evaded then set x = GetUnitX(.defender) set y = GetUnitY(.defender) call NewTextTag( "|c007EBFF1evade|r",10, x, y,GetUnitFlyHeight(.defender), 60, 90,3,1 , true ) else set x = GetUnitX(.attacker) set y = GetUnitY(.attacker) call NewTextTag( "|c007EBFF1miss|r",10, x, y,GetUnitFlyHeight(.defender), 60, 90,3,1 , true ) endif endif endif if UnitData[inx].unitConst.atkWeapon==0 then//--- melee call .onMeleeHit() elseif UnitData[inx].unitConst.atkWeapon==1 then //--- range call .doRangeAttack() elseif UnitData[inx].unitConst.atkWeapon==2 then //--- instant call .onRangeInstantHit() elseif UnitData[inx].unitConst.atkWeapon==3 then //--- bounce call .doBounceAttack() endif endmethod private method CheckCriticalHit takes nothing returns nothing local integer inx = GetUnitId(.attacker) local real crit = 1. local integer lvl local integer ran = GetRandomInt(1,100) local boolean btmp set lvl = GetUnitAbilityLevel(.attacker,'AN0T') if lvl > 0 and GetRandomInt(1,100)<=15+5*lvl then set crit = 1.8+0.2*lvl endif set lvl = GetUnitAbilityLevel(.attacker,'AN0V') set btmp = (lvl<3) if lvl > 0 and GetRandomInt(1,100)<=IntCond( 5+5*lvl, 5*lvl, btmp ) then set crit = RealCond(1.5,2.,btmp) endif if GetUnitAbilityLevel(.attacker,'AD0L') > 0 then set crit = 1.75 endif if GetUnitAbilityLevel(.attacker,'B017') > 0 then set crit = 2.25 endif if GetUnitAbilityLevel(.attacker,'AI21') > 0 and GetRandomInt(1,100)<=20 then set crit = 2.25 endif set .criticalHit = crit endmethod private method onSwingCheck takes nothing returns boolean local integer inx=GetUnitId(.attacker) local boolean ally = IsUnitAlly(.defender, GetOwningPlayer(.attacker)) local boolean structure = IsUnitType(.defender, UNIT_TYPE_STRUCTURE) local boolean elite = IsUnitTypeElite(.defender) local boolean champ = IsUnitTypeChampion(.defender) local integer lvl local real r local boolean immune = IsUnitType(.defender,UNIT_TYPE_MAGIC_IMMUNE) local boolean doslam = false if GetUnitAbilityLevel(.defender,'BN1Q')>0 and GetUnitAbilityLevel(.attacker,'A04W')==0 and CustomSpells3_Nightmare.Rebound(.attacker,.defender) then return true endif set lvl = GetUnitAbilityLevel(.attacker,'AN00') if lvl > 0 and GetRandomInt(1,100)<=R2I(12.5+2.5*lvl) and UnitMatch(.attacker,.defender,"00100002200000200000") then set .onHitAbilities = .onHitAbilities + I2S('AN00')+":"+I2S(lvl)+";" set doslam = true endif set lvl = GetUnitAbilityLevel(.attacker,'AN01') if lvl > 0 and GetRandomInt(1,100)<=18+2*lvl then set .onHitAbilities = .onHitAbilities + I2S('AN01')+":"+I2S(lvl)+";" call SetUnitAnimation(.attacker,"Attack Slam") call QueueUnitAnimation(.attacker, "Stand Ready") endif set lvl = GetUnitAbilityLevel(.attacker,'A02N') if lvl > 0 and UnitMatch(.attacker,.defender,"00000000200000200000") and GetRandomInt(1,100)<=10+5*lvl then set .onHitAbilities = .onHitAbilities + I2S('A02N')+":"+I2S(lvl)+";" set doslam = true endif if UnitData[inx].spellData.phantomWalkHit > 0 then set .phantom_walk_damage = 175 set UnitData[inx].spellData.phantomWalkHit = 0 set .onSwingBonus = .onSwingBonus+"atbn_"+I2S(.phantom_walk_damage)+"_0_0;" set doslam = true endif if GetUnitAbilityLevel(.attacker,'AI28')>0 and GetUnitAbilityLevel(.attacker,'AD0S')==0 and GetRandomInt(1,100)<=IntCond(10,25,.isRange) then set doslam = true set .pass_StunningBlow = true set .onHitAbilities = .onHitAbilities + I2S('AI28')+":1;" endif call .CheckCriticalHit() set doslam = doslam or (.criticalHit > 1) if doslam and GetUnitAbilityLevel(.attacker,'AItg')==0 then call SetUnitAnimation(.attacker,"Attack Slam"+UnitData[inx].animTag) call QueueUnitAnimation(.attacker, "Stand"+UnitData[inx].animTag+" Ready") endif //----- set lvl = GetUnitAbilityLevel(.attacker,'AN0A') if lvl > 0 then set .onHitAbilities = .onHitAbilities + I2S('AN0A')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'AN0Q') if lvl > 0 and not structure and not IsUnitType(.defender,UNIT_TYPE_ETHEREAL) and not IsUnitType(.defender,UNIT_TYPE_MECHANICAL) then set .onHitAbilities = .onHitAbilities + I2S('AN0Q')+":"+I2S(lvl)+";" endif if GetUnitAbilityLevel(.attacker,'Aif5') > 0 and not structure and not immune then set .onHitAbilities = .onHitAbilities + I2S('Aif5')+":1;" endif if GetUnitAbilityLevel(.attacker,'Aif6') > 0 and not structure and not immune then set .onHitAbilities = .onHitAbilities + I2S('Aif6')+":1;" endif if GetUnitAbilityLevel(.attacker,'Aif7') > 0 and not structure and not immune then set .onHitAbilities = .onHitAbilities + I2S('Aif7')+":1;" endif if GetUnitAbilityLevel(.attacker,'Aifa') > 0 and not structure and not immune then set .onHitAbilities = .onHitAbilities + I2S('Aifa')+":1;" endif set lvl = GetUnitAbilityLevel(.attacker,'A00U') if lvl > 0 and not structure and not IsUnitType(.defender,UNIT_TYPE_MAGIC_IMMUNE) then set .onHitAbilities = .onHitAbilities + I2S('A00U')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A00W') if lvl > 0 and not structure and not IsUnitType(.defender,UNIT_TYPE_MAGIC_IMMUNE) and GetRandomInt(1,100)<=5+5*lvl then set .onHitAbilities = .onHitAbilities + I2S('A00W')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A011') if lvl > 0 and UnitMatch(.attacker,.defender,"00000000220000202001") then set .onHitAbilities = .onHitAbilities + I2S('A011')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A01A') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000202000") and GetRandomInt(1,100)<=5+5*lvl then set .onSwingBonus = .onSwingBonus+"atbn_"+I2S(20+10*lvl)+"_0_0;" set .onHitAbilities = .onHitAbilities + I2S('A01A')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A01I') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000202000") and GetRandomInt(1,100)<=16 then set .onSwingBonus = .onSwingBonus+"atsh_"+I2S(20+10*lvl)+"_0_0;" set .onHitAbilities = .onHitAbilities + I2S('A01I')+":"+I2S(lvl)+";" set .pass_ChillingTouch = true endif set lvl = GetUnitAbilityLevel(.attacker,'AI12') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000200001") and GetRandomInt(1,100)<=15 then set .onHitAbilities = .onHitAbilities + I2S('AI12')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A027') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000202000") and GetRandomInt(1,100)<=20 then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl",.attacker,"weapon")) set .onSwingBonus = .onSwingBonus+"atbn_"+I2S(20+20*lvl)+"_0_0;" endif if UnitData[inx].spellData.chronoWalkDmg > 0 then set .chrono_walk_damage = UnitData[inx].spellData.chronoWalkDmg set UnitData[inx].spellData.chronoWalkDmg = 0 set .onSwingBonus = .onSwingBonus+"atbn_"+I2S(.chrono_walk_damage)+"_0_0;" endif set lvl = GetUnitAbilityLevel(.attacker,'A02G') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002202000200000") then set .onHitAbilities = .onHitAbilities + I2S('A02G')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A02W') if lvl > 0 and UnitMatch(.attacker,.defender,"00000002200000200000") then set .onHitAbilities = .onHitAbilities + I2S('A02W')+":"+I2S(lvl)+";" endif set lvl = GetUnitAbilityLevel(.attacker,'A039') if lvl > 0 and UnitMatch(.attacker,.defender,"00000000220000202001") then set .onHitAbilities = .onHitAbilities + I2S('A039')+":"+I2S(lvl)+";" endif //----- call S2UB(.attacker,.onSwingBonus,1) return false endmethod private method doSwing takes nothing returns nothing local integer inx=GetUnitId(.attacker) set UnitData[inx].atkData=this if .onSwingCheck() then return endif set .animationAttack=UnitData[inx].unitConst.atkPoint set UnitData[inx].atkSwinging=true set UnitData[inx].atkTarget=.defender set UnitData[inx].atkOrder=GetUnitCurrentOrder(.attacker) set .swingDuration=.animationAttack/(1+UnitData[inx].atkSpeedCur/100) + 0.01 set .attackerX=GetUnitX(.attacker) set .attackerY=GetUnitY(.attacker) set UnitData[inx].atkSwing=NewTimer() call SetTimerData(UnitData[inx].atkSwing, this ) call TimerStart( UnitData[inx].atkSwing, .swingDuration, false, function thistype.onDamagePoint ) //call BJDebugMsg("swing "+R2S(.swingDuration)) //if IsUnitType(.attacker,UNIT_TYPE_HERO) then // set .debug_time = TimerGetElapsed(POLLEDWAIT) //endif endmethod static method create takes unit atk, unit def returns thistype local thistype this = thistype.allocate() call thistype.onInterrupt(atk) set .attacker=atk set .defender=def set .isRange=(not IsUnitType(.attacker,UNIT_TYPE_MELEE_ATTACKER)) //call BJDebugMsg(" ") //call BJDebugMsg("attack") call .doSwing() return this endmethod endstruct private function AttackDetect takes nothing returns nothing local unit c = GetAttacker() local unit a = GetTriggerUnit() local integer inx if GetUnitAbilityLevel(c,'Aloc') > 0 then call CustomSpells2_LocustSwarmAttack.execute(c,a) // for Locust Swarm spells set c = null set a = null return endif call CustomAttack.create( c,a) set c = null set a = null endfunction private function Init takes nothing returns nothing local trigger t local integer index set t = CreateTrigger() set index = 0 loop call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null) set index = index + 1 exitwhen index == 16 endloop call TriggerAddAction( t, function AttackDetect ) endfunction endlibrary please see the function onAttackCheck, this function is ran whenever a unit attacks and finishes its "damage point" animation. There highlighted code is the "EventCheck" thing in the first post below in onSwingCheck, there are the similar code highlighted as well. the code works as the following: a unit is attacked -> onSwingCheck -> Swing --- (finish damage point) ---> onAttackCheck ---> ... (others)onSwingCheck is called from action of a trigger onAttackCheck is called from "callback function" of a one-short timer the above code is the first method mentioned in first post, I'm planing to rewrite it follow the second method but I'm not sure if it's more efficient. tell me if you need any other info also, is this function too heavy: JASS:function UnitMatch takes unit c, unit f, string fil returns boolean local integer i = 0 local integer array ch local boolean ok = true local integer inx local player p if fil=="" then return true endif if GetUnitAbilityLevel(f,tj_IgnoredUnit)>0 then return false endif set inx = GetUnitId(f) set p = GetOwningPlayer(c) loop exitwhen i == 20 set ch[i] = S2I(SubString(fil,i,i+1)) set i = i + 1 endloop if ch[0]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_GROUND)==(ch[0]==1) endif if ch[1]!=0 then set ok = ok and UnitAlive(f)==(ch[1]==1) endif if ch[2]!=0 then if ch[2] < 3 then set ok = ok and IsUnitEnemy(f,p)==(ch[2]==1) else set ok = ok and GetOwningPlayer(f)==p endif endif if ch[3]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_MELEE_ATTACKER)==(ch[3]==1) endif if ch[4]!=0 then if ch[4]==3 then set ok = ok and IsUnitType(f,UNIT_TYPE_HERO)==true else set ok = ok and UnitData[inx].isHero==(ch[4]==1) endif endif if ch[5]!=0 then set ok = ok and IsUnitTypeChampion(f)==(ch[5]==1) endif if ch[6]!=0 then set ok = ok and IsUnitTypeElite(f)==(ch[6]==1) endif if ch[7]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_MECHANICAL)==(ch[7]==1) endif if ch[8]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_STRUCTURE)==(ch[8]==1) endif if ch[9]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_MAGIC_IMMUNE)==(ch[9]==1) endif if ch[10]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_ETHEREAL)==(ch[10]==1) endif if ch[11]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_POLYMORPHED)==(ch[11]==1) endif if ch[12]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_SNARED)==(ch[12]==1) endif if ch[13]!=0 then set ok = ok and IsUnitType(f,UNIT_TYPE_SLEEPING)==(ch[13]==1) endif if ch[14]!=0 then set ok = ok and (GetUnitAbilityLevel(f,tj_IsWardCheck)>0)==(ch[14]==1) endif if ch[15]!=0 then set ok = ok and IsUnitIllusion(f)==(ch[15]==1) endif if ch[16]!=0 then set ok = ok and IsUnitInvulnerable(f)==(ch[16]==1) endif if ch[17]!=0 then set ok = ok and IsUnitVisibleEx(f,p)==(ch[17]==1) endif if ch[18]!=0 then set ok = ok and (IsUnitFogged(f,p) or IsUnitMasked(f,p))!=(ch[18]==1) endif if ch[19]!=0 then set ok = ok and (GetUnitState(f,UNIT_STATE_MAX_MANA)>0)==(ch[19]==1) endif return ok endfunction thanks for reading! |
| 03-13-2011, 12:01 AM | #6 |
Hardcoding all the effects from various abilities into one trigger like that is not a very good way of organizing your code. Each ability should have all the ability-specific code in its own library or scope. Furthermore, checking for all abilities one each event is inefficient; checking for all abilities that were picked isn't much better, you'll have fewer checks but each one will need a trigger evaluate. You will need to use evaluates anyway if you want to move the spell specific code to separate libraries like mentioned above, but there's a better way to do this: simply keep a list of picked abilities on a per-unit basis. This way, you will only do a check if the unit has the ability, so you don't even need to check, just do an .evaluate on the ability's event function. Libraries that allow you to efficiently maintain a list of structs on a per-unit basis already exist, I recommend AutoIndex with its AutoData feature. There's also ABuff which is a bit more high-level and already contains code for handling attack and damage events, which seem like they should correspond with your onSwingCheck and onAttackCheck events. |
| 03-13-2011, 01:09 AM | #7 |
thanks, I will now reorganize my code ![]() I have already used AutoIndex but haven't used AutoData, I will look into it and ABuff ![]() |
