public void AddTextureIfNotExists(uint key, DuplicatableStream texture)
        {
            SkitTex containedTexture;

            if (Cache.TryGetValue(key, out containedTexture))
            {
                const bool verify = false;
                if (verify)
                {
                    using (DuplicatableStream otex = containedTexture.Stream.Duplicate())
                        using (DuplicatableStream ntex = texture.Duplicate()) {
                            otex.Position = 0;
                            ntex.Position = 0;
                            if (!(otex.Length == ntex.Length && StreamUtils.IsIdentical(otex, ntex, otex.Length)))
                            {
                                throw new Exception("texture added does not match known texture");
                            }
                        }
                }
            }
            else
            {
                Cache.Add(key, new SkitTex()
                {
                    Stream = texture.Duplicate()
                });
            }
        }
Beispiel #2
0
        public PartialStream(DuplicatableStream stream, long position, long length)
        {
            if (position < 0)
            {
                throw new Exception("Invalid position, must be positive.");
            }
            if (length < 0)
            {
                throw new Exception("Invalid length, must be positive.");
            }

            if (stream is PartialStream)
            {
                // optimization to better chain partial stream of partial stream
                PartialStream parent = stream as PartialStream;
                BaseStreamInternal = parent.BaseStreamInternal.Duplicate();
                Initialized        = false;
                PartialStart       = parent.PartialStart + position;
                PartialLength      = length;
                CurrentPosition    = 0;
            }
            else
            {
                BaseStreamInternal = stream.Duplicate();
                Initialized        = false;
                PartialStart       = position;
                PartialLength      = length;
                CurrentPosition    = 0;
            }
        }
Beispiel #3
0
        private bool LoadFile(DuplicatableStream headerStream, DuplicatableStream contentStream)
        {
            DuplicatableStream infile = headerStream.Duplicate();

            contentFile = contentStream.Duplicate();

            infile.Seek(0x00, SeekOrigin.Begin);
            string magic = infile.ReadAscii(4);

            if (magic != "FPS4")
            {
                Console.WriteLine("Not an FPS4 file!");
                return(false);
            }

            Endian     = Util.Endianness.BigEndian;
            FileCount  = infile.ReadUInt32().FromEndian(Endian);
            HeaderSize = infile.ReadUInt32().FromEndian(Endian);

            // if header seems huge then we probably have assumed the wrong endianness
            if (HeaderSize > 0xFFFF)
            {
                Endian     = Util.Endianness.LittleEndian;
                FileCount  = FileCount.ToEndian(Util.Endianness.BigEndian).FromEndian(Endian);
                HeaderSize = HeaderSize.ToEndian(Util.Endianness.BigEndian).FromEndian(Endian);
            }

            FirstFileStart      = infile.ReadUInt32().FromEndian(Endian);
            EntrySize           = infile.ReadUInt16().FromEndian(Endian);
            ContentBitmask      = new ContentInfo(infile.ReadUInt16().FromEndian(Endian));
            Unknown2            = infile.ReadUInt32().FromEndian(Endian);
            ArchiveNameLocation = infile.ReadUInt32().FromEndian(Endian);
            infile.Position     = ArchiveNameLocation;
            if (ArchiveNameLocation > 0)
            {
                ArchiveName = infile.ReadShiftJisNullterm();
            }

            Alignment = FirstFileStart;

            Console.WriteLine("Content Bitmask: 0x" + ContentBitmask.Value.ToString("X4"));
            if (ContentBitmask.HasUnknownDataTypes)
            {
                Console.WriteLine("WARNING: Bitmask identifies unknown data types, data interpretation will probably be incorrect.");
            }

            Files = new List <FileInfo>((int)FileCount);
            for (uint i = 0; i < FileCount; ++i)
            {
                infile.Position = HeaderSize + (i * EntrySize);
                Files.Add(new FileInfo(infile, i, ContentBitmask, Endian, Util.GameTextEncoding.ASCII));
            }

            FileLocationMultiplier          = CalculateFileLocationMultiplier();
            ShouldGuessFilesizeFromNextFile = !ContentBitmask.ContainsFileSizes && !ContentBitmask.ContainsSectorSizes && CalculateIsLinear();

            infile.Dispose();
            return(true);
        }
Beispiel #4
0
 public NUB(DuplicatableStream duplicatableStream, EndianUtils.Endianness?e)
 {
     Stream          = duplicatableStream.Duplicate();
     Stream.Position = 0;
     Header          = new NubHeader(Stream, e);
     Endian          = Header.Endian;
     Stream.Position = Header.StartOfEntries;
     Entries         = Stream.ReadUInt32Array(Header.EntryCount, Endian);
 }
 public override string ToString()
 {
     using (FPS4 fps4 = new FPS4(Stream.Duplicate()))
         using (DuplicatableStream txmvStream = fps4.GetChildByIndex(1).AsFile.DataStream.Duplicate())
             using (FPS4 txmv = new FPS4(txmvStream.Duplicate()))
                 using (DuplicatableStream txmStream = txmv.GetChildByIndex(0).AsFile.DataStream.Duplicate()) {
                     TXM txm = new TXM(txmStream.Duplicate());
                     return(txm.TXMRegulars[0].Name);
                 }
 }
Beispiel #6
0
        private bool LoadFile(DuplicatableStream inputStream, EndianUtils.Endianness?endianParam, TextUtils.GameTextEncoding encoding)
        {
            DuplicatableStream stream = inputStream.Duplicate();

            stream.Position = 0;
            EndianUtils.Endianness endian;
            if (endianParam == null)
            {
                uint magic = stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
                if (magic == 0x53453320)
                {
                    endian = EndianUtils.Endianness.BigEndian;
                }
                else if (magic == 0x20334553)
                {
                    endian = EndianUtils.Endianness.LittleEndian;
                }
                else
                {
                    Console.WriteLine("Invalid magic: " + magic);
                    return(false);
                }
            }
            else
            {
                endian = endianParam.Value;
                uint magic = stream.ReadUInt32(endian);
                if (magic != 0x53453320)
                {
                    Console.WriteLine("Invalid magic: " + magic);
                    return(false);
                }
            }

            this.Endian = endian;

            uint lengthOfFilenameSection = stream.ReadUInt32(endian);            // probably?
            uint startOfFilenameSection  = stream.ReadUInt32(endian);            // probably?

            DataBegin = stream.ReadUInt32(endian);

            stream.Position = startOfFilenameSection;
            uint magicOfFilenameSection = stream.ReadUInt32(endian);

            FileCount = stream.ReadUInt32(endian);
            Filenames = new List <string>((int)FileCount);
            for (uint i = 0; i < FileCount; ++i)
            {
                Filenames.Add(stream.ReadSizedString(48, encoding).TrimNull());
            }

            Data = stream;

            return(true);
        }
Beispiel #7
0
        public void PrintData(EndianUtils.Endianness endian, Dictionary <uint, TSS.TSSEntry> inGameDic, List <ItemDat.ItemDatSingle> itemDataSorted, T8BTEMST.T8BTEMST enemies)
        {
            using (DuplicatableStream stream = Stream.Duplicate()) {
                stream.ReadUInt32().FromEndian(endian);   // ?
                stream.ReadUInt32().FromEndian(endian);   // ?
                stream.ReadUInt32Array(9, endian);
                stream.ReadUInt32().FromEndian(endian);   // play time in frames, assuming 60 frames = 1 second
                stream.ReadUInt32().FromEndian(endian);   // gald
                stream.DiscardBytes(4);                   // ?
                uint[] itemCounts        = stream.ReadUInt32Array(3072, endian);
                uint[] itemBookBitfields = stream.ReadUInt32Array(3072 / 32, endian);
                stream.DiscardBytes(4);                   // ?
                stream.ReadUInt32Array(4, endian);        // control modes for the four active party slots
                stream.ReadUInt32Array(3, endian);        // strategies assigned to dpad directions
                stream.DiscardBytes(0x40);                // ??
                for (int i = 0; i < 8; ++i)
                {
                    // custom strategy names
                    // game seems to read these till null byte so this could totally be abused to buffer overflow...
                    stream.ReadAscii(0x40);
                }

                stream.DiscardBytes(0xA84D0 - 0xA7360);                   // ?
                uint[] monsterBookBitfieldsScanned = stream.ReadUInt32Array(0x48 / 4, endian);
                stream.DiscardBytes(0xA8680 - 0xA8518);                   // ?
                uint[] monsterBookBitfieldsSeen = stream.ReadUInt32Array(0x48 / 4, endian);
                stream.DiscardBytes(0xA8928 - 0xA86C8);                   // ?

                uint collectorsBookIndex = 0;
                foreach (var item in itemDataSorted)
                {
                    uint i = item.Data[(int)ItemDat.ItemData.ID];
                    if (item.Data[(int)ItemDat.ItemData.InCollectorsBook] > 0)
                    {
                        bool haveItem = ((itemBookBitfields[i / 32] >> (int)(i % 32)) & 1) > 0;
                        Console.WriteLine((haveItem ? "Y" : "N") + (collectorsBookIndex) + ": " + inGameDic[item.NamePointer].StringEngOrJpn);
                        ++collectorsBookIndex;
                    }
                }


                uint monsterBookIndex = 0;
                foreach (var enemy in enemies.EnemyList)
                {
                    uint i = enemy.InGameID;
                    if (enemy.InMonsterBook > 0)
                    {
                        bool haveSeen    = ((monsterBookBitfieldsSeen[i / 32] >> (int)(i % 32)) & 1) > 0;
                        bool haveScanned = ((monsterBookBitfieldsScanned[i / 32] >> (int)(i % 32)) & 1) > 0;
                        Console.WriteLine((haveSeen ? "Y" : "N") + (haveScanned ? "Y" : "N") + (monsterBookIndex) + ": " + inGameDic[enemy.NameStringDicID].StringEngOrJpn);
                        ++monsterBookIndex;
                    }
                }
            }
        }
