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); }
public static Graphic Concat(params Graphic[] graphics) { var concatGraphic = new Graphic(graphics.Sum(g => g.Width), graphics.Max(g => g.Height), 0); uint x = 0; foreach (var graphic in graphics) { concatGraphic.AddOverlay(x, 0, graphic, false); x += (uint)graphic.Width; } return(concatGraphic); }
public static List <Graphic> Create() { // This is used by the healing animation (falling stars) // and the magic item animation (blinking stars). // There are 3 frames. byte[] redStarFrameData = new byte[] { // Transparency: 0 // Red: 20 (CC4433) // Orange: 21 (EE6633) // Yellow: 16 (FFCC00) // White: 1 (EEDDCC) // ----------------------- // 1st frame: Big star 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 20, 16, 20, 0, 0, 20, 21, 16, 1, 16, 21, 20, 0, 0, 20, 16, 20, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, // 2nd frame: Small star 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 20, 21, 16, 21, 20, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3rd frame: Single orange pixel 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Graphic GetRedStarFrame(int frame) { return(new Graphic { Width = 7, Height = 7, Data = redStarFrameData.Skip(frame * 49).Take(49).ToArray(), IndexedGraphic = true }); } Graphic CreateBlinkingStars() { var stars = new List <Star>(); var addAmountsPerFrame = new int[] { 1, 1, 0, 1, 0, 0, 0, 0 }; var random = new Random(); // always use a new random to produce the same effect var animation = new Graphic(8 * 16, 16, 0); // 11 frames with 16x16 for (int i = 0; i < 8; ++i) // 8 frames in total { // in each frame we have several stars in specific states (star frame) var frame = new Graphic(16, 16, 0); // first update existing stars for (int s = stars.Count - 1; s >= 0; --s) { var star = stars[s]; if (++star.Frame == 5) { stars.RemoveAt(s); } else { frame.AddOverlay((uint)star.Position.X, (uint)star.Position.Y, GetRedStarFrame(star.Frame > 1 ? star.Frame - 2 : 2 - star.Frame)); } } // then add new stars for (int a = 0; a < addAmountsPerFrame[i]; ++a) { var star = new Star { Position = new Position((int)random.Next() % 10, (int)random.Next() % 10), Frame = 0 }; stars.Add(star); frame.AddOverlay((uint)star.Position.X, (uint)star.Position.Y, GetRedStarFrame(0)); } animation.AddOverlay((uint)i * 16, 0, frame); } return(animation); } // See UIElementGraphic return(new List <Graphic> { // Small vertical scrollbar GraphicBuilder.Create(6, 28) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 4, 1), 30) .AddColoredArea(new Rect(5, 0, 1, 1), 28) .AddColoredArea(new Rect(0, 1, 1, 25), 30) .AddColoredArea(new Rect(1, 1, 4, 25), 29) .AddColoredArea(new Rect(5, 1, 1, 25), 27) .AddColoredArea(new Rect(0, 26, 1, 1), 28) .AddColoredArea(new Rect(1, 26, 5, 1), 27) .AddColoredArea(new Rect(0, 27, 6, 1), 26) .Build(), // Small vertical scrollbar highlighted GraphicBuilder.Create(6, 28) .AddColoredArea(new Rect(0, 0, 5, 1), 31) .AddColoredArea(new Rect(5, 0, 1, 1), 29) .AddColoredArea(new Rect(0, 1, 1, 25), 31) .AddColoredArea(new Rect(1, 1, 4, 25), 30) .AddColoredArea(new Rect(5, 1, 1, 25), 28) .AddColoredArea(new Rect(0, 26, 1, 1), 29) .AddColoredArea(new Rect(1, 26, 5, 1), 28) .AddColoredArea(new Rect(0, 27, 6, 1), 26) .Build(), // Large vertical scrollbar GraphicBuilder.Create(6, 57) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 4, 1), 30) .AddColoredArea(new Rect(5, 0, 1, 1), 28) .AddColoredArea(new Rect(0, 1, 1, 54), 30) .AddColoredArea(new Rect(1, 1, 4, 54), 29) .AddColoredArea(new Rect(5, 1, 1, 54), 27) .AddColoredArea(new Rect(0, 55, 1, 1), 28) .AddColoredArea(new Rect(1, 55, 5, 1), 27) .AddColoredArea(new Rect(0, 56, 6, 1), 26) .Build(), // Large vertical scrollbar highlighted GraphicBuilder.Create(6, 57) .AddColoredArea(new Rect(0, 0, 5, 1), 31) .AddColoredArea(new Rect(5, 0, 1, 1), 29) .AddColoredArea(new Rect(0, 1, 1, 54), 31) .AddColoredArea(new Rect(1, 1, 4, 54), 30) .AddColoredArea(new Rect(5, 1, 1, 54), 28) .AddColoredArea(new Rect(0, 55, 1, 1), 29) .AddColoredArea(new Rect(1, 55, 5, 1), 28) .AddColoredArea(new Rect(0, 56, 6, 1), 26) .Build(), // Small vertical scrollbar background GraphicBuilder.Create(6, 53) .AddColoredArea(new Rect(1, 1, 5, 52), 27) .AddColoredArea(new Rect(0, 1, 1, 52), 26) .AddColoredArea(new Rect(0, 0, 6, 1), 26) .Build(), // Small vertical scrollbar disabled GraphicBuilder.Create(6, 53) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 4, 1), 30) .AddColoredArea(new Rect(5, 0, 1, 1), 32) .AddColoredArea(new Rect(0, 1, 1, 51), 30) .AddColoredArea(new Rect(1, 1, 4, 51), 28) .AddColoredArea(new Rect(5, 1, 1, 51), 26) .AddColoredArea(new Rect(0, 52, 1, 1), 32) .AddColoredArea(new Rect(1, 52, 5, 1), 26) .Build(), // Large vertical scrollbar background GraphicBuilder.Create(6, 112) .AddColoredArea(new Rect(1, 1, 5, 111), 27) .AddColoredArea(new Rect(0, 1, 1, 111), 26) .AddColoredArea(new Rect(0, 0, 6, 1), 26) .Build(), // Large vertical scrollbar disabled GraphicBuilder.Create(6, 112) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 4, 1), 30) .AddColoredArea(new Rect(5, 0, 1, 1), 32) .AddColoredArea(new Rect(0, 1, 1, 110), 30) .AddColoredArea(new Rect(1, 1, 4, 110), 28) .AddColoredArea(new Rect(5, 1, 1, 110), 26) .AddColoredArea(new Rect(0, 111, 1, 1), 32) .AddColoredArea(new Rect(1, 111, 5, 1), 26) .Build(), // Item slot background new Graphic(16, 24, 27), // Item slot disabled GraphicBuilder.Create(16, 24) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 14, 1), 30) .AddColoredArea(new Rect(15, 0, 1, 1), 32) .AddColoredArea(new Rect(0, 1, 1, 22), 30) .AddColoredArea(new Rect(1, 1, 14, 22), 28) .AddColoredArea(new Rect(15, 1, 1, 22), 26) .AddColoredArea(new Rect(0, 23, 1, 1), 32) .AddColoredArea(new Rect(1, 23, 15, 1), 26) .Build(), // Portrait background Graphic.CreateGradient(32, 34, 4, 2, 8, 23), // Thin portrait border Graphic.FromIndexedData(32, 1, new byte[32] { 28, 28, 28, 28, 27, 28, 27, 28, 27, 28, 27, 28, 27, 28, 27, 28, 28, 27, 28, 27, 28, 27, 28, 27, 28, 27, 28, 27, 28, 28, 28, 28 }), // Map disable overlay (UI palette-> 32 = black, 0 = transparent) Graphic.FromIndexedData(320, 144, Enumerable.Range(0, 320 * 144).Select(i => (byte)((i + i / 320) % 2 == 0 ? 0 : 32)).ToArray()), // Ambermoon info box (shown over the map when opening option menu) GraphicBuilder.Create(128, 19) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 126, 1), 30) .AddColoredArea(new Rect(127, 0, 1, 1), 27) .AddColoredArea(new Rect(0, 1, 1, 17), 30) .AddColoredArea(new Rect(1, 1, 126, 17), 28) .AddColoredArea(new Rect(127, 1, 1, 17), 26) .AddColoredArea(new Rect(0, 18, 1, 1), 27) .AddColoredArea(new Rect(1, 18, 127, 1), 26) .Build(), // Bigger info box GraphicBuilder.Create(144, 26) .AddColoredArea(new Rect(0, 0, 1, 1), 31) .AddColoredArea(new Rect(1, 0, 142, 1), 30) .AddColoredArea(new Rect(143, 0, 1, 1), 27) .AddColoredArea(new Rect(0, 1, 1, 24), 30) .AddColoredArea(new Rect(1, 1, 142, 24), 28) .AddColoredArea(new Rect(143, 1, 1, 24), 26) .AddColoredArea(new Rect(0, 25, 1, 1), 27) .AddColoredArea(new Rect(1, 25, 143, 1), 26) .Build(), // BattleFieldYellowBorder GraphicBuilder.Create(16, 13) .AddColoredArea(new Rect(0, 0, 16, 1), Color.ActivePartyMember) .AddColoredArea(new Rect(0, 1, 1, 11), Color.ActivePartyMember) .AddColoredArea(new Rect(15, 1, 1, 11), Color.ActivePartyMember) .AddColoredArea(new Rect(0, 12, 16, 1), Color.ActivePartyMember) .Build(), // BattleFieldOrangeBorder GraphicBuilder.Create(16, 13) .AddColoredArea(new Rect(0, 0, 16, 1), Color.LightRed) .AddColoredArea(new Rect(0, 1, 1, 11), Color.LightRed) .AddColoredArea(new Rect(15, 1, 1, 11), Color.LightRed) .AddColoredArea(new Rect(0, 12, 16, 1), Color.LightRed) .Build(), // BattleFieldGreenHighlight GraphicBuilder.Create(16, 13) .AddColoredArea(new Rect(1, 1, 14, 11), Color.LightGreen) .Build(), // HealingStarAnimation (3 frames of a redish star) Graphic.FromIndexedData(7 * 3, 7, redStarFrameData), // BattleFieldBlockedMovementCursor Graphic.FromIndexedData(14, 11, new byte[14 * 11] { // Transparency: 0 // Red: 19 (881122) // ----------------------- 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), // ItemMagicAnimation CreateBlinkingStars(), // BrokenItemOverlay Graphic.FromIndexedData(16, 16, new byte[16 * 16] { // Transparency: 0 // Dark gray: 26 (222222) // ----------------------- 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 0, 0, 0, 0, 0, 0, 26, 0, 0, 26, 0, 0, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 0, 0, 0, 26, 26, 0, 0, 0, 0, 26, 0, 0, 26, 26, 26, 26, 26, 26, 0, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 26, 26, 26, 26, 26, 0, 0, 0, 26, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 0, 26, 0, 0, 26, 0, 0, 0, 0, }), // AutomapWallFrames Graphic.Concat ( // Map background: 6 // Wall color: 7 // ----------------------- // End pieces Graphic.FromIndexedData(32, 8, new byte[32 * 8] { // top open right open bottom open left open 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, }), // Corners Graphic.FromIndexedData(32, 8, new byte[32 * 8] { // b+r open b+l open // t+r open t+l open 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, }), // T-crossings Graphic.FromIndexedData(32, 8, new byte[32 * 8] { // t+l+r open t+b+r open b+l+r open t+b+l open 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, }), // crossing, vertical and horizontal piece and single closed tile Graphic.FromIndexedData(32, 8, new byte[32 * 8] { // all open t+b open l+r open Closed 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, }) ), // FakeWallOverlay Graphic.FromIndexedData(8, 8, new byte[8 * 8] { 6, 0, 6, 0, 6, 0, 6, 0, 0, 6, 0, 6, 0, 6, 0, 6, 6, 0, 6, 0, 6, 0, 6, 0, 0, 6, 0, 6, 0, 6, 0, 6, 6, 0, 6, 0, 6, 0, 6, 0, 0, 6, 0, 6, 0, 6, 0, 6, 6, 0, 6, 0, 6, 0, 6, 0, 0, 6, 0, 6, 0, 6, 0, 6, }) }); }
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)); }
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 }
public void ReadLabdata(Labdata labdata, IDataReader dataReader, IGameData gameData) { labdata.WallHeight = dataReader.ReadWord(); labdata.CombatBackground = dataReader.ReadWord() & 0x0fu; labdata.CeilingColorIndex = dataReader.ReadByte(); labdata.FloorColorIndex = dataReader.ReadByte(); // 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. // To be more precisely if the texture index (ceiling and also floor) is // 0, the color index is used to draw instead. For example the town of // S'Angrila doesn't use a floor texture but only a color. uint ceilingTextureIndex = dataReader.ReadByte(); uint floorTextureIndex = dataReader.ReadByte(); labdata.Objects.Clear(); int numObjects = dataReader.ReadWord(); var objects = new List <Tuple <ushort, List <Tuple <short, short, short, int> > > >(numObjects); for (int i = 0; i < numObjects; ++i) { var obj = Tuple.Create(dataReader.ReadWord(), new List <Tuple <short, short, short, 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( (short)dataReader.ReadWord(), (short)dataReader.ReadWord(), (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 { Flags = (Tileset.TileFlags)dataReader.ReadDword(), TextureIndex = dataReader.ReadWord(), NumAnimationFrames = dataReader.ReadByte(), ColorIndex = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte(), MappedTextureWidth = dataReader.ReadWord(), MappedTextureHeight = dataReader.ReadWord() }; labdata.ObjectInfos.Add(objectInfo); } 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 { AutomapType = (AutomapType)obj.Item1, SubObjects = subObjects }); } labdata.Walls.Clear(); int numWalls = dataReader.ReadWord(); for (int i = 0; i < numWalls; ++i) { var wallData = new Labdata.WallData { Flags = (Tileset.TileFlags)dataReader.ReadDword(), TextureIndex = dataReader.ReadByte(), AutomapType = (AutomapType)dataReader.ReadByte(), ColorIndex = 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 { Blend = dataReader.ReadByte() != 0, TextureIndex = dataReader.ReadByte(), PositionX = dataReader.ReadByte(), PositionY = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte() }; } } labdata.Walls.Add(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, true); } if (ceilingTextureIndex != 0) { labdata.CeilingGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)ceilingTextureIndex], 64, 64, false, false, true); } 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) { if (objectInfo.NumAnimationFrames == 1) { labdata.ObjectGraphics.Add(ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true, true)); } else { var compoundGraphic = new Graphic((int)objectInfo.NumAnimationFrames * (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, 0); for (uint i = 0; i < objectInfo.NumAnimationFrames; ++i) { var partialGraphic = ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true, i == 0); compoundGraphic.AddOverlay(i * objectInfo.TextureWidth, 0u, partialGraphic, false); } labdata.ObjectGraphics.Add(compoundGraphic); } } 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(Tileset.TileFlags.Transparency), true, 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, true), overlay.Blend); } } ++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); } } }