Beispiel #1
0
        // Second data hunk, right behind UITexts.
        internal Buttons(IDataReader dataReader)
        {
            var graphicInfo = new GraphicInfo
            {
                Width         = 32,
                Height        = 13,
                Alpha         = true,
                GraphicFormat = GraphicFormat.Palette3Bit,
                PaletteOffset = 24
            };
            var graphicReader = new GraphicReader();

            Graphic ReadGraphic(IDataReader dataReader)
            {
                var graphic = new Graphic();

                graphicReader.ReadGraphic(graphic, dataReader, graphicInfo);

                return(graphic);
            }

            foreach (var buttonType in Enum.GetValues <ButtonType>())
            {
                entries.Add(buttonType, ReadGraphic(dataReader));
            }

            dataReader.AlignToWord();
        }
Beispiel #2
0
        internal Cursors(IDataReader dataReader)
        {
            var graphicReader = new GraphicReader();
            var graphicInfo   = new GraphicInfo
            {
                Width         = 16,
                Height        = 16,
                Alpha         = true,
                GraphicFormat = GraphicFormat.Palette3Bit,
                PaletteOffset = 24
            };

            Graphic ReadGraphic()
            {
                var graphic = new Graphic();

                graphicReader.ReadGraphic(graphic, dataReader, graphicInfo);

                return(graphic);
            }

            for (int i = 0; i < Count; ++i)
            {
                entries.Add(new Cursor
                {
                    HotspotX = (short)dataReader.ReadWord(),
                    HotspotY = (short)dataReader.ReadWord(),
                    Graphic  = ReadGraphic()
                });
            }
        }
        Graphic LoadGraphic(Monster monster)
        {
            var file = gameData.Files["Monster_gfx.amb"].Files[(int)monster.CombatGraphicIndex];

            file.Position = 0;
            var graphic       = new Graphic();
            var graphicReader = new GraphicReader();
            var graphicInfo   = new GraphicInfo
            {
                Width         = (int)monster.FrameWidth,
                Height        = (int)monster.FrameHeight,
                GraphicFormat = GraphicFormat.Palette5Bit,
                Alpha         = true,
                PaletteOffset = 0
            };
            int numFrames       = file.Size / ((graphicInfo.Width * graphicInfo.Height * 5 + 7) / 8); // TODO: is this inside monster data?
            var compoundGraphic = new Graphic(numFrames * (int)monster.MappedFrameWidth, (int)monster.MappedFrameHeight, 0);

            for (int i = 0; i < numFrames; ++i)
            {
                graphicReader.ReadGraphic(graphic, file, graphicInfo);
                compoundGraphic.AddOverlay((uint)i * monster.MappedFrameWidth, 0, graphic.CreateScaled((int)monster.MappedFrameWidth, (int)monster.MappedFrameHeight), false);
            }
            for (int i = 0; i < compoundGraphic.Data.Length; ++i)
            {
                compoundGraphic.Data[i] = monster.MonsterPalette[compoundGraphic.Data[i] & 0x1f];
            }
            return(compoundGraphic);
        }
        /* Some interesting offsets:
         *
         * 2nd data hunk
         * =============
         *
         * Offsets are for German 1.05.
         *
         * 0x7AA0: Palette indices for event pix (only 8 of 9)
         * 0x8085: Name of the dictionary file. From here on the relative
         *         text offsets will differ between german and english version!
         */

        public ExecutableData(List <AmigaExecutable.IHunk> hunks)
        {
            var firstCodeHunk = hunks.FirstOrDefault(h => h.Type == AmigaExecutable.HunkType.Code);

            if (firstCodeHunk == null)
            {
                DataInfoString = "Unknown data version";
            }
            else
            {
                var infoReader = new DataReader((firstCodeHunk as AmigaExecutable.Hunk?)?.Data);
                infoReader.Position = 6;
                DataVersionString   = infoReader.ReadNullTerminatedString(AmigaExecutable.Encoding);
                DataInfoString      = infoReader.ReadNullTerminatedString(AmigaExecutable.Encoding);
            }

            var reloc32Hunk     = (AmigaExecutable.Reloc32Hunk?)hunks.LastOrDefault(h => h.Type == AmigaExecutable.HunkType.RELOC32);
            var dataHunkReaders = hunks.Where(h => h.Type == AmigaExecutable.HunkType.Data)
                                  .Select(h => new DataReader(((AmigaExecutable.Hunk)h).Data)).ToArray();
            int dataHunkIndex = 0;

            if (reloc32Hunk == null || !reloc32Hunk.Value.Entries.ContainsKey(5) || reloc32Hunk.Value.Entries[5].Count != 15)
            {
                throw new AmbermoonException(ExceptionScope.Data, "Unexpected executable format.");
            }

            var  relocOffsets   = reloc32Hunk.Value.Entries[5];
            uint digitOffset    = relocOffsets.Take(9).Aggregate((a, b) => a + b) + 0x76D; // TODO: does this work for all versions?
            uint codepageOffset = relocOffsets.Take(12).Aggregate((a, b) => a + b);
            uint textOffset     = codepageOffset + relocOffsets.Skip(12).Take(2).Aggregate((a, b) => a + b) + 4;
            uint glyphOffset    = codepageOffset + relocOffsets.Skip(12).Aggregate((a, b) => a + b) + 262;

            if (glyphOffset % 4 != 0)
            {
                glyphOffset += 4 - glyphOffset % 4;
            }

            dataHunkIndex = 0;

            UIGraphics = Read <UIGraphics>(dataHunkReaders, ref dataHunkIndex);

            dataHunkIndex = 1;
            dataHunkReaders[1].Position = (int)digitOffset;
            DigitGlyphs = Read <DigitGlyphs>(dataHunkReaders, ref dataHunkIndex);

            // TODO ...

            dataHunkReaders[1].Position = (int)glyphOffset;
            Glyphs  = Read <Glyphs>(dataHunkReaders, ref dataHunkIndex);
            Cursors = Read <Cursors>(dataHunkReaders, ref dataHunkIndex);

            // Here are the 3 builtin palettes for primary UI, automap and secondary UI.
            for (int i = 0; i < 3; ++i)
            {
                BuiltinPalettes[i] = GraphicProvider.ReadPalette(dataHunkReaders[dataHunkIndex]);
            }

            // Then 9 vertical color gradients used for skies are stored. They are stored
            // as 16 bit XRGB colors and not color indices!
            // The first 3 skies are for Lyramion, the next 3 for the forest moon and the last
            // 3 for Morag. The first sky is night, the second twilight and the third day.
            // Transitions blend night with twilight or day with twilight.
            var skyGraphicInfo = new GraphicInfo
            {
                Alpha         = false,
                GraphicFormat = GraphicFormat.XRGB16,
                Width         = 1,
                Height        = 72
            };
            var         graphicReader = new GraphicReader();
            List <uint> colors        = new List <uint>();

            for (int i = 0; i < 9; ++i)
            {
                var sky = SkyGradients[i] = new Graphic();
                graphicReader.ReadGraphic(sky, dataHunkReaders[dataHunkIndex], skyGraphicInfo);
            }

            // After the 9 sky gradients there are 6 partial palettes (16 colors).
            // Two of them per world (first for night, second for twilight).
            // They are also blended together (the first 16 colors of the map's palette is
            // used for day) and then replaces the first 16 colors of the map's palette.
            var daytimePaletteReplacementInfo = new GraphicInfo
            {
                Alpha         = false,
                GraphicFormat = GraphicFormat.XRGB16,
                Width         = 1,
                Height        = 16
            };

            for (int i = 0; i < 6; ++i)
            {
                var replacement = DaytimePaletteReplacements[i] = new Graphic();
                graphicReader.ReadGraphic(replacement, dataHunkReaders[dataHunkIndex], daytimePaletteReplacementInfo);
            }

            // TODO ...

            const string search = "Amberfiles/";

            dataHunkReaders[1].Position = (int)dataHunkReaders[1].FindString(search, dataHunkReaders[1].Position) + search.Length + 50;

            FileList       = Read <FileList>(dataHunkReaders, ref dataHunkIndex);
            WorldNames     = Read <WorldNames>(dataHunkReaders, ref dataHunkIndex);
            Messages       = Read <Messages>(dataHunkReaders, ref dataHunkIndex);
            AutomapNames   = Read <AutomapNames>(dataHunkReaders, ref dataHunkIndex);
            OptionNames    = Read <OptionNames>(dataHunkReaders, ref dataHunkIndex);
            SongNames      = Read <SongNames>(dataHunkReaders, ref dataHunkIndex);
            SpellTypeNames = Read <SpellTypeNames>(dataHunkReaders, ref dataHunkIndex);
            SpellNames     = Read <SpellNames>(dataHunkReaders, ref dataHunkIndex);
            LanguageNames  = Read <LanguageNames>(dataHunkReaders, ref dataHunkIndex);
            ClassNames     = Read <ClassNames>(dataHunkReaders, ref dataHunkIndex);
            RaceNames      = Read <RaceNames>(dataHunkReaders, ref dataHunkIndex);
            AbilityNames   = Read <AbilityNames>(dataHunkReaders, ref dataHunkIndex);
            AttributeNames = Read <AttributeNames>(dataHunkReaders, ref dataHunkIndex);
            AbilityNames.AddShortNames(dataHunkReaders[dataHunkIndex]);
            AttributeNames.AddShortNames(dataHunkReaders[dataHunkIndex]);
            ItemTypeNames = Read <ItemTypeNames>(dataHunkReaders, ref dataHunkIndex);
            AilmentNames  = Read <AilmentNames>(dataHunkReaders, ref dataHunkIndex);
            UITexts       = Read <UITexts>(dataHunkReaders, ref dataHunkIndex);
            Buttons       = Read <Buttons>(dataHunkReaders, ref dataHunkIndex);

            int itemCount = dataHunkReaders[dataHunkIndex].ReadWord();

            if (dataHunkReaders[dataHunkIndex].ReadWord() != itemCount || itemCount != 402)
            {
                throw new AmbermoonException(ExceptionScope.Data, "Invalid item data.");
            }

            var itemReader = new ItemReader();
            var items      = new Dictionary <uint, Item>();

            for (uint i = 1; i <= 402; ++i) // there are 402 items
            {
                items.Add(i, Item.Load(i, itemReader, dataHunkReaders[dataHunkIndex]));
            }

            ItemManager = new ItemManager(items);
        }