Beispiel #8
0
        public void Add(SHA1 hash, DuplicatableStream stream, bool writeToBackup)
        {
            FileData ofd;

            if (Map.TryGetValue(hash, out ofd))
            {
                using (var newdata = stream.Duplicate())
                    using (var olddata = ofd.Data.Duplicate()) {
                        if (!StreamUtils.IsIdentical(newdata, olddata))
                        {
                            throw new Exception("Storage already contains a different file for the given hash.");
                        }
                    }
                if (writeToBackup)
                {
                    ofd.WriteToBackup = true;
                }
                return;
            }

            FileData fd = new FileData(stream.Duplicate(), writeToBackup);

            Map.Add(hash, fd);
        }
Beispiel #9
0
        public SHBP(DuplicatableStream duplicatableStream, EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian)
        {
            using (DuplicatableStream s = duplicatableStream.Duplicate()) {
                uint magic = s.ReadUInt32(EndianUtils.Endianness.LittleEndian);
                if (magic != 0x50424853)
                {
                    throw new Exception("wrong magic");
                }

                uint count = s.ReadUInt32(e);
                Hashes = new List <uint>((int)count);
                for (uint i = 0; i < count; ++i)
                {
                    Hashes.Add(s.ReadUInt32(e));
                }
            }
        }
Beispiel #10
0
        public static DuplicatableStream Pack(List <SpkdPackFileData> packs, EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian)
        {
            using (MemoryStream ms = new MemoryStream()) {
                ms.WriteUInt32(0x444B5053, EndianUtils.Endianness.LittleEndian);
                ms.WriteUInt32((uint)packs.Count, e);
                ms.WriteUInt32(0, e);
                ms.WriteUInt32(0x20, e);
                ms.WriteAlign(0x20);
                long headerstart = ms.Position;
                for (int i = 0; i < packs.Count; ++i)
                {
                    var p = packs[i];
                    ms.WriteAscii(p.Name, 0x10);
                    ms.WriteUInt32(p.Unknown, e);
                    // file offsets, we'll fill these in later...
                    ms.WriteUInt32(0xffffffffu, e);
                    ms.WriteUInt32(0xffffffffu, e);
                    ms.WriteUInt32(0xffffffffu, e);
                }
                for (int i = 0; i < packs.Count; ++i)
                {
                    var p = packs[i];
                    for (int j = 0; j < 3; ++j)
                    {
                        DuplicatableStream inject = j == 0 ? p.File0 : j == 1 ? p.File1 : p.File2;
                        if (inject != null)
                        {
                            long pos = ms.Position;
                            ms.Position = headerstart + (i * 0x20) + 0x14 + (j * 4);
                            ms.WriteUInt32((uint)pos, e);
                            ms.Position = pos;
                            using (var ds = inject.Duplicate()) {
                                ds.Position = 0;
                                StreamUtils.CopyStream(ds, ms);
                            }
                            ms.WriteAlign(0x10);
                        }
                    }
                }

                return(ms.CopyToByteArrayStreamAndDispose());
            }
        }
Beispiel #11
0
 public Dol(DuplicatableStream stream)
 {
     Stream          = stream.Duplicate();
     Stream.Position = 0;
     FileOffsets     = new List <uint>(18);
     LoadingAddress  = new List <uint>(18);
     SectionSizes    = new List <uint>(18);
     for (int i = 0; i < 18; ++i)
     {
         FileOffsets.Add(Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian));
     }
     for (int i = 0; i < 18; ++i)
     {
         LoadingAddress.Add(Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian));
     }
     for (int i = 0; i < 18; ++i)
     {
         SectionSizes.Add(Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian));
     }
     BssAddress = Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
     BssSize    = Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
     EntryPoint = Stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian);
 }
Beispiel #12
0
        public SPKD(DuplicatableStream duplicatableStream, EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian)
        {
            Stream          = duplicatableStream.Duplicate();
            Stream.Position = 4;
            uint fileCount = Stream.ReadUInt32(e);

            Stream.Position = 12;
            uint dataStart = Stream.ReadUInt32(e);

            Files           = new List <SpkdFileData>((int)fileCount);
            Stream.Position = dataStart;
            for (uint i = 0; i < fileCount; ++i)
            {
                var f = new SpkdFileData();
                f.Name       = Stream.ReadAscii(16).TrimNull();
                f.Unknown    = Stream.ReadUInt32(e);
                f.FileStart0 = Stream.ReadUInt32(e);
                f.FileStart1 = Stream.ReadUInt32(e);
                f.FileStart2 = Stream.ReadUInt32(e);
                Files.Add(f);
            }
            LastFileEnd = (uint)Stream.Length;
        }
Beispiel #13
0
        public static Stream ProcessAreaNameTexture(FileFetcher _fc, string name, DuplicatableStream jstream, DuplicatableStream ustream)
        {
            DuplicatableStream wstream     = _fc.GetFile(name, Version.W);
            FPS4               wani        = new FPS4(wstream.Duplicate());
            FPS4               uani        = new FPS4(new HyoutaTools.Tales.tlzc.TlzcDecompressor().Decompress(ustream.Duplicate()));
            var                clgfileinfo = wani.Files.Where(x => x.FileName.EndsWith(".CLG")).First();
            string             clgname     = clgfileinfo.FileName;
            FPS4               waniclg     = new FPS4(wani.GetChildByName(clgname).AsFile.DataStream);
            FPS4               uaniclg     = new FPS4(uani.GetChildByName(clgname).AsFile.DataStream);
            DuplicatableStream wtexstream  = waniclg.GetChildByIndex(1).AsFile.DataStream;
            DuplicatableStream utexstream  = uaniclg.GetChildByIndex(1).AsFile.DataStream;

            Stream wtexstreammod = ProcessTexture(name + "/" + clgname, utexstream, wtexstream);

            long   injectOffset = clgfileinfo.Location.Value + waniclg.Files[1].Location.Value;
            Stream wstreammod   = wstream.CopyToMemory();

            wstreammod.Position    = injectOffset;
            wtexstreammod.Position = 0;
            StreamUtils.CopyStream(wtexstreammod, wstreammod, wtexstreammod.Length);
            wstreammod.Position = 0;
            return(wstreammod);
        }
Beispiel #14
0
        public iPck(DuplicatableStream duplicatableStream, EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian)
        {
            using (DuplicatableStream s = duplicatableStream.Duplicate()) {
                uint magic = s.ReadUInt32(EndianUtils.Endianness.LittleEndian);
                if (magic != 0x6b635069)
                {
                    throw new Exception("wrong magic");
                }

                uint count        = s.ReadUInt32(e);
                uint offsetsStart = s.ReadUInt32(e);
                uint dataStart    = s.ReadUInt32(e);

                s.Position = offsetsStart;
                uint[] offsets = s.ReadUInt32Array(count, e);

                s.Position = dataStart;
                long dataEnd = s.Length - dataStart;
                Data = new List <byte[]>((int)count);
                for (uint i = 0; i < count; ++i)
                {
                    long start = offsets[i];
                    if (start == 0xffffffffu)
                    {
                        Data.Add(null);
                    }
                    else
                    {
                        long end = FindFileEnd(offsets, i, dataEnd);
                        long len = end - start;
                        s.Position = dataStart + start;
                        Data.Add(s.ReadUInt8Array(len));
                    }
                }
            }
        }
