Ejemplo n.º 1
0
 // Block Layout:
 // 000-001 U16 Index
 // 002-002 U8  Type
 // 003-003 U8  List Icon ID (e.g. 40-47 for the elemental-colored dots)
 // 004-005 U16 MP Cost
 // 006-007 U16 Unknown (used to be the cooldown time)
 // 008-009 U16 Valid Targets
 // 00a-029 TXT Name
 // 02a-129 TXT Description (exact length unknown)
 // 12a-3fe U8  Padding (NULs)
 // 3ff-3ff U8  End marker (0xff)
 public bool Read(BinaryReader BR)
 {
     this.Clear();
     try
     {
         byte[] Bytes = BR.ReadBytes(0x400);
         if (Bytes[0x3ff] != 0xff || Bytes[9] != 0x00 || !FFXIEncryption.DecodeDataBlock(Bytes))
         {
             return(false);
         }
         FFXIEncoding E = new FFXIEncoding();
         BR                 = new BinaryReader(new MemoryStream(Bytes, false));
         this.ID_           = BR.ReadUInt16();
         this.Type_         = (AbilityType)BR.ReadByte();
         this.ListIconID_   = BR.ReadByte();
         this.MPCost_       = BR.ReadUInt16();
         this.Unknown1_     = BR.ReadUInt16();
         this.ValidTargets_ = (ValidTarget)BR.ReadUInt16();
         this.Name_         = E.GetString(BR.ReadBytes(32)).TrimEnd('\0');
         this.Description_  = E.GetString(BR.ReadBytes(256)).TrimEnd('\0');
         BR.Close();
         return(true);
     }
     catch
     {
         return(false);
     }
 }
Ejemplo n.º 2
0
        // Block Layout:
        // 000-003 U32 Index
        // 004-007 U32 Unknown
        // 008-00b U32 Unknown
        // 00c-00f U32 Unknown
        // 010-013 U32 Unknown
        // 014-02b     Unknown
        // 02c-0ab TXT Description
        // 0ac-27f     Unknown
        // 280-281 U16 Icon Size
        // 282-bff IMG Icon (+ padding)
        public bool Read(BinaryReader BR)
        {
            this.Clear();
            try
            {
                byte[] Bytes     = BR.ReadBytes(0x280);
                byte[] IconBytes = BR.ReadBytes(0x980);
                if (!FFXIEncryption.DecodeDataBlock(Bytes))
                {
                    return(false);
                }
                if (IconBytes[0x97f] != 0xff)
                {
                    return(false);
                }
                {
                    // Verify that the icon info is valid
                    Graphic      StatusIcon = new Graphic();
                    BinaryReader IconBR     = new BinaryReader(new MemoryStream(IconBytes, false));
                    int          IconSize   = IconBR.ReadInt32();
                    if (IconSize > 0 && IconSize <= 0x97b)
                    {
                        if (!StatusIcon.Read(IconBR) || IconBR.BaseStream.Position != 4 + IconSize)
                        {
                            IconBR.Close();
                            return(false);
                        }
                    }
                    IconBR.Close();
                    if (StatusIcon == null)
                    {
                        return(false);
                    }
                    this.Icon_ = StatusIcon;
                }
                BR = new BinaryReader(new MemoryStream(Bytes, false));
            }
            catch
            {
                return(false);
            }
            FFXIEncoding E = new FFXIEncoding();

            this.ID_       = BR.ReadUInt16();
            this.Unknown1_ = BR.ReadUInt16();
            this.Unknown2_ = BR.ReadUInt32();
            this.Unknown3_ = BR.ReadUInt32();
            this.Unknown4_ = BR.ReadUInt32();
            this.Unknown4_ = BR.ReadUInt32();
            BR.ReadBytes(0x18);
            this.Description_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0');
            BR.Close();
            return(true);
        }
Ejemplo n.º 3
0
        // Block Layout:
        // 000-001 U16 Index
        // 002-003 U16 Magic Type (1/2/3/4/5/6 - White/Black/Summon/Ninja/Bard/Blue)
        // 004-005 U16 Element
        // 006-007 U16 Valid Targets
        // 008-009 U16 Skill
        // 00a-00b U16 MP Cost
        // 00c-00c U8  Cast Time (1/4 second)
        // 00d-00d U8  Recast Delay (1/4 second)
        // 00e-025 U8  Level required (1 byte per job, 0xff if not learnable; first is for the NUL job, so always 0xff; only 24 slots despite 32 possible job flags)
        // 026-027 U16 ID (0 for "unused" spells; starts out equal to the index, but doesn't stay that way)
        // 028-028 U8  List Icon ID (not sure what this is an index of, but it seems to match differences in item icon)
        // 029-029 U8  Unknown #1
        // 02a-02b U8  Unknown #2
        // 02c-02d U8  Unknown #3
        // 02e-02f U8  Unknown #4
        // 030-03e U8  Padding (NULs)
        // 03f-03f U8  End marker (0xff)
        public bool Read(BinaryReader BR)
        {
            Clear();
            try
            {
                var Bytes = BR.ReadBytes(0x64);
                if (Bytes[0x3] != 0x00 || Bytes[0x5] != 0x00 || Bytes[0x7] != 0x00 || Bytes[0x9] != 0x00 || Bytes[0xE] != 0xFF || Bytes[0x63] != 0xFF)
                {
                    return(false);
                }
                if (!FFXIEncryption.DecodeDataBlockMask(Bytes))
                {
                    return(false);
                }
                BR = new BinaryReader(new MemoryStream(Bytes, false));
            }
            catch
            {
                return(false);
            }
            Index_         = BR.ReadUInt16();
            MagicType_     = (MagicType)BR.ReadUInt16();
            Element_       = (Element)BR.ReadUInt16();
            ValidTargets_  = (ValidTarget)BR.ReadUInt16();
            Skill_         = (Skill)BR.ReadUInt16();
            MPCost_        = BR.ReadUInt16();
            CastingTime_   = BR.ReadByte();
            RecastDelay_   = BR.ReadByte();
            LevelRequired_ = new int[0x18];
            for (var i = 0; i < 0x18; ++i)
            {
                LevelRequired_[i] = BR.ReadInt16();
            }
            ID_         = BR.ReadUInt16();
            ListIconID_ = BR.ReadByte();
            Unknown1_   = BR.ReadByte();
            Unknown2_   = BR.ReadByte();
            Unknown3_   = BR.ReadByte();
            Unknown4_   = BR.ReadByte();
            Unknown5_   = BR.ReadUInt32();

#if DEBUG // Check the padding bytes for unexpected data
            for (byte i = 0; i < 26; ++i)
            {
                var PaddingByte = BR.ReadByte();
                if (PaddingByte != 0)
                {
                    Console.WriteLine("SpellInfo2: Entry #{0}: Padding Byte #{1} is non-zero: {2:X2} ({2})", Index_, i + 1, PaddingByte);
                }
            }
#endif
            BR.Close();
            return(true);
        }
