ZoneBuilder/Source/Core/Windows/OpenMapOptionsForm.cs
MaxED a82102a611 Added, Draw Ellipse mode: angle setting can now be changed using "Rotate Clockwise" and "Rotate Counterclockwise" actions.
Added, Draw Line and Draw Curve modes: added "Auto-finish drawing" setting. When enabled, the modes will automatically finish drawing when currently drawn lines and already existing level geometry form a closed shape.
Changed: sector-wise linedef flipping is now done using the new "Align Linedefs" action. "Flip Linedefs" action works the same as in DB2 again.
Changed: when a map was already loaded, using "Open Map" action will use that map's directory as the starting directory.
Changed: official IWADs can no longer be saved.
Changed: disabled lump ranges/duplicate entries checks for official IWADs.
Changed: wad type is now preserved when saving a map (previously all wads were saved as PWADs).
Changed: moved Updater.exe launch much closer to the editor termination point to avoid any chance of it closing the editor before it properly closes itself.
Updated ZDoom_DECORATE.cfg (A_Blast).
Updated documentation.
2023-01-04 13:30:21 +01:00

597 lines
No EOL
19 KiB
C#

#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<string, ScriptConfiguration> 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<ListViewItem> mapnames = new List<ListViewItem>();
// 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<string, ScriptConfiguration> 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;
}
}
}