Beispiel #15
0
        public static Stream ProcessTexture(string name, DuplicatableStream ustream, DuplicatableStream wstream)
        {
            FPS4 w    = new FPS4(wstream.Duplicate());
            TXM  wtxm = new TXM(w.GetChildByIndex(0).AsFile.DataStream.Duplicate());
            TXV  wtxv = new TXV(wtxm, w.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false);
            FPS4 u    = new FPS4(ustream.Duplicate());
            TXM  utxm = new TXM(u.GetChildByIndex(0).AsFile.DataStream.Duplicate());
            TXV  utxv = new TXV(utxm, u.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false);
            List <TexConvRules> convs = new List <TexConvRules>();

            if (name == "rootR.cpk/mg/tex/karuta.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 2, UTexId = 1, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 82, 134, 294)
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 4, UTexId = 3, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 86, 134, 294)
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 7, UTexId = 7, Method = TexConvMethod.DownscaleTwoThirds
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 13, UTexId = 13, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKaruta13(wtex, utex)
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 17, UTexId = 17, Method = TexConvMethod.DownscaleTwoThirds
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 22, UTexId = 23, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DownscaleTwoThirds(CropExpandCanvas(utex, 2, -2, (uint)(utex.Width + 3), (uint)(utex.Height - 3)))
                });
            }
            else if (name == "rootR.cpk/mnu/tex/main.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 110, UTexId = 61, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 111, UTexId = 62, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 112, UTexId = 63, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 113, UTexId = 64, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 114, UTexId = 65, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 115, UTexId = 66, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 116, UTexId = 67, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 117, UTexId = 68, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 118, UTexId = 69, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 119, UTexId = 70, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 124, UTexId = 75, Method = TexConvMethod.Downscale2x
                });
            }
            else if (name == "rootR.cpk/mnu/tex/shop.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 6, UTexId = 6, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 7, UTexId = 7, Method = TexConvMethod.Downscale2x
                });
            }
            else if (name == "rootR.cpk/mnu/tex/skill.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 0, UTexId = 0, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x
                });
            }
            else if (name == "rootR.cpk/mnu/tex/snd_test.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x
                });
            }
            else if (name == "rootR.cpk/SysSub/JA/TitleTexture.tex")
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 1, UTexId = 1, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 2, UTexId = 4, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 3, UTexId = 6, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 4, UTexId = 8, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 6, UTexId = 12, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 7, UTexId = 14, Method = TexConvMethod.CropExpandCanvas
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 8, UTexId = 16, Method = TexConvMethod.CropExpandCanvas
                });
            }
            else if (name.EndsWith(".CLG"))
            {
                convs.Add(new TexConvRules()
                {
                    WTexId = 0, UTexId = 0, Method = TexConvMethod.DownscaleTwoThirds
                });
                convs.Add(new TexConvRules()
                {
                    WTexId = 1, UTexId = 1, Method = TexConvMethod.Clear
                });
            }

            MemoryStream s = wstream.Duplicate().CopyToMemory();

            s.Position = 0;
            foreach (TexConvRules c in convs)
            {
                var wm = wtxm.TXMRegulars[c.WTexId];
                var um = utxm.TXMRegulars[c.UTexId];
                var wv = wtxv.textures.Where(x => x.TXM == wm).First();
                var uv = utxv.textures.Where(x => x.TXM == um).First();
                System.Drawing.Bitmap newImage = null;
                switch (c.Method)
                {
                case TexConvMethod.Downscale2x: {
                    newImage = FontProcessing.DownscaleInteger(uv.GetBitmaps()[0], 2);
                }
                break;

                case TexConvMethod.DownscaleTwoThirds: {
                    newImage = DownscaleTwoThirds(uv.GetBitmaps()[0]);
                }
                break;

                case TexConvMethod.CropExpandCanvas: {
                    newImage = DoCropExpandCanvas(uv.GetBitmaps()[0], wm.Width, wm.Height);
                }
                break;

                case TexConvMethod.Clear: {
                    newImage = new Bitmap(wv.GetBitmaps()[0]);
                    for (int y = 0; y < newImage.Height; ++y)
                    {
                        for (int x = 0; x < newImage.Width; ++x)
                        {
                            newImage.SetPixel(x, y, Color.FromArgb(0, 0, 0, 0));
                        }
                    }
                }
                break;

                case TexConvMethod.Delegate: {
                    newImage = c.Delegate(wv.GetBitmaps()[0], uv.GetBitmaps()[0]);
                }
                break;

                default: {
                    throw new Exception("don't know how to convert " + uv.TXM.Name);
                }
                }
                if (newImage != null)
                {
                    HyoutaTools.Util.Assert(newImage.Width == wm.Width);
                    HyoutaTools.Util.Assert(newImage.Height == wm.Height);
                    if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.Indexed8Bits_RGB5A3)
                    {
                        ChopBitsRGB5A3(newImage);
                        var palette = GeneratePalette256(newImage);

                        s.Position = w.Files[1].Location.Value + wm.TxvLocation;
                        foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 8, 4))
                        {
                            int cval = 0;
                            if (loc.X < newImage.Width && loc.Y < newImage.Height)
                            {
                                cval = palette.lookup[newImage.GetPixel(loc.X, loc.Y)];
                            }
                            s.WriteByte((byte)cval);
                        }

                        for (int ci = 0; ci < 256; ++ci)
                        {
                            ushort cval = 0;
                            if (ci < palette.colors.Count)
                            {
                                cval = HyoutaTools.Textures.ColorFetchingIterators.ColorFetcherRGB5A3.ColorToRGB5A3(palette.colors[ci]);
                            }
                            s.WriteUInt16(cval.ToEndian(EndianUtils.Endianness.BigEndian));
                        }
                    }
                    else if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.GamecubeRGBA8)
                    {
                        s.Position = w.Files[1].Location.Value + wm.TxvLocation;
                        byte[] tmpb = new byte[0x40];
                        int    tmpp = 0;
                        foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 4, 4))
                        {
                            Color col = newImage.GetPixel(loc.X, loc.Y);
                            tmpb[tmpp * 2 + 0]        = col.A;
                            tmpb[tmpp * 2 + 1]        = col.R;
                            tmpb[tmpp * 2 + 0 + 0x20] = col.G;
                            tmpb[tmpp * 2 + 1 + 0x20] = col.B;
                            ++tmpp;
                            if (tmpp == 16)
                            {
                                tmpp = 0;
                                s.Write(tmpb);
                            }
                        }
                        if (tmpp != 0)
                        {
                            throw new Exception("Unexpected tile size for " + wm.Name);
                        }
                    }
                    else
                    {
                        Console.WriteLine("don't know how to encode into " + wm.Format);
                    }
                }
            }

            s.Position = 0;
            return(s);
        }