Ejemplo n.º 4
0
        // Block Layout:
        // 000-001 U16 Index
        // 002-003 U16 Magic Type (1/2/3/4/5/6 - White/Black/Summon/Ninja/Bard/Blue)
        // 004-005 U16 Element
        // 006-007 U16 Valid Targets
        // 008-009 U16 Skill
        // 00a-00b U16 MP Cost
        // 00c-00c U8  Cast Time (1/4 second)
        // 00d-00d U8  Recast Delay (1/4 second)
        // 00e-025 U8  Level required (1 byte per job, 0xff if not learnable; first is for the NUL job, so always 0xff; only 24 slots despite 32 possible job flags)
        // 026-027 U16 ID (0 for "unused" spells; starts out equal to the index, but doesn't stay that way)
        // 028-028 U8  List Icon ID (not sure what this is an index of, but it seems to match differences in item icon)
        // 029-029 U8  Unknown #1
        // 02a-02b U8  Unknown #2
        // 02c-02d U8  Unknown #3
        // 02e-02f U8  Unknown #4
        // 030-03e U8  Padding (NULs)
        // 03f-03f U8  End marker (0xff)
        public bool Read(BinaryReader BR)
        {
            this.Clear();
            try
            {
                byte[] Bytes = BR.ReadBytes(0x58);
                //if (Bytes[0x3] != 0x00 || Bytes[0x5] != 0x00 || Bytes[0x7] != 0x00 || Bytes[0x9] != 0x00 || Bytes[0xf] != 0xff || Bytes[0x3f] != 0xff)
                //return false;
                if (!FFXIEncryption.DecodeDataBlockMask(Bytes))
                {
                    return(false);
                }
                BR = new BinaryReader(new MemoryStream(Bytes, false));
            }
            catch
            {
                return(false);
            }
            this.Index_         = BR.ReadUInt16();
            this.MagicType_     = (MagicType)BR.ReadUInt16();
            this.Element_       = (Element)BR.ReadUInt16();
            this.ValidTargets_  = (ValidTarget)BR.ReadUInt16();
            this.Skill_         = (Skill)BR.ReadUInt16();
            this.MPCost_        = BR.ReadUInt16();
            this.CastingTime_   = BR.ReadByte();
            this.RecastDelay_   = BR.ReadByte();
            this.LevelRequired_ = new int[0x18];
            for (var i = 0; i < 0x18; ++i)
            {
                this.LevelRequired_[i] = BR.ReadInt16();
            }
            this.ID_         = BR.ReadUInt16();
            this.ListIconID_ = BR.ReadByte();
            this.Unknown1_   = BR.ReadByte();
            this.Unknown2_   = BR.ReadByte();
            this.Unknown3_   = BR.ReadByte();
            this.Unknown4_   = BR.ReadByte();
            this.Unknown5_   = BR.ReadUInt32();
#if DEBUG // Check the padding bytes for unexpected data
            for (byte i = 0; i < 14; ++i)
            {
                byte PaddingByte = BR.ReadByte();
                if (PaddingByte != 0)
                {
                    Console.WriteLine("MonsterSpellInfo2: Entry #{0}: Padding Byte #{1} is non-zero: {2:X2} ({2})", this.Index_,
                                      i + 1, PaddingByte);
                }
            }
#endif
            BR.Close();
            return(true);
        }
