Example #1
0
        public OutroData(IGameData gameData)
        {
            var outroHunks = AmigaExecutable.Read(gameData.Files["Ambermoon_extro"].Files[1]);
            var codeHunks  = outroHunks.Where(h => h.Type == AmigaExecutable.HunkType.Code)
                             .Select(h => new DataReader(((AmigaExecutable.Hunk)h).Data))
                             .ToList();
            var dataHunks = outroHunks
                            .Where(h => h.Type == AmigaExecutable.HunkType.Data)
                            .Select(h => new DataReader(((AmigaExecutable.Hunk)h).Data))
                            .ToList();
            var graphicReader = new GraphicReader();
            var graphicInfo   = new GraphicInfo
            {
                GraphicFormat = GraphicFormat.Palette5Bit,
                Alpha         = false,
                PaletteOffset = 0
            };
            var dataHunk         = dataHunks[0];
            var imageHunk        = dataHunks[1];
            var actionCache      = new Dictionary <uint, List <OutroAction> >();
            var imageDataOffsets = new List <uint>();

            Graphic LoadPalette(DataReader hunk)
            {
                var paletteGraphic = new Graphic();

                graphicReader.ReadGraphic(paletteGraphic, hunk, paletteGraphicInfo);
                return(paletteGraphic);
            }

            LoadFonts(codeHunks[0]);

            #region Hunk 0 - Actions and texts

            // Initial palette (all zeros)
            outroPalettes.Add(LoadPalette(dataHunk));

            // There are actually 3 outro sequence lists dependent on if Valdyn
            // is in the party and if you found the yellow teleporter sphere.
            for (int i = 0; i < 3; ++i)
            {
                var sequence = new List <OutroAction>();

                while (true)
                {
                    uint actionListOffset = dataHunk.ReadBEUInt32();

                    if (actionListOffset == 0)
                    {
                        break;
                    }

                    uint imageDataOffset = dataHunk.ReadBEUInt32();

                    if (!imageDataOffsets.Contains(imageDataOffset))
                    {
                        imageDataOffsets.Add(imageDataOffset);
                    }

                    sequence.Add(new OutroAction
                    {
                        Command     = OutroCommand.ChangePicture,
                        ImageOffset = imageDataOffset
                    });

                    if (actionCache.TryGetValue(actionListOffset, out var cachedActions))
                    {
                        sequence.AddRange(cachedActions);
                    }
                    else
                    {
                        int readPosition = dataHunk.Position;
                        dataHunk.Position = (int)actionListOffset;
                        var actions = new List <OutroAction>();

                        while (true)
                        {
                            byte scrollAmount = dataHunk.ReadByte();

                            if (scrollAmount == 0xff)
                            {
                                actions.Add(new OutroAction
                                {
                                    Command = OutroCommand.WaitForClick
                                });
                                break;
                            }

                            int    textDisplayX = dataHunk.ReadByte();
                            bool   largeText    = dataHunk.ReadByte() != 0;
                            string text         = dataHunk.ReadNullTerminatedString();
                            int?   textIndex    = text.Length == 0 ? (int?)null : texts.Count;

                            if (text.Length != 0)
                            {
                                texts.Add(text);
                            }

                            actions.Add(new OutroAction
                            {
                                Command      = OutroCommand.PrintTextAndScroll,
                                LargeText    = largeText,
                                TextIndex    = textIndex,
                                ScrollAmount = scrollAmount + 1
                            });
                        }

                        sequence.AddRange(actions);
                        actionCache.Add(actionListOffset, actions);
                        dataHunk.Position = readPosition;
                    }
                }

                outroActions.Add((OutroOption)i, sequence.AsReadOnly());
            }

            #endregion

            #region Hunk 1 - Images

            Graphic LoadGraphic(int width, int height)
            {
                graphicInfo.Width  = width;
                graphicInfo.Height = height;
                var graphic = new Graphic();

                graphicReader.ReadGraphic(graphic, imageHunk, graphicInfo);
                return(graphic);
            }

            foreach (var imageDataOffset in imageDataOffsets)
            {
                imageHunk.Position = (int)imageDataOffset;
                int width  = imageHunk.ReadBEUInt16() * 16;
                int height = imageHunk.ReadBEUInt16();
                imageHunk.Position += 2; // unused word
                byte paletteIndex = (byte)outroPalettes.Count;
                outroPalettes.Add(LoadPalette(imageHunk));
                graphics.Add(imageDataOffset, KeyValuePair.Create(LoadGraphic(width, height), paletteIndex));
            }

            #endregion
        }
