private void OKButton_Click(object sender, EventArgs e) { if (OKButton.Text == "OK") { Close(); } else { textBox1.AppendText(Environment.NewLine + "Start!"); checkboxAngelscriptFunctions.Enabled = checkboxExcludeDefault.Enabled = checkboxIncludeMusic.Enabled = checkboxMissing.Enabled = checkboxMultipleLevels.Enabled = OKButton.Enabled = false; Directory.SetCurrentDirectory(Path.GetDirectoryName(initialLevelFilepath)); string angelscriptPragmaPattern = "(#pragma\\s+require|#pragma\\s+offer"; if (checkboxAngelscriptFunctions.Checked) { angelscriptPragmaPattern += "|jjNxt\\s*\\(|jjMusicLoad\\s*\\(|jjLayersFromLevel\\s*\\(|jjTilesFromTileset\\s*\\(|jjSampleLoad\\s*\\(\\s*SOUND\\s*::\\s*[a-z0-9_]+\\s*,"; } angelscriptPragmaPattern += ")\\s*(['\"])(.+?)\\2"; var levelFilepaths = new List <string>(); levelFilepaths.Add(initialLevelFilepath); for (int levelID = 0; levelID < levelFilepaths.Count; ++levelID) { string levelFilepath = levelFilepaths[levelID]; textBox1.AppendText(Environment.NewLine + "Inspecting level \"" + levelFilepath + '"'); switch (extendedAddFilepath(ref levelFilepath)) { case DialogResult.Yes: break; case DialogResult.No: //e.g. file not found continue; case DialogResult.Cancel: return; } J2LFile j2l = new J2LFile(); var Data5 = new byte[0]; var openResults = j2l.OpenLevel(levelFilepath, ref Data5, onlyInterestedInData1: true); if (!(openResults == OpeningResults.Success || openResults == OpeningResults.SuccessfulButAmbiguous)) { textBox1.AppendText(Environment.NewLine + "Unexpected error while opening level." + Environment.NewLine + "Packaging cancelled."); return; } if (tilesetExtension != String.Empty) //not GorH { var tilesetFilename = Path.ChangeExtension(j2l.MainTilesetFilename, tilesetExtension); if (addFilepath(ref tilesetFilename) == DialogResult.Cancel) { return; } } if (checkboxIncludeMusic.Checked) { var musicFilename = j2l.Music; if (musicFilename.Trim() != String.Empty) { if (!Path.HasExtension(musicFilename)) { musicFilename = Path.ChangeExtension(musicFilename, "j2b"); } if (addFilepath(ref musicFilename) == DialogResult.Cancel) { return; } } } if (checkboxMultipleLevels.Checked) { foreach (var additionalLevelFilename in new string[] { j2l.NextLevel, j2l.SecretLevel }) { if (additionalLevelFilename != String.Empty && !(additionalLevelFilename.Length >= 3 && StringComparer.InvariantCultureIgnoreCase.Compare(additionalLevelFilename.Substring(0, 3), "end") == 0)) //any level filename starting with END is invalid (to JJ2, at least) { levelFilepaths.Add(Path.ChangeExtension(additionalLevelFilename, levelExtension)); //come back to this level later in the loop } } } if (checkScripts) { string mainScriptFilename = Path.ChangeExtension(levelFilepath, "j2as"); if (File.Exists(mainScriptFilename)) //not all levels have them, and we don't want to go down this path otherwise { var scriptFilepaths = new List <string>(); scriptFilepaths.Add(mainScriptFilename); for (int scriptID = 0; scriptID < scriptFilepaths.Count; ++scriptID) { string scriptFilepath = scriptFilepaths[scriptID]; switch (extendedAddFilepath(ref scriptFilepath)) { case DialogResult.Yes: break; case DialogResult.No: //e.g. file not found continue; case DialogResult.Cancel: return; } var fileContents = System.IO.File.ReadAllText(scriptFilepath, J2LFile.FileEncoding); foreach (System.Text.RegularExpressions.Match match in System.Text.RegularExpressions.Regex.Matches(fileContents, "#include\\s+(['\"])(.+?)\\1", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) //actually I don't even know whether #include is case-insensitive jjSampleLoad(SOUND::ORANGE_BOEMR, "expmine.wav"); { scriptFilepaths.Add(match.Groups[2].Value); //come back to this script later in the loop } foreach (System.Text.RegularExpressions.Match match in System.Text.RegularExpressions.Regex.Matches(fileContents, angelscriptPragmaPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { string foundFilepath = match.Groups[3].Value; if (match.Groups[1].Value.Contains("jjN")) //don't need to worry about case here, because it's a function. { levelFilepaths.Add(foundFilepath); } else if (addFilepath(ref foundFilepath) == DialogResult.Cancel) { return; } } } } } } textBox1.AppendText(Environment.NewLine + "Beginning ZIP..."); if (File.Exists(finalZipFilepath)) { File.Delete(finalZipFilepath); } using (var zip = ZipFile.Open(finalZipFilepath, ZipArchiveMode.Create)) { foreach (string filepath in filePathsToInclude) { textBox1.AppendText(Environment.NewLine + "Compressing " + filepath); zip.CreateEntryFromFile(filepath, Path.GetFileName(filepath)); } } textBox1.AppendText(Environment.NewLine + "Done! Packaged " + filePathsToInclude.Count.ToString() + " files (" + (new System.IO.FileInfo(finalZipFilepath).Length / 1024).ToString() + " kb)"); textBox1.AppendText(Environment.NewLine + "Click OK to finish."); OKButton.Enabled = true; CancelButton.Enabled = false; OKButton.Text = "OK"; } }
internal bool LevelIsReadable(byte[] Data5, List <J2TFile> Tilesets, List <Layer> Layers, string Filepath) { if (Data5 == null || Data5.Length < 20) //level stops at the end of data4, as is good and proper { this = new PlusPropertyList(null); return(true); } using (BinaryReader data5reader = new BinaryReader(new MemoryStream(Data5), J2LFile.FileEncoding)) { if (new string(data5reader.ReadChars(4)) != MLLEData5MagicString) { return(false); } uint data5Version = data5reader.ReadUInt32(); if (data5Version > CurrentMLLEData5Version) { return(false); } //should be okay to read at this point this = new PlusPropertyList(null); uint csize = data5reader.ReadUInt32(); uint usize = data5reader.ReadUInt32(); using (BinaryReader data5bodyreader = new BinaryReader(new MemoryStream(ZlibStream.UncompressBuffer(data5reader.ReadBytes((int)csize))))) { IsSnowing = data5bodyreader.ReadBoolean(); IsSnowingOutdoorsOnly = data5bodyreader.ReadBoolean(); SnowingIntensity = data5bodyreader.ReadByte(); SnowingType = (SnowTypeEnum)data5bodyreader.ReadByte(); WarpsTransmuteCoins = data5bodyreader.ReadBoolean(); DelayGeneratedCrateOrigins = data5bodyreader.ReadBoolean(); Echo = data5bodyreader.ReadInt32(); DarknessColor = Color.FromArgb(data5bodyreader.ReadInt32()); WaterChangeSpeed = data5bodyreader.ReadSingle(); WaterInteraction = (WaterInteractionEnum)data5bodyreader.ReadByte(); WaterLayer = data5bodyreader.ReadInt32(); WaterLighting = (WaterLightingEnum)data5bodyreader.ReadByte(); WaterLevel = data5bodyreader.ReadSingle(); WaterGradientStart = Color.FromArgb(data5bodyreader.ReadInt32()); WaterGradientStop = Color.FromArgb(data5bodyreader.ReadInt32()); if (data5bodyreader.ReadBoolean()) { Palette = new Palette(data5bodyreader, true); } for (int i = 0; i < Mainframe.RecolorableSpriteNames.Length; ++i) { if ((i < 11 || data5Version >= 0x105) && data5bodyreader.ReadBoolean()) //the recolorable sprite list was expanded in MLLE-Include-1.5 { ColorRemappings[i] = new byte[Palette.PaletteSize]; for (uint j = 0; j < Palette.PaletteSize; ++j) { ColorRemappings[i][j] = data5bodyreader.ReadByte(); } } else { ColorRemappings[i] = null; } } var extraTilesetCount = data5bodyreader.ReadByte(); for (uint tilesetID = 0; tilesetID < extraTilesetCount; ++tilesetID) { var tilesetFilepath = Path.Combine(Path.GetDirectoryName(Filepath), data5bodyreader.ReadString()); if (File.Exists(tilesetFilepath)) { var tileset = new J2TFile(tilesetFilepath); tileset.FirstTile = data5bodyreader.ReadUInt16(); tileset.TileCount = data5bodyreader.ReadUInt16(); if (data5bodyreader.ReadBoolean()) { tileset.ColorRemapping = new byte[Palette.PaletteSize]; for (uint i = 0; i < Palette.PaletteSize; ++i) { tileset.ColorRemapping[i] = data5bodyreader.ReadByte(); } } Tilesets.Add(tileset); } else { this = new PlusPropertyList(null); MessageBox.Show("Additional tileset \"" + tilesetFilepath + "\" not found; MLLE will stop trying to read this Data5 section.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand); return(false); } } if (data5Version >= 0x102) //layers were added in MLLE-Include-1.2 { var defaultLayers = Layers.ToArray(); Layers.Clear(); int layerCount = (int)data5bodyreader.ReadUInt32(); List <Layer> nonDefaultLayers = new List <Layer>(); for (int i = 8; i < layerCount; i += 8) { J2LFile extraLevel = new J2LFile(); string levelFilePath = GetExtraDataLevelFilepath(Filepath, i / 8 - 1); if (File.Exists(levelFilePath)) { extraLevel.OpenLevel(levelFilePath, ref Data5, SecurityStringOverride: J2LFile.SecurityStringExtraDataNotForDirectEditing); nonDefaultLayers.AddRange(extraLevel.DefaultLayers); } else { this = new PlusPropertyList(null); MessageBox.Show("Additional file \"" + levelFilePath + "\" not found; MLLE will stop trying to read this Data5 section.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand); return(false); } } int nextNonDefaultLayerID = 0; for (uint i = 0; i < layerCount; ++i) { sbyte layerID = data5bodyreader.ReadSByte(); Layer layer; if (layerID >= 0) { layer = defaultLayers[layerID]; } else { layer = nonDefaultLayers[nextNonDefaultLayerID++]; layer.id = -1; } layer.Name = data5bodyreader.ReadString(); layer.Hidden = data5bodyreader.ReadBoolean(); layer.SpriteMode = data5bodyreader.ReadByte(); layer.SpriteParam = data5bodyreader.ReadByte(); layer.RotationAngle = data5bodyreader.ReadInt32(); layer.RotationRadiusMultiplier = data5bodyreader.ReadInt32(); Layers.Add(layer); } if (data5Version >= 0x103) //edited tiles were added in MLLE-Include-1.3 { int levelTileCount = Tilesets.Sum(ts => (int)ts.TileCount); foreach (byte[][] images in new byte[][][] { TileImages, TileMasks }) { int numberOfImages = data5bodyreader.ReadUInt16(); for (int i = 0; i < numberOfImages; ++i) { int tileID = data5bodyreader.ReadUInt16(); images[tileID] = data5bodyreader.ReadBytes(32 * 32); } } if (data5Version >= 0x105) //weapons were added in MLLE-Include-1.5(w) { for (int weaponID = 0; weaponID < 9; ++weaponID) { bool customWeapon = data5bodyreader.ReadBoolean(); Weapon weapon = Weapons[weaponID]; weapon.Options[0] = data5bodyreader.ReadInt32(); //maximum for (int optionID = 1; optionID < Weapon.NumberOfCommonOptions; ++optionID) { weapon.Options[optionID] = data5bodyreader.ReadByte(); //birds and crates and gems and replenishment } if (weaponID == 6) { Gun7Crate = data5bodyreader.ReadByte(); } else if (weaponID == 7) { Gun8Crate = data5bodyreader.ReadByte(); } else if (weaponID == 8) { Gun9Crate = data5bodyreader.ReadByte(); } if (customWeapon) { string name = data5bodyreader.ReadString(); var extendedWeapon = WeaponsForm.GetAllAvailableWeapons().Find(w => w.Name == name); if (extendedWeapon == null) { MessageBox.Show(String.Format("Sorry, the MLLE \"Weapons\" folder did not include any .ini file defining a weapon with the name \"{0}.\"", name), "Weapon not found", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } Weapons[weaponID].Name = name; Array.Resize(ref Weapons[weaponID].Options, extendedWeapon.Options.Length); data5bodyreader.ReadInt32(); //length of jjSTREAM for (int optionID = Weapon.NumberOfCommonOptions; optionID < weapon.Options.Length; ++optionID) { switch (extendedWeapon.OptionTypes[optionID]) { case WeaponsForm.ExtendedWeapon.oTypes.Bool: case WeaponsForm.ExtendedWeapon.oTypes.Dropdown: weapon.Options[optionID] = data5bodyreader.ReadByte(); break; case WeaponsForm.ExtendedWeapon.oTypes.Int: weapon.Options[optionID] = data5bodyreader.ReadInt32(); break; } } } else if (weaponID == 7) { weapon.Options[Weapon.NumberOfCommonOptions] = data5bodyreader.ReadByte(); //Gun8 style } } } } } } } return(true); }