using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenVIII
{
namespace Kernel
{
///
/// Magic Data
///
///
public class MagicData
{
#region Fields
public const int Count = 57;
public const int ID = 1;
#endregion Fields
#region Constructors
private MagicData(BinaryReader br, int i)
{
Name = Memory.Strings.Read(Strings.FileID.Kernel, ID, i * 2);
Description = Memory.Strings.Read(Strings.FileID.Kernel, ID, i * 2 + 1);
MagicDataID = (byte)i;
br.BaseStream.Seek(4, SeekOrigin.Current);
MagicID = (MagicID)br.ReadUInt16();
Unknown = br.ReadByte();
AttackType = (AttackType)br.ReadByte();
SpellPower = br.ReadByte();
Unknown2 = br.ReadByte();
Target = (Target)br.ReadByte();
AttackFlags = (AttackFlags)br.ReadByte();
DrawResist = br.ReadByte();
HitCount = br.ReadByte();
Element = (Element)br.ReadByte();
Unknown3 = br.ReadByte();
Statuses1 = (BattleOnlyStatuses)br.ReadUInt32();
Statuses0 = (PersistentStatuses)br.ReadUInt16();
StatusAttack = br.ReadByte();
var jVal = new Dictionary()
{
{Stat.HP, br.ReadByte()},
{Stat.STR, br.ReadByte()},
{Stat.VIT, br.ReadByte()},
{Stat.MAG, br.ReadByte()},
{Stat.SPR, br.ReadByte()},
{Stat.SPD, br.ReadByte()},
{Stat.EVA, br.ReadByte()},
{Stat.HIT, br.ReadByte()},
{Stat.Luck, br.ReadByte()}
};
ElAtk = (Element)br.ReadByte();
jVal.Add(Stat.ElAtk, br.ReadByte());
ElDef = (Element)br.ReadByte();
jVal.Add(Stat.ElDef1, br.ReadByte());
jVal.Add(Stat.ElDef2, jVal[Stat.ElDef1]);
jVal.Add(Stat.ElDef3, jVal[Stat.ElDef1]);
jVal.Add(Stat.ElDef4, jVal[Stat.ElDef1]);
jVal.Add(Stat.StAtk, br.ReadByte());
jVal.Add(Stat.StDef1, br.ReadByte());
jVal.Add(Stat.StDef2, jVal[Stat.StDef1]);
jVal.Add(Stat.StDef3, jVal[Stat.StDef1]);
jVal.Add(Stat.StDef4, jVal[Stat.StDef1]);
JVal = jVal;
StAtk = (JunctionStatuses)br.ReadUInt16();
StDef = (JunctionStatuses)br.ReadUInt16();
GFCompatibility = br.ReadBytes(16);
Unknown4 = br.ReadBytes(2);
}
#endregion Constructors
#region Properties
///0x000B 1 byte Attack Flags
public AttackFlags AttackFlags { get; }
///0x0007 1 byte Attack type
public AttackType AttackType { get; }
///0x0002 2 bytes Offset to spell description
public FF8String Description { get; }
///0x000C 1 byte Draw resist(how hard is the magic to draw)
public byte DrawResist { get; }
///0x0020 1 byte Characters J - Elem attack
/// //public byte J_Val[Kernel_bin.Stat.EL_Atk];//0x0021 1 byte Characters J - Elem attack value
public Element ElAtk { get; }
///0x0022 1 byte Characters J - Elem defense
/// //public byte J_Val[Kernel_bin.Stat.EL_Def_1];//0x0023 1 byte Characters J - Elem defense value
public Element ElDef { get; }
///0x000E 1 byte Element
public Element Element { get; }
///
///0x002A 1 byte Quezacotl compatibility
///0x002B 1 byte Shiva compatibility
///0x002C 1 byte Ifrit compatibility
///0x002D 1 byte Siren compatibility
///0x002E 1 byte Brothers compatibility
///0x002F 1 byte Diablos compatibility
///0x0030 1 byte Carbuncle compatibility
///0x0031 1 byte Leviathan compatibility
///0x0032 1 byte Pandemona compatibility
///0x0033 1 byte Cerberus compatibility
///0x0034 1 byte Alexander compatibility
///0x0035 1 byte Doomtrain compatibility
///0x0036 1 byte Bahamut compatibility
///0x0037 1 byte Cactuar compatibility
///0x0038 1 byte Tonberry compatibility
///0x0039 1 byte Eden compatibility
///
public byte[] GFCompatibility { get; }
///0x000D 1 byte Hit Count(works with meteor animation, not sure about others)
public byte HitCount { get; }
///
///public byte HP_J; 0x0017 1 byte Characters HP junction value
///public byte STR_J; 0x0018 1 byte Characters STR junction value
///public byte VIT_J; 0x0019 1 byte Characters VIT junction value
///public byte MAG_J; 0x001A 1 byte Characters MAG junction value
///public byte SPR_J; 0x001B 1 byte Characters SPR junction value
///public byte SPD_J; 0x001C 1 byte Characters SPD junction value
///public byte EVA_J; 0x001D 1 byte Characters EVA junction value
///public byte HIT_J; 0x001E 1 byte Characters HIT junction value
///public byte LUCK_J; 0x001F 1 byte Characters LUCK junction value
///
public IReadOnlyDictionary JVal { get; }
public byte MagicDataID { get; }
///0x0004 2 bytes Magic ID
public MagicID MagicID { get; }
///0x0000 2 bytes Offset to spell name
public FF8String Name { get; }
public bool PositiveMagic
{
get
{
switch (AttackType)
{
case AttackType.CurativeItem:
case AttackType.CurativeMagic:
case AttackType.GivePercentageHP:
case AttackType.Revive:
case AttackType.ReviveAtFullHP:
case AttackType.WhiteWindQuistis:
case AttackType.Scan: //scan is kinda both.
return true;
case AttackType.None:
case AttackType.PhysicalAttack:
case AttackType.MagicAttack:
case AttackType.PhysicalDamage:
case AttackType.MagicDamage:
case AttackType.RenzokukenFinisher:
case AttackType.SquallGunbladeAttack:
case AttackType.GF:
case AttackType.LvDown:
case AttackType.SummonItem:
case AttackType.GFIgnoreTargetSPR:
case AttackType.LvUp:
case AttackType.Card:
case AttackType.Kamikaze:
case AttackType.Devour:
case AttackType.GFDamage:
case AttackType.Unknown1:
case AttackType.MagicAttackIgnoreTargetSPR:
case AttackType.AngeloSearch:
case AttackType.MoogleDance:
case AttackType.LvAttack:
case AttackType.FixedDamage:
case AttackType.TargetCurrentHP1:
case AttackType.FixedMagicDamageBasedOnGFLevel:
case AttackType.Unknown2:
case AttackType.Unknown3:
case AttackType.Unknown4:
case AttackType.EveryoneGrudge:
case AttackType._1_HP_Damage:
case AttackType.PhysicalAttackIgnoreTargetVIT:
return false;
default:
throw new ArgumentOutOfRangeException();
}
}
}
///0x0008 1 byte Spell power(used in damage formula)
public byte SpellPower { get; }
///
/// //0x0026 2 bytes Characters J - Statuses Attack
/// //public byte J_Val[Kernel_bin.Stat.ST_Atk];//0x0024 1 byte Characters J - Status attack value
///
public JunctionStatuses StAtk { get; }
///0x0016 1 byte Status attack enabler
public byte StatusAttack { get; }
///0x0014 2 bytes Statuses 0
public PersistentStatuses Statuses0 { get; }
///0x0010 4 bytes Statuses 1
public BattleOnlyStatuses Statuses1 { get; }
///
/// //0x0028 2 bytes Characters J - Statuses Defend
/// //public byte J_Val[Kernel_bin.Stat.ST_Def_1];//0x0025 1 byte Characters J - Status defense value
///
public JunctionStatuses StDef { get; }
///0x000A 1 byte Default_target
public Target Target { get; }
///0x0006 1 byte Unknown
public byte Unknown { get; }
///0x0009 1 byte Unknown
public byte Unknown2 { get; }
///0x000F 1 byte Unknown
public byte Unknown3 { get; }
///0x003A 2 bytes Unknown
public byte[] Unknown4 { get; }
#endregion Properties
#region Methods
public static IReadOnlyList Read(BinaryReader br)
=> Enumerable.Range(0, Count).Select(x => CreateInstance(br, x)).ToList();
public override string ToString() => Name;
public uint TotalStatVal(Stat stat)
{
switch (stat)
{
case Stat.HP:
case Stat.STR:
case Stat.VIT:
case Stat.MAG:
case Stat.SPR:
case Stat.SPD:
case Stat.EVA:
case Stat.HIT:
case Stat.Luck:
return JVal[stat];
case Stat.ElAtk:
return JVal[stat] * ElAtk.Count();
case Stat.StAtk:
return JVal[stat] * StAtk.Count();
case Stat.ElDef1:
case Stat.ElDef2:
case Stat.ElDef3:
case Stat.ElDef4:
return JVal[stat] * ElDef.Count();
case Stat.StDef1:
case Stat.StDef2:
case Stat.StDef3:
case Stat.StDef4:
return JVal[stat] * StDef.Count();
case Stat.None:
return 0;
default:
throw new ArgumentOutOfRangeException(nameof(stat), stat, null);
}
}
private static MagicData CreateInstance(BinaryReader br, int i) => new MagicData(br, i);
#endregion Methods
}
}
}