From 2dd8c107240aee245f17253dfa56d1075b6f2a0a Mon Sep 17 00:00:00 2001 From: petfriendamy Date: Sat, 11 Feb 2023 12:39:38 -0700 Subject: [PATCH] Add attack and command data --- Shojy.FF7.Elena/Attacks/Attack.cs | 45 ++++++++++++ Shojy.FF7.Elena/Attacks/ConditionSubmenu.cs | 16 ++++ Shojy.FF7.Elena/Attacks/StatusChange.cs | 43 +++++++++++ Shojy.FF7.Elena/Battle/Command.cs | 29 ++++++++ Shojy.FF7.Elena/Equipment/Weapon.cs | 5 ++ Shojy.FF7.Elena/Items/Item.cs | 4 + Shojy.FF7.Elena/KernelReader.cs | 20 +++++ Shojy.FF7.Elena/Sections/AttackData.cs | 81 +++++++++++++++++++++ Shojy.FF7.Elena/Sections/CommandData.cs | 63 +++++++++++++++- Shojy.FF7.Elena/Sections/ItemData.cs | 8 +- Shojy.FF7.Elena/Sections/MateriaData.cs | 4 + Shojy.FF7.Elena/Sections/WeaponData.cs | 6 ++ 12 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 Shojy.FF7.Elena/Attacks/Attack.cs create mode 100644 Shojy.FF7.Elena/Attacks/ConditionSubmenu.cs create mode 100644 Shojy.FF7.Elena/Attacks/StatusChange.cs create mode 100644 Shojy.FF7.Elena/Battle/Command.cs create mode 100644 Shojy.FF7.Elena/Sections/AttackData.cs diff --git a/Shojy.FF7.Elena/Attacks/Attack.cs b/Shojy.FF7.Elena/Attacks/Attack.cs new file mode 100644 index 0000000..4f8b62a --- /dev/null +++ b/Shojy.FF7.Elena/Attacks/Attack.cs @@ -0,0 +1,45 @@ +using Shojy.FF7.Elena.Battle; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shojy.FF7.Elena.Attacks +{ + public class Attack + { + #region Public Constructors + + public Attack() { } + + #endregion + + #region Public Properties + + public byte AccuracyRate { get; set; } + public byte AditionalEffects { get; set; } + public byte AdditionalEffectsModifier { get; set; } + public byte AttackEffectID { get; set; } + public byte AttackStrength { get; set; } + public ushort CameraMovementIDSingle { get; set; } + public ushort CameraMovementIDMulti { get; set; } + public ConditionSubmenu ConditionSubmenu { get; set; } + public byte DamageCalculationID { get; set; } + public string Description { get; set; } + public Elements Elements { get; set; } + public byte ImpactEffectID { get; set; } + public ushort ImpactSound { get; set; } + public int Index { get; set; } + public ushort MPCost { get; set; } + public string Name { get; set; } + public SpecialEffects SpecialAttackFlags { get; set; } + public StatusChange StatusChange { get; set; } + public Statuses Statuses { get; set; } + public TargetData TargetFlags { get; set; } + public byte TargetHurtActionIndex { get; set; } + + #endregion + } +} diff --git a/Shojy.FF7.Elena/Attacks/ConditionSubmenu.cs b/Shojy.FF7.Elena/Attacks/ConditionSubmenu.cs new file mode 100644 index 0000000..4638c44 --- /dev/null +++ b/Shojy.FF7.Elena/Attacks/ConditionSubmenu.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shojy.FF7.Elena.Attacks +{ + public enum ConditionSubmenu : byte + { + PartyHP = 0x00, + PartyMP = 0x01, + PartyStatus = 0x02, + None = 0xFF + } +} diff --git a/Shojy.FF7.Elena/Attacks/StatusChange.cs b/Shojy.FF7.Elena/Attacks/StatusChange.cs new file mode 100644 index 0000000..31508e3 --- /dev/null +++ b/Shojy.FF7.Elena/Attacks/StatusChange.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shojy.FF7.Elena.Attacks +{ + public enum StatusChangeType + { + None, Inflict, Cure, Swap + } + + public class StatusChange + { + public StatusChangeType Type { get; set; } + public int Amount { get; set; } + + public StatusChange(byte value) + { + if (value == 0xFF) + { + Type = StatusChangeType.None; + Amount = 0; + } + else if ((value & 0x40) != 0) + { + Type = StatusChangeType.Cure; + Amount = value - 0x40; + } + else if ((value & 0x80) != 0) + { + Type = StatusChangeType.Swap; + Amount = value - 0x80; + } + else + { + Type = StatusChangeType.Inflict; + Amount = value; + } + } + } +} diff --git a/Shojy.FF7.Elena/Battle/Command.cs b/Shojy.FF7.Elena/Battle/Command.cs new file mode 100644 index 0000000..77b9d94 --- /dev/null +++ b/Shojy.FF7.Elena/Battle/Command.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Shojy.FF7.Elena.Battle +{ + public class Command + { + #region Public Constructors + + public Command() { } + + #endregion + + #region Public Properties + + public ushort CameraMovementIDSingle { get; set; } + public ushort CameraMovementIDMulti { get; set; } + public string Description { get; set; } + public int Index { get; set; } + public string Name { get; set; } + public byte InitialCursorAction { get; set; } + public TargetData TargetFlags { get; set; } + + #endregion + } +} diff --git a/Shojy.FF7.Elena/Equipment/Weapon.cs b/Shojy.FF7.Elena/Equipment/Weapon.cs index 079cb70..0f7cb0e 100644 --- a/Shojy.FF7.Elena/Equipment/Weapon.cs +++ b/Shojy.FF7.Elena/Equipment/Weapon.cs @@ -27,14 +27,19 @@ public Weapon() public byte BoostedStat3Bonus { get; set; } public CharacterStat BoostedStat4 { get; set; } public byte BoostedStat4Bonus { get; set; } + public byte CriticalHitSoundID { get; set; } public byte CriticalRate { get; set; } public byte DamageCalculationId { get; set; } public string Description { get; set; } public EquipableBy EquipableBy { get; set; } public GrowthRate GrowthRate { get; set; } + public byte HighSoundIDMask { get; set; } + public byte ImpactEffectID { get; set; } public int Index { get; set; } public MateriaSlot[] MateriaSlots { get; set; } + public byte MissedAttackSoundID { get; set; } public string Name { get; set; } + public byte NormalHitSoundID { get; set; } public Restrictions Restrictions { get; set; } public EquipmentStatus Status { get; set; } public TargetData Targets { get; set; } diff --git a/Shojy.FF7.Elena/Items/Item.cs b/Shojy.FF7.Elena/Items/Item.cs index eea4596..d7327b6 100644 --- a/Shojy.FF7.Elena/Items/Item.cs +++ b/Shojy.FF7.Elena/Items/Item.cs @@ -14,6 +14,10 @@ public class Item public byte AttackEffectId { get; set; } public byte DamageCalculationId { get; set; } public byte AttackPower { get; set; } + public ConditionSubmenu ConditionSubmenu { get; set; } + public StatusChange StatusChange { get; set; } + public byte AdditionalEffects { get; set; } + public byte AdditionalEffectsModifier { get; set; } public Statuses Status { get; set; } public Elements Element { get; set; } public SpecialEffects Special { get; set; } diff --git a/Shojy.FF7.Elena/KernelReader.cs b/Shojy.FF7.Elena/KernelReader.cs index 8131190..871420e 100644 --- a/Shojy.FF7.Elena/KernelReader.cs +++ b/Shojy.FF7.Elena/KernelReader.cs @@ -138,11 +138,21 @@ private static Dictionary DecompressKernel2(string path) /// public TextSection ArmorNames { get; protected set; } + /// + /// Kernel section 2 + /// + public AttackData AttackData { get; protected set; } + /// /// Kernel section 26 /// public TextSection BattleText { get; protected set; } + /// + /// Kernel section 1 + /// + public CommandData CommandData { get; protected set; } + /// /// Kernel section 10 /// @@ -313,6 +323,16 @@ private void LoadSections() this.BattleText = new TextSection(this.KernelData[KernelSection.BattleText]); this.SummonAttackNames = new TextSection(this.KernelData[KernelSection.SummonAttackNames]); + this.CommandData = new CommandData( + this.KernelData[KernelSection.CommandData], + this.CommandNames.Strings, + this.CommandDescriptions.Strings); + + this.AttackData = new AttackData( + this.KernelData[KernelSection.AttackData], + this.MagicNames.Strings, + this.MagicDescriptions.Strings); + this.WeaponData = new WeaponData( this.KernelData[KernelSection.WeaponData], this.WeaponNames.Strings, diff --git a/Shojy.FF7.Elena/Sections/AttackData.cs b/Shojy.FF7.Elena/Sections/AttackData.cs new file mode 100644 index 0000000..8415871 --- /dev/null +++ b/Shojy.FF7.Elena/Sections/AttackData.cs @@ -0,0 +1,81 @@ +using Shojy.FF7.Elena.Attacks; +using Shojy.FF7.Elena.Battle; +using System; +using System.Collections.Generic; + +namespace Shojy.FF7.Elena.Sections +{ + public class AttackData + { + #region Private Fields + + private const int AttackSize = 28; + private readonly byte[] _sectionData; + + #endregion + + #region Public Constructors + + public AttackData(byte[] sectionData, IReadOnlyList names, IReadOnlyList descriptions) + { + this._sectionData = sectionData; + + var count = sectionData.Length / AttackSize; + var attacks = new Attack[count]; + + for (var atk = 0; atk < count; ++atk) + { + var atkBytes = new byte[AttackSize]; + Array.Copy( + sectionData, + atk * AttackSize, + atkBytes, + 0, + AttackSize); + attacks[atk] = this.ParseAttackData(atkBytes); + + attacks[atk].Index = atk; + attacks[atk].Name = names[atk]; + attacks[atk].Description = descriptions[atk]; + } + this.Attacks = attacks; + } + + #endregion + + #region Public Properties + + public Attack[] Attacks; + + #endregion + + #region Private Methods + + private Attack ParseAttackData(byte[] atkData) + { + var atk = new Attack(); + atk.AccuracyRate = atkData[0x0]; + atk.ImpactEffectID = atkData[0x1]; + atk.TargetHurtActionIndex = atkData[0x2]; + atk.MPCost = BitConverter.ToUInt16(atkData, 0x4); + atk.ImpactSound = BitConverter.ToUInt16(atkData, 0x6); + atk.CameraMovementIDSingle = BitConverter.ToUInt16(atkData, 0x8); + atk.CameraMovementIDMulti = BitConverter.ToUInt16(atkData, 0xA); + atk.TargetFlags = (TargetData)atkData[0xC]; + atk.AttackEffectID = atkData[0xD]; + atk.DamageCalculationID = atkData[0xE]; + atk.AttackStrength = atkData[0xF]; + atk.ConditionSubmenu = (ConditionSubmenu)atkData[0x10]; + atk.StatusChange = new StatusChange(atkData[0x11]); + atk.AditionalEffects = atkData[0x12]; + atk.AdditionalEffectsModifier = atkData[0x13]; + atk.Statuses = (Statuses)BitConverter.ToUInt32(atkData, 0x14); + atk.Elements = (Elements)BitConverter.ToUInt16(atkData, 0x18); + + atk.SpecialAttackFlags = (SpecialEffects) ~ BitConverter.ToUInt16(atkData, 0x1A); + return atk; + } + + #endregion + } +} diff --git a/Shojy.FF7.Elena/Sections/CommandData.cs b/Shojy.FF7.Elena/Sections/CommandData.cs index 7474fd6..5e15185 100644 --- a/Shojy.FF7.Elena/Sections/CommandData.cs +++ b/Shojy.FF7.Elena/Sections/CommandData.cs @@ -1,7 +1,66 @@ -namespace Shojy.FF7.Elena.Sections +using Shojy.FF7.Elena.Attacks; +using Shojy.FF7.Elena.Battle; +using System.Collections.Generic; +using System; + +namespace Shojy.FF7.Elena.Sections { public class CommandData { - + #region Private Fields + + private const int CommandSize = 8; + private readonly byte[] _sectionData; + + #endregion + + #region Public Constructors + + public CommandData(byte[] sectionData, IReadOnlyList names, IReadOnlyList descriptions) + { + this._sectionData = sectionData; + + var count = sectionData.Length / CommandSize; + var commands = new Command[count]; + + for (var cmd = 0; cmd < count; ++cmd) + { + var cmdBytes = new byte[CommandSize]; + Array.Copy( + sectionData, + cmd * CommandSize, + cmdBytes, + 0, + CommandSize); + commands[cmd] = this.ParseCommandData(cmdBytes); + + commands[cmd].Index = cmd; + commands[cmd].Name = names[cmd]; + commands[cmd].Description = descriptions[cmd]; + } + this.Commands = commands; + } + + #endregion + + #region Public Properties + + public Command[] Commands; + + #endregion + + #region Private Methods + + private Command ParseCommandData(byte[] cmdData) + { + var cmd = new Command(); + cmd.InitialCursorAction = cmdData[0x0]; + cmd.TargetFlags = (TargetData)cmdData[0x1]; + cmd.CameraMovementIDSingle = BitConverter.ToUInt16(cmdData, 0x4); + cmd.CameraMovementIDMulti = BitConverter.ToUInt16(cmdData, 0x6); + return cmd; + } + + #endregion } } \ No newline at end of file diff --git a/Shojy.FF7.Elena/Sections/ItemData.cs b/Shojy.FF7.Elena/Sections/ItemData.cs index 42a8357..85ac70b 100644 --- a/Shojy.FF7.Elena/Sections/ItemData.cs +++ b/Shojy.FF7.Elena/Sections/ItemData.cs @@ -1,4 +1,5 @@ -using Shojy.FF7.Elena.Battle; +using Shojy.FF7.Elena.Attacks; +using Shojy.FF7.Elena.Battle; using Shojy.FF7.Elena.Items; using System; using System.Collections.Generic; @@ -62,8 +63,13 @@ private Item ParseItemData(byte[] data) item.AttackEffectId = data[0xD]; item.DamageCalculationId = data[0xE]; item.AttackPower = data[0xF]; + item.ConditionSubmenu = (ConditionSubmenu)data[0x10]; + item.StatusChange = new StatusChange(data[0x11]); + item.AdditionalEffects = data[0x12]; + item.AdditionalEffectsModifier = data[0x13]; item.Status = (Statuses)BitConverter.ToUInt32(data, 0x14); item.Element = (Elements)BitConverter.ToUInt16(data, 0x18); + item.Special = (SpecialEffects) ~ BitConverter.ToUInt16(data, 0x1A); return item; } diff --git a/Shojy.FF7.Elena/Sections/MateriaData.cs b/Shojy.FF7.Elena/Sections/MateriaData.cs index 7f7b978..66684ec 100644 --- a/Shojy.FF7.Elena/Sections/MateriaData.cs +++ b/Shojy.FF7.Elena/Sections/MateriaData.cs @@ -60,6 +60,10 @@ private static Materia ParseData(byte[] data) materia.Level3AP = BitConverter.ToUInt16(data, 0x2) * 100; materia.Level4AP = BitConverter.ToUInt16(data, 0x4) * 100; materia.Level5AP = BitConverter.ToUInt16(data, 0x6) * 100; + materia.EquipEffect = data[0x8]; + var temp = new byte[4]; + Array.Copy(data, 0x9, temp, 0, 3); + materia.Status = (Statuses)BitConverter.ToUInt32(temp); materia.Element = (MateriaElements)data[0xC]; materia.MateriaType = Materia.GetMateriaType(data[0xD]); diff --git a/Shojy.FF7.Elena/Sections/WeaponData.cs b/Shojy.FF7.Elena/Sections/WeaponData.cs index 5a7c362..8c82740 100644 --- a/Shojy.FF7.Elena/Sections/WeaponData.cs +++ b/Shojy.FF7.Elena/Sections/WeaponData.cs @@ -63,6 +63,7 @@ private Weapon ParseWeaponData(byte[] wpnData) wpn.CriticalRate = wpnData[0x7]; wpn.AccuracyRate = wpnData[0x8]; wpn.WeaponModelId = wpnData[0x9]; + wpn.HighSoundIDMask = wpnData[0xB]; wpn.EquipableBy = (EquipableBy)BitConverter.ToUInt16(wpnData, 0xE); wpn.AttackElements = (Elements)BitConverter.ToUInt16(wpnData, 0x10); wpn.BoostedStat1 = (CharacterStat)wpnData[0x14]; @@ -79,6 +80,11 @@ private Weapon ParseWeaponData(byte[] wpnData) wpn.MateriaSlots[slot] = (MateriaSlot)wpnData[0x1C + slot]; } + wpn.NormalHitSoundID = wpnData[0x24]; + wpn.CriticalHitSoundID = wpnData[0x25]; + wpn.MissedAttackSoundID = wpnData[0x26]; + wpn.ImpactEffectID = wpnData[0x27]; + wpn.Restrictions = (Restrictions) ~BitConverter.ToUInt16(wpnData, 0x2A); return wpn; }