Beispiel #5
0
        internal UIGraphics(IDataReader dataReader)
        {
            var graphicReader = new GraphicReader();
            var graphicInfo   = new GraphicInfo
            {
                Width         = 16,
                Height        = 6,
                Alpha         = true,
                GraphicFormat = GraphicFormat.Palette3Bit,
                PaletteOffset = 24
            };

            Graphic ReadGraphic(IDataReader dataReader, byte maskColor = 0)
            {
                var graphic = new Graphic();

                graphicReader.ReadGraphic(graphic, dataReader, graphicInfo, maskColor);

                return(graphic);
            }

            Graphic ReadOpaqueGraphic(IDataReader dataReader)
            {
                var graphic = new Graphic();

                graphicReader.ReadGraphic(graphic, dataReader, graphicInfo);
                graphic.ReplaceColor(0, 32);

                return(graphic);
            }

            // Note: First 156 bytes seem to be some offsets etc.

            dataReader.Position = 156;
            entries.Add(UIGraphic.DisabledOverlay16x6, ReadGraphic(dataReader));
            graphicInfo.Height = 16;
            // window frames
            entries.Add(UIGraphic.FrameUpperLeft, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameLeft, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameLowerLeft, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameTop, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameBottom, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameUpperRight, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameRight, ReadGraphic(dataReader));
            entries.Add(UIGraphic.FrameLowerRight, ReadGraphic(dataReader));

            graphicInfo.GraphicFormat = GraphicFormat.Palette5Bit;
            graphicInfo.PaletteOffset = 0;
            for (int i = (int)UIGraphic.StatusDead; i <= (int)UIGraphic.StatusRangeAttack; ++i)
            {
                entries.Add((UIGraphic)i, ReadGraphic(dataReader));
            }

            graphicInfo.Width         = 32;
            graphicInfo.Height        = 29;
            graphicInfo.GraphicFormat = GraphicFormat.Palette5Bit;
            graphicInfo.PaletteOffset = 0;
            entries.Add(UIGraphic.Eagle, ReadGraphic(dataReader));
            graphicInfo.Height = 26;
            entries.Add(UIGraphic.Explosion, ReadGraphic(dataReader));
            graphicInfo.Height        = 23;
            graphicInfo.GraphicFormat = GraphicFormat.Palette3Bit;
            graphicInfo.PaletteOffset = 24;
            entries.Add(UIGraphic.Ouch, ReadGraphic(dataReader));

            graphicInfo.Width  = 16;
            graphicInfo.Height = 60;
            entries.Add(UIGraphic.StarBlinkAnimation, ReadGraphic(dataReader));
            graphicInfo.Height = 40;
            entries.Add(UIGraphic.PlusBlinkAnimation, ReadGraphic(dataReader));
            graphicInfo.Height = 36;
            entries.Add(UIGraphic.LeftPortraitBorder, ReadGraphic(dataReader));
            entries.Add(UIGraphic.CharacterValueBarFrames, ReadGraphic(dataReader));
            entries.Add(UIGraphic.RightPortraitBorder, ReadGraphic(dataReader));
            graphicInfo.Height = 1;
            entries.Add(UIGraphic.SmallBorder1, ReadGraphic(dataReader));
            entries.Add(UIGraphic.SmallBorder2, ReadGraphic(dataReader));
            graphicInfo.Height = 16;
            for (int i = (int)UIGraphic.Candle; i <= (int)UIGraphic.Map; ++i)
            {
                entries.Add((UIGraphic)i, ReadOpaqueGraphic(dataReader));
            }

            graphicInfo.Width  = 32;
            graphicInfo.Height = 15;
            entries.Add(UIGraphic.Windchain, ReadOpaqueGraphic(dataReader));
            graphicInfo.Height = 32;
            entries.Add(UIGraphic.MonsterEyeInactive, ReadOpaqueGraphic(dataReader));
            entries.Add(UIGraphic.MonsterEyeActive, ReadOpaqueGraphic(dataReader));
            entries.Add(UIGraphic.Night, ReadOpaqueGraphic(dataReader));
            entries.Add(UIGraphic.Dusk, ReadOpaqueGraphic(dataReader));
            entries.Add(UIGraphic.Day, ReadOpaqueGraphic(dataReader));
            entries.Add(UIGraphic.Dawn, ReadOpaqueGraphic(dataReader));

            graphicInfo.Height = 17;
            graphicInfo.Alpha  = true;
            entries.Add(UIGraphic.ButtonFrame, ReadGraphic(dataReader));
            entries.Add(UIGraphic.ButtonFramePressed, ReadGraphic(dataReader));
            // Note: There is a 1-bit mask here where a 0 bit means transparent (keep color) and 1 means overlay.
            // As we use this for buttons we will set the color as the button back color (28).
            // The disable overlay is 32x11 in size.
            var disableOverlay = new Graphic(32, 11, 0);

            for (int y = 0; y < 11; ++y)
            {
                var bits = dataReader.ReadDword();

                for (int x = 0; x < 32; ++x)
                {
                    if ((bits & 0x80000000) != 0)
                    {
                        disableOverlay.Data[y * 32 + x] = 28;
                    }
                    bits <<= 1;
                }
            }
            entries.Add(UIGraphic.ButtonDisabledOverlay, disableOverlay);
            graphicInfo.Width  = 32;
            graphicInfo.Height = 32;
            entries.Add(UIGraphic.Compass, ReadOpaqueGraphic(dataReader));
            graphicInfo.Width  = 16;
            graphicInfo.Height = 9;
            entries.Add(UIGraphic.Attack, ReadGraphic(dataReader));
            entries.Add(UIGraphic.Defense, ReadGraphic(dataReader));
            graphicInfo.Width  = 32;
            graphicInfo.Height = 34;
            entries.Add(UIGraphic.Skull, ReadGraphic(dataReader, 25));
            entries.Add(UIGraphic.EmptyCharacterSlot, ReadOpaqueGraphic(dataReader));
            graphicInfo.Width         = 16;
            graphicInfo.Height        = 16;
            graphicInfo.GraphicFormat = GraphicFormat.Palette3Bit;
            graphicInfo.PaletteOffset = 0;
            var compoundGraphic = new Graphic(176, 16, 0);

            for (uint i = 0; i < 11; ++i)
            {
                compoundGraphic.AddOverlay(i * 16u, 0u, ReadGraphic(dataReader), false);
            }
            entries.Add(UIGraphic.ItemConsume, compoundGraphic);
            graphicInfo.Width         = 32;
            graphicInfo.Height        = 29;
            graphicInfo.GraphicFormat = GraphicFormat.Palette5Bit;
            graphicInfo.PaletteOffset = 0;
            entries.Add(UIGraphic.Talisman, ReadGraphic(dataReader));
            graphicInfo.Width         = 16;
            graphicInfo.Height        = 47;
            graphicInfo.GraphicFormat = GraphicFormat.Palette3Bit;
            graphicInfo.PaletteOffset = 24;
            entries.Add(UIGraphic.UnknownChain, ReadGraphic(dataReader));
            graphicInfo.Width  = 8;
            graphicInfo.Height = 84;
            entries.Add(UIGraphic.BorderWithTriangles, ReadGraphic(dataReader));
        }