Example #2
0
        public IntroData(GameData gameData)
        {
            var introHunks = AmigaExecutable.Read(gameData.Files["Ambermoon_intro"].Files[1])
                             .Where(h => h.Type == AmigaExecutable.HunkType.Data).Select(h => new DataReader(((AmigaExecutable.Hunk)h).Data))
                             .ToList();
            var graphicReader = new GraphicReader();

            #region Hunk 0 - Palettes and texts

            var hunk0 = introHunks[0];

            Graphic LoadPalette()
            {
                var paletteGraphic = new Graphic();

                graphicReader.ReadGraphic(paletteGraphic, hunk0, paletteGraphicInfo);
                return(paletteGraphic);
            }

            for (int i = 0; i < 9; ++i)
            {
                introPalettes.Add(LoadPalette());
            }

            hunk0.Position += 8; // 8 unknown bytes

            for (int i = 0; i < 8; ++i)
            {
                byte startByte = hunk0.PeekByte();
                if (startByte != 0x20 && (startByte < 'A' || startByte > 'Z'))
                {
                    ++hunk0.Position; // Sometimes there is an unknown start byte
                }
                texts.Add((IntroText)i, hunk0.ReadNullTerminatedString());
            }

            if (hunk0.ReadByte() != 4) // Should contain the amount of main menu text (= 4)
            {
                throw new AmbermoonException(ExceptionScope.Data, "Wrong intro data.");
            }

            for (int i = 0; i < 4; ++i)
            {
                // The 4 main menu texts are prefixed by 2 bytes (x and y render offset).
                hunk0.Position += 2; // We skip those bytes here.
                texts.Add((IntroText)(8 + i), hunk0.ReadNullTerminatedString());
            }

            // TODO: the credits will follow

            #endregion

            #region Hunk 1 - Main menu background and town graphics

            Size[] hunk1ImageSizes = new Size[8]
            {
                new Size(96, 300), // not sure
                new Size(320, 256),
                new Size(160, 128),
                new Size(160, 128),
                new Size(160, 128),
                new Size(160, 128),
                new Size(160, 128),
                new Size(160, 128)
            };

            for (int i = 0; i < 8; ++i)
            {
                var reader = introHunks[1];

                if (reader.PeekDword() == 0x494d5021) // "IMP!", may be imploded
                {
                    reader = new DataReader(Deploder.DeplodeFimp(reader).Reverse().ToArray());
                }

                var graphicInfo = new GraphicInfo
                {
                    Width         = hunk1ImageSizes[i].Width,
                    Height        = hunk1ImageSizes[i].Height,
                    GraphicFormat = GraphicFormat.Palette4Bit,
                    PaletteOffset = 0,
                    Alpha         = false
                };
                var graphic = new Graphic();
                graphicReader.ReadGraphic(graphic, reader, graphicInfo);
                graphics.Add((IntroGraphic)i, graphic);
            }

            #endregion

            #region Hunk 2 - Unknown

            // TODO

            #endregion

            #region Hunk 3 - Intro graphics (planets, etc)

            Size[] hunk3ImageSizes = new Size[6]
            {
                new Size(128, 82),  // Thalion Logo
                new Size(64, 64),   // Sun
                new Size(128, 128), // Lyramion
                new Size(64, 64),   // Morag
                new Size(64, 64),   // Forest Moon
                new Size(96, 96),   // Meteor
                // TODO ...
            };
            int[] hunk3FrameCounts = new int[6]
            {
                1,
                12,
                1,
                1,
                1,
                1,
                // TODO ...
            };

            for (int i = 0; i < 6; ++i)
            {
                var graphicInfo = new GraphicInfo
                {
                    Width         = hunk3ImageSizes[i].Width,
                    Height        = hunk3ImageSizes[i].Height,
                    GraphicFormat = GraphicFormat.Palette4Bit,
                    PaletteOffset = 0,
                    Alpha         = false
                };
                Graphic graphic;
                int     frames = hunk3FrameCounts[i];
                if (frames == 1)
                {
                    graphic = new Graphic();
                    graphicReader.ReadGraphic(graphic, introHunks[3], graphicInfo);
                }
                else
                {
                    graphic = new Graphic(frames * graphicInfo.Width, graphicInfo.Height, 0);

                    for (int f = 0; f < frames; ++f)
                    {
                        var frameGraphic = new Graphic();
                        graphicReader.ReadGraphic(frameGraphic, introHunks[3], graphicInfo);
                        graphic.AddOverlay((uint)(f * frameGraphic.Width), 0, frameGraphic, false);
                    }
                }
                graphics.Add(IntroGraphic.ThalionLogo + i, graphic);
                if (i == 0) // The other graphics start at 0x42B8 (the data between is unknown yet)
                {
                    introHunks[3].Position = 0x42B8;
                }
            }

            // TODO ...

            #endregion
        }