Here's the FiendCrafter loading code. The notes were written for someone I shared this to ages ago.
bNoUpdate = true;
byte[] MonsterData = G.SaveRec[(byte) RecType.MonsterStats][(byte) NameBox.SelectedIndex].nData;
//Monster HP
try
{
HPBox.Value = G.GetShort(MonsterData, 0x00);
}
catch (ArgumentOutOfRangeException)
{
HPBox.Maximum = 0xFFFF;
HPBox.Value = G.GetShort(MonsterData, 0x00);
HackRecord HPRec = (HackRecord)G.SaveRec[(byte)RecType.HPNegativeCheck][0];
HPRec.nData = new byte[2] { 0xEA, 0xEA };
HPRec.bModified = true;
G.SaveRec[(byte)RecType.HPNegativeCheck][0] = HPRec;
}
//Monster Level
LevelBox.Value = MonsterData[0x02];
//Monster Unk0x03
Unk0x03Box.Value = MonsterData[0x03];
//Monster Immune
// Here we do a bitwise AND to determine if each flag is set.
// To do this by hand, look at the binary value of two numbers.
// If a bit is set in both numbers, it is set in the result.
// In all of the below cases, only one bit is set.
BlindImmunity.Checked = ((MonsterData[0x04] & 0x01) == 0x01);
SleepImmunity.Checked = ((MonsterData[0x04] & 0x02) == 0x02);
ConfuseImmunity.Checked = ((MonsterData[0x04] & 0x04) == 0x04);
LockImmunity.Checked = ((MonsterData[0x04] & 0x08) == 0x08);
HPDrainImmunity.Checked = ((MonsterData[0x04] & 0x10) == 0x10);
SlowImmunity.Checked = ((MonsterData[0x04] & 0x20) == 0x20);
PoisonImmunity.Checked = ((MonsterData[0x04] & 0x40) == 0x40);
StopImmunity.Checked = ((MonsterData[0x04] & 0x80) == 0x80);
//Monster Unk0x05
Unk0x05Box.Value = MonsterData[0x05];
//Monster Constant Statuses 1
DoubleEvadeCheck.Checked = ((MonsterData[0x06] & 0x01) == 0x01);
UnknownStatusCheck.Checked = ((MonsterData[0x06] & 0x02) == 0x02);
Unused604Check.Checked = ((MonsterData[0x06] & 0x04) == 0x04);
Unused608Check.Checked = ((MonsterData[0x06] & 0x08) == 0x08);
Unused610Check.Checked = ((MonsterData[0x06] & 0x10) == 0x10);
Unused620Check.Checked = ((MonsterData[0x06] & 0x20) == 0x20);
Evade25Check.Checked = ((MonsterData[0x06] & 0x40) == 0x40);
HasteCheck.Checked = ((MonsterData[0x06] & 0x80) == 0x80);
//Monster Constant Statuses 2
Unused701Check.Checked = ((MonsterData[0x07] & 0x01) == 0x01);
AttackPowerUpCheck.Checked = ((MonsterData[0x07] & 0x02) == 0x02);
ProtectCheck.Checked = ((MonsterData[0x07] & 0x04) == 0x04);
MaxAttackPowerUpCheck.Checked = ((MonsterData[0x07] & 0x08) == 0x08);
Unused710Check.Checked = ((MonsterData[0x07] & 0x10) == 0x10);
MPRegenCheck.Checked = ((MonsterData[0x07] & 0x20) == 0x20);
BarrierCheck.Checked = ((MonsterData[0x07] & 0x40) == 0x40);
BerserkCheck.Checked = ((MonsterData[0x07] & 0x80) == 0x80);
//Monster Unk 0x08
Unk0x08Box.Value = MonsterData[0x08];
//Monster Speed
SpeedBox.Value = MonsterData[0x09];
//Monster Magic
MagicBox.Value = MonsterData[0x0A];
//Monster Hit
HitBox.Value = MonsterData[0x0B];
//Monster Evade
EvadeBox.Value = MonsterData[0x0C];
//Monster Magic Def
MagicDefenseBox.Value = MonsterData[0x0D];
//Monster Offense
OffenseBox.Value = MonsterData[0x0E];
//Monster Defense
DefenseBox.Value = MonsterData[0x0F];
//Monster Lightning
LightningAbsorbCheck.Checked = ((MonsterData[0x10] & 0x80) == 0x80);
LightningRatioBumpCheck.Checked = ((MonsterData[0x10] & 0x40) == 0x40);
LightningDefenseComboBox.SelectedIndex = (MonsterData[0x10] & 0x3F);
//Monster Shadow
ShadowAbsorbCheck.Checked = ((MonsterData[0x11] & 0x80) == 0x80);
ShadowRatioBumpCheck.Checked = ((MonsterData[0x11] & 0x40) == 0x40);
ShadowDefenseComboBox.SelectedIndex = (MonsterData[0x11] & 0x3F);
//Monster Water
WaterAbsorbCheck.Checked = ((MonsterData[0x12] & 0x80) == 0x80);
WaterRatioBumpCheck.Checked = ((MonsterData[0x12] & 0x40) == 0x40);
WaterDefenseComboBox.SelectedIndex = (MonsterData[0x12] & 0x3F);
////Monster Fire
FireAbsorbCheck.Checked = ((MonsterData[0x13] & 0x80) == 0x80);
FireRatioBumpCheck.Checked = ((MonsterData[0x13] & 0x40) == 0x40);
FireDefenseComboBox.SelectedIndex = (MonsterData[0x13] & 0x3F);
//Monster SettingsA
Unk1401Check.Checked = ((MonsterData[0x14] & 0x01) == 0x01);
AirborneCheck.Checked = ((MonsterData[0x14] & 0x02) == 0x02);
PhysicalMissCheck.Checked = ((MonsterData[0x14] & 0x04) == 0x04);
Unk1408Check.Checked = ((MonsterData[0x14] & 0x08) == 0x08);
Unk1410Check.Checked = ((MonsterData[0x14] & 0x10) == 0x10);
ImmovableCheck.Checked = ((MonsterData[0x14] & 0x20) == 0x20);
SupportCheck.Checked = ((MonsterData[0x14] & 0x40) == 0x40);
HPHalfDeathCheck.Checked = ((MonsterData[0x14] & 0x80) == 0x80);
//Monster SettingsB
BossDeathCheck.Checked = ((MonsterData[0x15] & 0x01) == 0x01);
SightScopeCheck.Checked = ((MonsterData[0x15] & 0x02) == 0x02);
Unk1504Check.Checked = ((MonsterData[0x15] & 0x04) == 0x04);
TypeMagicCheck.Checked = ((MonsterData[0x15] & 0x08) == 0x08);
TypeAquaCheck.Checked = ((MonsterData[0x15] & 0x10) == 0x10);
TypeHumanoidCheck.Checked = ((MonsterData[0x15] & 0x20) == 0x20);
TypeMachineCheck.Checked = ((MonsterData[0x15] & 0x40) == 0x40);
TypeUndeadCheck.Checked = ((MonsterData[0x15] & 0x80) == 0x80);
//Monster Attack 2 Index
Attack2IndexBox.Value = MonsterData[0x16];
byte[] RewardData = G.SaveRec[(byte)RecType.MonsterStats][(byte)NameBox.SelectedIndex].LocalRec[0].nData;
ExpPointsBox.Value = G.GetShort(RewardData, 0x00);
GilBox.Value = G.GetShort(RewardData, 0x02);
ItemDroppedBox.SelectedIndex = RewardData[0x04];
ItemCharmedBox.SelectedIndex = RewardData[0x05];
TechPointsBox.Value = RewardData[0x06];
byte[] SpriteData = G.SaveRec[(byte)RecType.MonsterStats][(byte)NameBox.SelectedIndex].LocalRec[1].nData;
GraphicsPacketBox.Value = SpriteData[0x00];
SpriteAssemblyBox.Value = SpriteData[0x01];
PaletteBox.Value = SpriteData[0x02];
AnimationBox.Value = SpriteData[0x03];
SpriteSizeBox.Value = SpriteData[0x04];
HandXBox.Value = SpriteData[0x05];
HandYBox.Value =SpriteData[0x06];
SpriteUnk0x07Box.Value = SpriteData[0x07];
SpriteUnk0x08Box.Value = SpriteData[0x08];
SpriteUnk0x09Box.Value = SpriteData[0x09];
UpdatePicture();
//EnemyDisplay.Image = DrawMonsterPicture(false);
TargetWindowCheck.Checked = (G.SaveRec[(byte)RecType.MonsterStats][(byte)NameBox.SelectedIndex].LocalRec[2].nData[0] == 1);
bNoUpdate = false;
These are the addresses for Enemy attacks. Attack 1 in the AI is always record 0, and Attack 2 is determined by the attack 2 index/hit effect. Order is JP, US, Pre-release.
SetRomAddr(PlugRomAddr.EnemyAttackControlData, new uint[3] { 0x0C8801, 0x0C88CA, 0x0C7B80 });
SetRomAddr(PlugRomAddr.EnemyAttackEffectData, new uint[3] { 0x0C8908, 0x0C89C6, 0x0C7C88 });
These are the pointers for player techs. I use pointers here to enable support for expansion projects. Normal attacks are at the end. Pointers are little endian, and SNES addresses. Subtract 0xC00000 for file addresses.
SetRomAddr(PlugRomAddr.PlayerTechControlPointer, new uint[3] { 0x01CBA1, 0x01CBA1, 0x01D1BA });
SetRomAddr(PlugRomAddr.PlayerTechEffectPointer, new uint[3] { 0x01D5F0, 0x01D5F0, 0x01D252 });
This is the pointer for attack bytes, which specify which control header is used in each PC's normal attacks.
SetRomAddr(PlugRomAddr.AttackHeaderBytePointer, new uint[3] { 0x01C000, 0x01C000, 0x01B487 })