In post 1 of Fire Emblem 10 Modding, we delved into the structure of the ISO and locations of key files that we care about. One of these files was FE10Data.cms
, which contains a substantial amount of data that we want to modify.
This post will describe FE10Data.cms
's sub-sections in more detail, as they were brushed over in post 1. It should act as a decent reference for anyone who plans to modify this file.
Part 1: Prerequisites
You'll need to do many of the steps in post 1 if you haven't already. Recall that we extracted the ISO and decompressed FE10Data.cms
into FE10Data.cms.decompressed
.
It is recommended going into part 2 to open FE10Data.cms.decompressed
in your favourite hex editor and follow along.
Part 2: Breaking down each sub-section
For convenience, I've attached the sub-section table from post 1:
Start location | Number of objects | Object byte size | Data stored (Official label) |
---|---|---|---|
0x2c | 461 | Varies | Character (PersonData) |
0x926c | 171 | Varies | Class (JobData) |
0xdf44 | 296 | Varies | Item (ItemData) |
0x12810 | 142 | 0x2c bytes | Skill (SkillData, SID_*) |
0x146d4 | 1 | 0x10 bytes | Support Gain Bonus (RelianceParam) |
0x146e4 | 9 | 0xc bytes | Affinity (DivineData) |
0x14754 | 1 | 0x40 bytes | Attack XP (GameData) |
0x14794 | 1 | 0x48 bytes | Unknown (GameData) |
0x147dc | 43 | 0x2c bytes | Terrain (TerrainData) |
0x15bb8 | 44 | 0x194 bytes | Battle Map (BattleTerrIndex) |
0x1a12c | 106 | 0x4 bytes | Battle Map Background (BattleTerrName) |
0x1a2d4 | 71 | 0x240 bytes | Buddy Support (RelianceData) |
0x24298 | 60 | 0xb4 bytes | Chapter (ChapterData) |
0x26ccc | 45 | 0xc bytes | Group (GroupData) |
0x26eec | 46 | 0xc bytes | Bond Support (KiznaData) |
0x2711c | 64 | 0xc bytes | Affinity Bonus (DivineParam) |
0x27420 | 27 | 0xc bytes | Weapon Triangle Bonus (3SukumiData) |
0x27568 | 10 | 0x10 bytes | Biorhythm Type (BioData) |
0x27608 | 5 | 0xc bytes | Biorhythm Level Bonus (BioParam) |
0x27644 | 22 | Varies | Pacifist (NOBTL_*) |
We'll go over in detail all the sub-sections. Note that some sub-sections start with 4 bytes denoting the number of objects in the list.
Character (PersonData)
Example: Ike's character data
00000030 0200 0b00 0003 245e 0003 035f 0002 fa34
00000040 0002 a1de 0002 b766 0003 42d6 0003 328a
00000050 0003 3766 0003 3624 0000 0000 0000 0000
00000060 0002 8cd0 0002 8cda 0000 0000 0703 0800
00000070 0300 0000 0006 0f01 0f0c 0e0c 0500 0041
00000080 370a 3c23 1e28 0f00
- 1 byte [unsigned int]: number of skills.
- 1 byte: null byte.
- 1 byte [unsigned int]: character's starting level.
- 1 byte [bool]: gender.
0
means male,1
means female. - 4 bytes [string pointer]: person (character) id (e.g.
PID_IKE
). - 4 bytes [string pointer]: mpid (base person id).
- 4 bytes [string pointer]: mnpid.
- 4 bytes [string pointer]: face id.
- 4 bytes [string pointer]: job (class) id.
- 4 bytes [string pointer]: affinity.
- 4 bytes [string pointer]: starting weapon ranks (e.g.
S-----------
). - (number of skills) * 4 bytes [string pointers]: starting skills.
- 4 bytes: null bytes.
- 4 * 4 bytes [string pointers]: action / animation ids.
- For Beorc, the first 3 pointers correspond to the character as a tier 1/2/3 unit, respectively (null bytes if they don't have a tier 1/2). Last pointer is always null bytes.
- For Laguz, the first pointer correspond to the character untransformed. The last 3 pointers are identical and correspond to the character transformed.
- 1 byte [unsigned int]: biorhythm. An integer between 0 and 9 corresponding to the biorhythm type, or 0xff if the character has no biorhythm.
- 3 bytes: unknown.
- First byte is always 0x3 for playable characters, and vary from 0x0 to 0x6 only for bosses.
- Second byte is always 0x8 for playable characters, and are a power of 2 only for bosses (0x4, 0x8 or 0xc).
- Third byte is either 0x0, 0x3, 0x7, 0xf, or 0x1f for playable characters, and 0x0 for everyone else.
- 1 byte [unsigned int]: number of authority stars.
- 4 * 1 bytes [2's complement int]: Laguz transform related values.
- For Beorc, these are all null bytes.
- For Laguz, these correspond to [amount gained per turn when untransformed, amount gained per battle when untransformed, amount lost per turn when transformed, amount lost per battle when transformed]. The first 2 values are always positive. The last 2 values are always negative.
- 10 bytes [2's complement int]: stat additions to be added to the character's current class base stats to calculate the starting stats.
- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES, CON, MOV].
- 8 bytes [unsigned int]: growth rates as a percentage.
- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES]
Class (JobData)
Example: Vanguard class data
000092e0 0002 be97 0002 f790 0003 4a76 0002 dd01
000092f0 0002 b766 0000 0000 0000 0000 0000 0000
00009300 0002 8cda 0003 3297 0002 7a14 0c01 0300
00009310 0004 0100 0107 3c04 0000 0000 0003 3783
00009320 0003 39a1 0003 388a 0003 33ea 0000 0000
00009330 0003 3318 4125 0f28 251e 2017 3513 0317
00009340 1300 1106 5032 0a46 281e 280f 0402 0402
00009350 0200 0204
- 4 bytes [string pointer]: job (class) id.
- 4 bytes [string pointer]: mjid (base / genderless job id).
- 4 bytes [string pointer]: Shift JIS encoded Japanese of the class name.
- 4 bytes [string pointer]: mh_j.
- 4 bytes [string pointer]: job id that promotes to this class.
- 4 bytes [string pointer]: job id that this class promotes to.
- 4 bytes [string pointer]: alternate job id.
- For Beorc class, always null bytes.
- For Laguz class, the transformed job id if this class is the untransformed version, and vice verse.
- 4 bytes [string pointer]: item id.
- For Beorc class, always null bytes.
- For Laguz class, the Laguz's attack item (e.g. fang / beak / claw).
- 4 bytes [string pointer]: action / animation id.
- 4 bytes [string pointer]: base weapon ranks.
- 4 bytes [string pointer]: max weapon ranks.
- 1 byte [unsigned int]: base constitution (CON).
- 1 byte [unsigned int]: armour type.
- 1 byte [2's complement int]: armour weight.
- 1 byte [unsigned int]: mount type (0: no mount, 2: horse, 3: pegasus, 4: wyvern).
- 1 byte [2's complement int]: mount weight.
- 1 byte [unsigned int]: number of skills.
- 1 byte [unsigned int]: number of sfxc (attributes).
- 1 byte [unsigned int]: promote level. Character promotes to the next class when hitting this level. Capped at 21 (Technically not capped, but characters gain no XP after level 21 so you'll not be able to promote at all). 0x0 if this is the final class and cannot promote.
- 1 byte [unsigned int]: movement type.
- 1 byte [unsigned int]: default movement amount.
- 1 byte [unsigned int]: skill capacity.
- 1 byte [unsigned int]: field-of-war vision.
- 4 bytes: null bytes.
- (number of skills) * 4 bytes [string pointer]: skills gained upon promotion to this class.
- 4 bytes [string pointer]: skill gained if a Satori Sign is used (null if this class cannot use a Satori Sign).
- (number of sfxc) * 4 bytes [string pointer]: sfxc (attributes). e.g.
SFXC_FLY
,SFXC_DRAGON
. This categorizes the class to determine whether a skill can be learned and item effectiveness. - 8 bytes [int]: max stats
- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES]
- 8 bytes [int]: base stats.
- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES]
- 8 bytes [unsigned int]: growth rates. Most characters have custom growth rates. This is used when they do not.
- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES]
- 8 bytes [int]: stat additions on promotion to this class. Null bytes if this is the initial class.
Item (ItemData)
Example: Ragnell item data
0000e3f8 0002 af92 0002 eba6 0002 d0ff 0003 42d0
0000e408 0003 42d0 0003 1608 0000 0000 0002 9cb2
0000e418 0000 0000 0012 0000 1250 0514 0f02 0102
0000e428 ff00 0000 0406 0001 0003 431b 0003 416a
0000e438 0003 42c8 0003 42b5 0003 41d0 0003 425d
0000e448 0000 0000 0000 0500 0000 0000
- 4 bytes [string pointer]: item id.
- 4 bytes [string pointer]: miid (base item id).
- 4 bytes [string pointer]: mh_i.
- 4 bytes [string pointer]: displayed weapon type,
- 4 bytes [string pointer]: actual weapon type. The only times this differs from the displayed weapon type are the white dragon breath and Ashera's judge items.
- 3 * 4 bytes [string pointer]: effect ids.
- 1 byte: null byte.
- 1 byte [unsigned int]: icon.
- 2 bytes [unsigned int]: cost per use. The cost in the shop is given by (cost per use * number of uses).
- 1 byte [int]: might.
- 1 byte [int]: accuracy as a percentage.
- 1 byte [int]: critical chance as a percentage.
- 1 byte [int]: weight.
- 1 byte [int]: number of uses. The cost in the shop is given by (cost per use * number of uses).
- 1 byte [int]: weapon experience gained per use.
- 1 byte [unsigned int]: minimum range.
- 1 byte [unsigned int]: maximum range.
- 1 byte: unknown. Is either 0x01, 0x02, or 0xff.
- 3 bytes: null bytes.
- 1 byte: always 0x4.
- 1 byte [unsigned int]: number of special attributes.
crit0
: cannot critical.poison
: applies poison to the enemy if the hit connects.twice
: attacks twice.valuable
: cannot be sold.stormsw
: (for swords only) can attack from range.infinity
: infinite durability.sealsteel
: cannot be stolen.lookschange
: (for Ragnell only) unknown.expandrange
: can attack at 3 range for tier 3 marksman.longfar
: can attack from far range.stone
: for onagers (probably for doing a diamond-shaped area of effect).sh
: for ballistae.absolutehit
: 100% hit rate.resire
: heals character the amount of damage dealt.blow
: physical attack.magblow
: magical attack.breath
: for dragon Laguz.finalonly
: unknown.healing
: heals user if equipped.rest
: restores user if equipped.curesilence
: cures silence if equipped.curesleep
: cures sleep if equipped.humanonly
: for Beorc only.beastonly
: for Laguz only.lycdamhalf
: halves Laguz damage (skill).movtw
: allows using up leftover movement after performing an action (skill). Similar to the Canto skill.flutter
: unknown.ownerreinforce
: gives the user defence points.特効封印
: negates effective bonus (skill).ラグズ特効封印
: negates Laguz effective bonus (skill).eqA
/eqB
/ ... /eqI
: only characters with the hidden skillSID_EQ_*
can equip.
- 1 byte [unsigned int]: number of sfxc (attributes).
- 1 byte [bool]: whether equipping / using this item gives the character stat boosts.
0
means no stat boosts,1
means there are stat boosts. - (number of attributes) * 4 bytes [string pointer]: attributes.
- (number of sfxc) * 4 bytes [string pointer]: sfxc (special attributes). This item is effective against classes with any of these attributes, or can perform a certain task (i.e.
SFXC_DOORBREAK
can break doors). - 12 bytes [int]: stat boosts. These 12 bytes only exist if field 21 was a
1
.- Correspond to [HP, STR, MAG, SKL, SPD, LCK, DEF, RES, CON, MOV].
- The last 2 bytes are always null bytes, so I'm not sure what they correspond to. It's probably just for alignment purposes.
Skill (SkillData, SID_*)
Skill data are broken into 2 sections: a list of skills and skill table beginning at 0x1407c. Each skill entry is also listed separately in section 3.5 under SID_* (e.g. SID_ADEPT).
Example: Nihil skill data
00013ce0 0003 388a 0003 0ff4 0002 e0db 0002 c6d7
00013cf0 0002 9c7f 0000 0000 0002 aee9 7901 143c
00013d00 0102 0000 0001 4404 0001 440c
The actual skill data consists of:
- 4 bytes [string pointer]: skill id.
- 4 bytes [string pointer]: msid (base skill id).
- 4 bytes [string pointer]: mh_skill.
- 4 bytes [string pointer]: mh2_skill.
- 2 * 4 bytes [string pointer]: effect ids.
- There's some difference between the first effect id and the second, but I haven't taken a close look.
- 4 bytes [string pointer]: item id. Item used to learn the skill.
- 1 byte [int]: counter.
- 1 byte: unknown. Either 0x1, 0x2, or 0x3.
- 0x3 means hidden (skill is not visible in-game).
- 1 byte [int]: capacity.
- 1 byte: unknown.
- 1 byte [unsigned int]: table pointer 1 count.
- 1 byte [unsigned int]: table pointer 2 count.
- 2 bytes: null bytes.
- 4 bytes [raw pointer]: table pointer 1 (offset by 0x20). 0x0 if no pointer.
- 4 bytes [raw pointer]: table pointer 2 (offset by 0x20). 0x0 if no pointer.
Example: Mercy table pointer 1 data (contains 3 entries):
000143f4 0100 0000 0003 3869 0000 0000 0003 3318
00014404 0000 0000 0003 22d1
One skill table entry consists of:
- 1 byte [bool]: explained later.
- 3 bytes: null bytes.
- 4 bytes [string pointer]: skill id / sfxc / job id / person id.
For a person/job id/sfxc, if the first byte in the entry is:
- 0x0: skill is whitelisted (only these classes/characters/classes with this attribute can learn the skill).
- 0x1: skill is blacklisted (these classes/characters/classes with this attribute cannot learn the skill).
For a skill id, if the first byte in the entry is:
- 0x0, skill is a prerequisite. For example, the Shove skill is a prerequisite for the Smite skill.
- 0x1, skill is an antirequisite. For example, the Formshift skill is an antirequisite for the Halfshift skill.
There doesn't seem to be any differentiation between the 2 pointers. My guess is two table pointers are used to save space. That is, multiple skills can point to the same location in the table if their entries are the same, and having 2 pointers increases the likelihood of entries being the same.
Support Gain Bonus (RelianceParam)
The support gain consists of 0x10 bytes:
000146d4 3264 9697 0f1e 0305 0401 0202 0100 fffe
- 1 byte [unsigned int]: max support points for no support.
- 1 byte [unsigned int]: max support points for a C support.
- 1 byte [unsigned int]: max support points for a B support.
- 1 byte [unsigned int]: max support points for an A support.
- 1 byte [int]: base chapter bonus.
- 1 byte [int]: unknown bonus. Is exactly 0x1e.
- 1 byte [int]: base adjacent bonus.
- 1 byte [int]: base carry bonus.
- 1 byte [int]: base heal bonus.
- 1 byte [int]: base shove bonus.
- 1 byte [int]: unknown bonus. Is exactly 0x2.
- 5 bytes [2's complement int]: delta type.
There are 5 different support types (00, 01, 02, 03, 04). The base bonus corresponds to support type 02, and the deltas determine the actual bonus using the base bonus and the support type.
Serenes Forest has great info on support bonuses, so I'm not going to restate what they wrote.
Affinity (DivineData)
Example: Thunder affinity data
00014700 0003 42dd 0001 0005 0000 0000
- 4 bytes [string pointer]: affinity name.
- 1 byte [int]: might delta.
- 1 byte [int]: defence delta.
- 1 byte [int]: hit delta.
- 1 byte [int]: avoid delta.
- 4 bytes: null bytes.
Attack XP (GameData)
The attack XP data consists of 0x40 bytes:
00014754 0028 001c 000f 000f 001e 0013 000a 0005
00014764 0064 0064 0064 0064 0064 0064 0064 0064
00014774 0005 0005 0005 0000 0005 0005 0005 0000
00014784 000f 000a 000a 0005 0028 003c 0028 001e
The data are broken into groups of 0x8 bytes. Each group corresponds to some modifier for each of the 3 difficulties and an unknown (probably debug) difficulty in the order [unknown, easy, normal, hard].
- 4 * 2 bytes [2's complement int]: kill modifier.
- 4 * 2 bytes [2's complement int]: attack modifier.
- 4 * 2 bytes [2's complement int]: kill percentage (always 100).
- 4 * 2 bytes [2's complement int]: attack percentage (always 100).
- 4 * 2 bytes [2's complement int]: "tier 2" kill modifier.
- 4 * 2 bytes [2's complement int]: "tier 3" kill modifier.
- 4 * 2 bytes [2's complement int]: Laguz attack modifier.
- 4 * 2 bytes [2's complement int]: boss kill modifier.
Some formulae for computing XP using these modifiers will be described later on as they are complex.
Unknown (GameData)
The relevant bytes are:
00014794 0028 001e 0014 000a 00c8 00c8 0064 0064
000147a4 0000 0000 0000 0000 0000 0000 0000 0000
000147b4 0000 0000 0000 0000 0005 0505 0505 0505
000147c4 0005 0505 0505 0505 0000 0000 0000 0000
000147d4 0000 0000 0000 0000
These bytes don't seem to affect the game in any way, but I may have missed something.
Terrain (TerrainData)
Terrain data are broken into 2 sections: a list of terrains, and a list of pointers to terrain data beginning at 0x14f40.
Example:
00014c54 0000 0000 0000 0000 0002 9b30 0003 33ab
00014c64 0003 33bf 0303 0303 0303 0202 0303 0101
00014c74 0101 0202 0101 0202 0202 0300
The actual terrain data consists of:
- 1 byte [int]: ground avoid bonus.
- 1 byte [int]: ground defence bonus.
- 1 byte [int]: ground resistance bonus.
- 1 byte [int]: air avoid bonus.
- 1 byte [int]: air defence bonus.
- 1 byte [int]: air resistance bonus.
- 1 byte [int]: HP recover percentage.
- 1 byte: unknown.
- 4 bytes [string pointer]: effect id.
- 2 * 4 bytes [string pointer]: sfx (sound effects).
- 17 * 1 bytes [unsigned int]: movement costs.
- Corresponds to [Foot 1, Foot 2, None, None, Armor 1, Armor 2, Mage 1, Mage 2, Horse 1, Horse 2, Flying, Thief 1, THief 2, Bandit, Beast 1, Dragon 1, Beast 2, Dragon 2, Civilian, None, None, Heron (Rafiel), Black Knight].
- 1 byte: null byte.
Example:
00014f90 0400 0000 0003 490d 0003 14d0 0001 4898
The terrain list of pointers consists of:
- 1 byte: unknown. Probably just an index.
- 3 bytes: null bytes.
- 4 bytes [string pointer]: Shift JIS encoded Japanese name
- 4 bytes [string pointer]: mt. Also Shift JIS encoded Japanese.
- 4 bytes [raw pointer]: pointer to terrain data (offset by 0x20).
Battle Map (BattleTerrIndex)
Note: only the last 2 of the 4 bytes are used to denote the number of objects. The first 2 bytes seem to be used for something else.
Example:
00016b84 0003 3ff7 0019 ffff 001a ffff ffff ffff
00016b94 ffff ffff ffff ffff ffff ffff ffff ffff
00016ba4 ffff ffff ffff ffff ffff ffff ffff ffff
00016bb4 ffff ffff ffff ffff ffff ffff ffff ffff
00016bc4 ffff ffff ffff ffff ffff ffff ffff ffff
00016bd4 ffff ffff ffff ffff ffff ffff ffff ffff
00016be4 ffff ffff ffff ffff ffff ffff ffff ffff
00016bf4 ffff ffff ffff ffff ffff ffff ffff ffff
00016c04 ffff ffff ffff ffff ffff ffff ffff ffff
00016c14 ffff ffff ffff ffff ffff ffff ffff ffff
00016c24 ffff ffff ffff ffff ffff ffff ffff ffff
00016c34 ffff ffff ffff ffff ffff ffff ffff ffff
00016c44 ffff ffff ffff ffff ffff 001a ffff ffff
00016c54 ffff ffff ffff ffff ffff ffff ffff ffff
00016c64 ffff ffff ffff ffff ffff ffff ffff ffff
00016c74 ffff ffff ffff ffff ffff ffff ffff ffff
00016c84 ffff ffff ffff ffff ffff ffff ffff ffff
00016c94 ffff ffff ffff ffff ffff ffff ffff ffff
00016ca4 ffff ffff ffff ffff ffff ffff ffff ffff
00016cb4 ffff ffff ffff ffff ffff ffff ffff ffff
00016cc4 ffff ffff ffff ffff ffff ffff ffff ffff
00016cd4 ffff ffff ffff ffff ffff ffff ffff ffff
00016ce4 ffff ffff ffff ffff ffff ffff ffff ffff
00016cf4 ffff ffff ffff ffff ffff ffff ffff ffff
00016d04 ffff ffff ffff ffff ffff ffff ffff ffff
00016d14 ffff 0000
- 4 bytes [string pointer]: bmap.
- 398 bytes: unknown. I'm not sure what this data is. Most of it is 0xff, with non-0xff bytes sparsely placed throughout.
- 2 bytes: null bytes.
Battle Map Background (BattleTerrName)
Consists of 106 string pointers to background ids (e.g. bgE3
). Not too sure what they're used for.
Buddy Support (RelianceData)
This one's interesting. Each of the 71 playable characters are paired with all of the other 71 playable characters (including themselves!) and a buddy support type is listed.
Example: Elincia's buddy support data
0001b058 0003 22d1 0000 0047 0003 245e ff02 0000
0001b068 0003 22c9 0002 0000 0003 22b2 0002 0000
0001b078 0003 307f 0002 0000 0003 303d 0002 0000
0001b088 0003 22a8 0002 0000 0003 22d1 0002 0000
0001b098 0003 277f 0002 0000 0003 276a 0002 0000
0001b0a8 0003 2775 0002 0000 0003 1b32 0001 0000
0001b0b8 0003 2347 0002 0000 0003 1b40 0001 0000
0001b0c8 0003 2531 0002 0000 0003 251b 0002 0000
0001b0d8 0003 2544 0002 0000 0003 2506 0001 0000
0001b0e8 0003 241f 0002 0000 0003 2c96 0002 0000
0001b0f8 0003 2baa ff01 0000 0003 2be3 0002 0000
0001b108 0003 1b7d 0002 0000 0003 237d 0002 0000
0001b118 0003 2352 ff01 0000 0003 24e6 0002 0000
0001b128 0003 2c7a 0002 0000 0003 2ce9 0001 0000
0001b138 0003 2bc1 0002 0000 0003 2c86 0002 0000
0001b148 0003 2d34 0002 0000 0003 2d0f 0002 0000
0001b158 0003 1b68 0002 0000 0003 30e7 0002 0000
0001b168 0003 2d63 0002 0000 0003 2d7c ff02 0000
0001b178 0003 2d9b 0002 0000 0003 2713 0002 0000
0001b188 0003 271d 0002 0000 0003 2737 0002 0000
0001b198 0003 2707 0002 0000 0003 272a 0002 0000
0001b1a8 0003 2749 0002 0000 0003 2435 0002 0000
0001b1b8 0003 2f6f 0002 0000 0003 2f78 0002 0000
0001b1c8 0003 1b1a 0002 0000 0003 231e 0002 0000
0001b1d8 0003 243e 0002 0000 0003 2789 0002 0000
0001b1e8 0003 1ade 0002 0000 0003 2677 0001 0000
0001b1f8 0003 2603 0001 0000 0003 2694 0002 0000
0001b208 0003 26b1 0002 0000 0003 26fc 0002 0000
0001b218 0003 268c 0002 0000 0003 26e4 0002 0000
0001b228 0003 24d2 0002 0000 0003 2f55 0001 0000
0001b238 0003 25e1 0002 0000 0003 2576 0001 0000
0001b248 0003 27c8 0002 0000 0003 257e ff01 0000
0001b258 0003 25c9 0002 0000 0003 2b78 0002 0000
0001b268 0003 25f7 ff00 0000 0003 25bc 0002 0000
0001b278 0003 2b5e 0002 0000 0003 2594 0000 0000
0001b288 0003 256c 0002 0000 0003 305a 0002 0000
- 4 bytes [string pointer]: person id.
- 4 bytes [unsigned int]: number of buddy supports.
- (number of buddy supports) * 8 bytes:
- 4 bytes [string pointer]: person id with which this support is for.
- 2 bytes [bytes]: support type.
- 2 bytes: null bytes.
Once again, Serenes Forest has some great info on buddy support types.
Chapter (ChapterData)
Example: Part 4 Chapter 13 chapter data
000257b4 0002 9695 0002 c00e 0003 40ab 0002 9695
000257c4 0002 9695 0000 0000 0000 0000 0000 0000
000257d4 0000 0000 0003 15ca 0003 1560 0000 0000
000257e4 0002 f882 0002 f83e 0002 f8f6 0000 0000
000257f4 0000 0000 0003 15ca 0003 1560 0000 0000
00025804 0002 f882 0002 f83e 0002 f8f6 0000 0000
00025814 0000 0000 0003 15ca 0003 1560 0000 0000
00025824 0002 f882 0002 f83e 0002 f8f6 0000 0000
00025834 0000 0000 1e00 0000 0200 01fe 0100 0406
00025844 0003 42d6 0003 3183 0003 3dcf 0003 48bc
00025854 0003 30f7 0003 2694 0000 0000 0000 0000
00025864 0000 0000
- 4 bytes [string pointer]: chapter.
- usually of the form
C<part><chapter><sub-chapter>
, one indexed where01
is the prologue chapter. C0000
is the debug chapter.CFINAL
is the final chapter.T<index>
is a tutorial chapter.
- usually of the form
- 4 bytes [string pointer]: mct.
- 4 bytes [string pointer]: bmap.
- 4 bytes [string pointer]: identical to chapter.
- 4 bytes [string pointer]: base chapter, excluding the
<sub-part>
. Tutorial chapters havetut
here. - 16 bytes: null bytes.
- 32 bytes: easy chapter conditions.
- 32 bytes: normal chapter conditions.
- 32 bytes: hard chapter conditions.
- 1 byte [int]: counter.
- 3 bytes: null bytes.
- 8 bytes: unknown.
- First byte is always 0x2, except for
C0000
andCFINAL
, in which case it is 0x0. - Second byte seems to be the convoy.
- First byte is always 0x2, except for
- 4 bytes [string pointer]: affinity.
- 4 bytes [string pointer]: rid 1. Shift JIS encoded Japanese.
- 4 bytes [string pointer]: background.
- 4 bytes [string pointer]: setting. Shift JIS encoded Japanese.
- 4 bytes [string pointer]: rid 2. Shift JIS encoded Japanese.
- 4 bytes [string pointer]: commander (person id).
- 12 bytes: null bytes.
Chapter conditions:
- 4 bytes [string pointer]: main win condition. Condition is Shift JIS encoded Japanese.
- 4 bytes [string pointer]: alternate win condition. Condition is Shift JIS encoded Japanese.
- 0x0 if there is no alternate win condition.
- 4 bytes: null bytes.
- 4 * 4 bytes [string pointer]: lose conditions. 0x0 is padded if there are less than 4 lose conditions.
Note that these conditions are the ones that are displayed. The ones that are actually used to determine a win / loss are written into each chapter script.
Group (GroupData)
Example:
00026cdc 0000 0001 0003 45c3 0002 c223
- 4 bytes [int]: counter.
- 4 bytes [string pointer]: Shift JIS encoded Japanese name.
- 4 bytes [string pointer]: mg. Also Shift JIS encoded Japanese.
Bond Support (KiznaData)
Example: Ike and Mist's bond support data
00026ef0 0003 245e 0003 26b1 010a 0000
- 4 bytes [string pointer]: person 1 id.
- 4 bytes [string pointer]: person 2 id.
- 1 byte: always 0x1.
- 1 byte [int]: critical chance boost.
- 2 bytes: null bytes.
Affinity Bonus (DivineParam)
Note: there's 4 null bytes preceding this section that seems to have been added by mistake.
Example:
00027120 0003 41a4 0003 41a4 0505 0000
- 4 bytes [string pointer]: character's affinity.
- 4 bytes [string pointer]: map affinity.
- 1 byte [2's complement int]: hit bonus.
- 1 byte [2's complement int]: avoid bonus.
- 2 bytes: null bytes.
The affinity bonus should be read like "If this character has X affinity, and the map has Y affinity, the character will gain H hit bonus and A avoid bonus".
Weapon Triangle Bonus (3SukumiData)
Example:
00027538 0003 432a 0003 42dd 010a 0000
This has identical structure to affinity bonus. Instead of character affinity and map affinity, it's character weapon type and enemy weapon type respectively. Also, instead of hit/avoid bonus, it's might/hit bonus.
Biorhythm Type (BioData)
Example:
00027568 3f80 0000 3f80 0000 3f80 0000 0000 0000
This is one sub-section I can't determine what the bytes mean. However, based on some testing, it seems:
- 4 bytes [int]: amplitude
- 4 bytes [int]: scaling
- 4 bytes [int]: period
- 4 bytes [int]: vertical scaling
I haven't determined the formula that uses these values to compute the actual biorhythm curve.
Biorhythm Level Bonus (BioParam)
Example:
00027608 3f4c cccd 0a0a 000a 1400 0000
- 4 bytes: unknown. Seems like some sort of threshold.
- 1 byte [2's complement int]: hit bonus.
- 1 byte [2's complement int]: avoid bonus.
- 1 byte: null byte.
- 1 byte [2's complement int]: skill activation bonus.
- 1 byte [2's complement int]: hidden treasure find bonus.
- 3 bytes: null bytes.
Pacifist (NOBTL_*)
Each pacifist entry is listed separately in section 3.5 under NOBTL_* (e.g. NOBTL_JILL).
Example: Micaiah's pacifist data
00027648 0003 2694 0003 22b2 0000 0000 0003 24e6
00027658 0000 0000 0003 30e7 0000 0000 0003 2b78
00027668 0000 0000 0003 257e 0000 0000 0000 0000
- 4 bytes [string pointer]: person id.
- (number of pacifists) * 8 bytes: pacifist.
- 4 bytes: null bytes.
- 4 bytes [string pointer]: pacifist (person id).
Note that the number of pacifists is not explicitly given. The list simply stops when the person id is 0x0.
Part 3: Miscellaneous Formulae
More formulae will be added as they are derived. Serenes Forest contains a bunch of formulae that you can reference.
Attack XP formula
Recall we have the following modifiers:
- kill modifier (\(\text{kill}\)).
- attack modifier (\(\text{attack}\)).
- kill percentage (\(\text{kill_pct}\)).
- attack percentage (\(\text{attack_pct}\)).
- "tier 2" kill modifier (\(\text{tier2_kill}\)) .
- "tier 3" kill modifier (\(\text{tier3_kill}\)).
- Laguz attack modifier (\(\text{laguz_attack}\)).
- boss kill modifier (\(\text{boss_kill}\)).
Define the following helper functions:
- \(\text{race}(x) = \text{laguz}\) if \(x\) is a Laguz, \(\text{beorc}\) if \(x\) is a Beorc.
- \(\text{base_level}(x) = x\)'s level displayed in-game (a value between 1 and 20).
- \(\text{base_tier}(x) = x\)'s tier (a value between 1 and 3).
- \(\text{actual_level}(x)\):
- \(\text{base_tier}(x) = 1 \land \text{race}(x) = \text{beorc} \Longrightarrow \text{base_level}\)
- \(\text{base_tier}(x) = 2 \land \text{race}(x) = \text{beorc} \Longrightarrow \text{base_level} + 20\)
- \(\text{base_tier}(x) = 3 \land \text{race}(x) = \text{beorc} \Longrightarrow \text{base_level} + 40\)
- Transformed \(\text{race}(x) = \text{laguz} \Longrightarrow \text{base_level} \times 2\)
- Untransformed \(\text{race}(x) = \text{laguz} \Longrightarrow \text{base_level}\)
- \(\text{actual_tier}(x)\):
- \(\text{race}(x) = \text{beorc} \Longrightarrow \text{base_tier}(x)\)
- \(\text{race}(x) = \text{laguz}\):
- Untransformed \(\Longrightarrow 1\)
- \(\text{base_level}(x) \lt 15 \Longrightarrow 1\)
- \(\text{base_level}(x) \ge 1\Longrightarrow 2\)
- \(\text{actual_power}(x)\):
- \(\text{actual_tier}(x) = 1 \land \text{race}(x) = \text{beorc} \Longrightarrow 0\)
- \(\text{actual_tier}(x) = 2 \land \text{race}(x) = \text{beorc} \Longrightarrow \text{tier2_kill}\)
- \(\text{actual_tier}(x) = 3 \land \text{race}(x) = \text{beorc} \Longrightarrow \text{tier3_kill}\)
- \(\text{actual_tier}(x) = 1 \land \text{race}(x) = \text{laguz} \Longrightarrow 0\)
- \(\text{actual_tier}(x) = 2 \land \text{race}(x) = \text{laguz} \Longrightarrow \text{tier2_kill} \times 2\)
Consider a battle between your character \(\text{player}\) and an enemy character \(\text{enemy}\).
- \(\text{laguz_mod}\):
- If \(\text{race}(\text{enemy}) = \text{laguz} \Longrightarrow \text{laguz_attack}\)
- Otherwise \(\Longrightarrow 0\)
- \(\text{delta_level} = \text{actual_level}(\text{enemy}) - \text{actual_level}(\text{player})\)
- \(\text{delta_power} = \text{actual_power}(\text{enemy}) - \text{actual_power}(\text{player})\)
The attack XP formula is given by: \[\text{base_attack_xp} = \left\lfloor\frac{\text{attack_pct}}{100} \times \left(\text{attack} + \left\lceil \frac{\text{delta_level}}{2} \right\rceil + \text{laguz_mod}\right)\right\rfloor\] \[\text{attack_xp} = \text{max}(1, \text{base_attack_xp})\]
The kill XP formula is given by: \[\text{base_kill_xp} = \left\lfloor\frac{\text{kill_pct}}{100} \times (\text{kill} + \text{delta_level} + \text{delta_power} + \text{boss_kill})\right\rfloor\] \[\text{kill_xp} = \text{max}(\text{base_kill_xp} + \text{attack_xp}, \text{attack_xp})\]
When your character engages but doesn't attack the enemy, your character will gain \(1\) XP.
When your character attacks but doesn't kill the enemy, your character will gain \(\text{attack_xp}\) XP.
When your character attacks and kills the enemy, your character will gain \(\text{kill_xp}\) XP.
Disclaimer: Scouring the internet, I found this link describing FE10's XP formula, which helped with deriving the formula above. However, the formula at that link is not completely correct.
Part 4: Final thoughts
Phew, that was a long one! Describing FE10Data.cms
in this much detail took a while, but on the bright side, we now know where almost every single byte in the file comes from. For the remaining bytes, if you figure out what they're used for, please contact me, and I'll be sure to update this post (with credit if you wish, of course!).
Fortunately, even with the unknown bytes, we have enough information to introduce my work in progress FE10 library, which we will do in the next post. Stay tuned!