Ejemplo n.º 5
0
        // Block Layout:
        // 000-001 U16 Index
        // 002-002 U8  Type
        // 003-003 U8  List Icon ID (e.g. 40-47 for the elemental-colored dots)
        // 004-005 U16 Unknown #1
        // 006-007 U16 MP Cost
        // 008-009 U16 Shared Timer ID
        // 00a-00b U16 Valid Targets
        // 00c-00c I8  TP Cost (percentage, or -1 if not applicable)
        // 00d-00d U8  Category ID (for entries that are categories instead of real abilities)
        // 010-02e U8  Padding (NULs)
        // 02f-02f U8  End marker (0xff)
        public bool Read(BinaryReader BR)
        {
            this.Clear();
            try
            {
                byte[] Bytes = BR.ReadBytes(0x30);
                if (Bytes[0x9] > 0xc0 || Bytes[0x2f] != 0xff)
                {
                    return(false);
                }
                if (!FFXIEncryption.DecodeDataBlockMask(Bytes))
                {
                    return(false);
                }
                FFXIEncoding E = new FFXIEncoding();
                BR = new BinaryReader(new MemoryStream(Bytes, false));
            }
            catch
            {
                return(false);
            }
            this.ID_            = BR.ReadUInt16();
            this.Type_          = (AbilityType)BR.ReadByte();
            this.ListIconID_    = BR.ReadByte();
            this.Unknown1_      = BR.ReadUInt16();
            this.MPCost_        = BR.ReadUInt16();
            this.SharedTimerID_ = BR.ReadUInt16();
            this.ValidTargets_  = (ValidTarget)BR.ReadUInt16();
            this.TPCost_        = BR.ReadByte();
            this.CategoryID_    = BR.ReadByte();
            this.Unknown1_      = BR.ReadUInt16();
#if DEBUG // Check the padding bytes for unexpected data
            for (byte i = 0; i < 31; ++i)
            {
                byte PaddingByte = BR.ReadByte();
                if (PaddingByte != 0)
                {
                    Console.WriteLine("AbilityInfo2: Entry #{0}: Padding Byte #{1} is non-zero: {2:X2} ({2})", this.ID_, i + 1,
                                      PaddingByte);
                }
            }
#endif
            BR.Close();
            return(true);
        }
Ejemplo n.º 6
0
        // Block Layout:
        // 000-001 U16 Index
        // 002-003 U16 Magic Type (1/2/3/4/5/6 - White/Black/Summon/Ninja/Bard/Blue)
        // 004-005 U16 Element
        // 006-007 U16 Valid Targets
        // 008-009 U16 Skill
        // 00a-00b U16 MP Cost
        // 00c-00c U8  Cast Time (1/4 second)
        // 00d-00d U8  Recast Delay (1/4 second)
        // 00e-025 U8  Level required (1 byte per job, 0xff if not learnable; first is for the NUL job, so always 0xff; only 24 slots despite 32 possible job flags)
        // 026-027 U16 ID (0 for "unused" spells; starts out equal to the index, but doesn't stay that way)
        // 028-028 U8  List Icon ID (not sure what this is an index of, but it seems to match differences in item icon)
        // 029-03c CHR Japanese Name (20 bytes)
        // 03d-051 CHR English Name (20 bytes)
        // 052-0d1 CHR Japanese Description (128 bytes)
        // 0d2-151 CHR English Description (128 bytes)
        // 152-3fe U8  Padding (NULs)
        // 3ff-3ff U8  End marker (0xff)
        public bool Read(BinaryReader BR)
        {
            this.Clear();
            try
            {
                byte[] Bytes = BR.ReadBytes(0x400);
                if (Bytes[0x3] != 0x00 || Bytes[0x5] != 0x00 || Bytes[0x7] != 0x00 || Bytes[0x9] != 0x00 || Bytes[0xf] != 0xff ||
                    Bytes[0x3ff] != 0xff)
                {
                    return(false);
                }
                if (!FFXIEncryption.DecodeDataBlock(Bytes))
                {
                    return(false);
                }
                BR = new BinaryReader(new MemoryStream(Bytes, false));
            }
            catch
            {
                return(false);
            }
            this.Index_         = BR.ReadUInt16();
            this.MagicType_     = (MagicType)BR.ReadUInt16();
            this.Element_       = (Element)BR.ReadUInt16();
            this.ValidTargets_  = (ValidTarget)BR.ReadUInt16();
            this.Skill_         = (Skill)BR.ReadUInt16();
            this.MPCost_        = BR.ReadUInt16();
            this.CastingTime_   = BR.ReadByte();
            this.RecastDelay_   = BR.ReadByte();
            this.LevelRequired_ = new int[0x18];
            for (var i = 0; i < 0x18; ++i)
            {
                this.LevelRequired_[i] = BR.ReadInt16();
            }
            this.ID_         = BR.ReadUInt16();
            this.ListIconID_ = BR.ReadByte();
            BR.ReadBytes(0x04);
            FFXIEncoding E = new FFXIEncoding();

            this.JapaneseName_        = E.GetString(BR.ReadBytes(20)).TrimEnd('\0');
            this.EnglishName_         = E.GetString(BR.ReadBytes(20)).TrimEnd('\0');
            this.JapaneseDescription_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0');
            this.EnglishDescription_  = E.GetString(BR.ReadBytes(128)).TrimEnd('\0');
            // A slightly newer revision of this format no longer has the names, so mark them unset when empty
            if (this.JapaneseName_.Length == 0)
            {
                this.JapaneseName_ = null;
            }
            if (this.EnglishName_.Length == 0)
            {
                this.EnglishName_ = null;
            }
            if (this.JapaneseDescription_.Length == 0)
            {
                this.JapaneseDescription_ = null;
            }
            if (this.EnglishDescription_.Length == 0)
            {
                this.EnglishDescription_ = null;
            }
#if DEBUG
            {
                // Read the next 64 bits, and report if it's not 0 (means there's new data to identify)
                ulong Next64 = BR.ReadUInt64();
                if (Next64 != 0)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Nonzero data after entry (Spell #{0}): {1:X16}", this.ID_, Next64);
                    Console.ResetColor();
                }
            }
#endif
            BR.Close();
            return(true);
        }
