#region ================== Copyright (c) 2007 Pascal vd Heiden /* * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com * This program is released under GNU General Public License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #endregion #region ================== Namespaces using System; using System.Collections.Generic; using System.Windows.Forms; using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Map; using System.IO; using System.Collections; using CodeImp.DoomBuilder.Data; using CodeImp.DoomBuilder.Config; #endregion namespace CodeImp.DoomBuilder.Windows { internal partial class OpenMapOptionsForm : Form { // Variables private Configuration mapsettings; private MapOptions options; private WAD wadfile; private readonly string filepathname; private string selectedmapname; // Properties public string FilePathName { get { return filepathname; } } public MapOptions Options { get { return options; } } // Constructor public OpenMapOptionsForm(string filepathname) { // Initialize InitializeComponent(); this.Text = "Open Map from " + Path.GetFileName(filepathname); this.filepathname = filepathname; datalocations.StartPath = filepathname; //mxd this.options = null; } // Constructor public OpenMapOptionsForm(string filepathname, MapOptions options) { // Initialize InitializeComponent(); this.Text = "Open Map from " + Path.GetFileName(filepathname); this.filepathname = filepathname; this.options = options; datalocations.StartPath = filepathname; //mxd datalocations.EditResourceLocationList(options.Resources); } // This loads the settings and attempt to find a suitable config private void LoadSettings() { string gameconfig; int index; // Busy Cursor.Current = Cursors.WaitCursor; // Check if the file exists if(!File.Exists(filepathname)) { // WAD file does not exist MessageBox.Show(this, "Could not open the WAD file: The file does not exist.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.Cancel; this.Close(); return; } try { // Open the WAD file wadfile = new WAD(filepathname, true); } catch(Exception e) { // Unable to open WAD file (or its config) MessageBox.Show(this, "Could not open the WAD file for reading.\n" + e.GetType().Name + ": " + e.Message + "\nPlease make sure the file you selected is valid and is not in use by any other application.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); if(wadfile != null) wadfile.Dispose(); this.DialogResult = DialogResult.Cancel; this.Close(); return; } // Open the Map Settings configuration string dbsfile = filepathname.Substring(0, filepathname.Length - 4) + ".dbs"; if(File.Exists(dbsfile)) try { mapsettings = new Configuration(dbsfile, true); } catch(Exception) { mapsettings = new Configuration(true); } else mapsettings = new Configuration(true); // Check strict patches box, check what game configuration is preferred if(options != null) { strictpatches.Checked = options.StrictPatches; gameconfig = options.ConfigFile; } else { strictpatches.Checked = mapsettings.ReadSetting("strictpatches", false); gameconfig = mapsettings.ReadSetting("gameconfig", ""); } //mxd. Fill script compilers list foreach(KeyValuePair group in General.CompiledScriptConfigs) { scriptcompiler.Items.Add(group.Value); } // Go for all configurations foreach(ConfigurationInfo info in General.Configs) { // Add config name to list index = config.Items.Add(info); // Select this item if(info.Filename == gameconfig) config.SelectedIndex = index; } // Still no configuration selected? if(config.SelectedIndex == -1) { //mxd. Then go for all ENABLED configurations with resources to find a suitable one foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is set for this configuration, if so, match the wad against this configuration if(info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile)) { //mxd. Already added? index = config.Items.IndexOf(info); // Select or add and select this item config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Still no configuration selected? if(config.SelectedIndex == -1) { // Then go for all DISABLED configurations with resources to find a suitable one foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is set for this configuration, if so, match the wad against this configuration if(!info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile)) { //mxd. Already added? index = config.Items.IndexOf(info); // Select or add and select this item config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Still no configuration selected? if(config.SelectedIndex == -1) { //mxd. Then go for all ENABLED configurations without resources to find a suitable one foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is not set for this configuration, if so, match the wad against this configuration if(info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile)) { //mxd. Already added? index = config.Items.IndexOf(info); // Select or add and select this item config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Still no configuration selected? if(config.SelectedIndex == -1) { // Then go for all DISABLED configurations without resources to find a suitable one foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is not set for this configuration, if so, match the wad against this configuration if(!info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile)) { //mxd. Already added? index = config.Items.IndexOf(info); // Select or add and select this item config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Bail out if still no dice... if(config.SelectedIndex == -1 || mapslist.Items.Count == 0) { General.ShowWarningMessage("Unable to find maps using any game configuration.\nDoes this wad contain any maps at all?..", MessageBoxButtons.OK); cancel_Click(this, EventArgs.Empty); } else { // Show the window this.Opacity = 1; } // Done Cursor.Current = Cursors.Default; } // mxd. This matches a WAD file with the specified game configuration // by checking if the specific lumps are detected private static bool MatchConfiguration(Configuration cfg, WAD wadfile) { int lumpsrequired = 0; // Get the map lump names IDictionary maplumpnames = cfg.ReadSetting("maplumpnames", new Hashtable()); // Count how many required lumps we have to find foreach(DictionaryEntry ml in maplumpnames) { // Ignore the map header (it will not be found because the name is different) if(ml.Key.ToString() != MapManager.CONFIG_MAP_HEADER) { // Read lump setting and count it if(cfg.ReadSetting("maplumpnames." + ml.Key + ".required", false)) lumpsrequired++; } } // Go for all the lumps in the wad for(int scanindex = 0; scanindex < (wadfile.Lumps.Count - 1); scanindex++) { // Make sure this lump is not part of the map. if(!maplumpnames.Contains(wadfile.Lumps[scanindex].Name)) { // Reset check int lumpsfound = 0; int checkoffset = 1; // Continue while still within bounds and lumps are still recognized while(((scanindex + checkoffset) < wadfile.Lumps.Count) && maplumpnames.Contains(wadfile.Lumps[scanindex + checkoffset].Name)) { string lumpname = wadfile.Lumps[scanindex + checkoffset].Name; //mxd. Lump cannot present in current map format, fail this check if(cfg.ReadSetting("maplumpnames." + lumpname + ".forbidden", false)) { lumpsfound = -1; break; } // Count the lump when it is marked as required if(cfg.ReadSetting("maplumpnames." + lumpname + ".required", false)) lumpsfound++; // Check the next lump checkoffset++; } // Map found? Let's call it a day :) if(lumpsfound >= lumpsrequired) return true; } } return false; } // Configuration is selected private void config_SelectedIndexChanged(object sender, EventArgs e) { // Anything selected? if(config.SelectedIndex < 0) return; // Keep selected name, if any string selectedname = (mapslist.SelectedItems.Count > 0 ? mapslist.SelectedItems[0].Text : ""); // Make an array for the map names List mapnames = new List(); // Get selected configuration info ConfigurationInfo ci = (config.SelectedItem as ConfigurationInfo); //mxd. Get configuration Configuration cfg = ci.Configuration; // Get the map lump names IDictionary maplumpnames = cfg.ReadSetting("maplumpnames", new Hashtable()); // Count how many required lumps we have to find int lumpsrequired = 0; foreach(DictionaryEntry ml in maplumpnames) { // Ignore the map header (it will not be found because the name is different) if(ml.Key.ToString() != MapManager.CONFIG_MAP_HEADER) { // Read lump setting and count it if(cfg.ReadSetting("maplumpnames." + ml.Key + ".required", false)) lumpsrequired++; } } // Go for all the lumps in the wad for(int scanindex = 0; scanindex < (wadfile.Lumps.Count - 1); scanindex++) { // Make sure this lump is not part of the map. if(!maplumpnames.Contains(wadfile.Lumps[scanindex].Name)) { // Reset check int lumpsfound = 0; int checkoffset = 1; // Continue while still within bounds and lumps are still recognized while(((scanindex + checkoffset) < wadfile.Lumps.Count) && maplumpnames.Contains(wadfile.Lumps[scanindex + checkoffset].Name)) { string lumpname = wadfile.Lumps[scanindex + checkoffset].Name; //mxd. Lump cannot present in current map format, fail this check if(cfg.ReadSetting("maplumpnames." + lumpname + ".forbidden", false)) { lumpsfound = -1; break; } // Count the lump when it is marked as required if(cfg.ReadSetting("maplumpnames." + lumpname + ".required", false)) lumpsfound++; // Check the next lump checkoffset++; } // Map found? Then add it to the list if(lumpsfound >= lumpsrequired) mapnames.Add(new ListViewItem(wadfile.Lumps[scanindex].Name)); } } // Clear the list and add the new map names mapslist.BeginUpdate(); mapslist.Items.Clear(); mapslist.Items.AddRange(mapnames.ToArray()); mapslist.Sort(); // Go for all items in the list foreach(ListViewItem item in mapslist.Items) { // Was this item previously selected? if(item.Text == selectedname) { // Select it again item.Selected = true; break; } } if((mapslist.SelectedItems.Count == 0) && (mapslist.Items.Count > 0)) mapslist.Items[0].Selected = true; mapslist.EndUpdate(); //mxd. Disable script compiler selector when there are no maps detected using current configuration if(mapslist.Items.Count == 0) { scriptcompiler.Enabled = false; scriptcompiler.SelectedIndex = -1; scriptcompilerlabel.Enabled = false; } // Show configuration resources datalocations.FixedResourceLocationList(ci.Resources); // Update long texture names checkbox (mxd) longtexturenames.Enabled = cfg.ReadSetting("longtexturenames", false); longtexturenames.Checked = (longtexturenames.Enabled && options != null && options.UseLongTextureNames); } // OK clicked private void apply_Click(object sender, EventArgs e) { // Configuration selected? if(config.SelectedIndex == -1) { // Select a configuration! MessageBox.Show(this, "Please select a game configuration to use for editing your map.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); config.Focus(); return; } //mxd. Script configuration selected? if(scriptcompiler.Enabled && scriptcompiler.SelectedIndex == -1) { // Select a configuration! MessageBox.Show(this, "Please select a script type to use for editing your map.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); scriptcompiler.Focus(); return; } // Collect information ConfigurationInfo configinfo = (config.SelectedItem as ConfigurationInfo); //mxd DataLocationList locations = datalocations.GetResources(); // Resources are valid? (mxd) if(!datalocations.ResourcesAreValid()) { MessageBox.Show(this, "Cannot open map: at least one resource doesn't exist!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); datalocations.Focus(); return; } // No map selected? if(mapslist.SelectedItems.Count == 0) { // Choose a map! MessageBox.Show(this, "Please select a map to load for editing.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); mapslist.Focus(); return; } //mxd. We cant't deal with this... We just can't... if(!configinfo.ValidateMapName(mapslist.SelectedItems[0].Text.ToUpperInvariant())) { // Choose a different map! MessageBox.Show(this, "Selected map name conflicts with a lump name defined for current map format.\nPlease rename the map and try again.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); mapslist.Focus(); return; } // Check if we should warn the user for missing resources if((!wadfile.IsIWAD) && (locations.Count == 0) && (configinfo.Resources.Count == 0)) { if(MessageBox.Show(this, "You are about to load a map without selecting any resources. Textures, flats and " + "sprites may not be shown correctly or may not show up at all. Do you want to continue?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.No) { return; } } // Apply changes options.ClearResources(); options.ConfigFile = configinfo.Filename; options.CurrentName = mapslist.SelectedItems[0].Text; options.StrictPatches = strictpatches.Checked; options.CopyResources(locations); //mxd. Store script compiler if(scriptcompiler.Enabled) { ScriptConfiguration scriptcfg = scriptcompiler.SelectedItem as ScriptConfiguration; foreach(KeyValuePair group in General.CompiledScriptConfigs) { if(group.Value == scriptcfg) { options.ScriptCompiler = group.Key; break; } } } //mxd. Use long texture names? if(longtexturenames.Enabled) options.UseLongTextureNames = longtexturenames.Checked; // Hide window wadfile.Dispose(); this.DialogResult = DialogResult.OK; this.Close(); } // Cancel clicked private void cancel_Click(object sender, EventArgs e) { // Just hide window wadfile.Dispose(); this.DialogResult = DialogResult.Cancel; this.Close(); } // Window is shown private void OpenMapOptionsForm_Shown(object sender, EventArgs e) { // Update window this.Update(); // Load settings LoadSettings(); } // Map name doubleclicked private void mapslist_DoubleClick(object sender, EventArgs e) { // Click OK if(mapslist.SelectedItems.Count > 0) apply.PerformClick(); } // Map name selected private void mapslist_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { if(!e.IsSelected) return; //mxd. Don't want to trigger this twice DataLocationList locations; DataLocationList listedlocations; string scriptconfig = string.Empty; //mxd // Map previously selected? if(!string.IsNullOrEmpty(selectedmapname)) { // Get locations from previous selected map settings locations = new DataLocationList(mapsettings, "maps." + selectedmapname + ".resources"); listedlocations = datalocations.GetResources(); // Remove data locations that this map has in its config foreach(DataLocation dl in locations) listedlocations.Remove(dl); // Set new data locations datalocations.EditResourceLocationList(listedlocations); // Done selectedmapname = null; } // Anything selected? if(mapslist.SelectedItems.Count > 0) { // Get the map name selectedmapname = mapslist.SelectedItems[0].Text; options = new MapOptions(mapsettings, selectedmapname, longtexturenames.Enabled); // Get locations from previous selected map settings locations = new DataLocationList(mapsettings, "maps." + selectedmapname + ".resources"); listedlocations = datalocations.GetResources(); // Add data locations that this map has in its config foreach(DataLocation dl in locations) if(!listedlocations.Contains(dl)) listedlocations.Add(dl); // Set new data locations datalocations.EditResourceLocationList(listedlocations); //mxd. Select script compiler ConfigurationInfo info = config.SelectedItem as ConfigurationInfo; if(info != null) { if(!string.IsNullOrEmpty(options.ScriptCompiler) && General.CompiledScriptConfigs.ContainsKey(options.ScriptCompiler)) { scriptconfig = options.ScriptCompiler; } else if(!string.IsNullOrEmpty(info.DefaultScriptCompiler) && General.CompiledScriptConfigs.ContainsKey(info.DefaultScriptCompiler)) { scriptconfig = info.DefaultScriptCompiler; } } } //mxd. Select proper script compiler if(!string.IsNullOrEmpty(scriptconfig)) { scriptcompiler.Enabled = true; scriptcompiler.SelectedItem = General.CompiledScriptConfigs[scriptconfig]; scriptcompilerlabel.Enabled = true; } else { scriptcompiler.Enabled = false; scriptcompiler.SelectedIndex = -1; scriptcompilerlabel.Enabled = false; } } // Help private void OpenMapOptionsForm_HelpRequested(object sender, HelpEventArgs hlpevent) { General.ShowHelp("w_openmapoptions.html"); hlpevent.Handled = true; } } }