Beispiel #16
0
 public SaveDataBlockSavePoint(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
Beispiel #17
0
        public void PrintData()
        {
            // save point flags, one byte each, 0x00 not visted 0x01 visited
            byte[] savePointFlags;
            using (DuplicatableStream stream = Stream.Duplicate()) {
                savePointFlags = stream.ReadUInt8Array(0x59);
            }

            PrintSavePoint(savePointFlags, 0x00, "Fiertia Deck (Docked at Atherum)");
            PrintSavePoint(savePointFlags, 0x01, "Atherum");
            PrintSavePoint(savePointFlags, 0x02, "Fiertia Hold");               // same flag for both opportunities?
            PrintSavePoint(savePointFlags, 0x03, "Keiv Moc (Middle)");
            PrintSavePoint(savePointFlags, 0x04, "Keiv Moc (Boss)");
            PrintSavePoint(savePointFlags, 0x05, "Zaphias (Lower Quarter)");
            PrintSavePoint(savePointFlags, 0x06, "Zaphias (Royal Quarter)");
            PrintSavePoint(savePointFlags, 0x07, "Zaphias Castle (Prison)");
            PrintSavePoint(savePointFlags, 0x08, "Zaphias Castle (Kitchen)");               // 2nd visit only
            PrintSavePoint(savePointFlags, 0x09, "Zaphias Castle (Hallways)");              // before zagi fight
            PrintSavePoint(savePointFlags, 0x0A, "Zaphias Castle (Sword Stair)");
            PrintSavePoint(savePointFlags, 0x0B, "Zaphias Castle (Big Hall)");              // 2nd visit only, that big room that leads to the sword stair
            PrintSavePoint(savePointFlags, 0x0C, "Weasand of Cados (Middle)");
            PrintSavePoint(savePointFlags, 0x0D, "Weasand of Cados (Exit)");
            PrintSavePoint(savePointFlags, 0x0E, "Halure (Inn)");
            PrintSavePoint(savePointFlags, 0x0F, "Ghasfarost (Bottom)");
            PrintSavePoint(savePointFlags, 0x10, "Ghasfarost (Top)");
            PrintSavePoint(savePointFlags, 0x11, "Myorzo (Vacant House)");
            PrintSavePoint(savePointFlags, 0x12, "Mt. Temza (Middle)");
            PrintSavePoint(savePointFlags, 0x13, "Mt. Temza (Boss)");
            PrintSavePoint(savePointFlags, 0x14, "Deidon Hold");
            PrintSavePoint(savePointFlags, 0x15, "Northeastern Hypionia");               // aurnion before it's built
            PrintSavePoint(savePointFlags, 0x16, "Aurnion (Developing)");
            PrintSavePoint(savePointFlags, 0x17, "Aurnion (Developed)");
            PrintSavePoint(savePointFlags, 0x18, "Caer Bocram");
            PrintSavePoint(savePointFlags, 0x19, "Quoi Woods");
            PrintSavePoint(savePointFlags, 0x1A, "Dahngrest (Inn)");
            PrintSavePoint(savePointFlags, 0x1B, "Ehmead Hill");
            PrintSavePoint(savePointFlags, 0x1C, "Erealumen (Middle)");
            PrintSavePoint(savePointFlags, 0x1D, "Erealumen (Boss)");
            PrintSavePoint(savePointFlags, 0x1E, "Heracles (Near Engine Room)");
            PrintSavePoint(savePointFlags, 0x1F, "Heracles (Near Control Room)"); // zagi fight
            PrintSavePoint(savePointFlags, 0x20, "Zopheir (Boss)");               // 1st visit only
            PrintSavePoint(savePointFlags, 0x21, "Zopheir (Near Aer Krene)");     // 2nd visit only
            PrintSavePoint(savePointFlags, 0x22, "Manor of the Wicked");
            PrintSavePoint(savePointFlags, 0x23, "Tarqaron (Middle)");
            PrintSavePoint(savePointFlags, 0x24, "Tarqaron (Top)");
            PrintSavePoint(savePointFlags, 0x25, "Baction B1F");
            PrintSavePoint(savePointFlags, 0x26, "Baction B2F");               // both save points on B2F share this flag...?
            PrintSavePoint(savePointFlags, 0x27, "Mantaic (Inn)");
            PrintSavePoint(savePointFlags, 0x28, "Relewiese (Middle)");
            PrintSavePoint(savePointFlags, 0x29, "Relewiese (Boss)");
            PrintSavePoint(savePointFlags, 0x2A, "Capua Nor (Outside Ragou's Mansion)");
            PrintSavePoint(savePointFlags, 0x2B, "Capua Nor (Inn)");
            PrintSavePoint(savePointFlags, 0x2C, "Capua Torim (Inn)");
            PrintSavePoint(savePointFlags, 0x2D, "Shaikos Ruins");
            PrintSavePoint(savePointFlags, 0x2E, "Zaude (Side Entrance)");
            PrintSavePoint(savePointFlags, 0x2F, "Zaude (Alexei)");
            PrintSavePoint(savePointFlags, 0x30, "Zaude (Yeager)");
            PrintSavePoint(savePointFlags, 0x31, "Aspio (Inn)");
            PrintSavePoint(savePointFlags, 0x32, "Nordopolica (Inn)");
            PrintSavePoint(savePointFlags, 0x33, "Heliord (Inn)");
            PrintSavePoint(savePointFlags, 0x34, "Yormgen (Inn)");
            PrintSavePoint(savePointFlags, 0x35, "Weasand of Kogorh (Oasis)");
            PrintSavePoint(savePointFlags, 0x36, "Weasand of Kogorh (Exit)");
            PrintSavePoint(savePointFlags, 0x37, "Egothor Forest");
            PrintSavePoint(savePointFlags, 0x38, "Dahngrest Underpass (Oath)");
            PrintSavePoint(savePointFlags, 0x39, "Ragou's Mansion");               // basement dungeon midpoint
            PrintSavePoint(savePointFlags, 0x3A, "Dahngrest Underpass (Exit)");
            PrintSavePoint(savePointFlags, 0x3B, "Abysmal Hollow (Aer Krene near Yumanju)");
            PrintSavePoint(savePointFlags, 0x3C, "? Abysmal Hollow (Aer Krene near Zaphias)");
            PrintSavePoint(savePointFlags, 0x3D, "Abysmal Hollow (Aer Krene near Heliord)");
            PrintSavePoint(savePointFlags, 0x3E, "Abysmal Hollow (Aer Krene near Nordopolica)");
            PrintSavePoint(savePointFlags, 0x3F, "? Abysmal Hollow (Center)");
            PrintSavePoint(savePointFlags, 0x40, "City of the Waning Moon");
            PrintSavePoint(savePointFlags, 0x41, "Necropolis of Nostalgia A3");
            PrintSavePoint(savePointFlags, 0x42, "Necropolis of Nostalgia A6");
            PrintSavePoint(savePointFlags, 0x43, "Necropolis of Nostalgia A9");
            PrintSavePoint(savePointFlags, 0x44, "Necropolis of Nostalgia A Bottom");
            PrintSavePoint(savePointFlags, 0x45, "Necropolis of Nostalgia B2");
            PrintSavePoint(savePointFlags, 0x46, "Necropolis of Nostalgia B5");
            PrintSavePoint(savePointFlags, 0x47, "Necropolis of Nostalgia B8");
            PrintSavePoint(savePointFlags, 0x48, "Necropolis of Nostalgia B Bottom");
            PrintSavePoint(savePointFlags, 0x49, "Necropolis of Nostalgia C3");
            PrintSavePoint(savePointFlags, 0x4A, "Necropolis of Nostalgia C6");
            PrintSavePoint(savePointFlags, 0x4B, "Necropolis of Nostalgia C9");
            PrintSavePoint(savePointFlags, 0x4C, "Necropolis of Nostalgia C Bottom");
            PrintSavePoint(savePointFlags, 0x4D, "Necropolis of Nostalgia D3");
            PrintSavePoint(savePointFlags, 0x4E, "Necropolis of Nostalgia D6");
            PrintSavePoint(savePointFlags, 0x4F, "Necropolis of Nostalgia D9");
            PrintSavePoint(savePointFlags, 0x50, "Necropolis of Nostalgia D Bottom");
            PrintSavePoint(savePointFlags, 0x51, "Necropolis of Nostalgia E3");
            PrintSavePoint(savePointFlags, 0x52, "Necropolis of Nostalgia E6");
            PrintSavePoint(savePointFlags, 0x53, "Necropolis of Nostalgia E9");
            PrintSavePoint(savePointFlags, 0x54, "Necropolis of Nostalgia E Bottom");
            PrintSavePoint(savePointFlags, 0x55, "Necropolis of Nostalgia F3");
            PrintSavePoint(savePointFlags, 0x56, "Necropolis of Nostalgia F6");
            PrintSavePoint(savePointFlags, 0x57, "Necropolis of Nostalgia F9");
            PrintSavePoint(savePointFlags, 0x58, "Necropolis of Nostalgia F Bottom");
        }
Beispiel #18
0
        public static (DuplicatableStream metrics, DuplicatableStream texture, Dictionary <char, (int w1, int w2)> charToWidthMap) Run(FileFetcher _fc, Config config)
        {
            bool debug         = config.DebugFontOutputPath != null;
            bool adjustMetrics = debug;

            DuplicatableStream metricsWiiStream = _fc.GetFile("rootR.cpk/sys/FontBinary2.bin", Version.W);
            DuplicatableStream textureWiiStream = _fc.GetFile("rootR.cpk/sys/FontTexture2.tex", Version.W);
            DuplicatableStream texturePs3Stream = _fc.GetFile("rootR.cpk/sys/FontTexture2.tex", Version.U);
            FPS4 metricsWiiFps4 = new FPS4(metricsWiiStream);
            DuplicatableStream metricsWiiData = metricsWiiFps4.GetChildByIndex(1).AsFile.DataStream;
            FPS4   textureWiiFps4             = new FPS4(textureWiiStream);
            FPS4   texturePs3Fps4             = new FPS4(texturePs3Stream);
            TXM    textureWiiTxm = new TXM(textureWiiFps4.GetChildByIndex(0).AsFile.DataStream);
            TXV    textureWiiTxv = new TXV(textureWiiTxm, textureWiiFps4.GetChildByIndex(1).AsFile.DataStream, false);
            TXM    texturePs3Txm = new TXM(texturePs3Fps4.GetChildByIndex(0).AsFile.DataStream);
            TXV    texturePs3Txv = new TXV(texturePs3Txm, texturePs3Fps4.GetChildByIndex(1).AsFile.DataStream, false);
            Bitmap bitmapWii     = textureWiiTxv.textures[0].GetBitmaps()[0];
            Bitmap bitmapPs3     = texturePs3Txv.textures[0].GetBitmaps()[0];

            if (debug)
            {
                Directory.CreateDirectory(config.DebugFontOutputPath);
                bitmapWii.Save(Path.Combine(config.DebugFontOutputPath, "wii.png"));
                bitmapPs3.Save(Path.Combine(config.DebugFontOutputPath, "ps3.png"));
            }

            var       img_wii = bitmapWii;
            var       img_ps3 = bitmapPs3;
            const int tile_extent_in_image = 25;
            const int tile_extent_actual   = 24;
            int       tiles_x = (img_wii.Width + 1) / tile_extent_in_image;
            int       tiles_y = (img_wii.Height + 1) / tile_extent_in_image;
            const int ps3_tile_extent_in_image = 37;
            const int ps3_tile_extent_actual   = 36;
            int       ps3_tiles_x = (img_ps3.Width + 1) / ps3_tile_extent_in_image;
            int       ps3_tiles_y = (img_ps3.Height + 1) / ps3_tile_extent_in_image;

            // split into individual tiles and extract source colors
            HashSet <Color> colors    = new HashSet <Color>();
            List <Bitmap>   tiles_wii = new List <Bitmap>();
            List <Bitmap>   tiles_ps3 = new List <Bitmap>();

            for (int ty = 0; ty < tiles_y; ++ty)
            {
                for (int tx = 0; tx < tiles_x; ++tx)
                {
                    var bmp = new Bitmap(tile_extent_actual, tile_extent_actual);
                    for (int y = 0; y < tile_extent_actual; ++y)
                    {
                        for (int x = 0; x < tile_extent_actual; ++x)
                        {
                            var px = img_wii.GetPixel(tx * tile_extent_in_image + x, ty * tile_extent_in_image + y);
                            colors.Add(px);
                            bmp.SetPixel(x, y, px);
                        }
                    }
                    tiles_wii.Add(bmp);
                }
            }
            for (int ty = 0; ty < ps3_tiles_y; ++ty)
            {
                for (int tx = 0; tx < ps3_tiles_x; ++tx)
                {
                    var bmp = new Bitmap(ps3_tile_extent_actual, ps3_tile_extent_actual);
                    for (int y = 0; y < ps3_tile_extent_actual; ++y)
                    {
                        for (int x = 0; x < ps3_tile_extent_actual; ++x)
                        {
                            var px = img_ps3.GetPixel(tx * ps3_tile_extent_in_image + x, ty * ps3_tile_extent_in_image + y);
                            bmp.SetPixel(x, y, px);
                        }
                    }
                    tiles_ps3.Add(bmp);
                }
            }

            // inject ps3 tiles over wii tiles
            List <(int where, int ps3where, string chars)> charsets = new List <(int where, int ps3where, string chars)>();

            charsets.Add((0, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
            charsets.Add((243, 74, ",."));
            charsets.Add((246, 77, ":;?!_"));
            charsets.Add((254, 83, "/\\~|…"));
            charsets.Add((260, 118, "‘"));
            charsets.Add((261, 118, "’"));
            charsets.Add((262, 119, "“"));
            charsets.Add((263, 119, "”"));
            charsets.Add((264, 93, "()[]{}"));
            charsets.Add((276, 105, "+"));
            charsets.Add((277, 82, "-"));             // copy the dash minus instead of the math minus, looks better in text flow
            charsets.Add((278, 107, "±×÷=≠<>≤≥"));
            charsets.Add((289, 118, "'\""));
            charsets.Add((293, 122, "$%#&*@"));

            Dictionary <char, (int w1, int w2)> charToWidthMap = new Dictionary <char, (int w1, int w2)>();

            byte[] metrics = new byte[metricsWiiData.Length];
            metricsWiiData.Read(metrics, 0, metrics.Length);

            foreach (var charset in charsets)
            {
                int where = charset.where;
                int ps3where = charset.ps3where;
                foreach (char ch in charset.chars)
                {
                    var wiitile       = tiles_wii[where];
                    var averagescaled = DownscaleTileFromPs3ToWiiWithUnweightedAverageScaling(tiles_ps3[ps3where]);
                    //var downscaled = DownscaleTileFromPs3ToWiiWithWeightedScaling(tiles_ps3[ps3where]);
                    var downscaled = averagescaled;
                    PosterizeImage(wiitile, downscaled, colors, tile_extent_actual);
                    PosterizeImage(averagescaled, averagescaled, colors, tile_extent_actual);
                    if (debug)
                    {
                        wiitile.Save(Path.Combine(config.DebugFontOutputPath, string.Format("wii_new_{0:D4}.png", where)));
                    }

                    int cutoff_1    = 180;
                    int cutoff_2    = 220;
                    int leftwhere   = where * 8 + 0;
                    int rightwhere  = where * 8 + 1;
                    int leftwhere2  = where * 8 + 4;
                    int rightwhere2 = where * 8 + 5;

                    // forcing vertical extents to be the same for all, because text looks *really weird* in english if lines have different heights
                    // for digits, forcing horizontal extents to be the same as well so they look nice in vertical lists
                    bool isDigit = ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' || ch == '9';
                    if (isDigit)
                    {
                        metrics[leftwhere]  = ch == '1' ? (byte)(6) : ch == '2' ? (byte)(6) : (byte)(7);
                        metrics[rightwhere] = ch == '1' ? (byte)(8) : ch == '2' ? (byte)(8) : (byte)(7);
                        //metrics[leftwhere2] = ch == '1' ? (byte)(7) : ch == '2' ? (byte)(7) : (byte)(8);
                        //metrics[rightwhere2] = ch == '1' ? (byte)(9) : ch == '2' ? (byte)(9) : (byte)(8);
                    }
                    else
                    {
                        metrics[leftwhere]  = (byte)MeasureAlphaFromLeft(averagescaled, cutoff_1);
                        metrics[rightwhere] = (byte)MeasureAlphaFromRight(averagescaled, cutoff_1);
                        //metrics[leftwhere2] = (byte)MeasureAlphaFromLeft(averagescaled, cutoff_2);
                        //metrics[rightwhere2] = (byte)MeasureAlphaFromRight(averagescaled, cutoff_2);
                    }

                    switch (ch)
                    {
                    case 'j':
                    case ';':
                        metrics[leftwhere] += 1;
                        break;

                    case 'A':
                    case 'P':
                    case 'Q':
                    case 'T':
                    case 'Y':
                    case 'W':
                    case 'f':
                    case 's':
                    case 'w':
                    case 'y':
                    case '[':
                        metrics[rightwhere] += 1;
                        break;

                    case 't':
                        metrics[leftwhere]  += 1;
                        metrics[rightwhere] += 1;
                        break;

                    default:
                        break;
                    }

                    metrics[leftwhere2]  = metrics[leftwhere];
                    metrics[rightwhere2] = metrics[rightwhere];

                    switch (ch)
                    {
                    case '.':
                    case ',':
                        metrics[leftwhere2] += 1;
                        metrics[rightwhere] += 1;
                        break;

                    default:
                        break;
                    }

                    metrics[where * 8 + 2] = 0;                     //(byte)MeasureAlphaFromTop(test, cutoff_1);
                    metrics[where * 8 + 3] = 4;                     //(byte)MeasureAlphaFromBottom(test, cutoff_1);
                    metrics[where * 8 + 6] = 0;                     //(byte)MeasureAlphaFromTop(test, cutoff_2);
                    metrics[where * 8 + 7] = 4;                     //(byte)MeasureAlphaFromBottom(test, cutoff_2);

                    int width1 = tile_extent_actual - (metrics[leftwhere] + metrics[rightwhere]);
                    int width2 = tile_extent_actual - (metrics[leftwhere2] + metrics[rightwhere2]);
                    charToWidthMap.Add(ch, (width1, width2));

                    ++where;
                    ++ps3where;
                }
            }

            // manually generate good metrics for space; see also code patches in main.dol
            metrics[0x6F70] = 10;
            metrics[0x6F71] = 10;
            metrics[0x6F72] = 0;
            metrics[0x6F73] = 4;
            metrics[0x6F74] = 10;
            metrics[0x6F75] = 10;
            metrics[0x6F76] = 0;
            metrics[0x6F77] = 4;
            charToWidthMap.Add(' ', (tile_extent_actual - 20, tile_extent_actual - 20));

            // write out visual representation of font metrics for adjustments
            if (adjustMetrics)
            {
                foreach (var charset in charsets)
                {
                    int where = charset.where;
                    foreach (char ch in charset.chars)
                    {
                        int factor = 10;
                        var test   = PointScale(tiles_wii[where], factor);

                        for (int metricsset = 0; metricsset < 2; ++metricsset)
                        {
                            Color col = metricsset == 0 ? Color.Red : Color.Yellow;
                            int   xl  = (metrics[where * 8 + metricsset * 4] - 1) * factor + factor - 1;
                            int   xr  = (tiles_wii[where].Width - metrics[where * 8 + metricsset * 4 + 1]) * factor;
                            int   yt  = (metrics[where * 8 + metricsset * 4 + 2] - 1) * factor + factor - 1;
                            int   yb  = (tiles_wii[where].Width - metrics[where * 8 + metricsset * 4 + 3]) * factor;
                            for (int y = 0; y < test.Height; ++y)
                            {
                                if (xl >= 0 && xl < test.Width)
                                {
                                    test.SetPixel(xl, y, col);
                                }
                                if (xr >= 0 && xr < test.Width)
                                {
                                    test.SetPixel(xr, y, col);
                                }
                            }
                            for (int x = 0; x < test.Width; ++x)
                            {
                                if (yt >= 0 && yt < test.Height)
                                {
                                    test.SetPixel(x, yt, col);
                                }
                                if (yb >= 0 && yb < test.Height)
                                {
                                    test.SetPixel(x, yb, col);
                                }
                            }
                        }

                        PointScale(test, 3).Save(Path.Combine(config.DebugFontOutputPath, string.Format("metrics_view_{0:D4}.png", where)));

                        ++where;
                    }
                }
            }

            // join indvidiual tiles back into full texture
            int idx = 0;

            for (int ty = 0; ty < tiles_y; ++ty)
            {
                for (int tx = 0; tx < tiles_x; ++tx)
                {
                    var bmp = tiles_wii[idx];
                    for (int y = 0; y < tile_extent_actual; ++y)
                    {
                        for (int x = 0; x < tile_extent_actual; ++x)
                        {
                            var px = bmp.GetPixel(x, y);
                            img_wii.SetPixel(tx * tile_extent_in_image + x, ty * tile_extent_in_image + y, px);
                        }
                    }
                    ++idx;
                }
            }

            if (debug)
            {
                img_wii.Save(Path.Combine(config.DebugFontOutputPath, "wii_new.png"));
            }

            // inject metrics
            DuplicatableStream outputMetricsStream;
            {
                Stream stream = metricsWiiStream.Duplicate().CopyToMemory();
                stream.Position = 0x43E0;
                stream.Write(metrics);

                stream.Position = 0;
                byte[] data = new byte[stream.Length];
                stream.Read(data, 0, data.Length);
                outputMetricsStream = new HyoutaUtils.Streams.DuplicatableByteArrayStream(data);
            }

            // encode texture
            DuplicatableStream outputTextureStream;

            {
                Stream stream = textureWiiStream.Duplicate().CopyToMemory();
                stream.Position = 0x80100;
                List <(int idx, ushort v)> stuff = new List <(int idx, ushort v)>();
                for (int i = 0; i < 16; ++i)
                {
                    stuff.Add((i, stream.ReadUInt16().FromEndian(EndianUtils.Endianness.BigEndian)));
                }

                stream.Position = 0x100;
                var  pxit    = new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(img_wii.Width, img_wii.Height, 8, 8);
                byte storage = 0;
                bool even    = false;
                foreach (var px in pxit)
                {
                    if (px.X < img_wii.Width && px.Y < img_wii.Height)
                    {
                        Color  col    = img_wii.GetPixel(px.X, px.Y);
                        ushort value  = HyoutaTools.Textures.ColorFetchingIterators.ColorFetcherGrey8Alpha8.ColorToGrey8Alpha8(col);
                        var    colidx = stuff.First(x => x.v == value).idx;
                        if (!even)
                        {
                            storage = (byte)colidx;
                        }
                        else
                        {
                            storage = (byte)(storage << 4 | (byte)colidx);
                            stream.WriteByte(storage);
                        }
                        even = !even;
                    }
                }

                stream.Position = 0;
                byte[] data = new byte[stream.Length];
                stream.Read(data, 0, data.Length);
                outputTextureStream = new HyoutaUtils.Streams.DuplicatableByteArrayStream(data);
            }

            return(outputMetricsStream, outputTextureStream, charToWidthMap);
        }
Beispiel #19
0
        private static Stream RebuildNubStream(DuplicatableStream wstream, string nubdir, string nubtype, GetFilenameDelegate getFilenameDelegate)
        {
            MemoryStream outstream = new MemoryStream();

            EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian;
            using (var stream = wstream.Duplicate()) {
                stream.Position = 0;
                var header = new HyoutaTools.Tales.Vesperia.NUB.NubHeader(stream, e);
                stream.Position = 0;
                StreamUtils.CopyStream(stream, outstream, header.StartOfFiles);
                stream.Position = header.StartOfEntries;
                uint[] entries = stream.ReadUInt32Array(header.EntryCount, e);
                for (long i = 0; i < entries.LongLength; ++i)
                {
                    uint entryLoc = entries[i];
                    if (nubtype == "bnsf")
                    {
                        using (var bnsfstream = new DuplicatableFileStream(Path.Combine(nubdir, getFilenameDelegate(i) + ".rawbnsf")))
                            using (var samplecountstream = new DuplicatableFileStream(Path.Combine(nubdir, getFilenameDelegate(i) + ".samplecount"))) {
                                // write file to outstream
                                long filestart = outstream.Position;
                                StreamUtils.CopyStream(bnsfstream, outstream, bnsfstream.Length);
                                outstream.WriteAlign(0x10);
                                long fileend = outstream.Position;
                                long filelen = fileend - filestart;

                                // update headers
                                outstream.Position = entryLoc + 0xbc + 0x4;
                                outstream.WriteUInt32((uint)(bnsfstream.Length + 0x28), e);
                                outstream.Position = entryLoc + 0xbc + 0x1c;
                                outstream.WriteUInt32((uint)(samplecountstream.ReadUInt64(EndianUtils.Endianness.LittleEndian)), e);
                                outstream.Position = entryLoc + 0xbc + 0x2c;
                                outstream.WriteUInt32((uint)(bnsfstream.Length), e);

                                outstream.Position = entryLoc + 0x14;
                                outstream.WriteUInt32((uint)filelen, e);
                                outstream.WriteUInt32((uint)(filestart - header.StartOfFiles), e);

                                outstream.Position = fileend;
                            }
                    }
                    else if (nubtype == "dsp")
                    {
                        using (var fs = new DuplicatableFileStream(Path.Combine(nubdir, getFilenameDelegate(i) + ".dsp"))) {
                            byte[] dspheader = fs.ReadUInt8Array(0x60);

                            // write file to outstream
                            long filestart = outstream.Position;
                            StreamUtils.CopyStream(fs, outstream, fs.Length - 0x60);
                            outstream.WriteAlign(0x10);
                            long fileend = outstream.Position;
                            long filelen = fileend - filestart;

                            // update headers
                            outstream.Position = entryLoc + 0xbc;
                            outstream.Write(dspheader);
                            outstream.Position = entryLoc + 0x14;
                            outstream.WriteUInt32((uint)filelen, e);
                            outstream.WriteUInt32((uint)(filestart - header.StartOfFiles), e);

                            outstream.Position = fileend;
                        }
                    }
                }

                long filesSize = outstream.Position - header.StartOfFiles;
                outstream.Position = 0x14;
                outstream.WriteUInt32((uint)filesSize, e);

                outstream.Position = 0;
                return(outstream);
            }
        }
Beispiel #20
0
        public HyoutaArchiveChunk(DuplicatableStream duplicatableStream, out ulong chunkLength)
        {
            using (DuplicatableStream data = duplicatableStream.Duplicate()) {
                data.Position = 0;

                // header
                ulong extraMagic = data.ReadUInt64(EndianUtils.Endianness.LittleEndian);
                ulong magic      = extraMagic & 0x00fffffffffffffful;
                if (magic != 0x6b6e7568636168)
                {
                    throw new Exception("wrong magic");
                }
                byte extra                  = (byte)((extraMagic >> 56) & 0xffu);
                byte packedAlignment        = (byte)(extra & 0x1fu);
                long unpackedAlignment      = 1L << packedAlignment;
                bool hasMetadata            = (extra & 0x20) != 0;
                bool isCompressed           = (extra & 0x40) != 0;
                bool isBigEndian            = (extra & 0x80) != 0;
                EndianUtils.Endianness e    = isBigEndian ? EndianUtils.Endianness.BigEndian : EndianUtils.Endianness.LittleEndian;
                ulong endOfFileOffset       = data.ReadUInt64(e) << packedAlignment;
                ulong tableOfContentsOffset = data.ReadUInt64(e) << packedAlignment;
                ulong filecount             = data.ReadUInt64(e);
                chunkLength = endOfFileOffset;

                if (hasMetadata)
                {
                    // just skip past this for now
                    ulong metadataLength = data.ReadUInt64(e);
                    data.DiscardBytes(metadataLength);
                }

                DuplicatableStream dataBlockStream;
                if (isCompressed)
                {
                    ushort compressionInfoLengthRaw       = data.ReadUInt16(e);
                    uint   compressionInfoLength          = compressionInfoLengthRaw & 0xfffcu;
                    int    compressionInfoAlignmentPacked = (compressionInfoLengthRaw & 0x3) + 1;
                    data.ReadAlign(1u << compressionInfoAlignmentPacked);
                    Compression.IHyoutaArchiveCompressionInfo?compressionInfo = HyoutaArchiveCompression.Deserialize(data, compressionInfoLength == 0 ? 0x10000u : compressionInfoLength, e);
                    if (compressionInfo == null)
                    {
                        throw new Exception("File is indicated to be compressed, but no decompressor found.");
                    }
                    dataBlockStream = compressionInfo.Decompress(data);
                }
                else
                {
                    data.ReadAlign(unpackedAlignment);
                    dataBlockStream = new PartialStream(data, data.Position, (long)(endOfFileOffset - (ulong)data.Position));
                }

                try {
                    data.Dispose();

                    dataBlockStream.Position = (long)tableOfContentsOffset;
                    uint offsetToFirstFileInfo = ReadContentLength(dataBlockStream, e);

                    // decode content bitfield(s)
                    long   numberOfUnknownBits = 0;
                    ushort contentBitfield1    = dataBlockStream.ReadUInt16(e);
                    bool   hasDummyContent     = (contentBitfield1 & 0x0001u) != 0;
                    bool   hasFilename         = (contentBitfield1 & 0x0002u) != 0;
                    bool   hasCompression      = (contentBitfield1 & 0x0004u) != 0;
                    bool   hasBpsPatch         = (contentBitfield1 & 0x0008u) != 0;
                    bool   hasCrc32            = (contentBitfield1 & 0x0010u) != 0;
                    bool   hasMd5  = (contentBitfield1 & 0x0020u) != 0;
                    bool   hasSha1 = (contentBitfield1 & 0x0040u) != 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x0080u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x0100u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x0200u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x0400u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x0800u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x1000u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x2000u) != 0 ? 1 : 0;
                    numberOfUnknownBits += (contentBitfield1 & 0x4000u) != 0 ? 1 : 0;
                    ushort currentBitfield = contentBitfield1;
                    while ((currentBitfield & 0x8000u) != 0)
                    {
                        // more bitfields, though we don't understand them since only the first handful of bits are defined at the moment, so just count and skip them
                        currentBitfield      = dataBlockStream.ReadUInt16(e);
                        numberOfUnknownBits += (currentBitfield & 0x0001u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0002u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0004u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0008u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0010u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0020u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0040u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0080u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0100u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0200u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0400u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x0800u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x1000u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x2000u) != 0 ? 1 : 0;
                        numberOfUnknownBits += (currentBitfield & 0x4000u) != 0 ? 1 : 0;
                    }
                    uint dummyContentLength   = hasDummyContent ? ReadContentLength(dataBlockStream, e) : 0;
                    uint filenameLength       = hasFilename ? ReadContentLength(dataBlockStream, e) : 0;
                    uint compressionLength    = hasCompression ? ReadContentLength(dataBlockStream, e) : 0;
                    uint bpspatchLength       = hasBpsPatch ? ReadContentLength(dataBlockStream, e) : 0;
                    uint crc32Length          = hasCrc32 ? ReadContentLength(dataBlockStream, e) : 0;
                    uint md5Length            = hasMd5 ? ReadContentLength(dataBlockStream, e) : 0;
                    uint sha1Length           = hasSha1 ? ReadContentLength(dataBlockStream, e) : 0;
                    long unknownContentLength = 0;
                    for (long i = 0; i < numberOfUnknownBits; ++i)
                    {
                        unknownContentLength += ReadContentLength(dataBlockStream, e);
                    }

                    dataBlockStream.Position = (long)(tableOfContentsOffset + offsetToFirstFileInfo);
                    List <HyoutaArchiveFileInfo> files = new List <HyoutaArchiveFileInfo>((int)filecount);
                    for (ulong i = 0; i < filecount; ++i)
                    {
                        ulong offset             = dataBlockStream.ReadUInt64(e) << packedAlignment;
                        ulong filesize           = dataBlockStream.ReadUInt64(e);
                        HyoutaArchiveFileInfo fi = new HyoutaArchiveFileInfo();
                        if (hasDummyContent)
                        {
                            fi.DummyContent = dataBlockStream.ReadBytes(dummyContentLength);
                        }
                        if (hasFilename)
                        {
                            fi.Filename = ReadString(dataBlockStream, filenameLength, e);
                        }
                        if (hasCompression)
                        {
                            fi.CompressionInfo    = HyoutaArchiveCompression.Deserialize(dataBlockStream, compressionLength, e);
                            fi.StreamIsCompressed = true;
                        }
                        if (hasBpsPatch)
                        {
                            fi.BpsPatchInfo     = HyoutaArchiveBpsPatchInfo.Deserialize(dataBlockStream, bpspatchLength, e, i, this);
                            fi.StreamIsBpsPatch = fi.BpsPatchInfo != null;
                        }
                        if (hasCrc32)
                        {
                            if (crc32Length >= 4)
                            {
                                fi.crc32 = new CRC32(dataBlockStream.ReadUInt32(EndianUtils.Endianness.BigEndian));
                                dataBlockStream.DiscardBytes(crc32Length - 4);
                            }
                            else
                            {
                                dataBlockStream.DiscardBytes(crc32Length);
                            }
                        }
                        if (hasMd5)
                        {
                            if (md5Length >= 16)
                            {
                                ulong a = dataBlockStream.ReadUInt64(EndianUtils.Endianness.BigEndian);
                                ulong b = dataBlockStream.ReadUInt64(EndianUtils.Endianness.BigEndian);
                                fi.md5 = new MD5(a, b);
                                dataBlockStream.DiscardBytes(md5Length - 16);
                            }
                            else
                            {
                                dataBlockStream.DiscardBytes(md5Length);
                            }
                        }
                        if (hasSha1)
                        {
                            if (sha1Length >= 20)
                            {
                                ulong a = dataBlockStream.ReadUInt64(EndianUtils.Endianness.BigEndian);
                                ulong b = dataBlockStream.ReadUInt64(EndianUtils.Endianness.BigEndian);
                                uint  c = dataBlockStream.ReadUInt32(EndianUtils.Endianness.BigEndian);
                                fi.sha1 = new SHA1(a, b, c);
                                dataBlockStream.DiscardBytes(sha1Length - 20);
                            }
                            else
                            {
                                dataBlockStream.DiscardBytes(sha1Length);
                            }
                        }
                        dataBlockStream.DiscardBytes(unknownContentLength);

                        fi.Data = new PartialStream(dataBlockStream, (long)offset, (long)filesize);
                        files.Add(fi);
                    }

                    Files = files;
                } finally {
                    dataBlockStream.Dispose();
                }
            }
        }
Beispiel #21
0
        internal static Stream InjectEnglishContainedVoice(Config config, FileFetcher _fc, string name, DuplicatableStream wstream, DuplicatableStream jstream, DuplicatableStream ustream, ContainedVoiceInfo cvi, SkitTexCache skitTexCache)
        {
            var fps4         = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(wstream.Duplicate());
            var se3stream    = fps4.GetChildByIndex(cvi.SE3Index).AsFile.DataStream;
            var se3          = new HyoutaTools.Tales.Vesperia.SE3.SE3(se3stream.Duplicate(), EndianUtils.Endianness.BigEndian, TextUtils.GameTextEncoding.ASCII);
            var se3ms        = se3.ExtractSe3HeaderStream();
            var nubms        = se3.ExtractNubStream();
            var nubstream    = new DuplicatableByteArrayStream(nubms.CopyToByteArrayAndDispose());
            var newnubstream = RebuildNubStream(nubstream, Path.Combine(config.EnglishVoiceProcessingDir, "other"), cvi.WiiType, x => Path.GetFileNameWithoutExtension(name));
            var newse3stream = new MemoryStream();

            se3ms.Position        = 0;
            newnubstream.Position = 0;
            StreamUtils.CopyStream(se3ms, newse3stream);
            StreamUtils.CopyStream(newnubstream, newse3stream);

            if (cvi.IsSkit)
            {
                using (var texIdStream = fps4.GetChildByIndex(3).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()) {
                    int    idx    = 4;
                    uint[] texIds = texIdStream.ReadUInt32Array(texIdStream.Length / 4, EndianUtils.Endianness.BigEndian);
                    foreach (uint texId in texIds)
                    {
                        skitTexCache.AddTextureIfNotExists(texId, fps4.GetChildByIndex(idx).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose());
                        ++idx;
                    }
                }
            }

            newse3stream.Position = 0;
            MemoryStream newfps4stream = new MemoryStream();

            using (var ufps4 = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(ustream.Duplicate())) {
                uint[] utexIds = null;
                if (cvi.IsSkit)
                {
                    using (var texIdStream = ufps4.GetChildByIndex(3).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()) {
                        utexIds = texIdStream.ReadUInt32Array(texIdStream.Length / 4, EndianUtils.Endianness.BigEndian);
                    }
                }

                List <HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo> packFileInfos = new List <HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo>(fps4.Files.Count);
                for (int i = 0; i < (cvi.IsSkit ? ufps4 : fps4).Files.Count - 1; ++i)
                {
                    var pf = new HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo();
                    pf.Name = (cvi.IsSkit ? ufps4 : fps4).Files[i].FileName;
                    if (i == cvi.SE3Index)
                    {
                        pf.DataStream = new DuplicatableByteArrayStream(newse3stream.CopyToByteArrayAndDispose());
                    }
                    else if (cvi.IsSkit && (i == 0 || i == 2 || i == 3))
                    {
                        // copy over the actual skit script/timing from the EN version so the voice timing and lipsync matches with the skit
                        pf.DataStream = ufps4.GetChildByIndex(i).AsFile.DataStream.Duplicate();
                    }
                    else if (cvi.IsSkit && i >= 4)
                    {
                        uint texId = NormalizePs3SkitTextureIdForWii(utexIds[i - 4]);
                        try {
                            pf.DataStream = skitTexCache.GetTextureStream(texId);
                        } catch (Exception ex) {
                            Console.WriteLine("ERROR: Failed to get skit texture with ID 0x" + texId.ToString("x4"));
                            Console.WriteLine("       tex name: " + new SkitTexCache.SkitTex()
                            {
                                Stream = ufps4.GetChildByIndex(i).AsFile.DataStream.Duplicate()
                            }.ToString());
                            throw ex;
                        }
                    }
                    else
                    {
                        pf.DataStream = fps4.GetChildByIndex(i).AsFile.DataStream.Duplicate();
                    }
                    pf.Length = pf.DataStream.Length;
                    packFileInfos.Add(pf);
                }
                packFileInfos = HyoutaTools.Tales.Vesperia.FPS4.FPS4.DetectDuplicates(packFileInfos);
                HyoutaTools.Tales.Vesperia.FPS4.FPS4.Pack(packFileInfos, newfps4stream, fps4.ContentBitmask, EndianUtils.Endianness.BigEndian, fps4.Unknown2, cvi.IsSkit ? null : wstream.Duplicate(), fps4.ArchiveName, fps4.FirstFileStart, 0x20);
            }

            //using (var fs = new FileStream(Path.Combine(@"c:\__graces\______fps4repacktest\", name.Replace("/", "_") + "_old.fps4"), FileMode.Create)) {
            //	using (var wcpy = wstream.Duplicate()) {
            //		wcpy.Position = 0;
            //		StreamUtils.CopyStream(wcpy, fs);
            //	}
            //}
            //using (var fs = new FileStream(Path.Combine(@"c:\__graces\______fps4repacktest\", name.Replace("/", "_") + "_new.fps4"), FileMode.Create)) {
            //	newfps4stream.Position = 0;
            //	StreamUtils.CopyStream(newfps4stream, fs);
            //}

            newfps4stream.Position = 0;
            return(newfps4stream);
        }
        public void PrintData(EndianUtils.Endianness endian, GameVersion version, Dictionary <uint, TSS.TSSEntry> inGameDic, FAMEDAT.FAMEDAT titles)
        {
            using (var characterDataStream = Stream.Duplicate()) {
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadAscii(0x40);                                  // custom character name
                uint character = characterDataStream.ReadUInt32().FromEndian(endian); // character ID
                characterDataStream.ReadUInt32().FromEndian(endian);                  // level
                characterDataStream.ReadUInt32().FromEndian(endian);                  // current HP
                characterDataStream.ReadUInt32().FromEndian(endian);                  // current TP
                characterDataStream.ReadUInt32().FromEndian(endian);                  // max HP
                characterDataStream.ReadUInt32().FromEndian(endian);                  // max TP
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // EXP
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base magic attack
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base def
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base mdef
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base agility
                characterDataStream.ReadUInt32().FromEndian(endian);                  // luck
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute fire
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute earth
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute wind
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute water
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute light
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute dark
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base attack attribute physical...?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier fire
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier earth
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier wind
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier water
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier light
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier dark
                characterDataStream.ReadUInt32().FromEndian(endian);                  // base damage multiplier physical?
                characterDataStream.DiscardBytes(0xA8A60 - 0xA89F0);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // modified attack (base + from equipment)
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod def
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod matk
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod mdef
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod agility
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod luck
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute fire
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute earth
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute wind
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute water
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute light
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute dark
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod attack attribute physical...?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier fire
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier earth
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier wind
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier water
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier light
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier dark
                characterDataStream.ReadUInt32().FromEndian(endian);                  // mod damage multiplier physical?
                characterDataStream.DiscardBytes(0xA8E04 - 0xA8ABC);                  // ?
                characterDataStream.ReadUInt32().FromEndian(endian);                  // enemy kill counter (?)
                characterDataStream.DiscardBytes(0xAAE28 - 0xA8E08);                  // ?

                // skill equipment is stored around here

                characterDataStream.DiscardBytes(0xAC5B8 - 0xAAE28);                   // ?
                uint[] titlesUnlockedBitfield = characterDataStream.ReadUInt32Array(15, endian);

                foreach (var title in titles.TitleList)
                {
                    bool haveTitle = ((titlesUnlockedBitfield[title.ID / 32] >> (int)(title.ID % 32)) & 1) > 0;
                    if (haveTitle || ((title.BunnyGuildPointsMaybe > 0 || (!version.Is360() && title.ID == 67)) && title.Character == character))
                    {
                        Console.WriteLine((haveTitle ? "Y" : "N") + ": " + inGameDic[title.NameStringDicID].StringEngOrJpn);
                    }
                }

                characterDataStream.DiscardBytes(0xAC938 - 0xAC5F4);                   // ?
            }
        }
Beispiel #23
0
 public SaveDataBlockPartyData(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
 public SaveDataBlockFieldGadget(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
Beispiel #25
0
 public DuplicatableStream DuplicateStream()
 {
     return(Stream.Duplicate());
 }
 public SaveDataBlockStandbyEnemy(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
 public SaveDataBlockTerasureSave(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
Beispiel #28
0
 public SaveDataBlockSnowBoard(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
 public SaveDataBlockPCStatus(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }
 public SaveDataBlockFieldCamera(DuplicatableStream blockStream)
 {
     Stream = blockStream.Duplicate();
 }