Graphic ReadPalette(GraphicReader graphicReader, IDataReader reader) { reader.Position = 0; var paletteGraphic = new Graphic(); graphicReader.ReadGraphic(paletteGraphic, reader, paletteGraphicInfo); return(paletteGraphic); }
internal static Graphic ReadPalette(IDataReader reader) { var graphicReader = new GraphicReader(); var paletteGraphic = new Graphic(); graphicReader.ReadGraphic(paletteGraphic, reader, paletteGraphicInfo); return(paletteGraphic); }
void LoadGraphics(GraphicType type) { if (!graphics.ContainsKey(type)) { graphics.Add(type, new List <Graphic>()); var reader = new GraphicReader(); var info = GraphicInfoFromType(type); var graphicList = graphics[type]; void LoadGraphic(IDataReader graphicDataReader, byte maskColor = 0) { graphicDataReader.Position = 0; int end = graphicDataReader.Size - info.DataSize; while (graphicDataReader.Position <= end) { var graphic = new Graphic(); reader.ReadGraphic(graphic, graphicDataReader, info, maskColor); graphicList.Add(graphic); } } var allFiles = new SortedDictionary <int, IDataReader>(); foreach (var graphicFile in graphicFiles[type]) { var containerFile = gameData.Files[graphicFile.File]; if (graphicFile.SubFiles == null) { foreach (var file in containerFile.Files) { allFiles[graphicFile.FileIndexOffset + file.Key] = file.Value; } } else { foreach (var file in graphicFile.SubFiles) { allFiles[graphicFile.FileIndexOffset + file] = containerFile.Files[file]; } } } foreach (var file in allFiles) { LoadGraphic(file.Value, (byte)(type switch { GraphicType.Portrait => 25, GraphicType.LabBackground => 9, // 9 is the sky color index _ => 0 }));
void LoadGraphics(GraphicType type) { if (!graphics.ContainsKey(type)) { graphics.Add(type, new List <Graphic>()); var reader = new GraphicReader(); var info = GraphicInfoFromType(type); var graphicList = graphics[type]; void LoadGraphic(IDataReader graphicDataReader) { graphicDataReader.Position = 0; int end = graphicDataReader.Size - info.DataSize; while (graphicDataReader.Position <= end) { var graphic = new Graphic(); reader.ReadGraphic(graphic, graphicDataReader, info); graphicList.Add(graphic); } } var allFiles = new SortedDictionary <int, IDataReader>(); foreach (var graphicFile in graphicFiles[type]) { var containerFile = gameData.Files[graphicFile.File]; if (graphicFile.SubFiles == null) { foreach (var file in containerFile.Files) { allFiles[graphicFile.FileIndexOffset + file.Key] = file.Value; } } else { foreach (var file in graphicFile.SubFiles) { allFiles[graphicFile.FileIndexOffset + file] = containerFile.Files[file]; } } } foreach (var file in allFiles) { LoadGraphic(file.Value); } } }
static Graphic ReadGraphic(GraphicReader graphicReader, IDataReader file, int width, int height, bool alpha, bool texture) { var graphic = new Graphic { Width = width, Height = height, IndexedGraphic = true }; file.Position = 0; // TODO: or 4? sometimes the file is 4 bytes bigger than expected graphicReader.ReadGraphic(graphic, file, new GraphicInfo { Width = width, Height = height, GraphicFormat = texture ? GraphicFormat.Texture4Bit : GraphicFormat.Palette4Bit, PaletteOffset = 0, Alpha = alpha }); return(graphic); }
void LoadTravelGraphics() { // Travel gfx stores graphics with a header: // uword NumberOfHorizontalSprites (a sprite has a width of 16 pixels) // uword Height (in pixels) // uword XOffset (in pixels relative to drawing position) // uword YOffset (in pixels relative to drawing position) IFileContainer container; try { container = Files["Travel_gfx.amb"]; } catch (KeyNotFoundException) { if (stopAtFirstError) { throw new FileNotFoundException("Unable to find travel graphics."); } else { return; } } var graphicReader = new GraphicReader(); var graphicInfo = new GraphicInfo { GraphicFormat = GraphicFormat.Palette5Bit, Alpha = true }; foreach (var file in container.Files) { var reader = file.Value; reader.Position = 0; Graphic LoadGraphic() { var graphic = new Graphic(); graphicReader.ReadGraphic(graphic, reader, graphicInfo); return(graphic); } for (int direction = 0; direction < 4; ++direction) { int numSprites = reader.ReadWord(); graphicInfo.Height = reader.ReadWord(); graphicInfo.Width = numSprites * 16; uint xOffset = reader.ReadWord(); uint yOffset = reader.ReadWord(); travelGraphicInfos.Add(new TravelGraphicInfo { Width = (uint)graphicInfo.Width, Height = (uint)graphicInfo.Height, OffsetX = xOffset, OffsetY = yOffset }); TravelGraphics.Add(LoadGraphic()); } } }
public GraphicProvider(GameData gameData) { this.gameData = gameData; var graphicReader = new GraphicReader(); Palettes = gameData.Files[paletteFile].Files.ToDictionary(f => f.Key, f => ReadPalette(graphicReader, f.Value)); // There is a special palette used for items and portraits. // Special thanks to Iceblizz who provided it to the Amberworld project. Palettes.Add(50, new Graphic { Width = 32, Height = 1, IndexedGraphic = false, Data = new byte[] { 0x00, 0x00, 0x00, 0xff, 0xed, 0xdc, 0xcb, 0xff, 0xfe, 0xfe, 0xed, 0xff, 0xba, 0xba, 0xcb, 0xff, 0x87, 0x98, 0xa9, 0xff, 0x54, 0x76, 0x87, 0xff, 0x21, 0x54, 0x65, 0xff, 0x00, 0x32, 0x43, 0xff, 0xfe, 0xcb, 0x98, 0xff, 0xed, 0xa9, 0x76, 0xff, 0xcb, 0x87, 0x54, 0xff, 0xa9, 0x65, 0x32, 0xff, 0x87, 0x43, 0x21, 0xff, 0x54, 0x21, 0x10, 0xff, 0xba, 0x87, 0x00, 0xff, 0xdc, 0xa9, 0x00, 0xff, 0xfe, 0xcb, 0x00, 0xff, 0xfe, 0x98, 0x00, 0xff, 0xcb, 0x65, 0x00, 0xff, 0x87, 0x10, 0x21, 0xff, 0xcb, 0x43, 0x32, 0xff, 0xed, 0x65, 0x32, 0xff, 0xa9, 0xa9, 0x43, 0xff, 0x54, 0x76, 0x32, 0xff, 0x21, 0x54, 0x43, 0xff, 0x00, 0x10, 0x00, 0xff, 0x21, 0x21, 0x21, 0xff, 0x43, 0x43, 0x32, 0xff, 0x65, 0x65, 0x54, 0xff, 0x87, 0x87, 0x76, 0xff, 0xa9, 0xa9, 0x98, 0xff, 0xcb, 0xcb, 0xba, 0xff } }); // We also use another palette for text rendering. It has transparent, black, white, gray, red, yellow etc. // Note: If a text is hovered (e.g. when choosing something to say) the color is inverted (e.g. yellow // background and text is just transparent to show the gray background). Palettes.Add(51, new Graphic { Width = 32, Height = 1, IndexedGraphic = false, Data = new byte[] { // transparent, black (shadow), white, gray 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xee, 0xff, 0xbb, 0xbb, 0xaa, 0xff, // red (character), yellow (active character), orange (battle text), blueish gray (dead character) 0xcc, 0x44, 0x33, 0xff, 0xff, 0xcc, 0x00, 0xff, 0xdd, 0x66, 0x33, 0xff, 0x99, 0xaa, 0xaa, 0xff, // rest unused (TODO: character with ailment?) 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff } }); // TODO: The following bytes were extracted from AM2_CPU (behind cursors). // It really looks like 3 palettes. Maybe for text rendering? /* 00 00 0E DC 0F FE 0B BC 08 9A 05 78 02 56 00 34 0F C9 0E A7 0C 85 0A 63 08 42 05 21 0B 80 0D A0 * 0F C0 0F 90 0C 60 08 12 0C 43 0E 63 0A A4 05 73 02 54 05 09 02 22 04 43 06 65 08 87 0A A9 0C CB * * 00 00 0F DC 0E B9 0C 96 04 10 08 51 0A 74 06 30 0F 60 0D 30 09 00 0F C0 0B 90 08 60 09 A3 05 70 * 02 40 08 BE 03 8C 00 48 0C 8D 0A 69 08 36 0F FF 07 9D 01 6A 02 11 04 32 06 54 08 76 0A 98 0C BA * * 00 00 0E DC 0F FE 0B BC 08 9A 05 78 02 56 00 34 0F C9 0E A7 0C 85 0A 63 08 42 05 21 0B 80 0D A0 * 0F C0 0F 90 0C 60 08 12 0C 43 0E 63 0A A4 05 73 04 9D 02 59 02 10 04 31 06 53 08 75 0A 97 0C B9 */ foreach (GraphicType type in Enum.GetValues(typeof(GraphicType))) { LoadGraphics(type); } }
public void ReadLabdata(Labdata labdata, IDataReader dataReader, IGameData gameData) { labdata.WallHeight = dataReader.ReadWord(); labdata.Unknown1 = dataReader.ReadByte(); // Unknown labdata.CombatBackground = dataReader.ReadByte() & 0x0fu; labdata.Unknown2 = dataReader.ReadBytes(2); // Unknown // Note: The ceiling texture index can be 0 in which case a sky is used. // The sky is composed of a color gradient and a lab background // which is given inside the map data. uint ceilingTextureIndex = dataReader.ReadByte(); uint floorTextureIndex = dataReader.ReadByte(); labdata.Objects.Clear(); int numObjects = dataReader.ReadWord(); var objects = new List <Tuple <ushort, List <Tuple <float, float, float, int> > > >(numObjects); for (int i = 0; i < numObjects; ++i) { var obj = Tuple.Create(dataReader.ReadWord(), new List <Tuple <float, float, float, int> >(8)); for (int n = 0; n < 8; ++n) // 8 sub entries (a map object can consist of up to 8 sub objects) { obj.Item2.Add(Tuple.Create( (float)(short)dataReader.ReadWord(), (float)(short)dataReader.ReadWord(), (float)(short)dataReader.ReadWord(), (int)dataReader.ReadWord())); } objects.Add(obj); } labdata.ObjectInfos.Clear(); int numObjectInfos = dataReader.ReadWord(); for (int i = 0; i < numObjectInfos; ++i) { var objectInfo = new Labdata.ObjectInfo { Unknown1 = dataReader.ReadBytes(3), // TODO: Collision info for all 3 axes? Flags = (Labdata.ObjectFlags)dataReader.ReadByte(), TextureIndex = dataReader.ReadWord(), NumAnimationFrames = dataReader.ReadByte(), Unknown2 = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte(), MappedTextureWidth = dataReader.ReadWord(), MappedTextureHeight = dataReader.ReadWord() }; labdata.ObjectInfos.Add(objectInfo); //Console.WriteLine($"Type: {objectInfo.Type}, Texture: {objectInfo.TextureIndex},{objectInfo.TextureWidth}x{objectInfo.TextureHeight} -> {objectInfo.MappedTextureWidth}x{objectInfo.MappedTextureHeight}, Frames: {objectInfo.NumAnimationFrames}"); } foreach (var obj in objects) { var subObjects = new List <Labdata.ObjectPosition>(8); foreach (var pos in obj.Item2) { if (pos.Item4 != 0) { subObjects.Add(new Labdata.ObjectPosition { X = pos.Item1, Y = pos.Item2, Z = pos.Item3, Object = labdata.ObjectInfos[pos.Item4 - 1] }); } } labdata.Objects.Add(new Labdata.Object { Header = obj.Item1, SubObjects = subObjects }); } labdata.Walls.Clear(); int numWalls = dataReader.ReadWord(); for (int i = 0; i < numWalls; ++i) { var wallData = new Labdata.WallData { Unknown1 = dataReader.ReadBytes(3), // TODO: Collision info for all 3 axes? Flags = (Labdata.WallFlags)dataReader.ReadByte(), TextureIndex = dataReader.ReadByte(), AutomapType = (AutomapType)dataReader.ReadByte(), Unknown2 = dataReader.ReadByte() }; int numOverlays = dataReader.ReadByte(); if (numOverlays != 0) { wallData.Overlays = new Labdata.OverlayData[numOverlays]; for (int o = 0; o < numOverlays; ++o) { wallData.Overlays[o] = new Labdata.OverlayData { NumAnimationFrames = dataReader.ReadByte(), TextureIndex = dataReader.ReadByte(), PositionX = dataReader.ReadByte(), PositionY = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte() }; } } labdata.Walls.Add(wallData); //Console.WriteLine($"Wall{i+1} -> {wallData}"); } // Load labyrinth graphics var graphicReader = new GraphicReader(); if (floorTextureIndex != 0) { labdata.FloorGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)floorTextureIndex], 64, 64, false, false); } if (ceilingTextureIndex != 0) { labdata.CeilingGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)ceilingTextureIndex], 64, 64, false, false); // TODO } var objectTextureFiles = gameData.Files[$"2Object3D.amb"].Files; gameData.Files[$"3Object3D.amb"].Files.ToList().ForEach(f => objectTextureFiles[f.Key] = f.Value); labdata.ObjectGraphics.Clear(); foreach (var objectInfo in labdata.ObjectInfos) { labdata.ObjectGraphics.Add(ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true)); } var wallTextureFiles = gameData.Files[$"2Wall3D.amb"].Files; var overlayTextureFiles = gameData.Files[$"2Overlay3D.amb"].Files; gameData.Files[$"3Wall3D.amb"].Files.ToList().ForEach(f => wallTextureFiles[f.Key] = f.Value); gameData.Files[$"3Overlay3D.amb"].Files.ToList().ForEach(f => overlayTextureFiles[f.Key] = f.Value); labdata.WallGraphics.Clear(); int wallIndex = 0; foreach (var wall in labdata.Walls) { var wallGraphic = ReadGraphic(graphicReader, wallTextureFiles[(int)wall.TextureIndex], 128, 80, wall.Flags.HasFlag(Labdata.WallFlags.Transparency), true); labdata.WallGraphics.Add(wallGraphic); if (wall.Overlays != null && wall.Overlays.Length != 0) { foreach (var overlay in wall.Overlays) { wallGraphic.AddOverlay(overlay.PositionX, overlay.PositionY, ReadGraphic(graphicReader, overlayTextureFiles[(int)overlay.TextureIndex], (int)overlay.TextureWidth, (int)overlay.TextureHeight, true, true)); } } ++wallIndex; } }
public GraphicProvider(GameData gameData, ExecutableData.ExecutableData executableData, IntroData introData, OutroData outroData) { this.gameData = gameData; var graphicReader = new GraphicReader(); Palettes = gameData.Files[paletteFile].Files.ToDictionary(f => f.Key, f => ReadPalette(graphicReader, f.Value)); // Add builtin palettes for (int i = 0; i < 3; ++i) { Palettes.Add(50 + i, executableData.BuiltinPalettes[i]); } // And another palette for some UI graphics. // The portraits have a blue gradient as background. It is also 32x34 pixels in size and the gradient // is in y-direction. All colors have R=0x00 and G=0x11. The blue component is increased by 0x11 // every 2 pixels starting at y=4 (first 4 pixel rows have B=0x00, next 2 have B=0x11, etc). // Last 2 rows have B=0xff. Palettes.Add(53, new Graphic { Width = 32, Height = 1, IndexedGraphic = false, Data = new byte[] { // The first colors are used for spells which use a materialize animation (earth and wind spells, waterfall, etc). // The animation uses black, dark red, light purple, dark purple, dark beige, light beige in that order. // We start with these color at offset 1. We leave the first color as fully transparent. // Index 7 is unused. 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0xff, 0x33, 0x11, 0x00, 0xff, 0x88, 0x77, 0xaa, 0xff, 0x66, 0x55, 0x88, 0xff, 0x99, 0x88, 0x77, 0xff, 0xbb, 0xbb, 0x99, 0xff, 0x00, 0x00, 0x00, 0x00, // 16 colors for the blue background gradient of portraits 0x00, 0x11, 0x00, 0xff, 0x00, 0x11, 0x11, 0xff, 0x00, 0x11, 0x22, 0xff, 0x00, 0x11, 0x33, 0xff, 0x00, 0x11, 0x44, 0xff, 0x00, 0x11, 0x55, 0xff, 0x00, 0x11, 0x66, 0xff, 0x00, 0x11, 0x77, 0xff, 0x00, 0x11, 0x88, 0xff, 0x00, 0x11, 0x99, 0xff, 0x00, 0x11, 0xaa, 0xff, 0x00, 0x11, 0xbb, 0xff, 0x00, 0x11, 0xcc, 0xff, 0x00, 0x11, 0xdd, 0xff, 0x00, 0x11, 0xee, 0xff, 0x00, 0x11, 0xff, 0xff, // some UI colors (TODO: character with ailment?) 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x55, 0xff, 0x44, 0x44, 0x33, 0xff, 0x22, 0x22, 0x22, 0xff, 0x88, 0x88, 0x77, 0xff, 0xaa, 0xaa, 0x99, 0xff, 0xcc, 0xcc, 0xbb, 0xff } }); // Add the 9 intro palettes int introPaletteCount = introData == null ? 0 : Math.Min(9, introData.IntroPalettes.Count); int p = 0; for (; p < introPaletteCount; ++p) { Palettes.Add(54 + p, introData.IntroPalettes[p]); } for (; p < 9; ++p) { Palettes.Add(54 + p, new Graphic { Width = 32, Height = 1, IndexedGraphic = false, Data = new byte[32 * 4] }); } // Add the 6 outro palettes int outroPaletteCount = outroData == null ? 0 : Math.Min(6, outroData.OutroPalettes.Count); p = 0; for (; p < outroPaletteCount; ++p) { Palettes.Add(63 + p, outroData.OutroPalettes[p]); } for (; p < 6; ++p) { Palettes.Add(63 + p, new Graphic { Width = 32, Height = 1, IndexedGraphic = false, Data = new byte[32 * 4] }); } foreach (var type in Enum.GetValues <GraphicType>()) { if (type == GraphicType.Cursor) { var cursorGraphics = graphics[GraphicType.Cursor] = new List <Graphic>(); foreach (var cursor in executableData.Cursors.Entries) { cursorGraphics.Add(cursor.Graphic); } } else if (type == GraphicType.UIElements) { graphics[type] = UIElementProvider.Create(); graphics[type].AddRange(executableData.UIGraphics.Entries.Values); graphics[type].AddRange(executableData.Buttons.Entries.Values); } else if (type == GraphicType.TravelGfx) { graphics[type] = gameData.TravelGraphics; } else if (type == GraphicType.Transports) { var reader = gameData.Files["Stationary"].Files[1]; reader.Position = 0; graphics[type] = gameData.StationaryImageInfos.Select(info => { var graphic = new Graphic(); graphicReader.ReadGraphic(graphic, reader, info.Value); return(graphic); }).ToList(); } else if (type == GraphicType.NPC) { var npcGraphics = new List <Graphic>(34); var graphicInfo = new GraphicInfo { Width = 16, Height = 32, GraphicFormat = GraphicFormat.Palette5Bit, Alpha = true, PaletteOffset = 0 }; var graphic = new Graphic(); foreach (var file in gameData.Files["NPC_gfx.amb"].Files) { NPCGraphicOffsets.Add(file.Key, npcGraphics.Count); var reader = file.Value; reader.Position = 0; while (reader.Position <= reader.Size - graphicInfo.DataSize) { int numFrames = reader.ReadByte(); reader.AlignToWord(); var compoundGraphic = new Graphic(16 * numFrames, 32, 0); for (int i = 0; i < numFrames; ++i) { graphicReader.ReadGraphic(graphic, reader, graphicInfo); compoundGraphic.AddOverlay((uint)i * 16, 0, graphic, false); } npcGraphics.Add(compoundGraphic); } } graphics[type] = npcGraphics; } else if (type == GraphicType.CombatGraphics) { var combatGraphics = new List <Graphic>(42); var graphicInfo = new GraphicInfo { GraphicFormat = GraphicFormat.Palette5Bit, Alpha = true, PaletteOffset = 0 }; var reader = gameData.Files["Combat_graphics"].Files[1]; reader.Position = 0; foreach (var combatGraphic in CombatGraphics.Info) { var info = combatGraphic.Value; if (combatGraphic.Key == CombatGraphicIndex.BattleFieldIcons) { var battleFieldIcons = new List <Graphic>(35); var iconGraphicInfo = new GraphicInfo { Width = 16, Height = 14, GraphicFormat = GraphicFormat.Palette5Bit, Alpha = true, PaletteOffset = 0 }; for (int i = 0; i < 35; ++i) { var graphic = new Graphic(); graphicReader.ReadGraphic(graphic, reader, iconGraphicInfo); battleFieldIcons.Add(graphic); } graphics[GraphicType.BattleFieldIcons] = battleFieldIcons; } else { var graphic = new Graphic(); var compoundGraphic = new Graphic((int)info.FrameCount * info.GraphicInfo.Width, info.GraphicInfo.Height, 0); for (int i = 0; i < info.FrameCount; ++i) { graphicReader.ReadGraphic(graphic, reader, info.GraphicInfo); compoundGraphic.AddOverlay((uint)(i * info.GraphicInfo.Width), 0, graphic, false); } combatGraphics.Add(compoundGraphic); } } graphics[type] = combatGraphics; } else if (type == GraphicType.BattleFieldIcons) { // Do nothing. This is filled when processing GraphicType.CombatGraphics. } else if (type == GraphicType.RiddlemouthGraphics) { var riddlemouthGraphics = new List <Graphic>(4 + 7); var reader = gameData.Files["Riddlemouth_graphics"].Files[1]; reader.Position = 0; // 4 eye frames ReadAndAddGraphics(4, 48, 9); // 7 mouth frames ReadAndAddGraphics(7, 48, 15); void ReadAndAddGraphics(int frames, int width, int height) { var graphicInfo = new GraphicInfo { Width = width, Height = height, GraphicFormat = GraphicFormat.Palette3Bit, Alpha = false, PaletteOffset = 24 }; var graphic = new Graphic(); var compoundGraphic = new Graphic(frames * width, height, 0); for (int f = 0; f < frames; ++f) { graphicReader.ReadGraphic(graphic, reader, graphicInfo); compoundGraphic.AddOverlay((uint)(f * width), 0, graphic, false); } riddlemouthGraphics.Add(compoundGraphic); } graphics[type] = riddlemouthGraphics; } else if (type == GraphicType.AutomapGraphics) { var automapGraphics = new List <Graphic>(43); var reader = gameData.Files["Automap_graphics"].Files[1]; reader.Position = 0x100; // TODO: maybe decode the bytes before that later void ReadAndAddGraphics(int amount, int width, int height, GraphicFormat graphicFormat, int frames = 1, bool alpha = false) { var graphicInfo = new GraphicInfo { Width = width, Height = height, GraphicFormat = graphicFormat, Alpha = alpha, PaletteOffset = 0 }; for (int i = 0; i < amount; ++i) { Graphic graphic = new Graphic(); if (frames == 1) { graphicReader.ReadGraphic(graphic, reader, graphicInfo); } else { var compoundGraphic = new Graphic(frames * width, height, 0); for (int f = 0; f < frames; ++f) { graphicReader.ReadGraphic(graphic, reader, graphicInfo); compoundGraphic.AddOverlay((uint)(f * width), 0, graphic, false); } graphic = compoundGraphic; } automapGraphics.Add(graphic); } } // Map corners ReadAndAddGraphics(4, 32, 32, GraphicFormat.Palette3Bit); // Top map border ReadAndAddGraphics(4, 16, 32, GraphicFormat.Palette3Bit); // Right map border ReadAndAddGraphics(2, 32, 32, GraphicFormat.Palette3Bit); // Bottom map border ReadAndAddGraphics(4, 16, 32, GraphicFormat.Palette3Bit); // Left map border ReadAndAddGraphics(2, 32, 32, GraphicFormat.Palette3Bit); // 10 pin graphics ReadAndAddGraphics(10, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Riddlemouth (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Teleport (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Spinner (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Trap (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Trapdoor (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Special (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Monster (4 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 4, true); // Door closed (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Door open (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Merchant (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Inn (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Chest closed (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Exit (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Chest open (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Pile (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Person (1 frame) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 1, true); // Goto point (7 frames) ReadAndAddGraphics(1, 16, 16, GraphicFormat.Palette5Bit, 7, true); graphics[type] = automapGraphics; } else { LoadGraphics(type); } } }