Tes5Mod:ChangeFlags

Change Flags

ChangeFlags are part of the ChangeForm structure in a savefile. 
It's the uint32 that follows the changeFormId for every changeForm in a savefile. 
The changeFormId may influence the amount of data stored per ChangeFlag. 
ChangeFlags have different meanings per ChangeForm type. 
Sizes may also be different for combinations of ChangeFlags



Initial type

Certain changeforms first have an initial data type and data.

These are applied in order.
If change form type is CELL:
:If flag CHANGE_CELL_DETACHTIME is not set, initialType = 0.
:Else if flag CHANGE_CELL_EXTERIOR_CHAR is set, initialType = 1.
:Else if flag CHANGE_CELL_EXTERIOR_SHORT is set initialType = 2.
:Else if flag CHANGE_CELL_DETACHTIME is set initialType = 3.
:Else initialType = 0.

If change form type is one of these (REFR, ACHR, PMIS, PGRE, PBEA, PFLA, PHZD, PBAR, PCON, PARW):
:If change form is created one (FormId >= FF000000) intialType = 5.
:Else if flag CHANGE_REFR_PROMOTED or CHANGE_REFR_CELL_CHANGED is set, initialType is 6.
:Else if flag CHANGE_REFR_HAVOK_MOVE or CHANGE_REFR_MOVE is set, initialType = 4.
:Else initialType = 0.




Change form flags




CELL change form flags




QUST change form




REFR change form

Data Elements

These are the elements I have so far seen in a REFR change form.



Flags

This table lists which fields will be present for which flags. It is incomplete at the moment.



The 0xff000000 type changeFormIds have at least 31 bytes of data in structure called 'Base', containing at least a RefId and the location/rotation fields. In this case the additional data added by the other flags may be different, for example CHANGE_REFR_MOVE and CHANGE_REFR_CELL_CHANGED will not add any data, while CHANGE_REFR_PROMOTED will only add 6 bytes instead of 40. The CHANGE_REFR_MOVE flag appears to be set on every changeForm of this type.

extraData

The extra data starts with the number of items contained in the field. Bit 0 and 1 of the first byte probably indicate how many bytes are used to store the size: 00 = just this byte, 01 = 1 extra byte, 10 = ?, 11 = ?. The count is obtained by reading the bytes and shifting them two bits to the right. 0x04 thus becomes 1, 0x08 becomes 2, ...

The next bytes tell something about the data that follows.

An incomplete list of possible data in the extraData field:



The fields with a repeat should be interpreted like this: after the fieldType there is a count (again bit 0 and 1 of the first count byte indicate how many extra bytes are used for the count). After the count, count * bytesToFollow will follow. So 0x8c 0x08 .... indicates that 2 (0x08 shifted by 2) records of type 0x8c follow, which are 3 bytes per record, so 6 bytes in total. Frequently 0x88 0x00 is observed, meaning 0 * 7 bytes follow. As another example, 0x88 0x81 0x01 means count is (81>>2 + 1<<6) = 96, so 96 * 7 bytes follow.

NPC_ change form

{| class="wikitable" width="100%"
!Bit
!Value
!Name
!Data Size
!Data
|-
|0
|0000 0001
|CHANGE_FORM_FLAGS
|6
|Change form flags
|-
|1
|0000 0002
|CHANGE_ACTOR_BASE_DATA 
|24
|See ACBS field of NPC_ record
|-
|6
|0000 0040
|CHANGE_ACTOR_BASE_FACTIONS 
|var
|vsval count
struct {refID factionID; uint8 rank} [count]
|-
|4
|0000 0010
|CHANGE_ACTOR_BASE_SPELLLIST 
|var
|vsval spellCount
refID spells[spellCount]

vsval leveledspellCount

refID leveledspells[leveledspellCount]

vsval shoutCount

refID shouts[shoutCount] 
|-
|3
|0000 0008
|CHANGE_ACTOR_BASE_AIDATA 
|20
|See AIDT field of NPC_ record
|-
|5
|0000 0020
|CHANGE_ACTOR_BASE_FULLNAME
|var
|wstring name
|-
|9
| 0000 0200
|CHANGE_NPC_SKILLS
|52
|See DNAM field of NPC_ record
|-
|10
| 0000 0400
|CHANGE_NPC_CLASS
|3
|refID class
|-
|25
|0200 0000
| CHANGE_NPC_RACE
|6
|refID race
refID race2 (?)
|-
|11
|0000 0800
| CHANGE_NPC_FACE
|var
|?
|-
|24
|0100 0000
| CHANGE_NPC_GENDER
|1
|uint8 gender (0 – male, 1 - female)
|-
|12
|0000 1000
| CHANGE_NPC_DEFAULT_OUTFIT
|3
|refID defOutfit
|-
|12
|0000 1000
| CHANGE_NPC_SLEEP_OUTFIT
|3
|refID sleepOutfit
|}

The order of data in changeForm is the same as in the table

Skills/Health, etc are stored in ACHR records (as floats) associated with the NPC (for the player this is formid 0x00000014, refid=0x40 0x00 0x14 and is zlib compressed)
if any of the data is stored in the NPC_ record it seems to be ignored by the game.