Ejemplo n.º 7
0
        public bool Read(BinaryReader BR, Type T)
        {
            this.Clear();
            try
            {
                byte[] ItemBytes = BR.ReadBytes(0xC00);
                FFXIEncryption.Rotate(ItemBytes, 5);
                BR = new BinaryReader(new MemoryStream(ItemBytes, false));
                BR.BaseStream.Seek(0x280, SeekOrigin.Begin);
                Graphic G           = new Graphic();
                int     GraphicSize = BR.ReadInt32();
                if (GraphicSize < 0 || !G.Read(BR) || BR.BaseStream.Position != 0x280 + 4 + GraphicSize)
                {
                    BR.Close();
                    return(false);
                }
                this.Icon_ = G;
                BR.BaseStream.Seek(0, SeekOrigin.Begin);
            }
            catch
            {
                return(false);
            }
            // Common Fields (14 bytes)
            this.ID_           = BR.ReadUInt32();
            this.Flags_        = (ItemFlags)BR.ReadUInt16();
            this.StackSize_    = BR.ReadUInt16(); // 0xe0ff for Currency, which kinda suggests this is really 2 separate bytes
            this.Type_         = (ItemType)BR.ReadUInt16();
            this.ResourceID_   = BR.ReadUInt16();
            this.ValidTargets_ = (ValidTarget)BR.ReadUInt16();
            // Extra Fields (22/30/10/6/2 bytes for Armor/Weapon/Puppet/Item/UsableItem)

            if (T == Type.Armor || T == Type.Weapon)
            {
                this.Level_         = BR.ReadUInt16();
                this.Slots_         = (EquipmentSlot)BR.ReadUInt16();
                this.Races_         = (Race)BR.ReadUInt16();
                this.Jobs_          = (Job)BR.ReadUInt32();
                this.SuperiorLevel_ = BR.ReadUInt16();
                if (T == Type.Armor)
                {
                    this.ShieldSize_ = BR.ReadUInt16();
                }
                else
                {
                    // Weapon
                    this.Unknown4_ = BR.ReadUInt16();
                    this.Damage_   = BR.ReadUInt16();
                    this.Delay_    = BR.ReadInt16();
                    this.DPS_      = BR.ReadUInt16();
                    this.Skill_    = (Skill)BR.ReadByte();
                    this.JugSize_  = BR.ReadByte();
                    this.Unknown1_ = BR.ReadUInt32();
                }
                this.MaxCharges_  = BR.ReadByte();
                this.CastingTime_ = BR.ReadByte();
                this.UseDelay_    = BR.ReadUInt16();
                this.ReuseDelay_  = BR.ReadUInt32();
                this.Unknown2_    = BR.ReadUInt16();
                this.iLevel_      = BR.ReadUInt16();
                this.Unknown3_    = BR.ReadUInt32();
            }
            else if (T == Type.PuppetItem)
            {
                this.PuppetSlot_    = (PuppetSlot)BR.ReadUInt16();
                this.ElementCharge_ = BR.ReadUInt32();
                this.Unknown3_      = BR.ReadUInt32();
            }
            else if (T == Type.Instinct)
            {
                BR.ReadUInt32();
                BR.ReadUInt32();
                BR.ReadUInt16();
                this.InstinctCost_ = BR.ReadUInt16();
                BR.ReadUInt16();
                BR.ReadUInt32();
                BR.ReadUInt32();
                BR.ReadUInt32();
            }
            else if (T == Type.Item)
            {
                switch (this.Type_.Value)
                {
                case ItemType.Flowerpot:
                case ItemType.Furnishing:
                case ItemType.Mannequin:
                    this.Element_      = (Element)BR.ReadUInt16();
                    this.StorageSlots_ = BR.ReadInt32();
                    this.Unknown3_     = BR.ReadUInt32();
                    break;

                default:
                    this.Unknown2_ = BR.ReadUInt16();
                    this.Unknown3_ = BR.ReadUInt32();
                    this.Unknown3_ = BR.ReadUInt32();
                    break;
                }
            }
            else if (T == Type.UsableItem)
            {
                this.ActivationTime_ = BR.ReadUInt16();
                this.Unknown1_       = BR.ReadUInt32();
                this.Unknown3_       = BR.ReadUInt32();
                this.Unknown4_       = BR.ReadUInt32();
            }
            else if (T == Type.Currency)
            {
                this.Unknown2_ = BR.ReadUInt16();
            }
            else if (T == Type.Slip)
            {
                this.Unknown1_ = BR.ReadUInt16();
                for (int counter = 0; counter < 17; counter++)
                {
                    BR.ReadUInt32();
                }
            }
            else if (T == Type.Monipulator)
            {
                this.Unknown1_ = BR.ReadUInt16();
                for (int counter = 0; counter < 24; counter++)
                {
                    BR.ReadInt32();
                }
            }
            // Next Up: Strings (variable size)
            long StringBase  = BR.BaseStream.Position;
            uint StringCount = BR.ReadUInt32();

            if (StringCount > 9)
            {
                // Sanity check, for safety - 0 strings is fine for now
                this.Clear();
                return(false);
            }
            FFXIEncoding E = new FFXIEncoding();

            string[] Strings = new string[StringCount];
            for (byte i = 0; i < StringCount; ++i)
            {
                long Offset = StringBase + BR.ReadUInt32();
                uint Flag   = BR.ReadUInt32();
                if (Offset < 0 || Offset + 0x20 > 0x280 || (Flag != 0 && Flag != 1))
                {
                    this.Clear();
                    return(false);
                }
                // Flag seems to be 1 if the offset is not actually an offset. Could just be padding to make StringCount unique per language, or it could be an indication
                // of the pronoun to use (a/an/the/...). The latter makes sense because of the increased number of such flags for french and german.
                if (Flag == 0)
                {
                    BR.BaseStream.Position = Offset;
                    Strings[i]             = this.ReadString(BR, E);
                    if (Strings[i] == null)
                    {
                        this.Clear();
                        return(false);
                    }
                    BR.BaseStream.Position = StringBase + 4 + 8 * (i + 1);
                }
            }
            // Assign the strings to the proper fields
            switch (StringCount)
            {
            case 1:
                this.Name_ = Strings[0];
                break;

            case 2:     // Japanese
                this.Name_        = Strings[0];
                this.Description_ = Strings[1];
                break;

            case 5:     // English
                this.Name_ = Strings[0];
                // unused:              Strings[1]
                this.LogNameSingular_ = Strings[2];
                this.LogNamePlural_   = Strings[3];
                this.Description_     = Strings[4];
                break;

            case 6:     // French
                this.Name_ = Strings[0];
                // unused:              Strings[1]
                // unused:              Strings[2]
                this.LogNameSingular_ = Strings[3];
                this.LogNamePlural_   = Strings[4];
                this.Description_     = Strings[5];
                break;

            case 9:     // German
                this.Name_ = Strings[0];
                // unused:              Strings[1]
                // unused:              Strings[2]
                // unused:              Strings[3]
                this.LogNameSingular_ = Strings[4];
                // unused:              Strings[5]
                // unused:              Strings[6]
                this.LogNamePlural_ = Strings[7];
                this.Description_   = Strings[8];
                break;
            }
            BR.Close();
            return(true);
        }
