Kernel_bin.Character_Stats.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using Microsoft.Xna.Framework;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. namespace OpenVIII
  6. {
  7. namespace Kernel
  8. {
  9. /// <summary>
  10. /// Character Stats from Kernel
  11. /// </summary>
  12. /// <see cref="https://github.com/alexfilth/doomtrain/wiki/Characters"/>
  13. /// <seealso cref="http://forums.qhimm.com/index.php?topic=16923.msg240609#msg240609"/>
  14. public class Character_Stats
  15. {
  16. public const int id = 6;
  17. public const int count = 11;
  18. private Characters char_id { get; set; }
  19. public FF8String Name => Memory.Strings.GetName((Faces.ID)char_id);
  20. public override string ToString() => Name;
  21. //public ushort Offset; //0x0000; 2 bytes; Offset to character name
  22. //Squall and Rinoa have name offsets of 0xFFFF because their name is in the save game data rather than kernel.bin.
  23. /// <summary>
  24. /// Crisis level modifier
  25. /// </summary>
  26. /// <see cref="https://finalfantasy.fandom.com/wiki/Crisis_Level#Crisis_Level"/>
  27. public byte Crisis { get; private set; } //0x0002; 1 byte; Crisis level hp multiplier
  28. public Gender Gender { get; private set; } //0x0003; 1 byte; Gender; 0x00 - Male 0x01 - Female
  29. private byte _limitid; //0x0004; 1 byte; Limit Break BattleID
  30. public BattleCommand Limit => Memory.Kernel_Bin.BattleCommands[_limitid];
  31. public byte LimitParam { get; private set; } //0x0005; 1 byte; Limit Break Param used for the power of each renzokuken hit before finisher
  32. private byte[] _EXP { get; set; } //0x0006; 2 bytes; EXP modifier
  33. private byte[] _HP { get; set; } //0x0008; 4 bytes; HP modifiers
  34. private byte[] _STR { get; set; } //0x000C; 4 bytes; STR modifiers
  35. private byte[] _VIT { get; set; } //0x0010; 4 bytes; VIT modifiers
  36. private byte[] _MAG { get; set; } //0x0014; 4 bytes; MAG modifiers
  37. private byte[] _SPR { get; set; } //0x0018; 4 bytes; SPR modifiers
  38. private byte[] _SPD { get; set; } //0x001C; 4 bytes; SPD modifiers
  39. private byte[] _LUCK { get; set; } //0x0020; 4 bytes; LUCK modifiers
  40. public void Read(BinaryReader br, Characters char_id)
  41. {
  42. this.char_id = char_id;
  43. //Offset = br.ReadUInt16(); //0x0000; 2 bytes; Offset to character name
  44. //Squall and Rinoa have name offsets of 0xFFFF because their name is in the save game data rather than kernel.bin.
  45. br.BaseStream.Seek(2, SeekOrigin.Current);
  46. Crisis = br.ReadByte(); //0x0002; 1 byte; Crisis level hp multiplier
  47. Gender = br.ReadByte() == 0 ? Gender.Male : Gender.Female; //0x0003; 1 byte; Gender; 0x00 - Male 0x01 - Female
  48. _limitid = br.ReadByte(); //0x0004; 1 byte; Limit Break BattleID
  49. LimitParam = br.ReadByte(); //0x0005; 1 byte; Limit Break Param used for the power of each renzokuken hit before finisher
  50. _EXP = br.ReadBytes(2); //0x0006; 2 bytes; EXP modifier
  51. _HP = br.ReadBytes(4); //0x0008; 4 bytes; HP modifiers
  52. _STR = br.ReadBytes(4); //0x000C; 4 bytes; STR modifiers
  53. _VIT = br.ReadBytes(4); //0x0010; 4 bytes; VIT modifiers
  54. _MAG = br.ReadBytes(4); //0x0014; 4 bytes; MAG modifiers
  55. _SPR = br.ReadBytes(4); //0x0018; 4 bytes; SPR modifiers
  56. _SPD = br.ReadBytes(4); //0x001C; 4 bytes; SPD modifiers
  57. _LUCK = br.ReadBytes(4); //0x0020; 4 bytes; LUCK modifiers
  58. int hp = HP(8);
  59. }
  60. public static Dictionary<Characters, Character_Stats> Read(BinaryReader br)
  61. {
  62. Dictionary<Characters, Character_Stats> ret = new Dictionary<Characters, Character_Stats>(count);
  63. for (int i = 0; i < count; i++)
  64. {
  65. Character_Stats tmp = new Character_Stats();
  66. tmp.Read(br, (Characters)i);
  67. ret[(Characters)i] = tmp;
  68. }
  69. return ret;
  70. }
  71. //public static Character_Stats[] Read(BinaryReader br)
  72. //{
  73. // Character_Stats[] ret = new Character_Stats[Count];
  74. // for (int i = 0; i < Count; i++)
  75. // {
  76. // Character_Stats tmp = new Character_Stats();
  77. // tmp.Read(br, (Characters)i);
  78. // ret[i] = tmp;
  79. // }
  80. // return ret;
  81. //}
  82. private const int _percent_mod = 100;
  83. private const int MAXLEVEL = 100;
  84. /// <summary>
  85. /// Experence to reach level
  86. /// </summary>
  87. /// <param name="lvl">Level</param>
  88. /// <returns></returns>
  89. public int EXP(byte lvl) => ((lvl - 1) * (lvl - 1) * _EXP[1]) / 256 + (lvl - 1) * _EXP[0] * 10;
  90. public byte LEVEL(uint exp)
  91. {
  92. //by default no character has this set.
  93. Debug.Assert(_EXP[1] == 0); // if set we need to update the formula.
  94. return (byte) MathHelper.Clamp(exp / (_EXP[0] * 10) + 1,0, MAXLEVEL);
  95. }
  96. /// <summary>
  97. /// </summary>
  98. /// <param name="lvl">Level</param>
  99. /// <param name="MagicID">Bonus Value of Junctioned Magic</param>
  100. /// <param name="magic_count">Total amount of Magic in slot</param>
  101. /// <param name="stat_bonus">Bonus integer based HP</param>
  102. /// <param name="percent_mod">50% = 50, 100%=100, etc</param>
  103. /// <returns></returns>
  104. public ushort HP(sbyte lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = 0)
  105. {
  106. int value = (((Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.HP] * magic_count) + stat_bonus + (lvl * _HP[0]) - ((10 * lvl * lvl) / _HP[1]) + _HP[2]) * (percent_mod + _percent_mod)) / 100;
  107. return (ushort)MathHelper.Clamp(value, 0, KernelBin.MaxHPValue);
  108. }
  109. public byte STR(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod, int weapon = 0)
  110. => STR_VIT_MAG_SPR(_STR[0], _STR[1], _STR[2], _STR[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.STR], magic_count, stat_bonus, percent_mod, weapon);
  111. public byte VIT(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod)
  112. => STR_VIT_MAG_SPR(_VIT[0], _VIT[1], _VIT[2], _VIT[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.VIT], magic_count, stat_bonus, percent_mod);
  113. public byte MAG(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod)
  114. => STR_VIT_MAG_SPR(_MAG[0], _MAG[1], _MAG[2], _MAG[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.MAG], magic_count, stat_bonus, percent_mod);
  115. public byte SPR(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod)
  116. => STR_VIT_MAG_SPR(_SPR[0], _SPR[1], _SPR[2], _SPR[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.SPR], magic_count, stat_bonus, percent_mod);
  117. private byte STR_VIT_MAG_SPR(int a, int b, int c, int d, int lvl, int magic_J_val, int magic_count, int stat_bonus, int percent_mod = 0, int UNK = 0)
  118. {
  119. int value = ((UNK + (magic_J_val * magic_count) / 100 + stat_bonus + ((lvl * a) / 10 + lvl / b - (lvl * lvl) / d / 2 + c) / 4) * (percent_mod + _percent_mod)) / 100;
  120. return (byte)MathHelper.Clamp(value, 0, KernelBin.MaxStatValue);
  121. }
  122. public byte SPD(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod)
  123. => SPD_LUCK(_SPD[0], _SPD[1], _SPD[2], _SPD[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.SPD], magic_count, stat_bonus, percent_mod);
  124. public byte LUCK(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int percent_mod = _percent_mod)
  125. => SPD_LUCK(_LUCK[0], _LUCK[1], _LUCK[2], _LUCK[3], lvl, Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.LUCK], magic_count, stat_bonus, percent_mod);
  126. private byte SPD_LUCK(int a, int b, int c, int d, int lvl, int magic_J_val, int magic_count, int stat_bonus, int percent_mod = 0, int UNK = 0)
  127. {
  128. int value = ((UNK + (magic_J_val * magic_count) / 100 + stat_bonus + lvl / b - lvl / d + lvl * a + c) * (percent_mod + _percent_mod)) / 100;
  129. return (byte)MathHelper.Clamp(value, 0, KernelBin.MaxStatValue);
  130. }
  131. public byte EVA(int lvl, int MagicID = 0, int magic_count = 0, int stat_bonus = 0, int spd = 0, int percent_mod = 0)
  132. {
  133. int value = (((Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.EVA] * magic_count) / 100 + spd / 4) * (percent_mod + _percent_mod)) / 100;
  134. return (byte)MathHelper.Clamp(value, 0, KernelBin.MaxStatValue);
  135. }
  136. public byte HIT(int MagicID = 0, int magic_count = 0, int weapon = 0)
  137. {
  138. int value = Memory.Kernel_Bin.MagicData[MagicID].J_Val[Stat.HIT] * magic_count + Memory.Kernel_Bin.WeaponsData[weapon].HIT;
  139. return (byte)MathHelper.Clamp(value, 0, KernelBin.MaxStatValue);
  140. }
  141. }
  142. }
  143. }