descawed / tesconvert

A tool for converting player characters between The Elder Scrolls III: Morrowind and The Elder Scrolls IV: Oblivion
0 stars 0 forks source link

Active magic effects #8

Open descawed opened 4 years ago

descawed commented 4 years ago

Need to convert over any magic effects that are currently active on the player. This definitely applies to permanent effects, but actually, do we want to convert over temporary effects? Fast travel advances time to reflect the distance traveled, and we're essentially fast traveling from Morrowind to Cyrodiil; surely any temporary effects would have expired in the time it takes to get there.

descawed commented 4 years ago

Research: on the Morrowind side, this stuff is stored in the SPLM record, which is a record that only appears once in the save. This record contains all active spell effects on all actors, so only convert the ones where the affected actor ID is PlayerSaveGame. See importsplm.hpp/cpp in OpenMW for details. Note: the only use I saw for the spell index was in linking it to projectiles (PROJ records). See ConvertPROJ::write in OpenMW converter.cpp.

On the Oblivion side, we're already pulling this in in the PlayerReferenceChange but not parsing it completely. The effect details seem to vary by (most likely) effect type.

In both games, it seems that the full details of each effect have not been fully decoded. We will have to do some original research. I think the fastest way to test this would be to make a mod with a spell that has every effect, cast it on ourselves, save, and inspect the results.

descawed commented 4 years ago

Something to consider: bringing over the active effects from Morrowind also means removing the active effects that were already there in Oblivion. I can imagine this getting weird if there are active summon effects (including bound items). Will we need to find the linked creature/item and remove it from the save?

descawed commented 4 years ago

Some great info on Oblivion active effects in OBSE: https://github.com/llde/xOBSE/blob/master/obse/obse/GameMagicEffects.h

descawed commented 4 years ago

Tested a Feather constant effect enchantment. A few interesting notes:

descawed commented 4 years ago

Details so far:

basic details: 00: time effect has been active 04: OBSE applied flag? 05: OBSE terminated flag? 06: 44 (0x2c) for Thief Birthsign effects, 0 for everything else; OBSE flags12? 07: magnitude, taking into account caster's spell effectiveness 0B: duration (original value, not time remaining), taking into account caster's spell effectiveness for "no magnitude" effects 0F: iref; likely target per OBSE 13: iref; likely caster per OBSE 17: iref to the enchanted item this effect originated from, if any 1B: ??? 1D: ??? 14 (decimal, not hex) on all the spell effects and all but the first potion and birthsign effects, where it's 0

for summon/bound effects: 21: iref to the summoned entity

for summons: 25: iref to the summon reference (as opposed to the actor base, which is what's at 21) 29: 0u8?

descawed commented 4 years ago

After reviewing a number of these effects, there is much more data stored in these active effects than I anticipated, and there are a large number of effects that have more than the basic 33 bytes of data. I have no idea what most of it means, and it appears that OBSE has also not decoded the meaning of most of it. Reverse engineering the meaning of all of this data looks like a very time-consuming process.

Given that, I'm thinking of taking a different approach. I've planned for a while on writing an OBSE plugin because I wanted to store things in the co-save, such as a mapping of Morrowind IDs to converted form IDs. Maybe, rather than converting the active effects directly, we wipe out all active effects in the save, and then in the co-save store a list of spells that need to be cast on the player and their elapsed duration. Then the plugin can call into the game to apply those when the save is loaded, and we can let the game handle creating the active effects. Once they're created, we'll loop through them and update the elapsed time, marking any expired effects for removal.

This comes with a few of its own challenges:

descawed commented 4 years ago

I have a test OBSE plugin working. I'll need to request an opcode range from the OBSE team before this goes live because you can't write to the co-save without one. Before I continue with that, I want to write the code to cancel out all active effects and convert the raw player stats. I need to make both Morrowind and Oblivion saves with a mix of temporary and permanent effects of different kinds so I can test that the removal code functions correctly for all types of effects.

descawed commented 3 years ago

I made an interesting discovery: if you have a Fortify Magicka ability, and then you add a Fortify Maximum Magicka ability (or if you have both on the same ability), the game will forget about the Fortify Magicka abilities. For instance, say you have a character with 40 INT and thus 40 magicka. You add a Fortify Magicka 10pts ability and now have 50 magicka. If you were to add a Fortify Maximum Magicka 1.0x INT, you would expect to get +40 magicka for a total of 90, but you'll actually end up with 80 because the game forgets about the 10pt Fortify Magicka. But if you then remove the Fortify Magicka ability, the game will still subtract 10 and leave you with 70. Conversely, if you add the Fortify Maximum Magicka ability and then the Fortify Magicka ability, you'll end up with the expected total of 90.

I don't think we can fix this in the converter without recalculating the magicka amount from scratch, which could reduce mod compatibility. I also don't think this is something that anyone has run into, because I couldn't find reference to it anywhere. I thought it was worth documenting, though.