Ejemplo n.º 8
0
        public static void DeduceType(BinaryReader BR, out Type T)
        {
            T = Type.Unknown;
            byte[] FirstItem = null;
            long   Position  = BR.BaseStream.Position;

            BR.BaseStream.Position = 0;
            try
            {
                while (BR.BaseStream.Position != BR.BaseStream.Length)
                {
                    FirstItem = BR.ReadBytes(0x4);
                    BR.BaseStream.Position += (0xc00 - 0x4);
                    FFXIEncryption.Rotate(FirstItem, 5);
                    {
                        // Type -> Based on ID
                        uint ID = 0;
                        for (int i = 0; i < 4; ++i)
                        {
                            ID <<= 8;
                            ID  += FirstItem[3 - i];
                        }
                        if (ID == 0xffff)
                        {
                            T = Type.Currency;
                        }
                        else if (ID < 0x1000)
                        {
                            T = Type.Item;
                        }
                        else if (ID < 0x2000)
                        {
                            T = Type.UsableItem;
                        }
                        else if (ID < 0x2200)
                        {
                            T = Type.PuppetItem;
                        }
                        else if (ID < 0x2800)
                        {
                            T = Type.Item;
                        }
                        else if (ID < 0x4000)
                        {
                            T = Type.Armor;
                        }
                        else if (ID < 0x5A00)
                        {
                            T = Type.Weapon;
                        }
                        else if (ID < 0x7000)
                        {
                            T = Type.Armor;
                        }
                        else if (ID < 0x7400)
                        {
                            T = Type.Slip;
                        }
                        else if (ID < 0x7800)
                        {
                            T = Type.Instinct;
                        }
                        else if (ID < 0xF200)
                        {
                            T = Type.Monipulator;
                        }
                    }
                    if (T != Type.Unknown)
                    {
                        break;
                    }
                }
            }
            catch { }
            BR.BaseStream.Position = Position;
        }
