public RoomClipboardData(Editor editor, Vector2 dropPosition) { _dropPositionX = dropPosition.X; _dropPositionY = dropPosition.Y; // Collect contour lines _contourLines = new List <ContourLine>(); foreach (Room room in editor.SelectedRooms) { for (int z = 1; z < room.NumZSectors; ++z) { for (int x = 1; x < room.NumXSectors; ++x) { Block thisBlock = room.Blocks[x, z]; Block aboveBlock = room.Blocks[x, z - 1]; Block leftBlock = room.Blocks[x - 1, z]; if (aboveBlock.IsAnyWall != thisBlock.IsAnyWall) { _contourLines.Add(new ContourLine { StartX = x + room.Position.X, StartY = z + room.Position.Z, EndX = x + room.Position.X + 1, EndY = z + room.Position.Z }); } if (leftBlock.IsAnyWall != thisBlock.IsAnyWall) { _contourLines.Add(new ContourLine { StartX = x + room.Position.X, StartY = z + room.Position.Z, EndX = x + room.Position.X, EndY = z + room.Position.Z + 1 }); } } } } // Write data _levelPath = editor.Level.Settings.LevelFilePath ?? ""; using (var stream = new MemoryStream()) { var writer = new BinaryWriterEx(stream); Prj2Writer.SaveToPrj2(stream, editor.Level, new Prj2Writer.Filter { RoomPredicate = room => editor.SelectedRoomsContains(room) }); _data = stream.GetBuffer(); } }
public static void UpdatePrj2GameSettings(string prj2FilePath, ProjectLevel destLevel, Project destProject) { Level level = Prj2Loader.LoadFromPrj2(prj2FilePath, null); string exeFilePath = Path.Combine(destProject.EnginePath, destProject.GetExeFileName()); string dataFileName = destLevel.DataFileName + destProject.GetLevelFileExtension(); string dataFilePath = Path.Combine(destProject.EnginePath, "data", dataFileName); level.Settings.LevelFilePath = prj2FilePath; level.Settings.GameDirectory = level.Settings.MakeRelative(destProject.EnginePath, VariableType.LevelDirectory); level.Settings.GameExecutableFilePath = level.Settings.MakeRelative(exeFilePath, VariableType.LevelDirectory); level.Settings.GameLevelFilePath = level.Settings.MakeRelative(dataFilePath, VariableType.LevelDirectory); level.Settings.GameVersion = destProject.GameVersion; Prj2Writer.SaveToPrj2(prj2FilePath, level); }
private void button_Create_Click(object sender, EventArgs e) { button_Create.Enabled = false; try { string levelName = PathHelper.RemoveIllegalPathSymbols(textBox_LevelName.Text.Trim()); levelName = LevelHandling.RemoveIllegalNameSymbols(levelName); if (string.IsNullOrWhiteSpace(levelName)) { throw new ArgumentException("You must enter a valid name for your level."); } // Check for name duplicates foreach (ProjectLevel projectLevel in _targetProject.Levels) { if (projectLevel.Name.ToLower() == levelName.ToLower()) { throw new ArgumentException("A level with the same name already exists on the list."); } } string dataFileName = textBox_CustomFileName.Text.Trim(); if (string.IsNullOrWhiteSpace(dataFileName)) { throw new ArgumentException("You must specify the custom PRJ2 / DATA file name."); } string levelFolderPath = Path.Combine(_targetProject.LevelsPath, levelName); // Create the level folder if (!Directory.Exists(levelFolderPath)) { Directory.CreateDirectory(levelFolderPath); } if (Directory.EnumerateFileSystemEntries(levelFolderPath).ToArray().Length > 0) // 99% this will never accidentally happen { throw new ArgumentException("A folder with the same name as the \"Level name\" already exists in\n" + "the project's /Levels/ folder and it's not empty."); } ProjectLevel createdLevel = new ProjectLevel { Name = levelName, DataFileName = dataFileName, FolderPath = levelFolderPath }; // Create a simple .prj2 file with pre-set project settings (game paths etc.) Level level = Level.CreateSimpleLevel(); string prj2FilePath = Path.Combine(createdLevel.FolderPath, createdLevel.DataFileName) + ".prj2"; string exeFilePath = Path.Combine(_targetProject.EnginePath, _targetProject.GetExeFileName()); string dataFilePath = Path.Combine(_targetProject.EnginePath, "data", createdLevel.DataFileName + _targetProject.GetLevelFileExtension()); level.Settings.LevelFilePath = prj2FilePath; level.Settings.GameDirectory = level.Settings.MakeRelative(_targetProject.EnginePath, VariableType.LevelDirectory); level.Settings.GameExecutableFilePath = level.Settings.MakeRelative(exeFilePath, VariableType.LevelDirectory); level.Settings.GameLevelFilePath = level.Settings.MakeRelative(dataFilePath, VariableType.LevelDirectory); level.Settings.GameVersion = _targetProject.GameVersion; Prj2Writer.SaveToPrj2(prj2FilePath, level); if (checkBox_GenerateSection.Checked) { int ambientSoundID = (int)numeric_SoundID.Value; bool horizon = checkBox_EnableHorizon.Checked; // // // // GeneratedScriptLines = LevelHandling.GenerateScriptLines(createdLevel, ambientSoundID, horizon); // // // // } // // // // CreatedLevel = createdLevel; // // // // } catch (Exception ex) { DarkMessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); button_Create.Enabled = true; DialogResult = DialogResult.None; } }
public static bool ConvertPrj2ToNewSoundFormat(Level level, string src, string dest, string soundsCatalog, bool save) { /* PROCEDURE: * 1. Collect all sound sources of level: if embedded sound info is null, then it's a sound source * that is referencing a Wad file and we should just remap it, otherwise it's a custom sound source * created inside Tomb Editor and we must export it to Xml and we must export samples too * 2. Try to guess the ID for Wad sounds and generate instead a new ID above 602 for custom sounds * (ID = 602 is the start of TR1 area of extended soundmap of TRNG and it should be rarely used) * 3. Show the dialog to the user. Here he can load an additional catalog if he changed sounds via TRLE tools * 4. Assign new IDs and new names to sound infos * 5. Remap sound sources * 6. Export samples if needed * 7. Save Prj2 + Xml if custom sounds are present */ try { // Check for sound system if (level.Settings.SoundSystem == SoundSystem.Xml) { return(true); } // Infer the wad version from level version TRVersion.Game version = level.Settings.GameVersion.Native(); // Collect all sounds to remap var conversionList = new List <SoundInfoConversionRow>(); // We start from sound id = 602 which is the TR1 sound area of TRNG extended soundmap. // This area is reserved for TR1 enemies and so it *** should *** be used rarely int lastSoundId = 602; foreach (var room in level.Rooms) { if (room != null) { foreach (var obj in room.Objects) { if (obj is SoundSourceInstance) { SoundSourceInstance soundSource = obj as SoundSourceInstance; if (soundSource.WadReferencedSoundName != null && soundSource.WadReferencedSoundName != "") { if (!conversionList.Select(f => f.OldName).Contains(soundSource.WadReferencedSoundName)) { // First try to get sound name from TrCatalog int newId = TrCatalog.TryGetSoundInfoIdByDescription(version, soundSource.WadReferencedSoundName); var row = new SoundInfoConversionRow(null, soundSource.WadReferencedSoundName); if (newId == -1) { // If sound was not found in catalog, then assign a generic Id and ask to the user row.NewName = Regex.Replace(soundSource.WadReferencedSoundName, "[^A-Za-z0-9 _]", "").ToUpper(); row.NewId = lastSoundId++; } else { // Otherwise, we are lucky, and we can just assign the correct Id row.NewName = TrCatalog.GetOriginalSoundName(version, (uint)newId); row.NewId = newId; } conversionList.Add(row); } } else if (soundSource.EmbeddedSoundInfo != null) { bool found = false; foreach (var r in conversionList) { if (r.SoundInfo != null && r.SoundInfo == soundSource.EmbeddedSoundInfo) { found = true; break; } } if (found) { continue; } // Let's first try a search in TrCatalog, maybe we are lucky // First try to get sound name from TrCatalog /*int newId = TrCatalog.TryGetSoundInfoIdByDescription(version, soundSource.EmbeddedSoundInfo.Name); * * var row = new SoundInfoConversionRow(soundSource.EmbeddedSoundInfo, soundSource.EmbeddedSoundInfo.Name); * if (newId == -1) * { * // If sound was not found in catalog, then assign a generic Id and ask to the user * row.NewName = Regex.Replace(soundSource.EmbeddedSoundInfo.Name, "[^A-Za-z0-9 _]", "").ToUpper(); * row.NewId = lastSoundId++; * } * else * { * // Otherwise, we are lucky, and we can just assign the correct Id * row.NewName = TrCatalog.GetOriginalSoundName(version, (uint)newId); * row.NewId = newId; * }*/ // TODO: Lwmte proposed to also there check in TrCatalog, but we should assume that // embedded sound sources are custom sound sources, created by thhe user with custom samples // and we should think carrefully about this var row = new SoundInfoConversionRow(soundSource.EmbeddedSoundInfo, soundSource.EmbeddedSoundInfo.Name); row.NewName = Regex.Replace(soundSource.EmbeddedSoundInfo.Name, "[^A-Za-z0-9 _]", "").ToUpper(); row.NewId = lastSoundId++; // These flags are handle by Tomb Editor and set only for embedded sound sources row.SaveToXml = true; row.ExportSamples = true; conversionList.Add(row); } } } } } WadSounds sounds = null; // Now we'll show a dialog with all conversion rows and the user will need to make some choices if (conversionList.Count != 0) { using (var form = new Prj2SoundsConversionDialog(version, conversionList)) { if (form.ShowDialog() == DialogResult.Cancel) { return(false); } // If the user has loaded an additional catalog, let's get a pointer to it if (form.Sounds != null) { sounds = form.Sounds; } } } // Assign new Id and name foreach (var row in conversionList) { if (row.SoundInfo != null) { row.SoundInfo.Id = row.NewId; row.SoundInfo.Name = row.NewName; } } // We'll export only embedded sound sources var newSounds = new WadSounds(); // Remap sound sources foreach (var room in level.Rooms) { if (room != null) { foreach (var obj in room.Objects) { if (obj is SoundSourceInstance) { SoundSourceInstance soundSource = obj as SoundSourceInstance; if (soundSource.WadReferencedSoundName != null && soundSource.WadReferencedSoundName != "") { soundSource.SoundId = -1; foreach (var row in conversionList) { if (row.OldName == soundSource.WadReferencedSoundName && row.NewId != -1) { soundSource.SoundId = row.NewId; break; } } soundSource.WadReferencedSoundName = ""; soundSource.EmbeddedSoundInfo = null; } else if (soundSource.EmbeddedSoundInfo != null) { // We export embedded sound infos if (!newSounds.SoundInfos.Contains(soundSource.EmbeddedSoundInfo)) { newSounds.SoundInfos.Add(soundSource.EmbeddedSoundInfo); } soundSource.SoundId = -1; foreach (var row in conversionList) { if (row.SoundInfo == soundSource.EmbeddedSoundInfo && row.NewId != -1) { soundSource.SoundId = row.NewId; // Try to bind samples from additional catalog, if loaded /*if (sounds != null) * { * WadSoundInfo catalogInfo = sounds.TryGetSoundInfo(row.NewId); * if (catalogInfo != null && catalogInfo.Samples.Count > 0) * { * soundSource.EmbeddedSoundInfo.Samples.Clear(); * soundSource.EmbeddedSoundInfo.Samples.AddRange(catalogInfo.Samples); * // TODO: in theory if valid samples are found in catalog, we shouldn't need to * // export them * row.ExportSamples = false; * } * }*/ break; } } soundSource.WadReferencedSoundName = ""; soundSource.EmbeddedSoundInfo = null; } } } } } // Export samples foreach (var row in conversionList) { if (row.SoundInfo != null && row.ExportSamples) { var samples = new List <string>(); foreach (var sample in row.SoundInfo.Samples) { if (sample.IsLoaded) { string sampleName = Path.GetFileNameWithoutExtension(dest) + "_" + row.NewName.ToLower() + "_" + row.SoundInfo.Samples.IndexOf(sample) + ".wav"; samples.Add(sampleName); File.WriteAllBytes(Path.GetDirectoryName(dest) + "\\" + sampleName, sample.Data); } } row.SoundInfo.Samples.Clear(); foreach (var sample in samples) { row.SoundInfo.Samples.Add(new WadSample(sample)); } } } // Sort sound infos newSounds.SoundInfos.Sort((a, b) => a.Id.CompareTo(b.Id)); // Make a backup copy if (save && src == dest) { int index = 0; string backupFilename = ""; while (true) { backupFilename = dest + "." + index + ".bak"; if (!File.Exists(backupFilename)) { break; } index++; } File.Copy(src, backupFilename, true); } // Save Xml to file if (newSounds.SoundInfos.Count != 0) { string xmlFileName = Path.GetDirectoryName(dest) + "\\" + Path.GetFileNameWithoutExtension(dest) + ".xml"; WadSounds.SaveToXml(xmlFileName, newSounds); // Assign Xml to level settings level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings, level.Settings.MakeRelative(xmlFileName, VariableType.LevelDirectory))); } level.Settings.SoundSystem = SoundSystem.Xml; // Try to get Xml and SFX files foreach (var wadRef in level.Settings.Wads) { if (wadRef != null && wadRef.LoadException == null) { string wadPath = level.Settings.MakeAbsolute(wadRef.Path); string extension = Path.GetExtension(wadPath).ToLower(); if (extension == ".wad") { string sfxPath = Path.GetDirectoryName(wadPath) + "\\" + Path.GetFileNameWithoutExtension(wadPath) + ".sfx"; if (File.Exists(sfxPath)) { sounds = WadSounds.ReadFromFile(sfxPath); if (sounds != null) { level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings, level.Settings.MakeRelative(sfxPath, VariableType.LevelDirectory))); } } } else if (extension == ".wad2") { string xmlPath = Path.GetDirectoryName(wadPath) + "\\" + Path.GetFileNameWithoutExtension(wadPath) + ".xml"; if (File.Exists(xmlPath)) { sounds = WadSounds.ReadFromFile(xmlPath); if (sounds != null) { level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings, level.Settings.MakeRelative(xmlPath, VariableType.LevelDirectory))); } } } } } // Assign sounds if possible foreach (var soundRef in level.Settings.SoundsCatalogs) { if (soundRef.LoadException == null) { foreach (var sound in soundRef.Sounds.SoundInfos) { if (!level.Settings.SelectedSounds.Contains(sound.Id)) { level.Settings.SelectedSounds.Add(sound.Id); } } } } // Save Prj2 with Xml sounds if (save) { using (var stream = File.OpenWrite(dest)) Prj2Writer.SaveToPrj2(stream, level); } return(true); } catch (Exception ex) { return(false); } }