Where is item condition stored in memory?

Discuss coding questions, pull requests, and implementation details.
User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Where is item condition stored in memory?

Post by numidium3rd »

I'm currently trying figure out how Classic lowers item condition of magic items on-equip. Before I can do that I need to figure out how to find item condition values in memory. I searched a memory dump and found an array of data that shows the items' name strings and their max condition values but their current condition values don't show up there.

I did find the current condition values in random places but the values there were oscillating between one value and another and not changing with my use of the item. It's likely that a coincidence since I'm working with a relatively large memory dump.

I'm using the DaggeD save editor to get the current condition values so I'm left with three possibilities:
1. DaggeD is misreading the condition values in the save file.
2. The values are stored on another memory segment that I'm not looking at.
3. Something else is going on that I don't understand (most likely)

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Where is item condition stored in memory?

Post by mikeprichard »

Numidium, I just want to wish you luck in this - as you know, confirming this behavior for wiki purposes (and of course to implement the correct classic behavior in DFU) has been in my plan for some time! (See viewtopic.php?f=24&t=2584&start=50#p42136.)

Related to this, it will also need to be determined how exactly an item with more than one "Cast When Held" enchantment decays - i.e. whether an item with two "Cast When Held" enchantments has its health decay at a rate of 14 (instead of 7) points after waiting/resting 7 in-game hours, and/or at a rate of 2 (instead of 1) points per 4 in-game minutes when awake in the game world. (See http://en.uesp.net/wiki/Daggerfall:Magi ... ical_Items.)

User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Re: Where is item condition stored in memory?

Post by numidium3rd »

mikeprichard wrote: Sat Apr 18, 2020 10:01 pm Numidium, I just want to wish you luck in this - as you know, confirming this behavior for wiki purposes (and of course to implement the correct classic behavior in DFU) has been in my plan for some time! (See viewtopic.php?f=24&t=2584&start=50#p42136.)

Related to this, it will also need to be determined how exactly an item with more than one "Cast When Held" enchantment decays - i.e. whether an item with two "Cast When Held" enchantments has its health decay at a rate of 14 (instead of 7) points after waiting/resting 7 in-game hours, and/or at a rate of 2 (instead of 1) points per 4 in-game minutes when awake in the game world. (See http://en.uesp.net/wiki/Daggerfall:Magi ... ical_Items.)
Thanks, Mike! There's some info in that article that I wasn't aware of so that should help me out a bit. I made a PR for degradation over time a couple of months ago (though I feel like I should redo it at some point since it's not entirely 1:1 with classic but I digress). I wonder if the current durability is calculated from a composite of values such as the number of times equipped and time worn. That might explain why the value itself isn't in memory. Pure speculation on my part - I'm still new to this reverse-engineering thing.

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Where is item condition stored in memory?

Post by mikeprichard »

Great! And if anyone can figure this out, I'm sure you can. There aren't many people around here with as much experience working on this project as you.

User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Re: Where is item condition stored in memory?

Post by numidium3rd »

Update: As it turns out, the reason I couldn't find item conditions in memory was that I was using my hex editor incorrectly. When I was searching for integer values it would highlight the value so that when you search again it searches within the highlighted region. In my defense, I'm new to this editor but yeah I'm facepalming hard right now.

I'm going to keep working on decompiling the code for lowering item condition on equip. I'll post here again if I have any more questions.

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Where is item condition stored in memory?

Post by mikeprichard »

Ha, OK! Good luck again figuring out the several points I mentioned above (health decay on equip, as well as health decay on equip/when waiting or resting/when awake over time for items with more than one "Cast When Held" enchantment).

User avatar
numidium3rd
Posts: 187
Joined: Sun Mar 25, 2018 12:34 am
Location: United States

Re: Where is item condition stored in memory?

Post by numidium3rd »

The process has been arduous but I made some progress. In the DosBox debugger, I found the function that subtracts item health on equip at 0838:15A0D7. My analysis of the assembly code came up with this formula for the amount to subtract:

Code: Select all

x = ((0x6E - a) * b) / 0x64

Where:
a = [6 * ([[[zeroInAllMyTests * 2 + itemDataLocation] + 0028706C] + 00292454]) + charInfoLocation + 0000009D]
b = [itemDataLocation + 000E] * [002A5E3C]
charInfoLocation = [ebp-0028]
itemDataLocation = [ebp-002C]
zeroInAllMyTests = [ebp-0024]
The process to get to a involves a lot of nested pointers but the only variable I've seen in a's computation is a value at the start of charInfoLocation (e.g. for the Amulet of the Orc Lord, it's 9). It's apparently an index that's stored for an item after it's created. Next step is to figure out where it's coming from. I know there are some talented reversers on this forum so I'm wondering... is anyone familiar enough with item data to know what this could be?

User avatar
Interkarma
Posts: 7236
Joined: Sun Mar 22, 2015 1:51 am

Re: Where is item condition stored in memory?

Post by Interkarma »

Just dropping in to say this is excellent progress Numidium. :)

Elenwel
Posts: 7
Joined: Tue Jan 01, 2019 5:14 pm

Re: Where is item condition stored in memory?

Post by Elenwel »

Hi !

I cannot answer your question yet, as I'm not sure I have found the functions responsible for magic item weakening. But Numidium, your code fragment can be simplified as :

Code: Select all

//a = [6 * ([[[zeroInAllMyTests * 2 + itemDataLocation] + 0028706C] + 00292454]) + charInfoLocation + 0000009D]
playerSkill = pPlayerData->skills[gMagicSchoolsToSkills[gSpellTypeToMagicSchool[pSpell->types[i].major]]].level
//b = [itemDataLocation + 000E] * [002A5E3C]
b = pSpell->duration * gSpellModifier->field_0
x = ((110 - playerSkill) * b) / 100
Spells types are as defined here.

Your itemDataLocation point to a spell (struct) and charInfoLocation to this struct.

gSpellModifier is a small structure (4 shorts) initialized with hard coded constants and depending on spell type.

In the code fragment i is an iterator over all spell's sub components (max 3).

As I said, I had yet not found the function you are speaking about (I'm using static analysis tools, not DosBox Debbugers). A similar function is situated @ offset 3A0C0 (or around line 1686 of spells.c :P) and is used to calculate spell cost :

Code: Select all

int __fastcall SC_spells::_3A0C0_GetCost_qqq(ELE_SpellsSTDEntry *pSpell, SC_OBJECT_TYPE3_PLAYER *pPlayerData)
{
  signed int i; // [esp+8h] [ebp-24h]
  int v6; // [esp+8h] [ebp-24h]
  int cost; // [esp+10h] [ebp-1Ch]
  __int16 v8; // [esp+14h] [ebp-18h]

  cost = 0;
  v8 = gCurrentSpellsTypeIdx;
  gCurrentSpellsEntry = pSpell;
  for ( i = 0; i < 3; ++i )
  {
    if ( pSpell->types[i].major != 0xFF )
    {
      gCurrentSpellsTypeIdx = i;
      if ( pSpell->types[i].minor == 0xFF )
        SC_jmem::memcpy(
          &stru_19961C,
          &stru_17AE13[stru_17AF6B[pSpell->types[i].major].field_0],
          sizeof(ELE_SPELL_S17AE13),
          "spells.c",
          1686,
          8);
      else
        SC_jmem::memcpy(
          &stru_19961C,
          &stru_17AE13[*(&stru_17AF6B[pSpell->types[i].major].field_0 + pSpell->types[i].minor)],
          sizeof(ELE_SPELL_S17AE13),
          "spells.c",
          1684,
          8);
      if ( pSpell->types[i].major >= 51 )
        ++cost;
      cost += ELE_SPELL::GetCost(gSpellTypeToCostType[pSpell->types[i].major] - 1)
            * (110 - pPlayerData->skills[gMagicSchoolsToSkills[gSpellTypeToMagicSchool[pSpell->types[i].major]]].level)
            / 100;
    }
  }
  gCurrentSpellsTypeIdx = v8;
  v6 = cost * word_17B235[pSpell->range] >> 1;
  if ( v6 < 5 )
    v6 = 5;
  return v6;
}
But it seems to be more mana cost related (it is used by spell absorption for example) than magic object degradation related... It may be the same function for both why not :)

User avatar
Interkarma
Posts: 7236
Joined: Sun Mar 22, 2015 1:51 am

Re: Where is item condition stored in memory?

Post by Interkarma »

Elenwel wrote: Mon May 11, 2020 8:30 am But it seems to be more mana cost related (it is used by spell absorption for example) than magic object degradation related... It may be the same function for both why not :)
Thank you for adding your help Elenwel. :)

That's an interesting point! Could durability loss on equip be derived from effect casting cost? There are a few places that formula is used - spell absorption as you say, and 10 * casting cost is the number of enchantment points for that effect at the item maker. It would not be surprising to find this is involved in the equip durability calculation.

Post Reply