Ejemplo n.º 9
0
        static public Dictionary <uint, FFXI_Item> ReadItemListFromDatFile(uint DatFileId)
        {
            Dictionary <uint, FFXI_Item> res = new Dictionary <uint, FFXI_Item>();

            if (!FFXI_FTable.TryGetValue(DatFileId, out var FileDatInfo))
            {
                return(res);
            }

            if (!File.Exists(FileDatInfo.FullFileName))
            {
                return(res);
            }

            var FS = new FileStream(FileDatInfo.FullFileName, FileMode.Open, FileAccess.Read);

            // needs to be in 3072 byte block size, and a minimum of 16 entries
            if (((FS.Length % 0x0C00) != 0) || (FS.Length < 0xC000))
            {
                return(res);
            }
            var BR = new BinaryReader(FS);

            FFXI_DeduceItemType(BR, out var ExpectedItemType);

            var itemCount = BR.BaseStream.Length / 0x0C00;

            for (var i = 0; i < itemCount; i++)
            {
                BR.BaseStream.Seek(i * 0x0C00, SeekOrigin.Begin);
                byte[] ItemBytes = BR.ReadBytes(0xC00);
                FFXIEncryption.Rotate(ItemBytes, 5);
                var MemBR = new BinaryReader(new MemoryStream(ItemBytes, false));

                FFXI_Item item = new FFXI_Item();
                // Common Fields (14 bytes)
                item.Id        = MemBR.ReadUInt32();
                item.Flags     = (FFXI_ItemFlags)MemBR.ReadUInt16();
                item.StackSize = MemBR.ReadUInt16(); // 0xe0ff for Currency, which kinda suggests this is really 2 separate bytes
                item.Type      = (FFXI_ItemType)MemBR.ReadUInt16();
                MemBR.ReadUInt16();                  // item.ResourceID_ = MemBR.ReadUInt16();
                MemBR.ReadUInt16();                  // item.ValidTargets_ = (ValidTarget)MemBR.ReadUInt16();
                // Extra Fields (22/30/10/6/2 bytes for Armor/Weapon/Puppet/Item/UsableItem)

                if (item.Type == FFXI_ItemType.Nothing)
                {
                    continue;
                }

                switch (ExpectedItemType)
                {
                case FFXI_ItemDatFileTypes.Armor:
                case FFXI_ItemDatFileTypes.Weapon:
                    MemBR.ReadUInt16();     // item.Level_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.Slots_ = (EquipmentSlot)MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.Races_ = (Race)MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Jobs_ = (Job)MemBR.ReadUInt32();
                    MemBR.ReadUInt16();     //item.SuperiorLevel_ = MemBR.ReadUInt16();
                    if (ExpectedItemType == FFXI_ItemDatFileTypes.Armor)
                    {
                        MemBR.ReadUInt16();     // item.ShieldSize_ = MemBR.ReadUInt16();
                    }
                    else
                    {
                        // Weapon
                        MemBR.ReadUInt16(); // item.Unknown4_ = MemBR.ReadUInt16();
                        MemBR.ReadUInt16(); // item.Damage_ = MemBR.ReadUInt16();
                        MemBR.ReadInt16();  // item.Delay_ = MemBR.ReadInt16();
                        MemBR.ReadUInt16(); // item.DPS_ = MemBR.ReadUInt16();
                        MemBR.ReadByte();   // item.Skill_ = (Skill)MemBR.ReadByte();
                        MemBR.ReadByte();   // item.JugSize_ = MemBR.ReadByte();
                        MemBR.ReadUInt32(); // item.Unknown1_ = MemBR.ReadUInt32();
                    }
                    MemBR.ReadByte();       // item.MaxCharges_ = MemBR.ReadByte();
                    MemBR.ReadByte();       // item.CastingTime_ = MemBR.ReadByte();
                    MemBR.ReadUInt16();     // item.UseDelay_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.ReuseDelay_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt16();     // item.Unknown2_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.iLevel_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.PuppetItem:
                    MemBR.ReadUInt16();     // item.PuppetSlot_ = (PuppetSlot)MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.ElementCharge_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Instinct:
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.InstinctCost_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Item:
                    switch (item.Type)
                    {
                    case FFXI_ItemType.Flowerpot:
                    case FFXI_ItemType.Furnishing:
                    case FFXI_ItemType.Mannequin:
                        MemBR.ReadUInt16();        // item.Element_ = (Element)MemBR.ReadUInt16();
                        MemBR.ReadInt32();         // item.StorageSlots_ = MemBR.ReadInt32();
                        MemBR.ReadUInt32();        // item.Unknown3_ = MemBR.ReadUInt32();
                        break;

                    default:
                        MemBR.ReadUInt16();         // item.Unknown2_ = MemBR.ReadUInt16();
                        MemBR.ReadUInt32();         // item.Unknown3_ = MemBR.ReadUInt32();
                        MemBR.ReadUInt32();         // item.Unknown3_ = MemBR.ReadUInt32();
                        break;
                    }
                    break;

                case FFXI_ItemDatFileTypes.UsableItem:
                    MemBR.ReadUInt16();     // item.ActivationTime_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Unknown1_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown4_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Currency:
                    MemBR.ReadUInt16();     // item.Unknown2_ = MemBR.ReadUInt16();
                    break;

                case FFXI_ItemDatFileTypes.ItemSlip:
                    MemBR.ReadUInt16();     // item.Unknown1_ = MemBR.ReadUInt16();
                    for (int counter = 0; counter < 17; counter++)
                    {
                        MemBR.ReadUInt32();
                    }
                    break;

                case FFXI_ItemDatFileTypes.Monipulator:
                    MemBR.ReadUInt16();     // item.Unknown1_ = MemBR.ReadUInt16();
                    for (int counter = 0; counter < 24; counter++)
                    {
                        MemBR.ReadInt32();
                    }
                    break;

                default:
                    // If this is a unknown expected file type, ignore and exit
                    return(res);
                }

                if (item.Type > FFXI_ItemType.Max)
                {
                    // Invalid item type ?
                    continue;
                }

                // Next Up: Strings (variable size)
                long StringBase  = MemBR.BaseStream.Position;
                uint StringCount = MemBR.ReadUInt32();
                if (StringCount > 9)
                {
                    // Sanity check, for safety - 0 strings is fine for now
                    // item.Clear();
                    continue;
                }
                FFXIEncoding E       = new FFXIEncoding();
                string[]     Strings = new string[StringCount];
                for (byte iStrings = 0; iStrings < StringCount; iStrings++)
                {
                    long Offset = StringBase + MemBR.ReadUInt32();
                    uint Flag   = MemBR.ReadUInt32();
                    if (Offset < 0 || Offset + 0x20 > 0x280 || (Flag != 0 && Flag != 1))
                    {
                        // item.Clear();
                        StringCount = 0;
                        break;
                    }
                    // Flag seems to be 1 if the offset is not actually an offset. Could just be padding to make StringCount unique per language, or it could be an indication
                    // of the pronoun to use (a/an/the/...). The latter makes sense because of the increased number of such flags for french and german.
                    if (Flag == 0)
                    {
                        MemBR.BaseStream.Position = Offset;
                        Strings[iStrings]         = FFXI_ReadString(MemBR, E);
                        if (Strings[iStrings] == null)
                        {
                            // item.Clear();
                            StringCount = 0;
                            break;
                        }
                        MemBR.BaseStream.Position = StringBase + 4 + 8 * (iStrings + 1);
                    }
                }
                // Assign the strings to the proper fields
                switch (StringCount)
                {
                case 0:
                    // Temporary hack until I can figure out what the hell is wrong with reading the strings
                    if ((Strings.Length > 1) && (Strings[0] != null))
                    {
                        item.Name = Strings[0];
                    }
                    else
                    {
                        item.Name = "<no name found>";
                    }
                    // item.Name = item.Type.ToString() + " - " + item.Id.ToString();
                    break;

                case 1:
                    item.Name = Strings[0];
                    break;

                case 2:     // Japanese
                    item.Name        = Strings[0];
                    item.Description = Strings[1];
                    break;

                case 5:     // English
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    item.NameSingle   = Strings[2];
                    item.NameMultiple = Strings[3];
                    item.Description  = Strings[4];
                    break;

                case 6:     // French
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    // unused:              Strings[2]
                    item.NameSingle   = Strings[3];
                    item.NameMultiple = Strings[4];
                    item.Description  = Strings[5];
                    break;

                case 9:     // German
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    // unused:              Strings[2]
                    // unused:              Strings[3]
                    item.NameSingle = Strings[4];
                    // unused:              Strings[5]
                    // unused:              Strings[6]
                    item.NameMultiple = Strings[7];
                    item.Description  = Strings[8];
                    break;
                }
                MemBR.Close();

                if ((item.Name != null) && (item.Name != string.Empty) && (item.Name != "."))
                {
                    res.Add(item.Id, item);
                }
            }
            return(res);
        }
