Oblivion Mod:Save File Format/ACHR Uncertainties
< Mod / Oblivion: Oblivion Mod: Modding: Save File FormatThis article summarizes uncertain information about the ACHR and ACRE change records.
OverviewEdit
Known record storing orders
Consult Locations of Subrecords for certain locations and Appearance of Subrecords table below to get an overview of currently known record storing order.
The Actor Flag is a one byte flag. It has following known states:
- 0 - High
- 1 - Mid High
- 2 - Mid Low
- 3 - Low
- FF - None.
It seems that the Actor Flag defines the role of an NPC actor and the appearance of subrecords in the ACHR record. There are named subrecords like Scale, Run Once and so on triggered by the records general flags and subrecords or sections with coded names that seems to be presented as two byte hex values. For instance in different ACHR records of NPC high actors there can be found subrecords with hex codes 0x803F, 0x80BF or 0x3036 at fix locations. Meaning is unknown. Inside often found references (iref) and or values(float).
Some named subrecords can be found in a structure containing flags and corresponding sets of values. It is suggested to be the Actor Properties structure and describes changed essential actor properties. Consult Properties for detailed information.
Some change records internal formats are still unknown. At best you can see here:
- Is change record's length constant or variable.
- Flags that are indicating change record's existence in the record.
- If there is more than one flag, then it is possible that there multiple flags indicating change record - or there wasn't enough data to find single flag.
- It is also possible that multiple change records are sharing same flags or change records are actually same record - they just have different name in dump file.
- Change record's minimal and maximal lengths.
- Possible substructures lengths inside change record. This length is largest common divider from all change records minimal and maximal lengths.
Appearance of Subrecords depending on Actors RoleEdit
Table describes appearance of subrecords depending on the state of the Actor Flag. This table is very speculative but provides currently a usable understanding of subrecord locations that helps to walk through a ACHR change record. Subrecord names with unknown meaning but fix locations are represented by their hex-values. Some other have only suggested names because it is unknown where they belong to.
How to read the table:
- a row filled with Aquamarine color means that the subrecord appears when the records general change flag is set
- a colored cell under the Actor Flag name means that the subrecord appears only when the corresponding flag is set
Name | Type | Size [bytes] | Info | High | MidHigh | MidLow | Low | None |
---|---|---|---|---|---|---|---|---|
Cell Changed | struct | 16 | ||||||
Created | struct | 36 | ||||||
Moved | struct | 28 | ||||||
Actor Flag | byte | 1 | flag | |||||
Form Flag | ulong | 4 | ||||||
Temporary Attribute Changes | struct | 876 | present only if PC record (0x14) | |||||
Inventory | struct | |||||||
Actor Properties | struct[num] | |||||||
Havok Moved | struct[size] | |||||||
Scale | float | 4 | ||||||
Dialogue/Mount Horse | struct | |||||||
Active Pack Data | struct | |||||||
0x362e/0x3630/0x3646 | 32 | |||||||
Game Modifier | struct[num] | |||||||
unknown | 9 | |||||||
Magic Modifier | struct[num] | |||||||
unknown | 6/5/2/0 | ?depends on actorFlag? | ||||||
0x3F80 | 6 | |||||||
Run Once | FormID | 4 | ||||||
unknown | 25 | |||||||
0xFFFF | 34 | ?0xff ff 00 7f in every save file? | ||||||
0x3F80 | 18 | also 0x3FB3, 0x3F8C, 0x3F86 | ||||||
Animation #1 | struct | |||||||
Unknown Struct | struct[num] | {{size, iref, flag, data[size]}, ... } | ||||||
Divider | 19 | usually 0x1, ?belongs to Anim #1? | ||||||
Divider | 84 | always present (0x1) | ||||||
0x3F80 | 40 | |||||||
Unknown Struct | struct[num] | {{byte[13}, ... } ?thrown inventory items? | ||||||
0x4CFF/0x4C03/0x58FF | 77/77/87 | |||||||
0x3F80 | 74 | |||||||
Common Divider #1 | flag | 1 | usually 0x1, common means it is a flag at a fix location for all records | |||||
Life State | flag | 1 | ||||||
Disposition Modifier | struct[num] | |||||||
Equipment | ulong | 4 | meaning unknown | |||||
|
short | 2 | belongs to Common Divider #1:
|
|||||
Script Modifiers | struct[num] | |||||||
unknown | 17/8 | skip 17 bytes if Actor Flag not 0xFF (None) | ||||||
Common Divider #2 | flag | 1 | Usually 0x1
|
|||||
PC section | present only if PC record (0x14) |
Active Package DataEdit
The interpretation of this subrecord is very speculative. It is not backed up by text file dumps and its meaning is deduced from found data inside this subrecord.
The subrecord is present for all type of actors. Its length is minimum 17 bytes except for None- actors where it has a fix length 6 bytes.
It is suggested that the subrecord stores the coordinate offset from a package's target reference point along with a flag that describes the state of the current package.
Name | Type/Size | Info |
---|---|---|
-AI Pack | iref | actually it appears and is an iref that points to a PACK only if the read number is greater than two otherwise it is the type (see next row), other conditions where not found |
type | ulong | seems to be related to property flag 0x1f, see Properties |
X | float | coordinate offset |
Y | float | coordinate offset |
Z | float | coordinate offset |
flag | ubyte | unknown |
None - Actor | ||
|
float | |
|
ushort |
Life State (6)Edit
This change record is used in ACHR, ACRE record types.
Name | Type/Size | Info |
---|---|---|
state | ubyte | Enum:
|
Disposition Modifiers (15)Edit
Entries in this subrecord are modifying an actors disposition towards another NPC.
This change record is used in ACHR, ACRE record types.
Name | Type/Size | Info |
---|---|---|
num | ushort | length of sub structure array |
dispModifiers | struct[count] | |
|
iref | points to an actor (ACHR) |
|
ulong | value added to initial disposition |
Movement Blocked (17)Edit
This change record's length is constant 32 byte(s).
This change record is used in ACHR, ACRE record types. There was 14 change records in save files.
This information is NOT verified from actual save files.
Name | Type/Size | Info |
---|---|---|
unknown | ubyte[32] | Constant length of observed change records. |
Run Once (19)Edit
This change record's length is constant 22 byte(s).
This change record is used in ACHR, ACRE record types. There was 6 change records in save files.
This information is NOT verified from actual save files.
Name | Type/Size | Info |
---|---|---|
unknown | ubyte[22] | Constant length of observed change records. |
Magic Modifiers (20)Edit
Entries in this subrecord are modifying base actor values. They are used for temporary and dispellable magic effects.
Despite the fact that there is a counter for the amount of entries the sub structure array never contains only one entry. There will be zero entries (number equals zero) or not less than two entries.
This change record is used in ACHR, ACRE record types.
Name | Type/Size | Info |
---|---|---|
num | ushort | length of sub structure array |
magModifiers | struct[num] | collection of modified actor values |
|
ubyte | base actor value that is modified, see Actor Value Indices |
|
float | modifier added to base actor value |
Script Modifiers (21)Edit
Entries in this subrecord are modifying base actor values. They are used for temporary and non-dispellable scripted effects.
This change record is used in ACHR, ACRE record types.
Name | Type/Size | Info |
---|---|---|
num | ushort | length of substructure array |
scriptModifiers | struct[num] | collection of modified actor values |
|
ubyte | base actor value that is modified, see Actor Value Indices |
|
float | modifier added to base actor value |
Game Modifiers (22)Edit
Entries in this subrecord are modifiers to base actor values. They are used for permanent effects.
This change record is used in ACHR, ACRE record types.
Name | Type/Size | Info |
---|---|---|
num | ushort | length of struct |
gameModifiers | struct[num] | collection of modified actor values |
|
ubyte | base actor value that is modified, see Actor Value Indicies |
|
float | modifier added to base actor value |
Animation (25)Edit
Part of properties section. See Properties, specifically flag 0x4a.
Animation data seems to be divided into two parts. For all records, if triggered by records flags, there is the Animation 3rd Person view section. Only for the PC change record (0x14) there exists a second part and this is probably the first person view data. In PC change record both parts are not connected. There is a defined gap in between filled with other data. It seems that the type of the current animation (Action, Idle) is described with special codes and only values of some variables are stored.
This change record is used in ACHR, ACRE, REFR record types.
This information was found in a couple of actual save files.
Name | Type/Size | Info |
---|---|---|
Animation 3rd Person | ||
animName | ushort | ?type of animation? |
list() | list, terminates with 0x0000 | |
|
ushort | defines structure of data |
|
different | animation control data |
|
next animation data code | |
|
next animation data | |
|
ushort | indicates end of list |
parent | iref | reference to parent animation (bench, bed) |
|
ushort | optional, only if parent not 0 |
|
||
... | ||
gap | other data | |
... | ||
Animation 1st Person | appears only within PC's ACHR change record | |
animName | ushort | ?type of animation? |
list() | list, terminates with 0x0000 | |
|
ushort | defines structure of data |
|
different | animation control data |
|
next animation data code | |
|
next animation data | |
|
ushort | indicates end of list |
dataStruct #3 | no animation code, always there | |
unknown | byte[35] | unknown animation data |
Animation namesEdit
Meaning of animation names are unknown.
Name | Info |
---|---|
0x01ff | |
0x05ff | |
0x09ff | |
0x11ff | |
... |
Animation Data CodesEdit
Meaning of codes are unknown.
Name | Type/Size | Dependent Data Structure | Info |
---|---|---|---|
0x0100 | ushort |
|
|
0x0115 | ushort |
|
|
0x0029 | ushort |
|
|
0x0000 | ushort |
|
|
0x0021 | ushort |
|
|
0x0022 | ushort |
|
|
... |
Data StructureEdit
Only loop time variables are verified from in-game debug tables. All other are guessed.
Number | Name | Type/Size | Info |
---|---|---|---|
|
unknown | int | ? |
unknown | byte[11] | ? | |
time | float | ?loop time? | |
unknown | int | ? | |
time | float | ?loop time? | |
time | float | ?loop time? | |
unknown | int | ?always 0xff 7f ff ff? | |
|
unknown | int | ? |
unknown | int | ? | |
unknown | int | ? | |
unknown | ushort | ?code? | |
time | float | ? | |
unknown | int | ? | |
time | float | ? | |
time | float | ? | |
unknown | int | ? | |
|
unknown | int | ? |
unknown | int | ? | |
unknown | int | ? | |
time | float | ? | |
time | float | ? | |
time | float | ? | |
unknown | int | ? |
Dialogue, Mount Horse, FollowEdit
It is suggested that this subrecord defines the procedure of the current AI package of an NPC actor. Text file dumps from save files include a formid with the subrecord special names. Except for the named Dialogue subrecord there is encountered a fix length of 32 bytes.
The Dialogue subrecord seems to appear when two NPC actors are in a conversation. For one actor the subrecords length will be 5 bytes (formid and type flag). This can be recognized by simultaneously set 'Non-saved-Package' flag. The other conversation partner will have a full data section with used topic texts and paths to voice files along with a data section containing reference to the targeted actor.
This change record is used in ACHR, ACRE, REFR record types.
Name | Type/Size | Info |
---|---|---|
reference | formid | seems to be an in game created record (0xFF...) |
flag | ubyte |
|
type1 | ubyte |
|
type2 | ubyte |
|
size | ushort | size of target data section, if Dialogue subrecord else it is zero |
Dialogue | ||
|
struct[size] | |
|
ushort | overall size of topic data section |
|
ushort | Number of subrecords |
|
struct[num] | |
|
ubyte | mostly 0x1 |
|
bstring | used topic text |
|
bstring | relative path to voice file |
|
struct[25] | |
|
ushort | always 0x0, ?terminates subrecord? |
Mount Horse | ||
|
struct[23] |