From 36b254bc46e2bb21f6f1f0b37a1969c776e27a0b Mon Sep 17 00:00:00 2001 From: MainMemory Date: Thu, 30 Jan 2014 17:31:06 -0600 Subject: [PATCH] Added default level file, completed level selection dialog --- BlupiEdit/BlupiEdit.csproj | 2 + BlupiEdit/LevelData.cs | 843 ++++++++++----------- BlupiEdit/LevelSelectForm.Designer.cs | 128 +++- BlupiEdit/LevelSelectForm.cs | 111 ++- BlupiEdit/MainForm.cs | 66 +- BlupiEdit/Properties/Resources.Designer.cs | 51 +- BlupiEdit/Properties/Resources.resx | 13 +- BlupiEdit/Resources/DefaultLevel.blp | Bin 0 -> 50468 bytes 8 files changed, 709 insertions(+), 505 deletions(-) create mode 100644 BlupiEdit/Resources/DefaultLevel.blp diff --git a/BlupiEdit/BlupiEdit.csproj b/BlupiEdit/BlupiEdit.csproj index e6f115b..6664eb1 100644 --- a/BlupiEdit/BlupiEdit.csproj +++ b/BlupiEdit/BlupiEdit.csproj @@ -68,11 +68,13 @@ True Resources.resx + True SettingsSingleFileGenerator Settings.Designer.cs + True Settings.settings diff --git a/BlupiEdit/LevelData.cs b/BlupiEdit/LevelData.cs index ca5eeb3..fed1403 100644 --- a/BlupiEdit/LevelData.cs +++ b/BlupiEdit/LevelData.cs @@ -7,450 +7,445 @@ using System.Text; namespace BlupiEdit { - public class LevelItem - { - public ItemTypes Type { get; set; } - [DisplayName("A to B time")] - public ushort ABTime { get; set; } - [DisplayName("A to B speed")] - public int ABSpeed - { - get - { - return (int)Math.Round(LevelData.Distance(PointA, PointB) / ABTime); - } - set - { - ABTime = (ushort)Math.Round(LevelData.Distance(PointA, PointB) / value); - } - } - [DisplayName("B to A time")] - public ushort BATime { get; set; } - [DisplayName("B to A speed")] - public int BASpeed - { - get - { - return (int)Math.Round(LevelData.Distance(PointB, PointA) / BATime); - } - set - { - BATime = (ushort)Math.Round(LevelData.Distance(PointB, PointA) / value); - } - } - [DisplayName("A Wait")] - public ushort AWait { get; set; } - [DisplayName("B Wait")] - public ushort BWait { get; set; } - public ushort field_A { get; set; } - [DisplayName("Point A")] - public Point PointA { get; set; } - [DisplayName("Point B")] - public Point PointB { get; set; } - [DisplayName("Point C?")] - public Point PointC { get; set; } - public ushort field_24 { get; set; } - public ushort field_26 { get; set; } - public ushort field_28 { get; set; } - [DisplayName("Art File")] - public TileTypes ArtFile { get; set; } - public ushort Tile { get; set; } - public ushort field_2E { get; set; } + public class LevelItem + { + public ItemTypes Type { get; set; } + [DisplayName("A to B time")] + public ushort ABTime { get; set; } + [DisplayName("A to B speed")] + public int ABSpeed + { + get + { + return (int)Math.Round(LevelData.Distance(PointA, PointB) / ABTime); + } + set + { + ABTime = (ushort)Math.Round(LevelData.Distance(PointA, PointB) / value); + } + } + [DisplayName("B to A time")] + public ushort BATime { get; set; } + [DisplayName("B to A speed")] + public int BASpeed + { + get + { + return (int)Math.Round(LevelData.Distance(PointB, PointA) / BATime); + } + set + { + BATime = (ushort)Math.Round(LevelData.Distance(PointB, PointA) / value); + } + } + [DisplayName("A Wait")] + public ushort AWait { get; set; } + [DisplayName("B Wait")] + public ushort BWait { get; set; } + public ushort field_A { get; set; } + [DisplayName("Point A")] + public Point PointA { get; set; } + [DisplayName("Point B")] + public Point PointB { get; set; } + [DisplayName("Point C?")] + public Point PointC { get; set; } + public ushort field_24 { get; set; } + public ushort field_26 { get; set; } + public ushort field_28 { get; set; } + [DisplayName("Art File")] + public TileTypes ArtFile { get; set; } + public ushort Tile { get; set; } + public ushort field_2E { get; set; } - public LevelItem(BinaryReader reader) - { - Type = (ItemTypes)reader.ReadUInt16(); - ABTime = reader.ReadUInt16(); - BATime = reader.ReadUInt16(); - AWait = reader.ReadUInt16(); - BWait = reader.ReadUInt16(); - field_A = reader.ReadUInt16(); - PointA = new Point(reader.ReadInt32(), reader.ReadInt32()); - PointB = new Point(reader.ReadInt32(), reader.ReadInt32()); - PointC = new Point(reader.ReadInt32(), reader.ReadInt32()); - field_24 = reader.ReadUInt16(); - field_26 = reader.ReadUInt16(); - field_28 = reader.ReadUInt16(); - ArtFile = (TileTypes)reader.ReadUInt16(); - Tile = reader.ReadUInt16(); - field_2E = reader.ReadUInt16(); - } + public LevelItem(BinaryReader reader) + { + Type = (ItemTypes)reader.ReadUInt16(); + ABTime = reader.ReadUInt16(); + BATime = reader.ReadUInt16(); + AWait = reader.ReadUInt16(); + BWait = reader.ReadUInt16(); + field_A = reader.ReadUInt16(); + PointA = new Point(reader.ReadInt32(), reader.ReadInt32()); + PointB = new Point(reader.ReadInt32(), reader.ReadInt32()); + PointC = new Point(reader.ReadInt32(), reader.ReadInt32()); + field_24 = reader.ReadUInt16(); + field_26 = reader.ReadUInt16(); + field_28 = reader.ReadUInt16(); + ArtFile = (TileTypes)reader.ReadUInt16(); + Tile = reader.ReadUInt16(); + field_2E = reader.ReadUInt16(); + } - public void Write(BinaryWriter writer) - { - writer.Write((ushort)Type); - writer.Write(ABTime); - writer.Write(BATime); - writer.Write(AWait); - writer.Write(BWait); - writer.Write(field_A); - writer.Write(PointA.X); writer.Write(PointA.Y); - writer.Write(PointB.X); writer.Write(PointB.Y); - writer.Write(PointC.X); writer.Write(PointC.Y); - writer.Write(field_24); - writer.Write(field_26); - writer.Write(field_28); - writer.Write((ushort)ArtFile); - writer.Write(Tile); - writer.Write(field_2E); - } - } + public void Write(BinaryWriter writer) + { + writer.Write((ushort)Type); + writer.Write(ABTime); + writer.Write(BATime); + writer.Write(AWait); + writer.Write(BWait); + writer.Write(field_A); + writer.Write(PointA.X); writer.Write(PointA.Y); + writer.Write(PointB.X); writer.Write(PointB.Y); + writer.Write(PointC.X); writer.Write(PointC.Y); + writer.Write(field_24); + writer.Write(field_26); + writer.Write(field_28); + writer.Write((ushort)ArtFile); + writer.Write(Tile); + writer.Write(field_2E); + } + } - public class TileInfo - { - public Rectangle Location { get; set; } - public Point Offset { get; set; } + public class TileInfo + { + public Rectangle Location { get; set; } + public Point Offset { get; set; } - public TileInfo(BinaryReader reader) - { - Point loc = new Point(reader.ReadInt16(), reader.ReadInt16()); - Offset = new Point(reader.ReadInt16(), reader.ReadInt16()); - Location = new Rectangle(loc, new Size(reader.ReadInt16(), reader.ReadInt16())); - } + public TileInfo(BinaryReader reader) + { + Point loc = new Point(reader.ReadInt16(), reader.ReadInt16()); + Offset = new Point(reader.ReadInt16(), reader.ReadInt16()); + Location = new Rectangle(loc, new Size(reader.ReadInt16(), reader.ReadInt16())); + } - public static TileInfo[] Read(Stream stream) - { - BinaryReader reader = new BinaryReader(stream); - TileInfo[] result = new TileInfo[reader.ReadInt16()]; - for (int i = 0; i < result.Length; i++) - result[i] = new TileInfo(reader); - return result; - } - } + public static TileInfo[] Read(Stream stream) + { + BinaryReader reader = new BinaryReader(stream); + TileInfo[] result = new TileInfo[reader.ReadInt16()]; + for (int i = 0; i < result.Length; i++) + result[i] = new TileInfo(reader); + return result; + } + } - public class LevelData - { - #region Instance Members - public byte MajorVersion { get; set; } - public byte MinorVersion { get; set; } - public bool HorizontalScroll { get; set; } - public bool VerticalScroll { get; set; } - public short Music { get; set; } - public short Background { get; set; } - public Point[] StartPositions { get; private set; } - public bool[] StartDirections { get; private set; } - public string LevelName { get; set; } - public short[,] Tiles { get; private set; } - public short[,] Tiles2 { get; private set; } - public List Items { get; private set; } + public class LevelData + { + #region Instance Members + public byte MajorVersion { get; set; } + public byte MinorVersion { get; set; } + public bool HorizontalScroll { get; set; } + public bool VerticalScroll { get; set; } + public short Music { get; set; } + public short Background { get; set; } + public Point[] StartPositions { get; private set; } + public bool[] StartDirections { get; private set; } + public string LevelName { get; set; } + public short[,] Tiles { get; private set; } + public short[,] Tiles2 { get; private set; } + public List Items { get; private set; } - public LevelData(string filename) - { - using (FileStream fs = File.OpenRead(filename)) - using (BinaryReader reader = new BinaryReader(fs, Encoding.ASCII)) - { - MajorVersion = reader.ReadByte(); - MinorVersion = reader.ReadByte(); - fs.Seek(0xD4, SeekOrigin.Begin); - HorizontalScroll = reader.ReadInt32() == 100; - VerticalScroll = reader.ReadInt32() == 100; - fs.Seek(2, SeekOrigin.Current); - Music = reader.ReadInt16(); - Background = reader.ReadInt16(); - fs.Seek(0x148, SeekOrigin.Begin); - StartPositions = new Point[4]; - for (int i = 0; i < 4; i++) - StartPositions[i] = new Point(reader.ReadInt32(), reader.ReadInt32()); - StartDirections = new bool[4]; - for (int i = 0; i < 4; i++) - StartDirections[i] = reader.ReadInt32() != 0; - LevelName = reader.ReadString(40); - fs.Seek(0x364, SeekOrigin.Begin); - Tiles = new short[100, 100]; - for (int x = 0; x < 100; x++) - for (int y = 0; y < 100; y++) - Tiles[x, y] = reader.ReadInt16(); - Tiles2 = new short[100, 100]; - for (int x = 0; x < 100; x++) - for (int y = 0; y < 100; y++) - Tiles2[x, y] = reader.ReadInt16(); - Items = new List(); - for (int i = 0; i < 200; i++) - { - LevelItem item = new LevelItem(reader); - if (item.Type != ItemTypes.None) - Items.Add(item); - } - } - } + public LevelData() + { - public void Save(string filename) - { - using (FileStream fs = File.Create(filename)) - using (BinaryWriter writer = new BinaryWriter(fs)) - { - writer.Write(MajorVersion); - writer.Write(MinorVersion); - writer.Seek(0xD4, SeekOrigin.Begin); - writer.Write(HorizontalScroll ? 100 : 0); - writer.Write(VerticalScroll ? 100 : 0); - writer.Seek(2, SeekOrigin.Current); - writer.Write(Music); - writer.Write(Background); - fs.Seek(0x148, SeekOrigin.Begin); - for (int i = 0; i < 4; i++) - { - writer.Write(StartPositions[i].X); - writer.Write(StartPositions[i].Y); - } - for (int i = 0; i < 4; i++) - writer.Write(StartDirections[i] ? 1 : 0); - writer.WriteString(LevelName, 40); - fs.Seek(0x364, SeekOrigin.Begin); - for (int x = 0; x < 100; x++) - for (int y = 0; y < 100; y++) - writer.Write(Tiles[x, y]); - for (int x = 0; x < 100; x++) - for (int y = 0; y < 100; y++) - writer.Write(Tiles2[x, y]); - for (int i = 0; i < Items.Count; i++) - Items[i].Write(writer); - if (Items.Count < 200) - writer.Write(new byte[0x30 * (200 - Items.Count)]); - } - } - #endregion - #region Static Members - public const int LevelSize = 100; - public const int GridSize = 64; - public const int PixelSize = LevelSize * GridSize; - public static bool IsBlupi2 { get; private set; } - public static string CurrentLevelPath { get; private set; } - public static LevelData CurrentLevel { get; private set; } - public static TileInfo[] BlupiTiles { get; private set; } - public static TileInfo[] ObjectTiles { get; private set; } - public static TileInfo[] ElementTiles { get; private set; } - public static TileInfo[] ExploTiles { get; private set; } - public static Dictionary TileImages { get; private set; } + } - public static void LoadGame(string filename) - { - IsBlupi2 = true; - Environment.CurrentDirectory = Path.GetDirectoryName(Path.GetFullPath(filename)); - using (FileStream fs = File.OpenRead(filename)) - { - if (IsBlupi2) - { - fs.Seek(0x862F0, SeekOrigin.Begin); - BlupiTiles = TileInfo.Read(fs); - fs.Seek(0x872B8, SeekOrigin.Begin); - ObjectTiles = TileInfo.Read(fs); - fs.Seek(0x88768, SeekOrigin.Begin); - ElementTiles = TileInfo.Read(fs); - fs.Seek(0x894F8, SeekOrigin.Begin); - ExploTiles = TileInfo.Read(fs); - } - TileImages = new Dictionary(); - List tmp = new List(BlupiTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE08\blupi000.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in BlupiTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Blupi000, tmp.ToArray()); - tmp = new List(BlupiTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE08\blupi001.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in BlupiTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Blupi001, tmp.ToArray()); - tmp = new List(BlupiTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE08\blupi002.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in BlupiTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Blupi002, tmp.ToArray()); - tmp = new List(BlupiTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE08\blupi003.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in BlupiTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Blupi003, tmp.ToArray()); - tmp = new List(ObjectTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE16\object.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in ObjectTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Object, tmp.ToArray()); - tmp = new List(ElementTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE16\element.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in ElementTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Element, tmp.ToArray()); - tmp = new List(ExploTiles.Length); - using (Bitmap bmp = new Bitmap(@"IMAGE16\explo.blp")) - { - bmp.MakeTransparent(Color.Blue); - foreach (TileInfo item in ExploTiles) - tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); - } - TileImages.Add(TileTypes.Explo, tmp.ToArray()); - } - } + public LevelData(string filename) + { + Stream str; + if (File.Exists(filename)) + str = File.OpenRead(filename); + else + str = new MemoryStream(Properties.Resources.DefaultLevel, false); + using (str) + using (BinaryReader reader = new BinaryReader(str)) + { + MajorVersion = reader.ReadByte(); + MinorVersion = reader.ReadByte(); + str.Seek(0xD4, SeekOrigin.Begin); + HorizontalScroll = reader.ReadInt32() == 100; + VerticalScroll = reader.ReadInt32() == 100; + str.Seek(2, SeekOrigin.Current); + Music = reader.ReadInt16(); + Background = reader.ReadInt16(); + str.Seek(0x148, SeekOrigin.Begin); + StartPositions = new Point[4]; + for (int i = 0; i < 4; i++) + StartPositions[i] = new Point(reader.ReadInt32(), reader.ReadInt32()); + StartDirections = new bool[4]; + for (int i = 0; i < 4; i++) + StartDirections[i] = reader.ReadInt32() != 0; + LevelName = reader.ReadString(40); + str.Seek(0x364, SeekOrigin.Begin); + Tiles = new short[100, 100]; + for (int x = 0; x < 100; x++) + for (int y = 0; y < 100; y++) + Tiles[x, y] = reader.ReadInt16(); + Tiles2 = new short[100, 100]; + for (int x = 0; x < 100; x++) + for (int y = 0; y < 100; y++) + Tiles2[x, y] = reader.ReadInt16(); + Items = new List(); + for (int i = 0; i < 200; i++) + { + LevelItem item = new LevelItem(reader); + if (item.Type != ItemTypes.None) + Items.Add(item); + } + } + } - public static void LoadLevel(int userid, int levelnum, bool userlevel) - { - CurrentLevelPath = GetLevelName(userid, levelnum, userlevel); - CurrentLevel = new LevelData(CurrentLevelPath); - } + public void Save(string filename) + { + using (FileStream fs = File.Create(filename)) + using (BinaryWriter writer = new BinaryWriter(fs)) + { + writer.Write(MajorVersion); + writer.Write(MinorVersion); + writer.Seek(0xD4, SeekOrigin.Begin); + writer.Write(HorizontalScroll ? 100 : 0); + writer.Write(VerticalScroll ? 100 : 0); + writer.Seek(2, SeekOrigin.Current); + writer.Write(Music); + writer.Write(Background); + fs.Seek(0x148, SeekOrigin.Begin); + for (int i = 0; i < 4; i++) + { + writer.Write(StartPositions[i].X); + writer.Write(StartPositions[i].Y); + } + for (int i = 0; i < 4; i++) + writer.Write(StartDirections[i] ? 1 : 0); + writer.WriteString(LevelName, 40); + fs.Seek(0x364, SeekOrigin.Begin); + for (int x = 0; x < 100; x++) + for (int y = 0; y < 100; y++) + writer.Write(Tiles[x, y]); + for (int x = 0; x < 100; x++) + for (int y = 0; y < 100; y++) + writer.Write(Tiles2[x, y]); + for (int i = 0; i < Items.Count; i++) + Items[i].Write(writer); + if (Items.Count < 200) + writer.Write(new byte[0x30 * (200 - Items.Count)]); + } + } + #endregion + #region Static Members + public const int LevelSize = 100; + public const int GridSize = 64; + public const int PixelSize = LevelSize * GridSize; + public static bool IsBlupi2 { get; private set; } + public static string CurrentLevelPath { get; private set; } + public static LevelData CurrentLevel { get; private set; } + public static TileInfo[] BlupiTiles { get; private set; } + public static TileInfo[] ObjectTiles { get; private set; } + public static TileInfo[] ElementTiles { get; private set; } + public static TileInfo[] ExploTiles { get; private set; } + public static Dictionary TileImages { get; private set; } - public static string GetLevelName(int userid, int levelnum, bool userlevel) - { - if (userlevel) - return string.Format("data\\u{0:000}-{1:000}.blp", userid, levelnum); - else - return string.Format("data\\world{0:000}.blp", levelnum); - } + public static void LoadGame(string filename) + { + IsBlupi2 = true; + Environment.CurrentDirectory = Path.GetDirectoryName(Path.GetFullPath(filename)); + using (FileStream fs = File.OpenRead(filename)) + { + if (IsBlupi2) + { + fs.Seek(0x862F0, SeekOrigin.Begin); + BlupiTiles = TileInfo.Read(fs); + fs.Seek(0x872B8, SeekOrigin.Begin); + ObjectTiles = TileInfo.Read(fs); + fs.Seek(0x88768, SeekOrigin.Begin); + ElementTiles = TileInfo.Read(fs); + fs.Seek(0x894F8, SeekOrigin.Begin); + ExploTiles = TileInfo.Read(fs); + } + TileImages = new Dictionary(); + List tmp = new List(BlupiTiles.Length); + using (Bitmap bmp = LoadImage("blupi000")) + foreach (TileInfo item in BlupiTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Blupi000, tmp.ToArray()); + tmp = new List(BlupiTiles.Length); + using (Bitmap bmp = LoadImage("blupi001")) + foreach (TileInfo item in BlupiTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Blupi001, tmp.ToArray()); + tmp = new List(BlupiTiles.Length); + using (Bitmap bmp = LoadImage("blupi002")) + foreach (TileInfo item in BlupiTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Blupi002, tmp.ToArray()); + tmp = new List(BlupiTiles.Length); + using (Bitmap bmp = LoadImage("blupi003")) + foreach (TileInfo item in BlupiTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Blupi003, tmp.ToArray()); + tmp = new List(ObjectTiles.Length); + using (Bitmap bmp = LoadImage("object")) + foreach (TileInfo item in ObjectTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Object, tmp.ToArray()); + tmp = new List(ElementTiles.Length); + using (Bitmap bmp = LoadImage("element")) + foreach (TileInfo item in ElementTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Element, tmp.ToArray()); + tmp = new List(ExploTiles.Length); + using (Bitmap bmp = LoadImage("explo")) + foreach (TileInfo item in ExploTiles) + tmp.Add(new Sprite(bmp.Clone(item.Location, bmp.PixelFormat), item.Offset)); + TileImages.Add(TileTypes.Explo, tmp.ToArray()); + } + } - public static void SaveLevel() - { - CurrentLevel.Save(CurrentLevelPath); - } + public static void LoadLevel(int userid, int levelnum) + { + CurrentLevelPath = GetLevelName(userid, levelnum); + CurrentLevel = new LevelData(CurrentLevelPath); + } - public static double Distance(Point p1, Point p2) - { - return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); - } + public static string GetLevelName(int userid, int levelnum) + { + if (userid != 0) + return string.Format("data\\u{0:000}-{1:000}.blp", userid, levelnum); + else + return string.Format("data\\world{0:000}.blp", levelnum); + } - public static Bitmap LoadImage(string filename) - { - if (File.Exists(string.Format(@"IMAGE16\{0}.blp", filename))) - return new Bitmap(string.Format(@"IMAGE16\{0}.blp", filename)); - else - return new Bitmap(string.Format(@"IMAGE08\{0}.blp", filename)); - } - #endregion - } + public static void SaveLevel() + { + CurrentLevel.Save(CurrentLevelPath); + } - public enum ItemTypes : ushort - { - None = 0, - Lift = 1, - Bomb = 2, - HangingBomb = 3, - Bulldozer = 4, - TreasureChest = 5, - Egg = 6, - Goal = 7, - Explosion1 = 8, - Explosion2 = 9, - Explosion3 = 10, - Explosion4 = 11, - WoodenCase = 12, - Helicopter = 13, - Splash = 14, - Bubbles = 15, - MovingBomb = 16, - Fish = 17, - Jeep = 19, - Bird = 20, - Key = 21, - Skateboard = 24, - Shield = 25, - Lollypop = 26, - Sparkles = 27, - GlueTank = 28, - GlueSupply = 29, - InvisibilityPotion = 30, - RechargingDevice = 31, - HeliportedEnemy = 32, - MotorizedEnemy = 33, - StuckEnemy = 34, - Inverter = 40, - Wasp = 44, - Hovercraft = 46, - LiftWithConveyerBelt = 47, - RedKey = 49, - GreenKey = 50, - BlueKey = 51, - SlimeCreature = 54, - Dynamite = 55, - HomingBomb = 96, - YellowBomb = 200, - OrangeBomb = 201, - BlueBomb = 202, - GreenBomb = 203, - } + public static double Distance(Point p1, Point p2) + { + return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); + } - public enum TileTypes : ushort - { - None = 0, - Object = 1, - Blupi000 = 2, - Explo = 9, - Element = 10, - Blupi001 = 11, - Blupi002 = 12, - Blupi003 = 13, - } + public static Bitmap LoadImage(string filename) + { + Bitmap bmp; + if (File.Exists(string.Format(@"IMAGE16\{0}.blp", filename))) + bmp = new Bitmap(string.Format(@"IMAGE16\{0}.blp", filename)); + else + bmp = new Bitmap(string.Format(@"IMAGE08\{0}.blp", filename)); + bmp.MakeTransparent(Color.Blue); + return bmp; + } - public struct Sprite - { - public Point Offset; - public Bitmap Image; - public int X { get { return Offset.X; } set { Offset.X = value; } } - public int Y { get { return Offset.Y; } set { Offset.Y = value; } } - public int Width { get { return Image.Width; } } - public int Height { get { return Image.Height; } } - public Size Size { get { return Image.Size; } } - public int Left { get { return X; } } - public int Top { get { return Y; } } - public int Right { get { return X + Width; } } - public int Bottom { get { return Y + Height; } } - public Rectangle Bounds { get { return new Rectangle(Offset, Size); } } + static readonly Encoding encoding = Encoding.GetEncoding(1252); + public static Encoding Encoding { get { return encoding; } } + #endregion + } - public Sprite(Bitmap spr, Point off) - { - Image = spr; - Offset = off; - } + public enum ItemTypes : ushort + { + None = 0, + Lift = 1, + Bomb = 2, + HangingBomb = 3, + Bulldozer = 4, + TreasureChest = 5, + Egg = 6, + Goal = 7, + Explosion1 = 8, + Explosion2 = 9, + Explosion3 = 10, + Explosion4 = 11, + WoodenCase = 12, + Helicopter = 13, + Splash = 14, + Bubbles = 15, + MovingBomb = 16, + Fish = 17, + Jeep = 19, + Bird = 20, + Key = 21, + Skateboard = 24, + Shield = 25, + Lollypop = 26, + Sparkles = 27, + GlueTank = 28, + GlueSupply = 29, + InvisibilityPotion = 30, + RechargingDevice = 31, + HeliportedEnemy = 32, + MotorizedEnemy = 33, + StuckEnemy = 34, + Inverter = 40, + Wasp = 44, + Hovercraft = 46, + LiftWithConveyerBelt = 47, + RedKey = 49, + GreenKey = 50, + BlueKey = 51, + SlimeCreature = 54, + Dynamite = 55, + HomingBomb = 96, + YellowBomb = 200, + OrangeBomb = 201, + BlueBomb = 202, + GreenBomb = 203, + } - public Sprite(Sprite sprite) - { - Image = (Bitmap)sprite.Image.Clone(); - Offset = sprite.Offset; - } - } + public enum TileTypes : ushort + { + None = 0, + Object = 1, + Blupi000 = 2, + Explo = 9, + Element = 10, + Blupi001 = 11, + Blupi002 = 12, + Blupi003 = 13, + } - public static class Extensions - { - /// - /// Reads a null-terminated ASCII string from the current stream and advances the position by bytes. - /// - /// The maximum length of the string, in bytes. - public static string ReadString(this BinaryReader br, int length) - { - byte[] buffer = br.ReadBytes(length); - for (int i = 0; i < length; i++) - if (buffer[i] == 0) - return Encoding.ASCII.GetString(buffer, 0, i); - return Encoding.ASCII.GetString(buffer); - } + public struct Sprite + { + public Point Offset; + public Bitmap Image; + public int X { get { return Offset.X; } set { Offset.X = value; } } + public int Y { get { return Offset.Y; } set { Offset.Y = value; } } + public int Width { get { return Image.Width; } } + public int Height { get { return Image.Height; } } + public Size Size { get { return Image.Size; } } + public int Left { get { return X; } } + public int Top { get { return Y; } } + public int Right { get { return X + Width; } } + public int Bottom { get { return Y + Height; } } + public Rectangle Bounds { get { return new Rectangle(Offset, Size); } } - public static void WriteString(this BinaryWriter bw, string value, int length) - { - if (value.Length > length) - value = value.Substring(0, length); - bw.Write(Encoding.ASCII.GetBytes(value)); - if (length > value.Length) - bw.Write(new byte[length - value.Length]); - } + public Sprite(Bitmap spr, Point off) + { + Image = spr; + Offset = off; + } - public static void DrawSprite(this Graphics gfx, Sprite spr, Point point) - { - gfx.DrawImage(spr.Image, point.X + spr.Offset.X, point.Y + spr.Offset.Y, spr.Width, spr.Height); - } - } + public Sprite(Sprite sprite) + { + Image = (Bitmap)sprite.Image.Clone(); + Offset = sprite.Offset; + } + } + + public static class Extensions + { + /// + /// Reads a null-terminated cp1252 string from the current stream and advances the position by bytes. + /// + /// The maximum length of the string, in bytes. + public static string ReadString(this BinaryReader br, int length) + { + byte[] buffer = br.ReadBytes(length); + for (int i = 0; i < length; i++) + if (buffer[i] == 0) + return LevelData.Encoding.GetString(buffer, 0, i); + return LevelData.Encoding.GetString(buffer); + } + + public static void WriteString(this BinaryWriter bw, string value, int length) + { + if (value.Length > length) + value = value.Substring(0, length); + bw.Write(LevelData.Encoding.GetBytes(value)); + if (length > value.Length) + bw.Write(new byte[length - value.Length]); + } + + public static void DrawSprite(this Graphics gfx, Sprite spr, Point point) + { + gfx.DrawImage(spr.Image, point.X + spr.Offset.X, point.Y + spr.Offset.Y, spr.Width, spr.Height); + } + } } \ No newline at end of file diff --git a/BlupiEdit/LevelSelectForm.Designer.cs b/BlupiEdit/LevelSelectForm.Designer.cs index 97f6315..01d4caa 100644 --- a/BlupiEdit/LevelSelectForm.Designer.cs +++ b/BlupiEdit/LevelSelectForm.Designer.cs @@ -28,22 +28,124 @@ /// private void InitializeComponent() { - this.SuspendLayout(); - // - // LevelSelectForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(284, 262); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "LevelSelectForm"; - this.Text = "LevelSelectForm"; - this.ResumeLayout(false); + this.levelSetList = new System.Windows.Forms.ListBox(); + this.levelList = new System.Windows.Forms.ListBox(); + this.cancelButton = new System.Windows.Forms.Button(); + this.openButton = new System.Windows.Forms.Button(); + this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // levelSetList + // + this.levelSetList.Items.AddRange(new object[] { + "Worlds"}); + this.levelSetList.Location = new System.Drawing.Point(12, 12); + this.levelSetList.Name = "levelSetList"; + this.levelSetList.Size = new System.Drawing.Size(120, 121); + this.levelSetList.TabIndex = 0; + this.levelSetList.SelectedIndexChanged += new System.EventHandler(this.levelSetList_SelectedIndexChanged); + // + // levelList + // + this.levelList.FormattingEnabled = true; + this.levelList.Location = new System.Drawing.Point(138, 12); + this.levelList.Name = "levelList"; + this.levelList.Size = new System.Drawing.Size(152, 173); + this.levelList.TabIndex = 1; + this.levelList.SelectedIndexChanged += new System.EventHandler(this.levelList_SelectedIndexChanged); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(215, 227); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "&Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // + // openButton + // + this.openButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.openButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.openButton.Location = new System.Drawing.Point(134, 227); + this.openButton.Name = "openButton"; + this.openButton.Size = new System.Drawing.Size(75, 23); + this.openButton.TabIndex = 3; + this.openButton.Text = "&Open"; + this.openButton.UseVisualStyleBackColor = true; + // + // numericUpDown1 + // + this.numericUpDown1.Location = new System.Drawing.Point(138, 192); + this.numericUpDown1.Maximum = new decimal(new int[] { + 399, + 0, + 0, + 0}); + this.numericUpDown1.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDown1.Name = "numericUpDown1"; + this.numericUpDown1.Size = new System.Drawing.Size(120, 20); + this.numericUpDown1.TabIndex = 5; + this.numericUpDown1.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged); + // + // pictureBox1 + // + this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBox1.Location = new System.Drawing.Point(296, 12); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(238, 238); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBox1.TabIndex = 6; + this.pictureBox1.TabStop = false; + // + // LevelSelectForm + // + this.AcceptButton = this.openButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(546, 262); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.numericUpDown1); + this.Controls.Add(this.openButton); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.levelList); + this.Controls.Add(this.levelSetList); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "LevelSelectForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "Select a level..."; + this.Load += new System.EventHandler(this.LevelSelectForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); } #endregion + + private System.Windows.Forms.ListBox levelSetList; + private System.Windows.Forms.ListBox levelList; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button openButton; + private System.Windows.Forms.NumericUpDown numericUpDown1; + private System.Windows.Forms.PictureBox pictureBox1; } } \ No newline at end of file diff --git a/BlupiEdit/LevelSelectForm.cs b/BlupiEdit/LevelSelectForm.cs index 656c7f0..de73f37 100644 --- a/BlupiEdit/LevelSelectForm.cs +++ b/BlupiEdit/LevelSelectForm.cs @@ -5,14 +5,109 @@ using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; +using System.IO; +using System.Drawing.Drawing2D; namespace BlupiEdit { - public partial class LevelSelectForm : Form - { - public LevelSelectForm() - { - InitializeComponent(); - } - } -} + public partial class LevelSelectForm : Form + { + public LevelSelectForm() + { + InitializeComponent(); + } + + List users = new List(8) { 0 }; + List levels; + + private void LevelSelectForm_Load(object sender, EventArgs e) + { + levelSetList.BeginUpdate(); + for (int i = 1; i < 9; i++) + if (File.Exists(string.Format("data\\info{0:000}.blp", i))) + { + users.Add(i); + using (FileStream str = File.OpenRead(string.Format("data\\info{0:000}.blp", i))) + using (BinaryReader r = new BinaryReader(str)) + { + str.Seek(0x16, SeekOrigin.Begin); + levelSetList.Items.Add("User " + i + " - " + r.ReadString(40)); + } + } + levelSetList.EndUpdate(); + levelSetList.SelectedIndex = 0; + } + + private void levelSetList_SelectedIndexChanged(object sender, EventArgs e) + { + int max = levelSetList.SelectedIndex == 0 ? 399 : 20; + numericUpDown1.Maximum = max; + levels = new List(); + levelList.BeginUpdate(); + levelList.Items.Clear(); + for (int i = 1; i <= max; i++) + { + string s = LevelData.GetLevelName(users[levelSetList.SelectedIndex], i); + if (File.Exists(s)) + { + levels.Add(i); + using (FileStream str = File.OpenRead(s)) + using (BinaryReader r = new BinaryReader(str)) + { + str.Seek(0x178, SeekOrigin.Begin); + string n = r.ReadString(40); + levelList.Items.Add("#" + i + (string.IsNullOrEmpty(n) ? "" : " - " + n)); + } + } + } + levelList.EndUpdate(); + } + + private void levelList_SelectedIndexChanged(object sender, EventArgs e) + { + if (levelList.SelectedIndex == -1) + pictureBox1.Image = null; + else + { + int imgsize = LevelData.GridSize * 8; + Bitmap bmp = new Bitmap(imgsize, imgsize); + Graphics gfx = Graphics.FromImage(bmp); + gfx.CompositingQuality = CompositingQuality.HighSpeed; + gfx.InterpolationMode = InterpolationMode.NearestNeighbor; + gfx.PixelOffsetMode = PixelOffsetMode.None; + gfx.SmoothingMode = SmoothingMode.None; + LevelData level = new LevelData(LevelData.GetLevelName(users[levelSetList.SelectedIndex], levels[levelList.SelectedIndex])); + int startx = level.HorizontalScroll ? Math.Max(Math.Min(level.StartPositions[0].X - (imgsize / 2), LevelData.PixelSize - imgsize), 0) : 0; + int starty = level.VerticalScroll ? Math.Max(Math.Min(level.StartPositions[0].Y - (imgsize / 2), LevelData.PixelSize - imgsize), 0) : 0; + using (Bitmap bg = LevelData.LoadImage(string.Format("decor{0:000}", level.Background))) + for (int x = -startx / 2; x < bmp.Width; x += 640) + for (int y = -starty / 2; y < bmp.Height; y += 480) + gfx.DrawImage(bg, x, y, bg.Width, bg.Height); + gfx.DrawSprite(LevelData.TileImages[TileTypes.Blupi000][level.StartDirections[0] ? 0 : 1], + level.StartPositions[0] - new Size(startx, starty)); + foreach (LevelItem item in level.Items) + gfx.DrawSprite(LevelData.TileImages[item.ArtFile][item.Tile], + item.PointA - new Size(startx, starty)); + for (int y = Math.Max(starty / LevelData.GridSize, 0); y < Math.Min((starty + imgsize), LevelData.PixelSize) / LevelData.GridSize; y++) + for (int x = Math.Max(startx / LevelData.GridSize, 0); x < Math.Min((startx + imgsize), LevelData.PixelSize) / LevelData.GridSize; x++) + if (level.Tiles[x, y] != -1) + gfx.DrawSprite(LevelData.TileImages[TileTypes.Object][level.Tiles[x, y]], + new Point(x * LevelData.GridSize - startx, y * LevelData.GridSize - starty)); + pictureBox1.Image = bmp; + numericUpDown1.Value = levels[levelList.SelectedIndex]; + } + } + + private void numericUpDown1_ValueChanged(object sender, EventArgs e) + { + if ((levelList.SelectedIndex = levels.IndexOf((int)numericUpDown1.Value)) == -1) + openButton.Text = "&New"; + else + openButton.Text = "&Open"; + } + + public int UserID { get { return users[levelSetList.SelectedIndex]; } } + + public int LevelNum { get { return (int)numericUpDown1.Value; } } + } +} \ No newline at end of file diff --git a/BlupiEdit/MainForm.cs b/BlupiEdit/MainForm.cs index 63e8130..951f249 100644 --- a/BlupiEdit/MainForm.cs +++ b/BlupiEdit/MainForm.cs @@ -9,43 +9,47 @@ using System.IO; namespace BlupiEdit { - public partial class MainForm : Form - { + public partial class MainForm : Form + { - public MainForm() - { - InitializeComponent(); - } + public MainForm() + { + InitializeComponent(); + } - private void MainForm_Load(object sender, EventArgs e) - { - if (Program.Arguments.Length > 0) - LoadGame(Program.Arguments[0]); - } + private void MainForm_Load(object sender, EventArgs e) + { + if (Program.Arguments.Length > 0) + LoadGame(Program.Arguments[0]); + } - private void MainForm_FormClosed(object sender, FormClosedEventArgs e) - { + private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + { - } + } - private void openToolStripMenuItem_Click(object sender, EventArgs e) - { - using (OpenFileDialog fd = new OpenFileDialog() { DefaultExt = "exe", Filter = "EXE Files|*.exe", RestoreDirectory = true }) - if (fd.ShowDialog(this) == DialogResult.OK) - LoadGame(fd.FileName); - } + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + using (OpenFileDialog fd = new OpenFileDialog() { DefaultExt = "exe", Filter = "EXE Files|*.exe", RestoreDirectory = true }) + if (fd.ShowDialog(this) == DialogResult.OK) + LoadGame(fd.FileName); + } - private void LoadGame(string filename) - { - LevelData.LoadGame(filename); - changeLevelToolStripMenuItem.Enabled = true; - } + private void LoadGame(string filename) + { + LevelData.LoadGame(filename); + changeLevelToolStripMenuItem.Enabled = true; + } - private void changeLevelToolStripMenuItem_Click(object sender, EventArgs e) - { - using (LevelSelectForm ls = new LevelSelectForm()) - ls.ShowDialog(this); - } - } + private void changeLevelToolStripMenuItem_Click(object sender, EventArgs e) + { + using (LevelSelectForm ls = new LevelSelectForm()) + if (ls.ShowDialog(this) == DialogResult.OK) + { + LevelData.LoadLevel(ls.UserID, ls.LevelNum); + // TODO: more stuff + } + } + } } diff --git a/BlupiEdit/Properties/Resources.Designer.cs b/BlupiEdit/Properties/Resources.Designer.cs index 6a13e84..eecdb66 100644 --- a/BlupiEdit/Properties/Resources.Designer.cs +++ b/BlupiEdit/Properties/Resources.Designer.cs @@ -1,17 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.5466 +// Runtime Version:2.0.50727.5472 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace BlupiEdit.Properties -{ - - +namespace BlupiEdit.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -22,50 +22,49 @@ namespace BlupiEdit.Properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BlupiEdit.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } + + internal static byte[] DefaultLevel { + get { + object obj = ResourceManager.GetObject("DefaultLevel", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/BlupiEdit/Properties/Resources.resx b/BlupiEdit/Properties/Resources.resx index af7dbeb..8a008f7 100644 --- a/BlupiEdit/Properties/Resources.resx +++ b/BlupiEdit/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -114,4 +117,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\DefaultLevel.blp;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/BlupiEdit/Resources/DefaultLevel.blp b/BlupiEdit/Resources/DefaultLevel.blp new file mode 100644 index 0000000000000000000000000000000000000000..dea803c900fe9c1353253ee8efced38bd2987de3 GIT binary patch literal 50468 zcmeIwQAz_b00hvqqJrPvKv2)&Sv+YGuccY5FmzDyV~eyeWjDh#B)hNOjEiw<<9WW& za*eSW+mCtu+io85Ii`wzuRy7>wQ`OmtpK5dc>pVa8gr%kfq zlNz1*v`IF6Qlm4UHpzxhYINq)CfV>wjm~`9BpW`d(V0)1WWy&lI`e6hZ1|)`XFhF` T4WHEL%%@GV;gcGj&)Mf4$w##B literal 0 HcmV?d00001