Ejemplo n.º 10
0
 public bool Read(BinaryReader BR, string Category, long MenuStart)
 {
     this.Clear();
     this.Category_ = Category;
     try {
         this.ID_ = BR.ReadUInt32();
         long Name1Start = BR.ReadInt32();
         long Name2Start = BR.ReadInt32();
         long BodyStart  = BR.ReadInt32();
         // Unknown (BodyEnd? not likely as it does not match "BodyStart + 4 * (1 + LineCount)"
         long Unknown = BR.ReadInt32();
         if (Name1Start < 0 || Name2Start < 0 || BodyStart < 0 || Unknown < 0)
         {
             return(false);
         }
         FFXIEncoding E      = new FFXIEncoding();
         long         CurPos = BR.BaseStream.Position;
         BR.BaseStream.Position = MenuStart + Name1Start;
         this.Name1_            = FFXIEncryption.ReadEncodedString(BR, E);
         BR.BaseStream.Position = MenuStart + Name2Start;
         this.Name2_            = FFXIEncryption.ReadEncodedString(BR, E);
         BR.BaseStream.Position = MenuStart + BodyStart;
         {
             int LineCount = BR.ReadInt32();
             if (LineCount < 0)
             {
                 BR.BaseStream.Position = CurPos;
                 return(false);
             }
             { // Read entry description lines
                 long[] LineStart = new long[LineCount];
                 for (int i = 0; i < LineCount; ++i)
                 {
                     LineStart[i] = BR.ReadInt32();
                     if (LineStart[i] < 0)
                     {
                         BR.BaseStream.Position = CurPos;
                         return(false);
                     }
                 }
                 this.Description_ = String.Empty;
                 for (int i = 0; i < LineCount; ++i)
                 {
                     BR.BaseStream.Position = MenuStart + LineStart[i];
                     if (i > 0)
                     {
                         this.Description_ += "\r\n";
                     }
                     this.Description_ += FFXIEncryption.ReadEncodedString(BR, E);
                 }
             }
         }
         BR.BaseStream.Position = MenuStart + Unknown;
         {
             int LineCount = BR.ReadInt32();
             if (LineCount < 0)
             {
                 BR.BaseStream.Position = CurPos;
                 return(false);
             }
             { // Read entry description lines
                 long[] LineStart = new long[LineCount];
                 for (int i = 0; i < LineCount; ++i)
                 {
                     LineStart[i] = BR.ReadInt32();
                     if (LineStart[i] < 0)
                     {
                         BR.BaseStream.Position = CurPos;
                         return(false);
                     }
                 }
                 this.Extra_ = String.Empty;
                 for (int i = 0; i < LineCount; ++i)
                 {
                     BR.BaseStream.Position = MenuStart + LineStart[i];
                     if (i > 0)
                     {
                         this.Extra_ += "\r\n";
                     }
                     this.Extra_ += FFXIEncryption.ReadEncodedString(BR, E);
                 }
             }
         }
         BR.BaseStream.Position = CurPos;
         return(true);
     } catch { return(false); }
 }
