-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Understanding Borderlands Weight and Probability Values
Before diving into this, it's recommended to have a general understanding of how Borderlands 2/TPS handles weighted probabilities -- a good primer on that can be found on Gearbox's blog in a post named The Borderlands 2 Loot System by Paul Hellquist.
Loot pools in Borderlands are generally defined using a BalancedItems
array which looks like this, taken from Borderlands 2's GD_Itempools.LootablePools.Pool_Locker_Items_SMGsAndPistols
:
BalancedItems(0)=(
ItmPoolDefinition=ItemPoolDefinition'GD_Itempools.WeaponPools.Pool_Weapons_Pistols',
InvBalanceDefinition=None,
Probability=(
BaseValueConstant=0.000000,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'GD_Balance.Weighting.Weight_2_Uncommon',
BaseValueScaleConstant=1.000000
),
bDropOnDeath=False
)
BalancedItems(1)=(
ItmPoolDefinition=ItemPoolDefinition'GD_Itempools.WeaponPools.Pool_Weapons_SMG',
InvBalanceDefinition=None,
Probability=(
BaseValueConstant=0.000000,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'GD_Balance.Weighting.Weight_3_Uncommoner',
BaseValueScaleConstant=1.000000
),
bDropOnDeath=True
)
The Probability
section will become very familiar over time, and consists of four elements: BaseValueConstant
, BaseValueAttribute
, InitializationDefinition
, and BaseValueScaleConstant
. We'll refer to them as BVC, BVA, ID, and BVSC.
When writing custom loot pools or playing with these kinds of stanzas in mods, the simplest thing to do is to set the middle two (BVA and ID) to None
and only use BVC and BVSC. In that case, the formula for finding out the numerical value of one of those stanzas is just BVC * BVSC
. So either of the following stanzas would evaluate to 50
:
Probability=(
BaseValueConstant=50.000000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
or:
Probability=(
BaseValueConstant=1.000000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=50.000000
)
or even:
Probability=(
BaseValueConstant=10.000000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=5.000000
)
In practice, you'll generally set BVC to the number you want, and leave the BVSC at 1
.
The next most common thing you'll find in loot pools is the use of the various GD_Balance.Weighting.Weight_*
values, set in the ID of the stanza. In our example at the top, Pistols are using Uncommon, and SMGs are using the amusingly-named "Uncommoner." You can take a look at these weights using obj dump
from the console, or from OpenBLCMM's Object Explorer, but the important bits of those objects are these, taken for example from Weight_1_Common
:
BaseValueMode=BASEVALUE_InitializationDefSetsBaseValue
ValueFormula=(
bEnabled=True,
Multiplier=(
BaseValueConstant=100.000000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
),
The BaseValueMode=BASEVALUE_InitializationDefSetsBaseValue
definition means that the weight will completely override whatever BVC is set in the main probability/weight stanza. The Multiplier
section uses the same kind of number stanza as we mentioned above, and in this case 100 * 1 = 100
, so the value put into the main weight would be 100
. So, for instance, the following stanza:
(
BaseValueConstant=0.000000,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'GD_Balance.Weighting.Weight_1_Common',
BaseValueScaleConstant=1.000000
)
... will evaluate to exactly the same as this stanza:
(
BaseValueConstant=42000.12345,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'GD_Balance.Weighting.Weight_1_Common',
BaseValueScaleConstant=1.000000
)
... and is functionally identical to this stanza:
(
BaseValueConstant=100.000000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
In each case, that number will evaluate to 100
.
All of the GD_Balance.Weighting.Weight_*
values do this substitution on BVC. It's possible that there are other types of objects which can be referenced besides those, and perhaps some of them have a different BaseValueMode
than BASEVALUE_InitializationDefSetsBaseValue
, but those are uncommon, if they do exist.
The values on each of the common weight variables are as follows:
Object | Weight |
---|---|
GD_Balance.Weighting.Weight_0_VeryCommon |
200 |
GD_Balance.Weighting.Weight_1_Common |
100 |
GD_Balance.Weighting.Weight_2_Uncommon |
10 |
GD_Balance.Weighting.Weight_3_Uncommoner |
5 |
GD_Balance.Weighting.Weight_4_Rare |
1 |
GD_Balance.Weighting.Weight_5_VeryRare |
0.1 |
GD_Balance.Weighting.Weight_6_Legendary |
0.01 |
GD_Balance.Weighting.Weight_1_Common_RareMod |
(varies depending on Vault Hunter's Relic) |
So, back to our first example, Pistols have a weight of 10, and SMGs have a weight of 5, so pistols will spawn from that pool 66% of the time, and SMGs the remaining 33%.
The other thing you may see is stanzas which use BVA to apply some trickier logic to the weights/probabilities. For instance, Knuckledragger has a loot pool which is defined like so:
(
ItemPool=ItemPoolDefinition'GD_Itempools.Runnables.Pool_Knuckledragger',
PoolProbability=(
BaseValueConstant=0.000000,
BaseValueAttribute=AttributeDefinition'GD_Itempools.DropWeights.DropODDS_BossUniques',
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
)
Like the weighting values which use ID, BVA objects tend to completely override the BVC, so if you're using a BVA, the BVC in the stanza gets completely ignored. For GD_Itempools.DropWeights.DropODDS_BossUniques
, it's a pretty simple object -- it just always resolves to the value 0.100000
. So in this case, KnuckleDragger has a 10% chance of dropping loot from GD_Itempools.Runnables.Pool_Knuckledragger
(which happens to be the Hornet).
Other BVAs can get more complicated. The Mini-Fridges commonly found in Bandit areas in BL2 contain a possible loot drop which has the following probability:
Weight=(
BaseValueConstant=1.000000,
BaseValueAttribute=AttributeDefinition'GD_Itempools.DropWeights.DropODDS_Health',
InitializationDefinition=None,
BaseValueScaleConstant=500.000000
),
That DropODDS_Health
object is pretty interesting. Here's the relevant bits:
Resource=ResourceDefinition'D_Resources.Health'
ResourceThreshold=(
BaseValueConstant=0.400000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
AboveThresholdWeight=(
BaseValueConstant=0.030000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
MinBelowThresholdWeight=(
BaseValueConstant=0.100000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
MaxBelowThresholdWeight=(
BaseValueConstant=0.250000,
BaseValueAttribute=None,
InitializationDefinition=None,
BaseValueScaleConstant=1.000000
)
Once again, we see that familiar stanza being used for all the values. So it's looking at player health, specifically at a threshhold of 40% (ResourceThreshold
). When the player's health is above 40%, this object will resolve to 0.03
, or 3% (inside AboveThresholdWeight
). If the player's health is below 40%, though, the object will resolve to somewhere inbetween 0.1
and 0.25
, or 10%-25% (MinBelowThresholdWeight
and MaxBelowThresholdWeight
). (I'm not totally sure what the exact numbers will be in that case -- it may scale based on the full health level, perhaps).
The upshot, of course, is that the Mini Fridge is more likely to contain health if the player is badly injured, and less likely if not. That object's final value takes over the BVC of the original Weight
section, and then the BVSC multiplies it by 500. So the total weight of that pool when the user is at full health is 0.03 * 500 = 15
, and at most will be 0.25 * 500 = 125
.
There are other objects in GD_Itempools.DropWeights.DropODDS_*
which do similar calculations based on ammo count, etc, which is how the game starts providing extra ammo for particular gun types, when you start getting low, etc.
You will doubtless notice this on your own, of course, but these stanzas are used in a lot of places throughout the Borderlands 2/TPS data, including in places which aren't specifically tied to probabilities or weights. It's used for the Quantity
field on all drop pools -- GD_Itempools.AmmoAndResourcePools.Pool_Ammo_Grenades_BoomBoom
for instance, which is used to drop grenade ammo from Boom Bewm, is defined like so:
Quantity=(
BaseValueConstant=1.000000,
BaseValueAttribute=AttributeDefinition'D_Attributes.GameProperties.NumberOfPlayers',
InitializationDefinition=None,
BaseValueScaleConstant=3.000000
)
So that pool will drop three grenade ammo per player in the game. (As usual, the BVC is ignored because BVA is in use.)