| 10-26-2009, 03:28 AM | #1 |
AttackEvents provides several attack-related events, as well as the capability for dynamic evasion. In other words, specific attacks can be made to miss, without any chance of other attacks being affected. However, your map must abide by several limitations for it to work properly:
Two addon libraries have been provided, AttackChance and AttackRatings, which provide completely different APIs for managing units' hit and evasion chances. You can also use AttackEvents to build your own API. Both AttackChance and AttackEvents can optionally use GetProc to normalize hit/miss streaks. I imagine that most people will want to use AttackChance, since it is easier to understand and matches the way evasion traditionally works. AttackRatings is a completely different approach that treats evasion as a "rating" granting the unit a linear time-to-live increase with each additional point, which is the same way WC3's armor system works. AttackEvents: requires TimerUtils, optionally requires BonusMod, AutoIndex and AbilityPreload JASS:library AttackEvents requires TimerUtils, optional BonusMod, optional AutoIndex, optional AbilityPreload //=========================================================================== // Information: //============== // // AttackEvents provides several attack-related events, as well as the cap- // ability for dynamic evasion. In other words, specific attacks can be made to // miss, without any chance of other attacks being affected. However, your map // must abide by several limitations for it to work properly. The limitations // are explained in the "How to use AttackMiss" section. // // Two addon libraries have been provided, AttackChance and AttackRatings, // which provide completely different APIs for managing units' hit and evasion // chances. You can also use AttackEvents to build your own API. // //=========================================================================== // How to install AttackEvents: //============================== // // 1.) Copy and paste this script into your map. // 2.) Save it to allow the ObjectMerger macro to generate the "AttackMiss" // ability for you. Close and re-open the map. After that, disable the // macro to prevent the save delay. // //=========================================================================== // How to use AttackMiss: //======================== // // Limitations: // -You must specify the damage point of all custom unit-types. You will re- // cieve an error message in debug mode if you forgot to specify one. // // -If you edit the damage point of an existing unit-type, you must call // SetUnitTypeDamagePoint(unitid, damagepoint) to correct it. // // -If you change the AgiAttackSpeedBonus gameplay constant, you must edit // the AgiAttackSpeedBonus configuration constant to the same value. // // -You cannot use any abilities, auras or items that alter the attack speed // of units, unless those attack speed changes are triggered using BonusMod. // // -You can still use standard evasion abilities, but OnUnitAttackHit may // fire when the attack actually missed. // // -If a unit has two attacks enabled, those attacks should have identical // damage points. If they do not, AttackMiss will only work for one of the // attacks. Certain units' secondary attacks may not be evadable by default. // // -Units that cannot have active abilities (such as illusions) cannot // dodge attacks or have attacks made against them miss. // // Below is an example of how to make an attack miss: // // function ApplyMissChance takes unit attacker, unit attacked returns nothing // if GetRandomReal(0., 1.) >= HitChance(attacker, attacked) then // call AttackMiss() //If attack miss is called, the attack will miss. // endif //Only works during an AttackDamagePoint event. // endfunction // // function OnInit takes nothing returns nothing // call OnUnitAttackDamagePoint(ApplyMissChance) // //This causes ApplyMissChance to run at the damage point of any attack. // endfunction // // AttackMiss optionally requires AutoIndex and AbilityPreload. If Auto- // Index is in your map script, certain operations will become slightly faster. // If AbilityPreload is in your map script, a slight delay the first time the // an attack misses will be prevented. // //=========================================================================== // AttackMiss API: //================= // // SetUnitTypeDamagePoint(unitid, damagepoint) // This function assigns a damage point for a unit-type. You must specify // the damage point of all custom unit-types in your map, or any that you // alter from default values. In debug mode, an error message will be dis- // played if you forgot to assign a damage point to a unit-type. // // GetUnitAttackSpeedFactor(unit) -> real // Returns the actual factor applied to the attack duration of the specified // unit. For example, if it returned 0.5, the length of the unit's attack // animation has been cut in half. // // GetUnitAttackTarget(unit) -> unit // Returns the unit that the specified unit is currently attacking. // Returns null if the unit currently has no attack target. // // AttackMiss() // If this is called at least once during an OnUnitAttackDamagePoint event, // that attack will miss. Does not work with any other event. // // Each of the below functions take an AttackFunc. To be used as an Attack- // Func, a function must take two units and returns nothing. The first unit is // the attacker, and the second unit is the attacked unit. The AttackFunc passed // to the function will be run when the corresponding event occurs. // // OnUnitAttackEngage(AttackFunc) // This event fires when a unit engages a target with its attack. In other // words, it fires when the first attack against a new target begins. It // will not fire again until the unit recieves a new order. // // OnUnitAttackDisengage(AttackFunc) // This event fires when a unit stops attacking its target. // // OnUnitAttack(AttackFunc) // This event fires each time a unit begins to swing at its target. It is the // same as EVENT_PLAYED_UNIT_ATTACKED, but it is included for consistency. // // OnUnitAttackDamagePoint(AttackFunc) // This event fires at the damage point of an attack. This is the only event // during which AttackMiss() can be used to make the attack miss. // // OnUnitAttackHit(AttackFunc) // This event fires when an attack hits the target, but before damage has // been dealt. If the attacked unit has a chance to dodge from an actual // skill, the attack may still miss. // // OnUnitAttackMiss(AttackFunc) // This event fires when an attack misses the target. Doesn't fire if the // reason the attack missed was an actual evasion skill. // //=========================================================================== // Configuration: //================ //! external ObjectMerger w3a AEev miss anam "AttackMiss" aart "" Eev1 1 1. aher 0 alev 1 arac 1 //Save your map with this Object Merger call enabled, then close and reopen your //map. Disable it by removing the exclamation to remove the delay while saving. globals private constant integer AttackMissAbilityID = 'miss' //This rawcode must match the parameter after "Adef" in the //ObjectMergermacro above. You can change both if you want. private constant real AgiAttackSpeedBonus = 0.02 //Make sure this matches the AgiAttackSpeedBonus gameplay constant. endglobals //=========================================================================== // User functions: //================= private keyword Attack function SetUnitTypeDamagePoint takes integer unitid, real damagepoint returns nothing call Attack.setUnitTypeDamagePoint(unitid, damagepoint) endfunction function GetUnitAttackSpeedFactor takes unit u returns real return Attack.getUnitAttackSpeedFactor(u) endfunction function AttackMiss takes nothing returns nothing call Attack.miss() endfunction function GetUnitAttackTarget takes unit u returns unit return Attack.getUnitAttackTarget(u) endfunction function interface AttackFunc takes unit attacker, unit attacked returns nothing function OnUnitAttackEngage takes AttackFunc func returns nothing call Attack.onUnitAttackEngage(func) endfunction function OnUnitAttackDisengage takes AttackFunc func returns nothing call Attack.onUnitAttackDisengage(func) endfunction function OnUnitAttack takes AttackFunc func returns nothing call Attack.onUnitAttack(func) endfunction function OnUnitAttackDamagePoint takes AttackFunc func returns nothing call Attack.onUnitAttackDamagePoint(func) endfunction function OnUnitAttackHit takes AttackFunc func returns nothing call Attack.onUnitAttackHit(func) endfunction function OnUnitAttackMiss takes AttackFunc func returns nothing call Attack.onUnitAttackMiss(func) endfunction //=========================================================================== private struct Attack private static hashtable ht = InitHashtable() private static Attack array attacks private static unit array attacking private static key DamagePoint private static key AttackSpeed private static key UnitAttack private static key UnitAttacking private static boolean hit private unit attacker private unit attacked private timer t //=========================================================================== //! textmacro AttackEvent takes EVENT private static AttackFunc array $EVENT$funcs private static integer $EVENT$funcs_n = -1 static method onUnit$EVENT$ takes AttackFunc func returns nothing set $EVENT$funcs_n = $EVENT$funcs_n + 1 set $EVENT$funcs[$EVENT$funcs_n] = func endmethod //! endtextmacro //! runtextmacro AttackEvent("AttackEngage") //! runtextmacro AttackEvent("AttackDisengage") //! runtextmacro AttackEvent("Attack") //! runtextmacro AttackEvent("AttackDamagePoint") //! runtextmacro AttackEvent("AttackHit") //! runtextmacro AttackEvent("AttackMiss") //! textmacro RunAttackEvent takes EVENT set n = 0 loop exitwhen n > $EVENT$funcs_n call $EVENT$funcs[n].evaluate(attacker, attacked) set n = n + 1 endloop //! endtextmacro //=========================================================================== private static method operator []= takes unit u, Attack a returns nothing if LIBRARY_AutoIndex then set attacks[GetUnitId(u)] = a else call SaveInteger(ht, UnitAttack, GetHandleId(u), a) endif endmethod private static method operator [] takes unit u returns Attack if LIBRARY_AutoIndex then return attacks[GetUnitId(u)] else return LoadInteger(ht, UnitAttack, GetHandleId(u)) endif endmethod private static method setUnitAttackTarget takes unit u, unit target returns nothing if LIBRARY_AutoIndex then set attacking[GetUnitId(u)] = target else call SaveUnitHandle(ht, UnitAttacking, GetHandleId(u), target) endif endmethod static method getUnitAttackTarget takes unit u returns unit if LIBRARY_AutoIndex then return attacking[GetUnitId(u)] else return LoadUnitHandle(ht, UnitAttacking, GetHandleId(u)) endif endmethod static method setUnitTypeDamagePoint takes integer unitid, real damagepoint returns nothing call SaveReal(ht, DamagePoint, unitid, damagepoint) endmethod private static method getUnitTypeDamagePoint takes integer unitid returns real if DEBUG_MODE then if not HaveSavedReal(ht, DamagePoint, unitid) then call BJDebugMsg("AttackMiss error: No damage point has been specified for unit-type "+GetObjectName(unitid)+".") endif endif return LoadReal(ht, DamagePoint, unitid) endmethod //=========================================================================== private static method getUnitAttackSpeedModifier takes unit u returns real static if LIBRARY_BonusMod then return GetUnitBonus(u, BONUS_ATTACK_SPEED)*0.01 else return 0. endif endmethod static method getUnitAttackSpeedFactor takes unit u returns real local real r = GetHeroAgi(u, true)*AgiAttackSpeedBonus + getUnitAttackSpeedModifier(u) if r < -0.8 then set r = -0.8 elseif r > 4. then set r = 4. endif return (1. / (1. + r)) endmethod private static method getUnitDamagePoint takes unit u returns real return getUnitAttackSpeedFactor(u) * getUnitTypeDamagePoint(GetUnitTypeId(u)) endmethod //=========================================================================== private method onDestroy takes nothing returns nothing call ReleaseTimer(t) set Attack[attacker] = 0 set attacker = null set attacked = null endmethod private static method removeMiss takes nothing returns nothing local Attack this = GetTimerData(GetExpiredTimer()) call UnitRemoveAbility(attacked, AttackMissAbilityID) call destroy() endmethod static method miss takes nothing returns nothing set hit = false endmethod private static method onDamagePoint takes nothing returns nothing local Attack this = GetTimerData(GetExpiredTimer()) local integer n set hit = true //! runtextmacro RunAttackEvent("AttackDamagePoint") if hit then //! runtextmacro RunAttackEvent("AttackHit") call destroy() else //! runtextmacro RunAttackEvent("AttackMiss") call UnitAddAbility(attacked, AttackMissAbilityID) call TimerStart(t, 0., false, function Attack.removeMiss) endif endmethod private static method onAttackStart takes nothing returns boolean local Attack this = allocate() local integer n set attacker = GetAttacker() set attacked = GetTriggerUnit() if getUnitAttackTarget(attacker) != attacked then call setUnitAttackTarget(attacker, attacked) //! runtextmacro RunAttackEvent("AttackEngage") endif set Attack[attacker] = this set t = NewTimer() call SetTimerData(t, this) call TimerStart(t, getUnitDamagePoint(GetAttacker()), false, function Attack.onDamagePoint) //! runtextmacro RunAttackEvent("Attack") return false endmethod private static method onAttackStop takes nothing returns nothing local unit attacker = GetTriggerUnit() local unit attacked = getUnitAttackTarget(GetTriggerUnit()) local Attack this = Attack[attacker] local integer n //! runtextmacro RunAttackEvent("AttackDisengage") if this != 0 then call destroy() endif call setUnitAttackTarget(attacker, null) set attacker = null set attacked = null endmethod private static method onAttackStopCondition takes nothing returns boolean static if LIBRARY_AutoIndex then return IsUnitIndexed(GetTriggerUnit()) and getUnitAttackTarget(GetTriggerUnit()) != null else return getUnitAttackTarget(GetTriggerUnit()) != null endif endmethod //=========================================================================== private static method onInit takes nothing returns nothing local trigger attack = CreateTrigger() local trigger order = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(attack, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddCondition(attack, function Attack.onAttackStart) call TriggerRegisterAnyUnitEventBJ(order, EVENT_PLAYER_UNIT_ISSUED_ORDER) call TriggerRegisterAnyUnitEventBJ(order, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER) call TriggerRegisterAnyUnitEventBJ(order, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER) call TriggerAddCondition(order, function Attack.onAttackStopCondition) call TriggerAddAction(order, function Attack.onAttackStop) static if LIBRARY_AbilityPreload then call AbilityPreload('miss') endif call initDamagePoints() endmethod //=========================================================================== private static method initDamagePoints takes nothing returns nothing call SetUnitTypeDamagePoint('Hamg', .55) call SetUnitTypeDamagePoint('Hblm', .55) call SetUnitTypeDamagePoint('Hmkg', .35) call SetUnitTypeDamagePoint('Hpal', .433) call SetUnitTypeDamagePoint('hbsh', .3) call SetUnitTypeDamagePoint('hdes', .3) call SetUnitTypeDamagePoint('hdhw', .43) call SetUnitTypeDamagePoint('hfoo', .5) call SetUnitTypeDamagePoint('hgry', .8) call SetUnitTypeDamagePoint('hgyr', .03) call SetUnitTypeDamagePoint('hkni', .66) call SetUnitTypeDamagePoint('hmil', .39) call SetUnitTypeDamagePoint('hmpr', .59) call SetUnitTypeDamagePoint('hmtm', 1.) call SetUnitTypeDamagePoint('hmtt', .5) call SetUnitTypeDamagePoint('hpea', .433) call SetUnitTypeDamagePoint('hphx', .43) call SetUnitTypeDamagePoint('hrif', .17) call SetUnitTypeDamagePoint('hrtt', .5) call SetUnitTypeDamagePoint('hsor', .75) call SetUnitTypeDamagePoint('hspt', .5) call SetUnitTypeDamagePoint('hwat', .4) call SetUnitTypeDamagePoint('hwt2', .4) call SetUnitTypeDamagePoint('hwt3', .4) call SetUnitTypeDamagePoint('hatw', .3) call SetUnitTypeDamagePoint('hctw', .3) call SetUnitTypeDamagePoint('hgtw', .3) call SetUnitTypeDamagePoint('Obla', .33) call SetUnitTypeDamagePoint('Ofar', .3) call SetUnitTypeDamagePoint('Oshd', .3) call SetUnitTypeDamagePoint('Otch', .36) call SetUnitTypeDamagePoint('ocat', .1) call SetUnitTypeDamagePoint('odes', .3) call SetUnitTypeDamagePoint('odoc', .73) call SetUnitTypeDamagePoint('ogru', .33) call SetUnitTypeDamagePoint('ohun', .31) call SetUnitTypeDamagePoint('okod', .85) call SetUnitTypeDamagePoint('opeo', .5) call SetUnitTypeDamagePoint('orai', .5) call SetUnitTypeDamagePoint('oshm', .43) call SetUnitTypeDamagePoint('osp1', .3) call SetUnitTypeDamagePoint('osp2', .3) call SetUnitTypeDamagePoint('osp3', .3) call SetUnitTypeDamagePoint('osp4', .3) call SetUnitTypeDamagePoint('ospw', .5) call SetUnitTypeDamagePoint('osw1', .33) call SetUnitTypeDamagePoint('osw2', .33) call SetUnitTypeDamagePoint('osw3', .33) call SetUnitTypeDamagePoint('otau', .467) call SetUnitTypeDamagePoint('otbk', .31) call SetUnitTypeDamagePoint('otbr', .6) call SetUnitTypeDamagePoint('owyv', .6) call SetUnitTypeDamagePoint('otrb', .3) call SetUnitTypeDamagePoint('owtw', .3) call SetUnitTypeDamagePoint('Edem', .3) call SetUnitTypeDamagePoint('Edmm', .26) call SetUnitTypeDamagePoint('Ekee', .4) call SetUnitTypeDamagePoint('Emoo', .3) call SetUnitTypeDamagePoint('Ewar', .3) call SetUnitTypeDamagePoint('earc', .72) call SetUnitTypeDamagePoint('ebal', .1) call SetUnitTypeDamagePoint('ebsh', .3) call SetUnitTypeDamagePoint('echm', .7) call SetUnitTypeDamagePoint('edcm', .5) call SetUnitTypeDamagePoint('edes', .3) call SetUnitTypeDamagePoint('edoc', .33) call SetUnitTypeDamagePoint('edot', .5) call SetUnitTypeDamagePoint('edry', .3) call SetUnitTypeDamagePoint('edtm', .6) call SetUnitTypeDamagePoint('efdr', .5) call SetUnitTypeDamagePoint('efon', .467) call SetUnitTypeDamagePoint('ehip', .6) call SetUnitTypeDamagePoint('ehpr', .633) call SetUnitTypeDamagePoint('emtg', .49) call SetUnitTypeDamagePoint('esen', .46) call SetUnitTypeDamagePoint('espv', .33) call SetUnitTypeDamagePoint('even', .33) call SetUnitTypeDamagePoint('eaoe', .5) call SetUnitTypeDamagePoint('eaom', .59) call SetUnitTypeDamagePoint('eaow', .5) call SetUnitTypeDamagePoint('eden', .5) call SetUnitTypeDamagePoint('etoa', .4) call SetUnitTypeDamagePoint('etoe', .4) call SetUnitTypeDamagePoint('etol', .4) call SetUnitTypeDamagePoint('etrp', .4) call SetUnitTypeDamagePoint('Ucrl', .46) call SetUnitTypeDamagePoint('Udea', .56) call SetUnitTypeDamagePoint('Udre', .55) call SetUnitTypeDamagePoint('Ulic', .46) call SetUnitTypeDamagePoint('uabo', .5) call SetUnitTypeDamagePoint('uaco', .4) call SetUnitTypeDamagePoint('uban', .56) call SetUnitTypeDamagePoint('ubsp', .633) call SetUnitTypeDamagePoint('ucry', .64) call SetUnitTypeDamagePoint('ucs1', .33) call SetUnitTypeDamagePoint('ucs2', .33) call SetUnitTypeDamagePoint('ucs3', .33) call SetUnitTypeDamagePoint('ufro', .5) call SetUnitTypeDamagePoint('ugar', .33) call SetUnitTypeDamagePoint('ugho', .39) call SetUnitTypeDamagePoint('umtw', .7) call SetUnitTypeDamagePoint('unec', .53) call SetUnitTypeDamagePoint('uobs', .53) call SetUnitTypeDamagePoint('uske', .56) call SetUnitTypeDamagePoint('uskm', .5) call SetUnitTypeDamagePoint('uubs', .3) call SetUnitTypeDamagePoint('unp1', .3) call SetUnitTypeDamagePoint('unp2', .3) call SetUnitTypeDamagePoint('uzg1', .5) call SetUnitTypeDamagePoint('uzg2', .5) call SetUnitTypeDamagePoint('Nbrn', .7) call SetUnitTypeDamagePoint('Nbst', .3) call SetUnitTypeDamagePoint('nnht', .4) call SetUnitTypeDamagePoint('npfl', .4) call SetUnitTypeDamagePoint('ndr1', .56) call SetUnitTypeDamagePoint('ndr2', .56) call SetUnitTypeDamagePoint('ndr3', .56) call SetUnitTypeDamagePoint('ngz1', .63) call SetUnitTypeDamagePoint('ngz2', .63) call SetUnitTypeDamagePoint('ngz3', .63) call SetUnitTypeDamagePoint('ngzc', .63) call SetUnitTypeDamagePoint('ngzd', .63) call SetUnitTypeDamagePoint('ngza', .63) call SetUnitTypeDamagePoint('ngz4', .63) call SetUnitTypeDamagePoint('npn1', .3) call SetUnitTypeDamagePoint('npn2', .4) call SetUnitTypeDamagePoint('npn3', .3) call SetUnitTypeDamagePoint('npn4', .3) call SetUnitTypeDamagePoint('npn5', .4) call SetUnitTypeDamagePoint('npn6', .3) call SetUnitTypeDamagePoint('nqb2', .5) call SetUnitTypeDamagePoint('nqb3', .633) call SetUnitTypeDamagePoint('nqb4', .633) call SetUnitTypeDamagePoint('nqbh', .6) call SetUnitTypeDamagePoint('nwe2', .5) call SetUnitTypeDamagePoint('nwe3', .5) call SetUnitTypeDamagePoint('nadk', .94) call SetUnitTypeDamagePoint('nadr', .94) call SetUnitTypeDamagePoint('nadw', .94) call SetUnitTypeDamagePoint('nahy', .7) call SetUnitTypeDamagePoint('nanb', .53) call SetUnitTypeDamagePoint('nanm', .53) call SetUnitTypeDamagePoint('nanc', .53) call SetUnitTypeDamagePoint('nane', .53) call SetUnitTypeDamagePoint('nano', .53) call SetUnitTypeDamagePoint('nanw', .53) call SetUnitTypeDamagePoint('narg', .3) call SetUnitTypeDamagePoint('nass', .3) call SetUnitTypeDamagePoint('nbal', .5) call SetUnitTypeDamagePoint('nba2', .5) call SetUnitTypeDamagePoint('nban', .3) call SetUnitTypeDamagePoint('nbda', .83) call SetUnitTypeDamagePoint('nbdk', .94) call SetUnitTypeDamagePoint('nbdm', .83) call SetUnitTypeDamagePoint('nbdo', .83) call SetUnitTypeDamagePoint('nbdr', .94) call SetUnitTypeDamagePoint('nbds', .83) call SetUnitTypeDamagePoint('nbdw', .83) call SetUnitTypeDamagePoint('nbld', .5) call SetUnitTypeDamagePoint('nbrg', .3) call SetUnitTypeDamagePoint('nbwm', .94) call SetUnitTypeDamagePoint('nbzd', .94) call SetUnitTypeDamagePoint('nbzk', .94) call SetUnitTypeDamagePoint('nbzw', .94) call SetUnitTypeDamagePoint('ncea', .3) call SetUnitTypeDamagePoint('ncen', .5) call SetUnitTypeDamagePoint('ncer', .5) call SetUnitTypeDamagePoint('ncfs', .38) call SetUnitTypeDamagePoint('ncim', .3) call SetUnitTypeDamagePoint('ncks', .3) call SetUnitTypeDamagePoint('ncnk', .3) call SetUnitTypeDamagePoint('ndqn', .33) call SetUnitTypeDamagePoint('ndqp', .33) call SetUnitTypeDamagePoint('ndqs', .33) call SetUnitTypeDamagePoint('ndqt', .33) call SetUnitTypeDamagePoint('ndqv', .33) call SetUnitTypeDamagePoint('ndrv', .6) call SetUnitTypeDamagePoint('ndtb', .3) call SetUnitTypeDamagePoint('ndth', .3) call SetUnitTypeDamagePoint('ndtp', .3) call SetUnitTypeDamagePoint('ndtr', .3) call SetUnitTypeDamagePoint('ndtt', .3) call SetUnitTypeDamagePoint('ndtw', .3) call SetUnitTypeDamagePoint('nehy', .7) call SetUnitTypeDamagePoint('nelb', .4) call SetUnitTypeDamagePoint('nele', .4) call SetUnitTypeDamagePoint('nenc', .467) call SetUnitTypeDamagePoint('nenf', .3) call SetUnitTypeDamagePoint('nenp', .467) call SetUnitTypeDamagePoint('nepl', .467) call SetUnitTypeDamagePoint('nerd', .5) call SetUnitTypeDamagePoint('ners', .5) call SetUnitTypeDamagePoint('nerw', .5) call SetUnitTypeDamagePoint('nfel', .4) call SetUnitTypeDamagePoint('nfgb', .4) call SetUnitTypeDamagePoint('nfgo', .26) call SetUnitTypeDamagePoint('nfgt', .6) call SetUnitTypeDamagePoint('nfgu', .4) call SetUnitTypeDamagePoint('nfod', .5) call SetUnitTypeDamagePoint('nfor', .3) call SetUnitTypeDamagePoint('nfot', .5) call SetUnitTypeDamagePoint('nfov', .4) call SetUnitTypeDamagePoint('nfpc', .3) call SetUnitTypeDamagePoint('nfpe', .3) call SetUnitTypeDamagePoint('nfpl', .3) call SetUnitTypeDamagePoint('nfps', .3) call SetUnitTypeDamagePoint('nfpt', .3) call SetUnitTypeDamagePoint('nfpu', .3) call SetUnitTypeDamagePoint('nfra', .3) call SetUnitTypeDamagePoint('nfrb', .3) call SetUnitTypeDamagePoint('nfre', .3) call SetUnitTypeDamagePoint('nfrg', .3) call SetUnitTypeDamagePoint('nfrl', .3) call SetUnitTypeDamagePoint('nfrp', .3) call SetUnitTypeDamagePoint('nfrs', .3) call SetUnitTypeDamagePoint('nfsh', .3) call SetUnitTypeDamagePoint('nfsp', .3) call SetUnitTypeDamagePoint('nftb', .3) call SetUnitTypeDamagePoint('nftk', .3) call SetUnitTypeDamagePoint('nftr', .3) call SetUnitTypeDamagePoint('nftt', .3) call SetUnitTypeDamagePoint('ngdk', .94) call SetUnitTypeDamagePoint('nggr', .3) call SetUnitTypeDamagePoint('ngh1', .56) call SetUnitTypeDamagePoint('ngh2', .56) call SetUnitTypeDamagePoint('ngir', .3) call SetUnitTypeDamagePoint('ngna', .4) call SetUnitTypeDamagePoint('ngnb', .3) call SetUnitTypeDamagePoint('ngno', .3) call SetUnitTypeDamagePoint('ngns', .4) call SetUnitTypeDamagePoint('ngnv', .3) call SetUnitTypeDamagePoint('ngnw', .3) call SetUnitTypeDamagePoint('ngrd', .94) call SetUnitTypeDamagePoint('ngrk', .3) call SetUnitTypeDamagePoint('ngrw', .94) call SetUnitTypeDamagePoint('ngst', .3) call SetUnitTypeDamagePoint('nhar', .3) call SetUnitTypeDamagePoint('nhdc', .53) call SetUnitTypeDamagePoint('nhfp', .53) call SetUnitTypeDamagePoint('nhhr', .53) call SetUnitTypeDamagePoint('nhrh', .3) call SetUnitTypeDamagePoint('nhrq', .35) call SetUnitTypeDamagePoint('nhrr', .3) call SetUnitTypeDamagePoint('nhrw', .3) call SetUnitTypeDamagePoint('nhyc', .7) call SetUnitTypeDamagePoint('nhyd', .7) call SetUnitTypeDamagePoint('nhyh', .7) call SetUnitTypeDamagePoint('nina', .5) call SetUnitTypeDamagePoint('ninc', .5) call SetUnitTypeDamagePoint('ninf', .26) call SetUnitTypeDamagePoint('ninm', .5) call SetUnitTypeDamagePoint('nith', .3) call SetUnitTypeDamagePoint('nitp', .3) call SetUnitTypeDamagePoint('nitr', .3) call SetUnitTypeDamagePoint('nits', .3) call SetUnitTypeDamagePoint('nitt', .3) call SetUnitTypeDamagePoint('nitw', .3) call SetUnitTypeDamagePoint('njgb', .3) call SetUnitTypeDamagePoint('njga', .3) call SetUnitTypeDamagePoint('njg1', .3) call SetUnitTypeDamagePoint('nkob', .38) call SetUnitTypeDamagePoint('nkog', .38) call SetUnitTypeDamagePoint('nkol', .38) call SetUnitTypeDamagePoint('nkot', .38) call SetUnitTypeDamagePoint('nlds', .53) call SetUnitTypeDamagePoint('nlkl', .3) call SetUnitTypeDamagePoint('nlpd', .66) call SetUnitTypeDamagePoint('nlpr', .38) call SetUnitTypeDamagePoint('nlps', .38) call SetUnitTypeDamagePoint('nlrv', .6) call SetUnitTypeDamagePoint('nlsn', .3) call SetUnitTypeDamagePoint('nltc', .3) call SetUnitTypeDamagePoint('nltl', .5) call SetUnitTypeDamagePoint('nmam', .5) call SetUnitTypeDamagePoint('nmbg', .6) call SetUnitTypeDamagePoint('nmcf', .38) call SetUnitTypeDamagePoint('nmdr', .5) call SetUnitTypeDamagePoint('nmfs', .66) call SetUnitTypeDamagePoint('nmgd', .66) call SetUnitTypeDamagePoint('nmgr', .66) call SetUnitTypeDamagePoint('nmgw', .66) call SetUnitTypeDamagePoint('nmit', .5) call SetUnitTypeDamagePoint('nmmu', .66) call SetUnitTypeDamagePoint('nmpg', .66) call SetUnitTypeDamagePoint('nmrm', .66) call SetUnitTypeDamagePoint('nmrr', .66) call SetUnitTypeDamagePoint('nmrv', .6) call SetUnitTypeDamagePoint('nmsc', .6) call SetUnitTypeDamagePoint('nmsh', .3) call SetUnitTypeDamagePoint('nmtw', .6) call SetUnitTypeDamagePoint('nmyr', .36) call SetUnitTypeDamagePoint('nndr', .4) call SetUnitTypeDamagePoint('nnmg', .7) call SetUnitTypeDamagePoint('nnrg', .36) call SetUnitTypeDamagePoint('nnsw', .5) call SetUnitTypeDamagePoint('nntg', .6) call SetUnitTypeDamagePoint('nnwl', .64) call SetUnitTypeDamagePoint('nnwq', .64) call SetUnitTypeDamagePoint('nnwr', .64) call SetUnitTypeDamagePoint('nnws', .3) call SetUnitTypeDamagePoint('nogl', .3) call SetUnitTypeDamagePoint('nogm', .3) call SetUnitTypeDamagePoint('nogn', .3) call SetUnitTypeDamagePoint('nogo', .3) call SetUnitTypeDamagePoint('nogr', .3) call SetUnitTypeDamagePoint('nomg', .3) call SetUnitTypeDamagePoint('nowe', .3) call SetUnitTypeDamagePoint('nowk', .3) call SetUnitTypeDamagePoint('npfm', .4) call SetUnitTypeDamagePoint('Npld', .8) call SetUnitTypeDamagePoint('Nplh', .8) call SetUnitTypeDamagePoint('Nfir', .5) call SetUnitTypeDamagePoint('nlv1', .4) call SetUnitTypeDamagePoint('nlv2', .4) call SetUnitTypeDamagePoint('nlv3', .4) call SetUnitTypeDamagePoint('nrdr', .94) call SetUnitTypeDamagePoint('nrel', .3) call SetUnitTypeDamagePoint('nrog', .3) call SetUnitTypeDamagePoint('nrvd', .6) call SetUnitTypeDamagePoint('nrvf', .6) call SetUnitTypeDamagePoint('nrvi', .6) call SetUnitTypeDamagePoint('nrvl', .6) call SetUnitTypeDamagePoint('nrvs', .65) call SetUnitTypeDamagePoint('nrwm', .94) call SetUnitTypeDamagePoint('nrzb', .6) call SetUnitTypeDamagePoint('nrzg', .5) call SetUnitTypeDamagePoint('nrzm', .5) call SetUnitTypeDamagePoint('nrzs', .5) call SetUnitTypeDamagePoint('nrzt', .6) call SetUnitTypeDamagePoint('nsat', .3) call SetUnitTypeDamagePoint('nsbm', .5) call SetUnitTypeDamagePoint('nsc2', .3) call SetUnitTypeDamagePoint('nsc3', .3) call SetUnitTypeDamagePoint('nscb', .5) call SetUnitTypeDamagePoint('nsel', .53) call SetUnitTypeDamagePoint('nsgb', .6) call SetUnitTypeDamagePoint('nsgg', .3) call SetUnitTypeDamagePoint('nsgh', .6) call SetUnitTypeDamagePoint('nsgn', .6) call SetUnitTypeDamagePoint('nsgt', .5) call SetUnitTypeDamagePoint('nska', .7) call SetUnitTypeDamagePoint('nske', .56) call SetUnitTypeDamagePoint('nsca', .7) call SetUnitTypeDamagePoint('nsce', .56) call SetUnitTypeDamagePoint('nskf', .7) call SetUnitTypeDamagePoint('nskg', .56) call SetUnitTypeDamagePoint('nskm', .7) call SetUnitTypeDamagePoint('nsko', .56) call SetUnitTypeDamagePoint('nslf', .3) call SetUnitTypeDamagePoint('nslh', .5) call SetUnitTypeDamagePoint('nsll', .5) call SetUnitTypeDamagePoint('nslm', .3) call SetUnitTypeDamagePoint('nsln', .3) call SetUnitTypeDamagePoint('nslr', .5) call SetUnitTypeDamagePoint('nslv', .5) call SetUnitTypeDamagePoint('nsnp', .3) call SetUnitTypeDamagePoint('nsns', .6) call SetUnitTypeDamagePoint('nsoc', .4) call SetUnitTypeDamagePoint('nsog', .56) call SetUnitTypeDamagePoint('nspb', .5) call SetUnitTypeDamagePoint('nspd', .3) call SetUnitTypeDamagePoint('nspg', .5) call SetUnitTypeDamagePoint('nspp', .33) call SetUnitTypeDamagePoint('nspr', .5) call SetUnitTypeDamagePoint('nsqa', .3) call SetUnitTypeDamagePoint('nsqe', .3) call SetUnitTypeDamagePoint('nsqo', .3) call SetUnitTypeDamagePoint('nsqt', .3) call SetUnitTypeDamagePoint('nsra', .3) call SetUnitTypeDamagePoint('nsrh', .3) call SetUnitTypeDamagePoint('nsrn', .53) call SetUnitTypeDamagePoint('nsrv', .6) call SetUnitTypeDamagePoint('nsrw', .3) call SetUnitTypeDamagePoint('nssp', .4) call SetUnitTypeDamagePoint('nsth', .3) call SetUnitTypeDamagePoint('nstl', .3) call SetUnitTypeDamagePoint('nsts', .3) call SetUnitTypeDamagePoint('nstw', .5) call SetUnitTypeDamagePoint('nsty', .3) call SetUnitTypeDamagePoint('nthl', .5) call SetUnitTypeDamagePoint('ntka', .3) call SetUnitTypeDamagePoint('ntkc', .36) call SetUnitTypeDamagePoint('ntkf', .36) call SetUnitTypeDamagePoint('ntkh', .36) call SetUnitTypeDamagePoint('ntks', .3) call SetUnitTypeDamagePoint('ntkt', .3) call SetUnitTypeDamagePoint('ntkw', .36) call SetUnitTypeDamagePoint('ntrd', .6) call SetUnitTypeDamagePoint('ntrg', .3) call SetUnitTypeDamagePoint('ntrh', .5) call SetUnitTypeDamagePoint('ntrs', .66) call SetUnitTypeDamagePoint('ntrt', .5) call SetUnitTypeDamagePoint('ntrv', .6) call SetUnitTypeDamagePoint('ntws', .6) call SetUnitTypeDamagePoint('nubk', .3) call SetUnitTypeDamagePoint('nubr', .3) call SetUnitTypeDamagePoint('nubw', .3) call SetUnitTypeDamagePoint('nvde', .3) call SetUnitTypeDamagePoint('nvdg', .3) call SetUnitTypeDamagePoint('nvdl', .3) call SetUnitTypeDamagePoint('nvdw', .3) call SetUnitTypeDamagePoint('nwen', .3) call SetUnitTypeDamagePoint('nwgs', .33) call SetUnitTypeDamagePoint('nwiz', .3) call SetUnitTypeDamagePoint('nwld', .33) call SetUnitTypeDamagePoint('nwlg', .33) call SetUnitTypeDamagePoint('nwlt', .33) call SetUnitTypeDamagePoint('nwna', .3) call SetUnitTypeDamagePoint('nwnr', .3) call SetUnitTypeDamagePoint('nwns', .3) call SetUnitTypeDamagePoint('nwrg', .3) call SetUnitTypeDamagePoint('nws1', .43) call SetUnitTypeDamagePoint('nwwd', .33) call SetUnitTypeDamagePoint('nwwf', .33) call SetUnitTypeDamagePoint('nwwg', .33) call SetUnitTypeDamagePoint('nwzd', .55) call SetUnitTypeDamagePoint('nwzg', .55) call SetUnitTypeDamagePoint('nwzr', .55) call SetUnitTypeDamagePoint('nzom', .3) call SetUnitTypeDamagePoint('nhym', .55) call SetUnitTypeDamagePoint('nchp', .3) call SetUnitTypeDamagePoint('nowb', .3) call SetUnitTypeDamagePoint('Npbm', .35) call SetUnitTypeDamagePoint('Nalc', .35) call SetUnitTypeDamagePoint('Nalm', .35) call SetUnitTypeDamagePoint('Nal2', .35) call SetUnitTypeDamagePoint('Nal3', .35) call SetUnitTypeDamagePoint('Ntin', .35) call SetUnitTypeDamagePoint('Nrob', .35) call SetUnitTypeDamagePoint('ncgb', .33) call SetUnitTypeDamagePoint('ncg1', .33) call SetUnitTypeDamagePoint('ncg2', .33) call SetUnitTypeDamagePoint('ncg3', .33) call SetUnitTypeDamagePoint('nplb', .63) call SetUnitTypeDamagePoint('nqb1', .5) call SetUnitTypeDamagePoint('nrdk', .94) call SetUnitTypeDamagePoint('nmrl', .66) call SetUnitTypeDamagePoint('noga', .3) call SetUnitTypeDamagePoint('Ecen', .4) call SetUnitTypeDamagePoint('Eevi', .3) call SetUnitTypeDamagePoint('Eevm', .26) call SetUnitTypeDamagePoint('Efur', .4) call SetUnitTypeDamagePoint('Eidm', .26) call SetUnitTypeDamagePoint('Eill', .3) call SetUnitTypeDamagePoint('Eilm', .26) call SetUnitTypeDamagePoint('Ekgg', .4) call SetUnitTypeDamagePoint('Emfr', .4) call SetUnitTypeDamagePoint('Emns', .4) call SetUnitTypeDamagePoint('Etyr', .3) call SetUnitTypeDamagePoint('Ewrd', .3) call SetUnitTypeDamagePoint('Hant', .55) call SetUnitTypeDamagePoint('Hapm', .433) call SetUnitTypeDamagePoint('Harf', .433) call SetUnitTypeDamagePoint('Hart', .433) call SetUnitTypeDamagePoint('Hdgo', .433) call SetUnitTypeDamagePoint('Hhkl', .433) call SetUnitTypeDamagePoint('Hjai', .55) call SetUnitTypeDamagePoint('Hkal', .55) call SetUnitTypeDamagePoint('Hlgr', .433) call SetUnitTypeDamagePoint('Hmbr', .633) call SetUnitTypeDamagePoint('Hmgd', .433) call SetUnitTypeDamagePoint('Hpb1', .433) call SetUnitTypeDamagePoint('Hpb2', .433) call SetUnitTypeDamagePoint('Huth', .433) call SetUnitTypeDamagePoint('Hvsh', .73) call SetUnitTypeDamagePoint('Hvwd', .7) call SetUnitTypeDamagePoint('Nbbc', .33) call SetUnitTypeDamagePoint('Nklj', .55) call SetUnitTypeDamagePoint('Nkjx', .55) call SetUnitTypeDamagePoint('Nmag', .8) call SetUnitTypeDamagePoint('Nman', .833) call SetUnitTypeDamagePoint('nplg', .63) call SetUnitTypeDamagePoint('Nsjs', .35) call SetUnitTypeDamagePoint('Ocbh', .36) call SetUnitTypeDamagePoint('Ocb2', .36) call SetUnitTypeDamagePoint('Odrt', .3) call SetUnitTypeDamagePoint('Ogld', .3) call SetUnitTypeDamagePoint('Ogrh', .5) call SetUnitTypeDamagePoint('Opgh', .5) call SetUnitTypeDamagePoint('Orex', .3) call SetUnitTypeDamagePoint('Orkn', .3) call SetUnitTypeDamagePoint('Osam', .33) call SetUnitTypeDamagePoint('Otcc', .36) call SetUnitTypeDamagePoint('Othr', .3) call SetUnitTypeDamagePoint('Uanb', .46) call SetUnitTypeDamagePoint('Ubal', .55) call SetUnitTypeDamagePoint('Uclc', .46) call SetUnitTypeDamagePoint('Udth', .55) call SetUnitTypeDamagePoint('Uear', .56) call SetUnitTypeDamagePoint('Uktl', .46) call SetUnitTypeDamagePoint('Umal', .55) call SetUnitTypeDamagePoint('Usyl', .3) call SetUnitTypeDamagePoint('Utic', .55) call SetUnitTypeDamagePoint('Uvar', .55) call SetUnitTypeDamagePoint('Uvng', .55) call SetUnitTypeDamagePoint('Uwar', .5) call SetUnitTypeDamagePoint('Hgam', .55) call SetUnitTypeDamagePoint('ensh', .46) call SetUnitTypeDamagePoint('eshd', .72) call SetUnitTypeDamagePoint('hcth', .5) call SetUnitTypeDamagePoint('hhes', .5) call SetUnitTypeDamagePoint('Naka', .59) call SetUnitTypeDamagePoint('nsw1', .33) call SetUnitTypeDamagePoint('nsw2', .33) call SetUnitTypeDamagePoint('nsw3', .33) call SetUnitTypeDamagePoint('ncat', .1) call SetUnitTypeDamagePoint('nbee', .5) call SetUnitTypeDamagePoint('nbel', .5) call SetUnitTypeDamagePoint('nchg', .33) call SetUnitTypeDamagePoint('nchr', .5) call SetUnitTypeDamagePoint('nchw', .43) call SetUnitTypeDamagePoint('nckb', .85) call SetUnitTypeDamagePoint('ncpn', .5) call SetUnitTypeDamagePoint('ndmu', .39) call SetUnitTypeDamagePoint('ndrd', .33) call SetUnitTypeDamagePoint('ndrn', .33) call SetUnitTypeDamagePoint('ndrt', .33) call SetUnitTypeDamagePoint('ndrf', .33) call SetUnitTypeDamagePoint('ndrh', .59) call SetUnitTypeDamagePoint('ndrj', .3) call SetUnitTypeDamagePoint('ndrm', .59) call SetUnitTypeDamagePoint('ndrp', .33) call SetUnitTypeDamagePoint('ndrs', .59) call SetUnitTypeDamagePoint('ndrw', .33) call SetUnitTypeDamagePoint('ndrl', .5) call SetUnitTypeDamagePoint('ndsa', .5) call SetUnitTypeDamagePoint('nemi', .59) call SetUnitTypeDamagePoint('nfgl', .3) call SetUnitTypeDamagePoint('ngbl', .3) call SetUnitTypeDamagePoint('nhea', .72) call SetUnitTypeDamagePoint('nhew', .5) call SetUnitTypeDamagePoint('njks', .5) call SetUnitTypeDamagePoint('nmdm', .6) call SetUnitTypeDamagePoint('nmed', .6) call SetUnitTypeDamagePoint('nmpe', .5) call SetUnitTypeDamagePoint('nmsn', .6) call SetUnitTypeDamagePoint('nser', .94) call SetUnitTypeDamagePoint('nssn', .3) call SetUnitTypeDamagePoint('nthr', .94) call SetUnitTypeDamagePoint('nw2w', .43) call SetUnitTypeDamagePoint('nwat', .33) call SetUnitTypeDamagePoint('odkt', .53) call SetUnitTypeDamagePoint('ogrk', .33) call SetUnitTypeDamagePoint('ojgn', .3) call SetUnitTypeDamagePoint('omtg', .5) call SetUnitTypeDamagePoint('onzg', .5) call SetUnitTypeDamagePoint('ovlj', .73) call SetUnitTypeDamagePoint('owar', .5) call SetUnitTypeDamagePoint('ownr', .6) call SetUnitTypeDamagePoint('uabc', .5) call SetUnitTypeDamagePoint('ubdd', .5) call SetUnitTypeDamagePoint('ubdr', .94) call SetUnitTypeDamagePoint('udes', .3) call SetUnitTypeDamagePoint('uktn', .53) call SetUnitTypeDamagePoint('uswb', .56) call SetUnitTypeDamagePoint('nbt1', .3) call SetUnitTypeDamagePoint('nbt2', .3) call SetUnitTypeDamagePoint('ncap', .4) call SetUnitTypeDamagePoint('ncaw', .59) call SetUnitTypeDamagePoint('ncta', .4) call SetUnitTypeDamagePoint('ncte', .4) call SetUnitTypeDamagePoint('nctl', .4) call SetUnitTypeDamagePoint('ndgt', .3) call SetUnitTypeDamagePoint('ndt1', .3) call SetUnitTypeDamagePoint('ndt2', .3) call SetUnitTypeDamagePoint('negf', .3) call SetUnitTypeDamagePoint('negm', .3) call SetUnitTypeDamagePoint('negt', .3) call SetUnitTypeDamagePoint('net1', .3) call SetUnitTypeDamagePoint('net2', .3) call SetUnitTypeDamagePoint('nft1', .3) call SetUnitTypeDamagePoint('nft2', .3) call SetUnitTypeDamagePoint('nndk', .4) call SetUnitTypeDamagePoint('Nngs', .73) call SetUnitTypeDamagePoint('nnsu', .5) call SetUnitTypeDamagePoint('nnwa', .3) call SetUnitTypeDamagePoint('ntt1', .3) call SetUnitTypeDamagePoint('ntx2', .3) call SetUnitTypeDamagePoint('ocbw', .3) call SetUnitTypeDamagePoint('zcso', .17) call SetUnitTypeDamagePoint('zhyd', .3) call SetUnitTypeDamagePoint('zjug', .17) call SetUnitTypeDamagePoint('zmar', .17) call SetUnitTypeDamagePoint('zshv', .38) call SetUnitTypeDamagePoint('zsmc', .55) call SetUnitTypeDamagePoint('zzrg', .3) endmethod endstruct endlibrary AttackChance: requires AttackEvents, optionally requires GetProc and AutoIndex JASS:library AttackChance initializer Init requires AttackEvents, optional GetProc, optional AutoIndex //=========================================================================== // Information: //============== // // AttackChance is an API for managing units' miss and evade chances. // It relies on AttackEvents, so your map must abide all the limitations // listed in its documentation. AttackChance allows you to set a baseline // global miss chance, set a default miss and evade chance per unit-type, // and adjust an individual unit's miss and evade chance. // // How to calculate the hit chance for a given attack: // // (1. - AttackerMissChance) * (1. - DefenderEvadeChance) - BaselineMissChance // // If GetProc is in your map script, it will automatically be used to // normalize hit/miss streaks. If AutoIndex is in your map script, certain // operations will become slightly faster. // //=========================================================================== // AttackChance API: //=================== // // SetUnitTypeMissChance(unitid, miss) / SetUnitTypeEvadeChance(unitid, evade) // Sets the default miss/evade chance of the specified unit-type to // the specified value. // // GetUnitTypeMissChance(unitid) -> real / GetUnitTypeEvadeChance(unitid) -> real // Returns the default miss/evade chance of the specified unit-type. // // SetUnitMissChance(unit, miss) / SetUnitEvadeChance(unit, evade) // Sets the miss/evade chance of the specified unit, overriding the // default value for the unit's unit-type. // // GetUnitMissChance(unit) -> real / GetUnitEvadeChance(unit) -> real // Returns the miss/evade chance of the specified unit. // // AdjustUnitMissChance(unit, miss) / AdjustUnitEvadeChance(unit, evade) // Adjusts the specified unit's miss/evade chance by the specified // amount. The value is added to its current miss/evade chance. // // GetUnitsHitChance(attacker, defender) // Returns the percentage chance that the specified attacker would // hit the specified defender, factoring in the baseline miss chance. // // GetUnitsWeightedHitChance(attacker, defender) // If you do not have GetProc in your map script, or the AttackWeight // value is set to 0.0, this will always return the same value as // GetUnitsHitChance. Otherwise, it will show the actual current // chance for the attacker to hit the defender. // // GetAttackHitChance() -> real // This function is an event response that can be used within the // OnAttackHit and OnAttackMiss events from AttackEvents. It returns // the actual weighted chance that the attack would have hit. // //=========================================================================== // Configuration: //================ globals private constant real BaselineMissChance = 0.0 //This is the baseline miss chance for all units. It can be reduced by //a negative miss chance on the attacker or a negative evade chance on //the defender. private constant real AttackWeight = 0.5 //When using GetProc, this is the Weight value that will be applied to //normalizing hit/miss streaks. endglobals //=========================================================================== globals private hashtable ht = InitHashtable() private key Attack endglobals //! textmacro ChanceFuncs takes CHANCE globals private key UnitType$CHANCE$ private key $CHANCE$ private real array $CHANCE$ar endglobals function SetUnitType$CHANCE$ takes integer unitid, real value returns nothing call SaveReal(ht, UnitType$CHANCE$, unitid, value) endfunction function GetUnitType$CHANCE$ takes integer unitid returns real return LoadReal(ht, UnitType$CHANCE$, unitid) endfunction function SetUnit$CHANCE$ takes unit u, real value returns nothing static if LIBRARY_AutoIndex then set $CHANCE$ar[GetUnitId(u)] = value - GetUnitType$CHANCE$(GetUnitTypeId(u)) else call SaveReal(ht, $CHANCE$, GetHandleId(u), value - GetUnitType$CHANCE$(GetUnitTypeId(u))) endif endfunction function GetUnit$CHANCE$ takes unit u returns real static if LIBRARY_AutoIndex then return $CHANCE$ar[GetUnitId(u)] + GetUnitType$CHANCE$(GetUnitTypeId(u)) else return LoadReal(ht, $CHANCE$, GetHandleId(u)) + GetUnitType$CHANCE$(GetUnitTypeId(u)) endif endfunction function AdjustUnit$CHANCE$ takes unit u, real value returns nothing static if LIBRARY_AutoIndex then set $CHANCE$ar[GetUnitId(u)] = $CHANCE$ar[GetUnitId(u)] + value else call SaveReal(ht, $CHANCE$, GetHandleId(u), LoadReal(ht, $CHANCE$, GetHandleId(u)) + value) endif endfunction //! endtextmacro //! runtextmacro ChanceFuncs("MissChance") //! runtextmacro ChanceFuncs("EvadeChance") //=========================================================================== function GetUnitsHitChance takes unit attacker, unit attacked returns real return (1. - GetUnitMissChance(attacker)) * (1. - GetUnitEvadeChance(attacked)) - BaselineMissChance endfunction function GetUnitsWeightedHitChance takes unit attacker, unit attacked returns real static if LIBRARY_GetProc then return GetProcChance(Attack, attacker, GetUnitsHitChance(attacker, attacked)) else return GetUnitsHitChance(attacker, attacked) endif endfunction //=========================================================================== globals private real AttackHitChance = 0. endglobals function GetAttackHitChance takes nothing returns real return AttackHitChance endfunction private function OnDamagePoint takes unit attacker, unit attacked returns nothing set AttackHitChance = GetUnitsWeightedHitChance(attacker, attacked) static if LIBRARY_GetProc then if not GetProc(Attack, attacker, GetUnitsHitChance(attacker, attacked)) then call AttackMiss() endif else if GetRandomReal(0., 1.) >= GetUnitsHitChance(attacker, attacked) then call AttackMiss() endif endif endfunction private function Init takes nothing returns nothing call OnUnitAttackDamagePoint(OnDamagePoint) static if LIBRARY_GetProc then call SetProcWeight(Attack, AttackWeight) endif endfunction endlibrary AttackRatings: requires AttackEvents, optionally requires GetProc and AutoIndex JASS:library AttackRatings initializer Init requires AttackEvents, optional GetProc, optional AutoIndex //=========================================================================== // Information: //============== // // AttackRatings is an API for managing units' miss and evade chances. // It relies on AttackEvents, so your map must abide all the limitations // listed in its documentation. AttackRatings allows you to set a baseline // global miss chance, set a default accuracy and evasion rating per unit- // type, and adjust an individual unit's accuracy and evasion ratings. // // The easiest way to understand evasion rating is by comparing it // to armor rating. It functions mathematically in exactly the same way, // and each point of evasion rating extends a unit's effective health by // the same amount as a point of armor (assuming that the EvasionDamage- // ReductionMultiplier configuration variable matches the ArmorDamage- // ReductionMultiplier gameplay constant). Evasion rating does not have // increasing returns; its effect on a unit's effective health stays // constant with each additional point. // // If evasion rating is analogous to armor rating, then accuracy rating // is analogous to armor penetration. It negates the evasion rating of the // target on a point-for-point basis, meaning each point of armor penetrat- // ion is equally valuable as a point of evasion. However, any accuracy // rating in excess of the target's evasion rating is wasted. // // How to understand Evasion Rating and Attack Rating: // -Each point of ER adds 6% (by default) to the effective hit points of the defender. // -Negative ER will continue to decrease the chance of being missed until it reaches 0%. // -Each point of AR for the attacker negates one point of ER for the defender. // -Negative AR will continue to decrease the chance of hitting until it reaches 0%. // -If the attacker's AR is higher than the defender's ER, the remaining amount is wasted. // // How to calculate hit chance for a given attack: // Let BER = Baseline evasion rating (converted from BaselineEvasionPercent) // Let ER = Evasion rating of defending unit // Let AR = Accuracy rating of attacking unit // Let EffectiveEvasionRating = BER + ER - AR (minimum 0) // Let EffectiveHitPointsFactor = 1 + (EffectiveEvasionRating * EvasionDamageReductionMultiplier) // HitChance = 1 / EffectiveHitPointsFactor // // If GetProc is in your map script, it will automatically be used to // normalize hit/miss streaks. If AutoIndex is in your map script, certain // operations will become slightly faster. // //=========================================================================== // API: // // SetUnitTypeAccuracyRating(unitid, accuracy) / SetUnitTypeEvasionRating(unitid, evasion) // Sets the default accuracy/evasion rating of the specified unit-type to // the specified value. // // GetUnitTypeAccuracyRating(unitid) -> real / GetUnitTypeEvasionRating(unitid) -> real // Returns the default accuracy/evasion rating of the specified unit-type. // // SetUnitAccuracyRating(unit, accuracy) / SetUnitEvasionRating(unit, evasion) // Sets the accuracy/evasion rating of the specified unit, overriding the // default value for the unit's unit-type. // // GetUnitAccuracyRating(unit) -> real / GetUnitEvasionRating(unit) -> real // Returns the accuracy/evasion rating of the specified unit. // // AdjustUnitAccuracyRating(unit, accuracy) / AdjustUnitEvasionRating(unit, evasion) // Adjusts the specified unit's accuracy/evasion rating by the specified // amount. The value is added to its current accuracy/evasion rating. // // EvasionRating2Evasion(evasionrating) -> real // Converts an evasion rating into an evasion percentage. // // Evasion2EvasionRating(evasion) -> real // Converts an evasion percentage into an evasion rating. // // GetRatingsHitChance(accuracy, evasion) // Gets the chance to hit resulting from the specified accuracy and evasion // ratings, without factoring in the baseline evasion percentage. // // GetUnitsHitChance(attacker, defender) // Returns the percentage chance that the specified attacker would hit the // specified defender, factoring in the baseline evasion percentage. // // GetUnitsWeightedHitChance(attacker, defender) // If you do not have GetProc in your map script, or the AttackWeight // value is set to 0.0, this will always return the same value as // GetUnitsHitChance. Otherwise, it will show the actual current // chance for the attacker to hit the defender. // // GetAttackHitChance() -> real // This function is an event response that can be used within the // OnAttackHit and OnAttackMiss events from AttackEvents. It returns // the actual weighted chance that the attack would have hit. // //=========================================================================== globals private constant real EvasionDamageReductionMultiplier = 0.06 //This is the percentage of base life effectively gained for each //point of evasion rating. It would be a good idea to make this //match the ArmorDamageReductionMultiplier, that way evasion //rating and armor can be directly compared to one another. private constant real BaselineEvasionPercent = 0.0 //This is the baseline evasion chance for all units. It can be //reduced by accuracy rating on the attacker or negative evasion //rating on the defender. private constant real AttackWeight = 0.5 //When using GetProc, this is the Weight value that will be applied to //normalizing hit/miss streaks. endglobals //=========================================================================== globals private real BaselineEvasionRating private hashtable ht = InitHashtable() private key Attack endglobals //! textmacro RatingFuncs takes RATING globals private key UnitType$RATING$ private key $RATING$ private real array $RATING$ar endglobals function SetUnitType$RATING$ takes integer unitid, real value returns nothing call SaveReal(ht, UnitType$RATING$, unitid, value) endfunction function GetUnitType$RATING$ takes integer unitid returns real return LoadReal(ht, UnitType$RATING$, unitid) endfunction function SetUnit$RATING$ takes unit u, real value returns nothing static if LIBRARY_AutoIndex then set $RATING$ar[GetUnitId(u)] = value - GetUnitType$RATING$(GetUnitTypeId(u)) else call SaveReal(ht, $RATING$, GetHandleId(u), value - GetUnitType$RATING$(GetUnitTypeId(u))) endif endfunction function GetUnit$RATING$ takes unit u returns real static if LIBRARY_AutoIndex then return $RATING$ar[GetUnitId(u)] + GetUnitType$RATING$(GetUnitTypeId(u)) else return LoadReal(ht, $RATING$, GetHandleId(u)) + GetUnitType$RATING$(GetUnitTypeId(u)) endif endfunction function AdjustUnit$RATING$ takes unit u, real value returns nothing static if LIBRARY_AutoIndex then set $RATING$ar[GetUnitId(u)] = $RATING$ar[GetUnitId(u)] + value else call SaveReal(ht, $RATING$, GetHandleId(u), LoadReal(ht, $RATING$, GetHandleId(u)) + value) endif endfunction //! endtextmacro //! runtextmacro RatingFuncs("AccuracyRating") //! runtextmacro RatingFuncs("EvasionRating") //=========================================================================== function EvasionRating2Evasion takes real rating returns real local real sign = 1 if rating == 0. then return 0. elseif rating < 0. then set rating = -rating set sign = -1 endif return sign * (1. - (1. / (1. + (rating * EvasionDamageReductionMultiplier)))) endfunction function Evasion2EvasionRating takes real evasion returns real local real sign = 1 if evasion < 0. then set evasion = -evasion set sign = -1 elseif evasion >= 1. then return sign * 1000000. endif return sign * ((1. / (1. - evasion)) - 1.) * (1. / EvasionDamageReductionMultiplier) endfunction function GetRatingsHitChance takes real accuracyrating, real evasionrating returns real return 1. - RMaxBJ(EvasionRating2Evasion(evasionrating - accuracyrating), 0.) endfunction function GetUnitsHitChance takes unit attacker, unit defender returns real return GetRatingsHitChance(GetUnitAccuracyRating(attacker), GetUnitEvasionRating(defender) + BaselineEvasionRating) endfunction function GetUnitsWeightedHitChance takes unit attacker, unit defender returns real static if LIBRARY_GetProc then return GetProcChance(Attack, attacker, GetUnitsHitChance(attacker, defender)) else return GetUnitsHitChance(attacker, defender) endif endfunction //=========================================================================== globals private real AttackHitChance = 0. endglobals function GetAttackHitChance takes nothing returns real return AttackHitChance endfunction private function OnDamagePoint takes unit attacker, unit attacked returns nothing set AttackHitChance = GetUnitsWeightedHitChance(attacker, attacked) static if LIBRARY_GetProc then if not GetProc(Attack, attacker, GetUnitsHitChance(attacker, attacked)) then call AttackMiss() endif else if GetRandomReal(0., 1.) >= GetUnitsHitChance(attacker, attacked) then call AttackMiss() endif endif endfunction private function Init takes nothing returns nothing call OnUnitAttackDamagePoint(OnDamagePoint) set BaselineEvasionRating = Evasion2EvasionRating(BaselineEvasionPercent) static if LIBRARY_GetProc then call SetProcWeight(Attack, AttackWeight) endif endfunction endlibrary |
| 10-26-2009, 03:34 AM | #2 |
You need to link to all libraries you require either optionally or completely. |
| 10-26-2009, 03:43 AM | #3 |
Yeah, I was working on that while you made that post. |
| 10-26-2009, 04:54 AM | #4 |
is there any way to detect when a unit attacks in general (even onto destructables and items, and by attack ground)? or if not generally, then completely? |
| 10-26-2009, 05:14 AM | #5 |
EVENT_PLAYER_UNIT_ATTACKED and EVENT_PLAYER_UNIT_ATTACKED are the only ways to detect attacks, so there's no way to detect it for non-units. |
| 10-26-2009, 08:35 AM | #6 |
Cant you check whether a units current order is 'attack' when it gets an order on any target (event)? |
| 10-26-2009, 09:13 AM | #7 | |
Quote:
Edit: GetUnitAttackSpeedFactor seems a bit awkward since for the duration of the attack to be halved the speed would have to be 2.0, not 0.5. Maybe the function should be named GetUnitAttackDurationFactor instead? |
| 10-26-2009, 09:56 AM | #8 |
So this is like UnitProperties attack module? Looks pretty neat. You should probably make this support triggered critical strikes too. I believe many people who will use this evasion system, would like to use criticals too, dont you think? Isnt there any ability that can add 100% miss chance, btw? With this 100% evasion method it is possible for unit to dodge many simultaneous attacks from different attackers, if one of those attackers misses his target. This probably isnt any real problem in real gameplay situation, though. Its too rare thigny to happen ( Curse could probably be used for adding miss change. I know that it can be casted instantly, even with only one dummy caster, but I havent tested any possible delays between spell casting and unit getting the curse buff. Also some resistance skin and buff removing thingies could probably make it fail, so its not maybe the best option. ) |
| 10-26-2009, 10:09 AM | #9 | ||||
Quote:
Quote:
Quote:
Quote:
|
| 10-26-2009, 10:12 AM | #10 | |
These things: Quote:
Are really bad limitations. I'd have to change lots of stuff of my map, so I will not use this. |
| 10-26-2009, 11:00 AM | #11 |
Unfortunately there's no other way to do it, so you pretty much have to design your map around this kind of thing from the start. It's best for maps where you trigger most spells to begin with. |
| 10-26-2009, 12:24 PM | #12 |
Ok, cool. Although, I think critical attacks should be controlled not through damage detection, but through this kind of systems, because this doesnt only allow you to modify units damage for attack and create a critical texttag, but also allows you to set units critical strike animation and stuff like that. I know that in wc3 units dont play their critical animation if attack is going to get dodget or misses its target, but it doesnt mean that someone would not need that kind of stuff. For example, if some archer hero has animation for shooting some critical arrow, he should probably play that animation, even though target dodges the attack few milliseconds later, when arrow misses its target, dont you think? Its just that only units with critical strike in wc3 are melee guys. |
| 10-26-2009, 12:24 PM | #13 | |
Quote:
a simple gmsi scipt can do all the boring preloading stuff you've only to execute it everytime you've changed something |
| 10-26-2009, 12:33 PM | #14 | ||
Quote:
Quote:
|
| 10-26-2009, 12:38 PM | #15 | |
Quote:
use script.ini |