Ejemplo n.º 11
0
        private void TranslateItemFile(int JPFileNumber, int ENFileNumber)
        {
            if (!this.mnuTranslateItemNames.Checked && !this.mnuTranslateItemDescriptions.Checked)
            {
                return;
            }
            if (!this.BackupFile(JPFileNumber))
            {
                return;
            }
            try
            {
                string JFileName = FFXI.GetFilePath(JPFileNumber);
                string EFileName = FFXI.GetFilePath(ENFileNumber);
                this.AddLogEntry(String.Format(I18N.GetText("TranslatingItems"), JFileName));
                this.AddLogEntry(String.Format(I18N.GetText("UsingEnglishFile"), EFileName));
                FileStream JStream = new FileStream(JFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                FileStream EStream = new FileStream(EFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                if ((JStream.Length % 0xc00) != 0)
                {
                    this.AddLogEntry(I18N.GetText("ItemFileSizeBad"));
                    goto TranslationDone;
                }
                if (JStream.Length != EStream.Length)
                {
                    this.AddLogEntry(I18N.GetText("FileSizeMismatch"));
                    goto TranslationDone;
                }
                Things.Item.Type T;
                {
                    BinaryReader BR = new BinaryReader(JStream);
                    Things.Item.DeduceType(BR, out T);
                    BR = new BinaryReader(EStream);
                    Things.Item.Type ET;
                    Things.Item.DeduceType(BR, out ET);
                    if (T != ET)
                    {
                        this.AddLogEntry(I18N.GetText("ItemTypeMismatch"));
                        goto TranslationDone;
                    }
                }
                ushort StringBase = 0;
                switch (T)
                {
                case Things.Item.Type.Armor:
                    StringBase = 36;
                    break;

                case Things.Item.Type.Item:
                    StringBase = 20;
                    break;

                case Things.Item.Type.PuppetItem:
                    StringBase = 24;
                    break;

                case Things.Item.Type.UsableItem:
                    StringBase = 16;
                    break;

                case Things.Item.Type.Weapon:
                    StringBase = 44;
                    break;

                case Things.Item.Type.Slip:
                    StringBase = 80;
                    break;

                default:
                    this.AddLogEntry(I18N.GetText("ItemTypeBad"));
                    goto TranslationDone;
                }
                long         ItemCount  = JStream.Length / 0xc00;
                byte[]       JData      = new byte[0x280];
                byte[]       EData      = new byte[0x280];
                MemoryStream JMemStream = new MemoryStream(JData, true);
                MemoryStream EMemStream = new MemoryStream(EData, false);
                FFXIEncoding E          = new FFXIEncoding();
                for (long i = 0; i < ItemCount; ++i)
                {
                    JStream.Seek(i * 0xc00, SeekOrigin.Begin);
                    JStream.Read(JData, 0, 0x280);
                    EStream.Seek(i * 0xc00, SeekOrigin.Begin);
                    EStream.Read(EData, 0, 0x280);
                    FFXIEncryption.Rotate(JData, 5);
                    FFXIEncryption.Rotate(EData, 5);
                    // Read English or Japanese Name
                    List <byte> Name = new List <byte>();
                    {
                        MemoryStream MS = null;
                        if (this.mnuTranslateItemNames.Checked)
                        {
                            MS = EMemStream;
                        }
                        else
                        {
                            MS = JMemStream;
                        }
                        MS.Position = StringBase + 4;
                        BinaryReader BR = new BinaryReader(MS);
                        MS.Position = StringBase + 0x1c + BR.ReadUInt32();
                        while (MS.Position < 0x280)
                        {
                            int B = MS.ReadByte();
                            if (B <= 0)
                            {
                                break;
                            }
                            Name.Add((byte)B);
                        }
                        Name.Add(0);
                        while (Name.Count % 4 != 0)
                        {
                            Name.Add(0);
                        }
                    }
                    // Read English or Japanese Description
                    List <byte> Description = new List <byte>();
                    {
                        MemoryStream MS = null;
                        if (this.mnuTranslateItemDescriptions.Checked)
                        {
                            EMemStream.Position = StringBase + 4 + 8 * 4;
                            MS = EMemStream;
                        }
                        else
                        {
                            JMemStream.Position = StringBase + 4 + 8 * 1;
                            MS = JMemStream;
                        }
                        BinaryReader BR = new BinaryReader(MS);
                        MS.Position = StringBase + 0x1c + BR.ReadUInt32();
                        while (MS.Position < 0x280)
                        {
                            int B = MS.ReadByte();
                            if (B <= 0)
                            {
                                break;
                            }
                            Description.Add((byte)B);
                        }
                        Description.Add(0);
                        while (Description.Count % 4 != 0)
                        {
                            Description.Add(0);
                        }
                    }
                    {
                        // Construct a new string table
                        BinaryWriter BW = new BinaryWriter(JMemStream);
                        Array.Clear(JData, StringBase, 0x280 - StringBase);
                        JMemStream.Position = StringBase;
                        uint NameOffset = 0x14; // Right after the string table header
                        uint DescOffset = NameOffset + (uint)Name.Count + 28;
                        BW.Write((uint)2);      // String Count
                        BW.Write(NameOffset);   // Entry #1
                        BW.Write((uint)0);
                        BW.Write(DescOffset);   // Entry #2
                        BW.Write((uint)0);
                        // String #1 - Padding + text bytes
                        BW.Write((uint)1);
                        BW.Write((ulong)0);
                        BW.Write((ulong)0);
                        BW.Write((ulong)0);
                        BW.Write(Name.ToArray());
                        // String #2 - Padding + text bytes
                        BW.Write((uint)1);
                        BW.Write((ulong)0);
                        BW.Write((ulong)0);
                        BW.Write((ulong)0);
                        BW.Write(Description.ToArray());
                        // End marker
                        BW.Write((uint)1);
                    }
                    // Update file data
                    FFXIEncryption.Rotate(JData, 3);
                    JStream.Seek(i * 0xc00, SeekOrigin.Begin);
                    JStream.Write(JData, 0, 0x280);
                }
TranslationDone:
                JStream.Close();
                EStream.Close();
            }
            catch
            {
                this.LogFailure("TranslateItemFile");
            }
        }