-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Issues with Skinpools and Challenge Rewards
It turns out there's some strange interactions which go on between the stock Borderlands 2 Challenge Rewards (where, for instance, you are awarded a skin for killing N enemies with an Assault Rifle, etc), and the UCP "Skinpool Fixes" section which reassigns skin and head pools for use by mods. This page attempts to detail the situation for anyone who might be curious what happens.
Basically, Borderlands has a "Rewards" pool for each flavor of skin/head, which contains a BalancedItems
section, one for each character. For instance, here is a very abbreviated version of the BalancedItems
array for GD_CustomItemPools_MainGame.Rewards.RedBoldAccent
:
BalancedItems(0)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_MainGame.Assassin.RedBoldAccent',
InvBalanceDefinition=None,
)
BalancedItems(1)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_MainGame.Mercenary.RedBoldAccent',
InvBalanceDefinition=None,
)
BalancedItems(2)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_MainGame.Siren.RedBoldAccent',
InvBalanceDefinition=None,
)
BalancedItems(3)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_MainGame.Soldier.RedBoldAccent',
InvBalanceDefinition=None,
)
BalancedItems(4)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_Lilac.Psycho.RedBoldAccent',
InvBalanceDefinition=None,
)
BalancedItems(5)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_tulip.Mechro.RedBoldAccent',
InvBalanceDefinition=None,
)
Each of those sub-pools that it calls out to have a BalancedItems
array itself, but with just a single item in it, which uses InvBalanceDefinition
instead of ItmPoolDefinition
. For instance, GD_CustomItemPools_MainGame.Assassin.RedBoldAccent
looks like this:
BalancedItems(0)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Assassin_Items_MainGame.BalanceDefs.Assassin_Skin_RedB',
)
So what UCP does in this "Skinpool Fixes" section, is to cut out the middleman and move the InvBalanceDefinition
s up into the main Rewards
pool. Nothing ever calls those middle pools directly, so they become freed up for any mod to make use of. The main Rewards pool above, for instance, ends up looking like this after all the hotfixes:
BalancedItems(0)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Assassin_Items_MainGame.BalanceDefs.Assassin_Skin_RedB',
)
BalancedItems(1)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Assassin_Items_MainGame.BalanceDefs.Mercenary_Skin_RedB',
)
BalancedItems(2)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Assassin_Items_MainGame.BalanceDefs.Siren_Skin_RedB',
)
BalancedItems(3)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Assassin_Items_MainGame.BalanceDefs.Soldier_Skin_RedB',
)
BalancedItems(4)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Psycho_Items_Lilac.BalanceDefs.Psycho_Skin_RedB',
)
BalancedItems(5)=(
ItmPoolDefinition=None,
InvBalanceDefinition=InventoryBalanceDefinition'GD_Mechro_Items_Tulip.BalanceDefs.Mechro_Skin_RedB',
)
So all six of those original pools, from GD_CustomItemPools_MainGame.Assassin.RedBoldAccent
to GD_CustomItemPools_tulip.Mechro.RedBoldAccent
, are now free for use. There's even a registry page here at the wiki where mod authors can claim skinpools for use in their mods: Custom Skin and Head Pool Registry
In general, using those freed skinpools works great, and many folks might never notice any problems. But it turns out that there's an unwanted side effect relating to how Borderlands hands out challenge rewards. It turns out to be related to the Probability
sections inside the main Rewards pools. I abbreviated the dump up at the top, but the full dump for one of the items in the Rewards pool looks like this:
BalancedItems(0)=(
ItmPoolDefinition=ItemPoolDefinition'GD_CustomItemPools_MainGame.Assassin.RedBoldAccent',
InvBalanceDefinition=None,
Probability=(
BaseValueConstant=1.000000,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'Transient.AttributeInitializationDefinition_10',
BaseValueScaleConstant=1.000000
),
bDropOnDeath=True
)
The problem happens because of that InitializationDefinition
attribute. This is something which Borderlands dynamically assigns to the skinpools. You can try changing the ID on these pools all you want, but the game will always silently overwrite your efforts with a new Transient ID. If you dig into those objects a bit with obj dump
on the console, you'll eventually find that they reference the character class that they're associated with. For instance, if you dig into that one, you'll find this:
*** Property dump for object 'PlayerClassAttributeValueResolver Transient.AttributeInitializationDefinition_10:AttributeDefinition_21.PlayerClassAttributeValueResolver_10' ***
=== PlayerClassAttributeValueResolver properties ===
PlayerClassId=PlayerClassIdentifierDefinition'GD_PlayerClassId.Assassin'
When giving out rewards for challenges, these Transient values end up resolving to 1
if they match the class you're currently playing, or 0
otherwise. The upshot being that when you complete a challenge to the required level, and the challenge rewards you from the Rewards pool, the only item which can drop is the one which matches your character. Nifty!
Well, not so nifty, because it turns out that actually using one of our freed skinpools ends up screwing up all these Transient attributes. Sometimes, the wrong Transient IDs end up getting assigned to the wrong characters' skinpools. So for instance if you're a Siren you might end up with a Gunzerker skin. In other cases, there might end up being no skin which can drop for your given class. Very frequently, this automatic Transient magic will even end up lopping off the very last entry in the Reward pool, which means that Mechromancers won't get any rewards at all!