When a Pawn (UT) takes damage it allows its Inventory (UT) items to reduce the damage by calling the ReduceDamage function of the first item in the inventory chain, but only if the Pawn's bIsPlayer property is True and the Pawn's ReducedDamageType property is not 'All'.
The damage reduction process is divided into two steps:
- Create a list of armor items and sort it by priority.
- Let the single items in that list reduce the damage until either the damage is 0 or the end of the list is reached.
Creating the List
When building the list of armor items every item in the Pawn's inventory list is checked even if its bIsAnArmor is False. (e.g. the Relic of Redemption is not an armor item, but still uses armor functions to check for probably deadly hits.)
The list is built by the recursively called PrioritizeArmor function:
function inventory PrioritizeArmor( int Damage, name DamageType, vector HitLocation ) { local Inventory FirstArmor, InsertAfter; if ( Inventory != None ) FirstArmor = Inventory.PrioritizeArmor(Damage, DamageType, HitLocation); else FirstArmor = None; if ( bIsAnArmor) { if ( FirstArmor == None ) { nextArmor = None; return self; } // insert this armor into the prioritized armor list if ( FirstArmor.ArmorPriority(DamageType) < ArmorPriority(DamageType) ) { nextArmor = FirstArmor; return self; } InsertAfter = FirstArmor; while ( (InsertAfter.nextArmor != None) && (InsertAfter.nextArmor.ArmorPriority(DamageType) > ArmorPriority(DamageType)) ) InsertAfter = InsertAfter.nextArmor; nextArmor = InsertAfter.nextArmor; InsertAfter.nextArmor = self; } return FirstArmor; }
If there is at least one more item in the inventory chain that item's PrioritizeArmor function is called and returns the first item of a sorted list of all armors behind this item in the inventory chain. That item is stored in the FirstArmor variable. When "if (bIsAnArmor)" is reached and the FirstArmor variable still contains None there are no armor items in the inventory chain behind this item, so if this item is an armor it will be returned as the first (and only) item of the armor list to either the previous PrioitizeArmor function or to the ReduceDamage function.
If the armor list is not empty the return values of the ArmorPriority functions of this item and of the items in the armor list are compared until the correct position for this item is found. The item is inserted into the list then and the first item of the list (which could also be this item) is returned to either the previous PrioitizeArmor function or to the ReduceDamage function.
When code execution is returned to the ReduceDamage function it has a reference to the complete and sorted list of armor items.
Reducing Damage
Now the items can start reducing the damage. The items in the armor list now receive ArmorAbsorbDamage calls untill the damage is 0 or the end of the list is reached.
By default the ArmorAbsorbDamage function works like this:
- If the damage type is not 'Drowned' the item's ArmorImpactEffect function is called.
- If the damage type is not 'None' and matches either ProtectionType1 or ProtectionType2 a damage of 0 si returned meaning all damage has been absorbed without using the armor's charge.
- If the damage type is 'Drowned' the full damage is returned meaning no damage has been absorbed at all.
- An "armor damage" value is calculated: ArmorDamage = (Damage * ArmorAbsorption) / 100
If the armor damage is greater than or equal to the armor's Charge the armor damage is reduced to Charge and the item is destroyed. If there's more charge than armor damage Charge is reduced by ArmorDamage.
In both cases Damage - ArmorDamage is returned as the new damage value to be processed by the next armor item.