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();
            }
        }
Esempio n. 2
0
        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;
            }
        }
Esempio n. 4
0
        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);
            }
        }