public static void ExportGM( string fileName, List <IBox> boxes, GTMP.GMFile.GMMetadata metadata, byte[] gmllData ) { List <Box> bigBoxes; List <IconImgBox> icons; SeparateBoxes(boxes, out bigBoxes, out icons); DebugLogger.Log( "Project", "Exporting as GMFile to {0} with {1} boxes, {2} item boxes, metadata ({3}), and gmllData of {4} bytes", fileName, bigBoxes.Count, icons.Count, metadata.ToString(), (gmllData == null) ? -1 : gmllData.Length ); // this can be possible is the user just starts drawing boxes and wants to export that // without loading an associated image if (gmllData == null) { // 4 - "GMLL" // 4 - int for number of positions // 0 - position data length // 32 * 16 * 2 = 32 palettes of 16 2-byte colour // 4 - int for number of tiles // 0 - bytes of tile pixel data gmllData = new byte[4 + 4 + 0 + (32 * 16 * 2) + 4 + 0]; Array.Copy(Encoding.ASCII.GetBytes("GMLL"), gmllData, 4); } try { using (MemoryStream ms = new MemoryStream(15000)) using (BinaryWriter bw = new BinaryWriter(ms)) { // the game files never have more than four iconimgs // in one box group, it seems to handle more than that // perfectly fine, so we make slightly smaller files by not // splitting them up like that int numIcons = icons.Count; int numBigBoxes = bigBoxes.Count; //int curIcon = 0; //int curBigBox = 0; //int boxGroups = numIcons / 4; bw.Write(Encoding.ASCII.GetBytes("GM\x3\x0")); bw.Write(numIcons > 0 ? 1 : 0); // 0x4 if (numIcons > 0) { bw.Write(numIcons); foreach (IconImgBox icon in icons) { icon.Serialize(bw); } } // if anybody ever wants to write files with the 4 iconimg per group // here it is, don't forget to comment out the above, or it won't work right // if(numIcons > 0) //{ //do //{ // int iconsToWrite = Math.Min(4, numIcons); // int bigBoxesToWrite = Math.Min(4, numBigBoxes); // bw.Write((ushort)iconsToWrite); // bw.Write((ushort)bigBoxesToWrite); // for (int i = 0; i < iconsToWrite; ++i) // { // icons[0].Serialize(bw); // icons.RemoveAt(0); // } // for(int i = 0; i < bigBoxesToWrite; ++i) // { // bigBoxes[0].Serialise(bw); // bigBoxes.RemoveAt(0); // } // numIcons -= iconsToWrite; // numBigBoxes -= bigBoxesToWrite; //} //while (numIcons != 0); //} bw.Write(numBigBoxes); // if any box is a CarDisplay, set flag 2 in the metadata flags // check for more than one box with the default cursor position attribute // don't care of there aren't any int numCars = 0; int defaultCursors = 0; foreach (Box b in bigBoxes) { if (b.Contents == GTMP.GMFile.BoxItem.CarDisplay) { if (++numCars > 1) { throw new InvalidBoxStateException("The game will not render more than 1 CarDisplay box", b); } } if ((b.BehaviourAttributes & GTMP.GMFile.InfoBoxAttributes.DefaultCursorPos) != 0) { if (++defaultCursors > 1) { throw new InvalidBoxStateException("More than one box has the DefaultCursorPos BehaviourAttribute set", b); } } b.Serialize(bw); } int screenBehaviour = (numCars != 0) ? 2 : 0; if (metadata.BackLinkToPreviousScreen) { screenBehaviour = 3; } bw.Write((sbyte)metadata.ManufacturerID); bw.Write((byte)screenBehaviour); bw.Write((ushort)metadata.ScreenType); bw.Write(metadata.BackLink); bw.Write((int)metadata.BackgroundIndex); bw.Write(gmllData); bw.Flush(); ms.Position = 0; #if DEBUG File.WriteAllBytes(@"T:\uncompressedgm.gm", ms.ToArray()); #endif MemoryStream compressed = Compress.GZipCompressStream(ms); byte[] compressedBytes = compressed.ToArray(); File.WriteAllBytes(fileName, compressedBytes); } } catch (InvalidBoxStateException ibse) { MainForm.DisplayMsgBox( System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, ibse.Message ); } }