afritz1 / OpenTESArena

Open-source re-implementation of The Elder Scrolls: Arena.
MIT License
987 stars 68 forks source link

Data offset corrections #259

Closed Allofich closed 5 months ago

Allofich commented 5 months ago

Fixes the offsets for SpellcastingItemAttackSpellPricesPerCharge. They were pointing into the previous data at SpellcastingItemAttackSpellQualities.

Here's the data in A.EXE (after decompression).

image

Each set of data has 15 entries for the 15 item attack spells. The value for the start of SpellcastingItemAttackSpellPricesPerCharge was pointing at 0x3D5E2, which is 4b80:1de2 here, within the SpellcastingItemAttackSpellQualities data.

Allofich commented 5 months ago

SpellcastingItemMiscSpellPricesPerCharge was similarly wrong. Here is the data from A.EXE.

image

Each set of data has 8 entries. The value for the start of SpellcastingItemMiscSpellPricesPerCharge was pointing to 4b80:1f1c here, halfway through the data.

Allofich commented 5 months ago

WaterTwilightLightLevels is probably incorrect, too, for A.EXE at least (I haven't checked ACD.EXE). The offset points into the middle of a two-byte value. It should probably be one byte less, at 0x3F40A.

From A.EXE: image

The current value of 0x3F40B points to 4b80:3c0b here (subtract 0x3B800 to get the value shown in the 4b80 segment here). The data starts at 3c0a, though, and 3c0a is what the code references, not 3c0b.

image

Allofich commented 5 months ago

src/Assets/ExeData.h has in it

std::array<uint16_t, 14> waterTwilightLightLevels;

but it looks like, starting from the corrected offset, it has 16 elements, the last two being 0.

image

Allofich commented 5 months ago

The spellcastingItemMiscSpell data had the wrong number of entries set in ExeData.h (9 instead of 8) for the values except for the spell names.

afritz1 commented 5 months ago

Thanks Allofich. I'm checking this branch but I think the spell prices per charge need to be two bytes each. Otherwise spellcastingItemAttackSpellPricesPerCharge is like [0x32, 0x0, 0x32, 0x0, 0x64, ...].

Allofich commented 5 months ago

You're right. I'll fix that as well.

afritz1 commented 5 months ago

I got it, no worries!

I'm looking at the water light level values but it seems okay at a glance. Will test some more. I'm pretty sure the game only has 14 light levels, so two extra ones might not make sense.

Allofich commented 5 months ago

armorEnchantmentBonusPrices, weaponEnchantmentBonusPrices, spellcastingItemBasePrices and enhancementItemBasePrices should also be read as 2-byte values.

plateArmorBasePrices, chainArmorBasePrices and leatherArmorBasePrices are correct as 1-byte values.

afritz1 commented 5 months ago

Done.

Yeah so about the light levels, if the water changes during sunrise/sunset like I'm thinking, then the values in that array should be between 1 and 13. They're probably indices into which .LGT light table to use to convert texture colors to shaded colors. See these in ArenaRenderUtils.h:

    constexpr uint8_t PALETTE_INDEX_LIGHT_LEVEL_LOWEST = 1;
    constexpr uint8_t PALETTE_INDEX_LIGHT_LEVEL_HIGHEST = 13;
Allofich commented 5 months ago

Well, if counting from the adjusted offset I suggested the final four 00 bytes seem to fit neatly in the array as two "0" values, and also the values are in descending order by 100h, so they fit with that.

The last few values of the array (if using the adjusted offset) are 400h, 400h, 300h, 300h, 200h, 200h, 100h, 100h, so the next two values being 0h and 0h fits the pattern.

It could be though that the game never accesses the water light level values with an index high enough that it would reach them.

Allofich commented 5 months ago

Of course values such as 400h, 300h, wouldn't be what you'd expect as indices.

But, as I showed above, the game code does access the data from the adjusted offset. I haven't reversed how the values are used after that.

afritz1 commented 5 months ago

I changed it. Maybe Arena treats them like # of bytes to skip. If there's nothing else then I'll merge this now.

If you're looking for anything else to help with, it would be awesome to have the screen-space fog finally documented in the wiki in a concise way. I haven't touched it since Carmina gave the info in #201 and honestly it still scares me a little (with the apparent self-modifying assembly from what I heard).

Allofich commented 5 months ago

WaterTwilightLightLevels seem to be related to how many 1/1024ths of the in-game day have passed.

Here is the only place in the code (as far as I can find) that references them:

MOV        BX,word ptr [1/1024thsOfDayThatHavePassed]
JS         LAB_1000_04b9
SUB        BX,0x100
JMP        LAB_1000_04bf
LAB_1000_04b9
SUB        BX,0x300
NEG        BX
LAB_1000_04bf
MOV        SI,BX
ADD        BX,BX
MOV        BX,word ptr [BX + WaterTwilightLightLevels]
CMP        BX,word ptr [DAT_4b80_3b4b]
JZ         LAB_1000_048a
MOV        word ptr [DAT_4b80_3b4b],BX

You can see that in MOV BX,word ptr [BX + WaterTwilightLightLevels] the value in BX, which was assigned 1/1024thsOfDayThatHavePassed with various adjustments then made to it, has the value of WaterTwilightLightLevels added to it. That suggests the values in WaterTwilightLightLevels also represent something related to 1/1024ths of a day.

1/1024thsOfDayThatHavePassed is the value at 4b80:cb70 in the disassembly of A.EXE. Another usage it has is in order to decide whether to play the night MIDI or not.

MOV        SI,s_night.xmi_4b80_40e2                         = "night.xmi"
CMP        word ptr [1/1024thsOfDayThatHavePassed],0x10c
JBE        LAB_311a_056a
CMP        word ptr [1/1024thsOfDayThatHavePassed],0x2f4
JNC        LAB_311a_056a
MOV        SI,s_sunnyday.xmi_4b80_40ec                      = "sunnyday.xmi"
Allofich commented 5 months ago

If you're looking for anything else to help with, it would be awesome to have the screen-space fog finally documented in the wiki in a concise way.

I may take a look at it, but if it's complicated it may be beyond me.

As you can see in the code snippet above, the values from WaterTwilightLightLevels are used to compute a value stored in DAT_4b80_3b4b. DAT_4b80_3b4b is used in a few different places. It is sometimes compared against 0xFFFF, and it is stored in BX right before a call to a function that references "waterani.rci", so it's probably used with that, which maybe you already know.

Allofich commented 5 months ago

If there's nothing else then I'll merge this now.

I don't intend to add any more commits.

Allofich commented 5 months ago

Sorry, the value I called GameMinutesPassedToday isn't game minutes, it is 1/1024ths of the day that have passed. (Looking back at the MIDI-related code I noticed that the values didn't match the game if they were interpreted as minutes). So the WaterTwilightLightLevels would be related to that.

Edit: I updated the above code to use 1/1024ths of the day.