Skyrim talk:The Steed Stone

The UESPWiki – Your source for The Elder Scrolls since 1995
Jump to: navigation, search

>"The Stone's effect also reduces the weight of any piece of armor in the player's inventory that is the same base item as any piece being worn. For example, if the player has 10 Glass Armor in their inventory, equipping one will make all of them weightless. This remains true even if the worn armor is enhanced by smithing, enchanted and renamed."

This isn't true (at least for my current character) anymore, was that fixed in one of these damned unofficial patches?--213.245.12.205 23:41, 25 January 2014 (GMT)

Reverse-engineering[edit]

I've identified the cause of the Steed Stone stack bug (wherein if you have 50 Glass Armors in your inventory and you equip one, all of them become weightless). The key piece of code involved is this excerpt from float ExtraContainerChanges::Data::GetTotalWeight(), in the general vicinity of offset 0x0047B7BD in Skyrim Classic:

  item_weight = GetFormWeight(ebp); // esp14
  if (0.0F >= item_weight)
     continue;
  auto ebx   = owner;
  auto count = edi->countDelta; // esp28
  if (ebx && ebp->formType == 0x1A) { // at 0x0047B7BD
     if (edi->IsWorn()) {
        if (count <= 0)
           continue;
        ecx = edi->type;
        CalculatePerkData(kEntryPoint_Mod_Armor_Weight, ebx, ecx, &item_weight); // at 0x0047B7D9
        --count;
        worn_armor_weight += item_weight;
     }
  }
  if (count > 0) {
     total_weight += count * item_weight; // count * form weight
  }

So what does all that mean? Well, let's start with the CalculatePerkData function, which is used to compute the effect of any Perk Entry Point in the game. The first argument is the entry point to compute -- in this case, "Mod Armor Weight," which is used by the Steed Stone's perk -- and the second argument is the actor who has the perk. The arguments after that vary depending on the perk type; in this case, we pass the item's base form and its weight. The weight is passed as a pointer to a float, which means that CalculatePerkData can modify it.

We get the item weight and then, if it's an armor and you're wearing it, we run it through the Mod Armor Weight calculations; we apply the modified weight separately, subtract one from the item count, and then apply the item weight times the item count. The intention is clearly to only modify the weight of the one instance of that item you're wearing, while using the normal weight for all the others. The trick is that Bethesda unwittingly used the same item-weight variable for both the perk and non-perk branches of code, so when the former branch modifies it, it stays modified for the latter branch. This means that the changes done by Mod Armor Weight apply to the whole stack. The fix for this would be to patch the subroutine to do this:

  item_weight = GetFormWeight(ebp); // esp14
  if (0.0F >= item_weight)
     continue;
  auto ebx   = owner;
  auto count = edi->countDelta; // esp28
  if (ebx && ebp->formType == 0x1A) { // at 0x0047B7BD
     if (edi->IsWorn()) {
        if (count <= 0)
           continue;
        float modified_item_weight = item_weight; // Use a separate variable for the perk computation.
        ecx = edi->type;
        CalculatePerkData(kEntryPoint_Mod_Armor_Weight, ebx, ecx, &modified_item_weight); // at 0x0047B7D9
        --count;
        worn_armor_weight += modified_item_weight;
     }
  }
  if (count > 0) {
     total_weight += count * item_weight; // count * form weight
  }

I have the full subroutine transliterated to C++ on Github.

Code analysis also implies another bug, and testing confirms it: the Iron Shield is not affected by the Mod Armor Weight perk. This is because the Mod Armor Weight perk is only applied to any items that are not in the ActorBase's inventory. The player-character actually has default items -- potions, iron weapons, full iron armor, and an Iron Shield -- and these are removed by scripts during the game's intro. The iron armor is conferred via the ActorBase's default outfit, so it is affected by Mod Armor Weight; however, the Iron Shield is in the base inventory, so it is not affected by Mod Armor Weight. If you have 50 Ebony Shields in your inventory and you equip one, the Steed Stone stack bug makes them all weightless, but if you have 50 Iron Shields in your inventory and you equip one, they all still have their normal weight. The solution to this would be to run the Mod Armor Weight perk on the items that exist in the ActorBase's internal TESContainer. DavidJCobb (talk) 21:31, 18 March 2020 (GMT)

There are a few articles on UESP where I've explained the exact causes of bugs on the talk pages, and in some cases I've mentioned that I have a mod for Skyrim Classic which fixes these via code injection. I've mentioned this because some bugs mention when the Unofficial Patches fix them, and I don't know if UESP wants to do that for mods in general. In this case, I've spent a couple hours or so fixing the bugs mentioned above in my "Cobb Bug Fixes" mod; I'll leave it up to any passing editors to decide if that should be mentioned. DavidJCobb (talk) 00:22, 19 March 2020 (GMT)