UltimateZoneBuilder/Source/General/General.cs

1375 lines
40 KiB
C#
Raw Normal View History

2007-06-13 19:39:38 +00:00
2007-06-14 23:31:57 +00:00
#region ================== Copyright (c) 2007 Pascal vd Heiden
2007-06-13 19:39:38 +00:00
/*
* 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.
*
*/
2007-06-14 23:31:57 +00:00
#endregion
#region ================== Namespaces
2007-06-13 19:39:38 +00:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Windows;
2007-06-13 19:39:38 +00:00
using CodeImp.DoomBuilder.IO;
2007-06-14 23:31:57 +00:00
using CodeImp.DoomBuilder.Map;
2007-06-15 22:38:42 +00:00
using CodeImp.DoomBuilder.Geometry;
2007-06-24 18:56:43 +00:00
using System.Runtime.InteropServices;
using CodeImp.DoomBuilder.Actions;
using System.Diagnostics;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Config;
2007-11-04 22:19:30 +00:00
using SlimDX.Direct3D9;
using System.Drawing;
2008-01-02 21:49:43 +00:00
using CodeImp.DoomBuilder.Plugins;
2008-05-29 16:44:20 +00:00
using CodeImp.DoomBuilder.Types;
using System.Collections.ObjectModel;
using System.Threading;
2007-06-14 23:31:57 +00:00
#endregion
2007-06-13 19:39:38 +00:00
namespace CodeImp.DoomBuilder
{
2007-10-24 17:25:03 +00:00
public static class General
2007-06-13 19:39:38 +00:00
{
2007-06-24 18:56:43 +00:00
#region ================== API Declarations
2008-10-27 08:19:15 +00:00
[DllImport("user32.dll")]
internal static extern bool LockWindowUpdate(IntPtr hwnd);
2007-06-24 18:56:43 +00:00
[DllImport("kernel32.dll", EntryPoint = "RtlZeroMemory", SetLastError = false)]
2008-01-02 21:49:43 +00:00
internal static extern void ZeroMemory(IntPtr dest, int size);
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
2008-01-02 21:49:43 +00:00
internal static extern unsafe void CopyMemory(void* dst, void* src, UIntPtr length);
2008-06-02 20:34:52 +00:00
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern int SendMessage(IntPtr hwnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MessageBeep(MessageBeepType type);
[DllImport("kernel32.dll")]
internal extern static IntPtr LoadLibrary(string filename);
[DllImport("kernel32.dll")]
internal extern static bool FreeLibrary(IntPtr moduleptr);
[DllImport("user32.dll")]
internal static extern IntPtr CreateWindowEx(uint exstyle, string classname, string windowname, uint style,
int x, int y, int width, int height, IntPtr parentptr, int menu,
IntPtr instanceptr, string param);
[DllImport("user32.dll")]
internal static extern bool DestroyWindow(IntPtr windowptr);
[DllImport("user32.dll")]
internal static extern int SetWindowPos(IntPtr windowptr, int insertafterptr, int x, int y, int cx, int cy, int flags);
2008-06-02 20:34:52 +00:00
2007-06-24 18:56:43 +00:00
#endregion
2007-06-13 19:39:38 +00:00
#region ================== Constants
2008-06-02 20:34:52 +00:00
// SendMessage API
2008-10-29 10:56:14 +00:00
internal const int WM_USER = 0x400;
2008-06-02 20:34:52 +00:00
internal const int CB_SETITEMHEIGHT = 0x153;
2008-10-29 10:56:14 +00:00
internal const int EM_GETSCROLLPOS = WM_USER + 221;
internal const int EM_SETSCROLLPOS = WM_USER + 222;
2008-06-02 20:34:52 +00:00
2007-06-13 19:39:38 +00:00
// Files and Folders
private const string SETTINGS_FILE = "Builder.cfg";
private const string SETTINGS_DIR = "Doom Builder";
private const string LOG_FILE = "Builder.log";
private const string GAME_CONFIGS_DIR = "Configurations";
2007-09-28 08:56:18 +00:00
private const string COMPILERS_DIR = "Compilers";
2008-01-02 21:49:43 +00:00
private const string PLUGINS_DIR = "Plugins";
private const string SETUP_DIR = "Setup";
2007-06-13 19:39:38 +00:00
#endregion
#region ================== Variables
// Files and Folders
private static string apppath;
private static string setuppath;
private static string settingspath;
private static string logfile;
2007-06-13 19:39:38 +00:00
private static string temppath;
private static string configspath;
2007-09-28 08:56:18 +00:00
private static string compilerspath;
2008-01-02 21:49:43 +00:00
private static string pluginspath;
2007-06-13 19:39:38 +00:00
// Main objects
2007-06-15 18:30:55 +00:00
private static Assembly thisasm;
2007-06-13 19:39:38 +00:00
private static MainForm mainwindow;
2007-12-01 01:32:56 +00:00
private static ProgramConfiguration settings;
2007-06-14 23:31:57 +00:00
private static MapManager map;
2007-06-24 22:53:41 +00:00
private static ActionManager actions;
2008-01-02 21:49:43 +00:00
private static PluginManager plugins;
private static ColorCollection colors;
2008-05-29 16:44:20 +00:00
private static TypesManager types;
2007-10-26 18:04:54 +00:00
private static Clock clock;
2007-06-14 23:31:57 +00:00
// Configurations
2007-06-14 23:31:57 +00:00
private static List<ConfigurationInfo> configs;
private static List<CompilerInfo> compilers;
2007-09-28 08:56:18 +00:00
private static List<NodebuilderInfo> nodebuilders;
// States
private static bool debugbuild;
// Command line arguments
private static string[] cmdargs;
private static string autoloadfile = null;
private static string autoloadmap = null;
private static string autoloadconfig = null;
private static bool delaymainwindow;
2007-06-13 19:39:38 +00:00
#endregion
#region ================== Properties
2008-01-02 21:49:43 +00:00
internal static Assembly ThisAssembly { get { return thisasm; } }
2007-06-13 19:39:38 +00:00
public static string AppPath { get { return apppath; } }
public static string TempPath { get { return temppath; } }
public static string ConfigsPath { get { return configspath; } }
2007-09-28 08:56:18 +00:00
public static string CompilersPath { get { return compilerspath; } }
2008-01-02 21:49:43 +00:00
public static string PluginsPath { get { return pluginspath; } }
public static ICollection<string> CommandArgs { get { return Array.AsReadOnly<string>(cmdargs); } }
2008-01-02 21:49:43 +00:00
internal static MainForm MainWindow { get { return mainwindow; } }
public static IMainForm Interface { get { return mainwindow; } }
2007-12-01 01:32:56 +00:00
public static ProgramConfiguration Settings { get { return settings; } }
public static ColorCollection Colors { get { return colors; } }
2008-01-02 21:49:43 +00:00
internal static List<ConfigurationInfo> Configs { get { return configs; } }
internal static List<NodebuilderInfo> Nodebuilders { get { return nodebuilders; } }
internal static List<CompilerInfo> Compilers { get { return compilers; } }
2007-06-14 23:31:57 +00:00
public static MapManager Map { get { return map; } }
2008-01-02 21:49:43 +00:00
internal static ActionManager Actions { get { return actions; } }
internal static PluginManager Plugins { get { return plugins; } }
2007-10-26 18:04:54 +00:00
public static Clock Clock { get { return clock; } }
public static bool DebugBuild { get { return debugbuild; } }
2008-05-29 16:44:20 +00:00
internal static TypesManager Types { get { return types; } }
public static string AutoLoadFile { get { return autoloadfile; } }
public static string AutoLoadMap { get { return autoloadmap; } }
public static string AutoLoadConfig { get { return autoloadconfig; } }
public static bool DelayMainWindow { get { return delaymainwindow; } }
2007-06-14 23:31:57 +00:00
#endregion
#region ================== Configurations
2007-09-27 22:55:03 +00:00
// This returns the game configuration info by filename
2008-01-02 21:49:43 +00:00
internal static ConfigurationInfo GetConfigurationInfo(string filename)
2007-09-27 22:55:03 +00:00
{
// Go for all config infos
foreach(ConfigurationInfo ci in configs)
{
// Check if filename matches
if(string.Compare(Path.GetFileNameWithoutExtension(ci.Filename),
Path.GetFileNameWithoutExtension(filename), true) == 0)
{
// Return this info
return ci;
}
}
// None found
return null;
}
2007-06-14 23:31:57 +00:00
// This loads and returns a game configuration
2008-01-02 21:49:43 +00:00
internal static Configuration LoadGameConfiguration(string filename)
2007-06-14 23:31:57 +00:00
{
Configuration cfg;
// Make the full filepathname
string filepathname = Path.Combine(configspath, filename);
// Load configuration
try
{
// Try loading the configuration
cfg = new Configuration(filepathname, true);
// Check for erors
if(cfg.ErrorResult != 0)
{
// Error in configuration
ShowErrorMessage("Unable to load the game configuration file \"" + filename + "\".\n" +
"Error near line " + cfg.ErrorLine + ": " + cfg.ErrorDescription, MessageBoxButtons.OK);
2007-06-14 23:31:57 +00:00
return null;
}
2007-09-27 22:55:03 +00:00
// Check if this is a Doom Builder 2 config
2007-06-16 19:53:51 +00:00
else if(cfg.ReadSetting("type", "") != "Doom Builder 2 Game Configuration")
{
// Old configuration
ShowErrorMessage("Unable to load the game configuration file \"" + filename + "\".\n" +
"This configuration is not a Doom Builder 2 game configuration.", MessageBoxButtons.OK);
2007-06-16 19:53:51 +00:00
return null;
}
2007-06-14 23:31:57 +00:00
else
{
// The following code was used to convert the linedef types of DB1 type
// configurations into proper categorized structures for DB2.
// I keep this code here in the repository because if it failed, I might
// need this again to convert from scratch.
/*
GameConfiguration gcfg = new GameConfiguration(cfg);
Configuration newcfg = new Configuration();
newcfg.NewConfiguration(true);
bool doommap = (gcfg.FormatInterface == "DoomMapSetIO");
foreach(LinedefActionInfo a in gcfg.SortedLinedefActions)
{
string catkey = a.Category.ToLowerInvariant().Trim();
string cattitle = a.Category;
string linekey = a.Index.ToString(CultureInfo.InvariantCulture);
string linetitle = a.Name;
string lineprefix = a.Prefix;
if(catkey.Length == 0) { catkey = "misc"; cattitle = ""; }
if(cattitle.Length > 0) newcfg.WriteSetting("linedeftypes." + catkey + ".title", cattitle);
newcfg.WriteSetting("linedeftypes." + catkey + "." + linekey + ".title", linetitle);
if(doommap) newcfg.WriteSetting("linedeftypes." + catkey + "." + linekey + ".prefix", lineprefix);
if(!doommap)
{
for(int i = 0; i < 5; i++)
{
if(a.ArgUsed[i])
{
newcfg.WriteSetting("linedeftypes." + catkey + "." + linekey + ".arg" + i.ToString(CultureInfo.InvariantCulture) + ".title", a.ArgTitle[i]);
if(a.ArgTagType[i] != TagType.None) newcfg.WriteSetting("linedeftypes." + catkey + "." + linekey + ".arg" + i.ToString(CultureInfo.InvariantCulture) + ".tag", (int)a.ArgTagType[i]);
}
}
}
}
newcfg.SaveConfiguration(Path.Combine(configspath, "_" + filename));
*/
2007-06-14 23:31:57 +00:00
// Return config
return cfg;
}
}
catch(Exception)
{
// Unable to load configuration
ShowErrorMessage("Unable to load the game configuration file \"" + filename + "\".", MessageBoxButtons.OK);
2007-06-14 23:31:57 +00:00
return null;
}
}
// This loads all game configurations
private static void LoadAllGameConfigurations()
2007-06-14 23:31:57 +00:00
{
Configuration cfg;
string[] filenames;
string name, fullfilename;
// Display status
mainwindow.DisplayStatus("Loading game configurations...");
2007-06-13 19:39:38 +00:00
2007-06-14 23:31:57 +00:00
// Make array
configs = new List<ConfigurationInfo>();
2007-09-28 08:56:18 +00:00
// Go for all cfg files in the configurations directory
2007-06-14 23:31:57 +00:00
filenames = Directory.GetFiles(configspath, "*.cfg", SearchOption.TopDirectoryOnly);
foreach(string filepath in filenames)
{
// Check if it can be loaded
2007-06-16 19:53:51 +00:00
cfg = LoadGameConfiguration(Path.GetFileName(filepath));
2007-06-14 23:31:57 +00:00
if(cfg != null)
{
fullfilename = Path.GetFileName(filepath);
ConfigurationInfo cfginfo = new ConfigurationInfo(cfg, fullfilename);
2007-06-14 23:31:57 +00:00
// Add to lists
General.WriteLogLine("Registered game configuration '" + cfginfo.Name + "' from '" + fullfilename + "'");
configs.Add(cfginfo);
2007-06-14 23:31:57 +00:00
}
}
// Sort the list
2007-06-14 23:31:57 +00:00
configs.Sort();
}
// This loads all nodebuilder configurations
private static void LoadAllNodebuilderConfigurations()
2007-09-28 08:56:18 +00:00
{
Configuration cfg;
IDictionary builderslist;
2007-09-28 08:56:18 +00:00
string[] filenames;
2007-09-28 08:56:18 +00:00
// Display status
mainwindow.DisplayStatus("Loading nodebuilder configurations...");
// Make array
nodebuilders = new List<NodebuilderInfo>();
// Go for all cfg files in the compilers directory
filenames = Directory.GetFiles(compilerspath, "*.cfg", SearchOption.TopDirectoryOnly);
foreach(string filepath in filenames)
{
try
{
// Try loading the configuration
cfg = new Configuration(filepath, true);
// Check for erors
if(cfg.ErrorResult != 0)
{
// Error in configuration
ShowErrorMessage("Unable to load the compiler configuration file \"" + Path.GetFileName(filepath) + "\".\n" +
"Error near line " + cfg.ErrorLine + ": " + cfg.ErrorDescription, MessageBoxButtons.OK);
}
else
{
// Get structures
builderslist = cfg.ReadSetting("nodebuilders", new Hashtable());
foreach(DictionaryEntry de in builderslist)
{
// Check if this is a structure
if(de.Value is IDictionary)
{
try
{
// Make nodebuilder info
nodebuilders.Add(new NodebuilderInfo(Path.GetFileName(filepath), de.Key.ToString(), cfg));
}
catch(Exception e)
{
// Unable to load configuration
ShowErrorMessage("Unable to load the nodebuilder configuration '" + de.Key.ToString() + "' from \"" + Path.GetFileName(filepath) + "\". Error: " + e.Message, MessageBoxButtons.OK);
}
}
}
}
}
catch(Exception)
{
// Unable to load configuration
ShowErrorMessage("Unable to load the compiler configuration file \"" + Path.GetFileName(filepath) + "\".", MessageBoxButtons.OK);
}
}
// Sort the list
nodebuilders.Sort();
}
// This loads all compiler configurations
private static void LoadAllCompilerConfigurations()
{
Configuration cfg;
IDictionary compilerslist;
string[] filenames;
// Display status
mainwindow.DisplayStatus("Loading compiler configurations...");
// Make array
compilers = new List<CompilerInfo>();
// Go for all cfg files in the compilers directory
filenames = Directory.GetFiles(compilerspath, "*.cfg", SearchOption.TopDirectoryOnly);
foreach(string filepath in filenames)
{
try
{
// Try loading the configuration
cfg = new Configuration(filepath, true);
// Check for erors
if(cfg.ErrorResult != 0)
{
// Error in configuration
ShowErrorMessage("Unable to load the compiler configuration file \"" + Path.GetFileName(filepath) + "\".\n" +
"Error near line " + cfg.ErrorLine + ": " + cfg.ErrorDescription, MessageBoxButtons.OK);
2007-09-28 08:56:18 +00:00
}
else
{
// Get structures
compilerslist = cfg.ReadSetting("compilers", new Hashtable());
foreach(DictionaryEntry de in compilerslist)
{
// Check if this is a structure
if(de.Value is IDictionary)
{
// Make compiler info
compilers.Add(new CompilerInfo(Path.GetFileName(filepath), de.Key.ToString(), cfg));
}
}
2007-09-28 08:56:18 +00:00
}
}
catch(Exception)
{
// Unable to load configuration
ShowErrorMessage("Unable to load the compiler configuration file \"" + Path.GetFileName(filepath) + "\".", MessageBoxButtons.OK);
2007-09-28 08:56:18 +00:00
}
}
}
// This returns a nodebuilder by name
2008-01-02 21:49:43 +00:00
internal static NodebuilderInfo GetNodebuilderByName(string name)
{
// Go for all nodebuilders
foreach(NodebuilderInfo n in nodebuilders)
{
// Name matches?
if(n.Name == name) return n;
}
2007-09-28 08:56:18 +00:00
// Cannot find that nodebuilder
return null;
2007-09-28 08:56:18 +00:00
}
2007-06-13 19:39:38 +00:00
#endregion
#region ================== Startup
2007-06-13 19:39:38 +00:00
// Main program entry
2007-06-15 10:18:03 +00:00
[STAThread]
2008-01-02 21:49:43 +00:00
internal static void Main(string[] args)
2007-06-13 19:39:38 +00:00
{
2007-06-15 18:30:55 +00:00
Uri localpath;
Version thisversion;
// Determine states
#if DEBUG
debugbuild = true;
#else
debugbuild = false;
#endif
2007-11-04 22:19:30 +00:00
// Enable OS visual styles
Application.EnableVisualStyles();
Application.DoEvents(); // This must be here to work around a .NET bug
// Hook to DLL loading failure event
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
2007-06-15 18:30:55 +00:00
// Set current thread name
Thread.CurrentThread.Name = "Main Application";
2007-06-15 18:30:55 +00:00
// Get a reference to this assembly
thisasm = Assembly.GetExecutingAssembly();
thisversion = thisasm.GetName().Version;
2007-06-15 18:30:55 +00:00
2007-06-13 19:39:38 +00:00
// Find application path
2007-06-15 18:30:55 +00:00
localpath = new Uri(Path.GetDirectoryName(thisasm.GetName().CodeBase));
2007-06-13 19:39:38 +00:00
apppath = Uri.UnescapeDataString(localpath.AbsolutePath);
2007-09-28 08:56:18 +00:00
// Setup directories
2007-06-13 19:39:38 +00:00
temppath = Path.GetTempPath();
setuppath = Path.Combine(apppath, SETUP_DIR);
settingspath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), SETTINGS_DIR);
configspath = Path.Combine(apppath, GAME_CONFIGS_DIR);
2007-09-28 08:56:18 +00:00
compilerspath = Path.Combine(apppath, COMPILERS_DIR);
2008-01-02 21:49:43 +00:00
pluginspath = Path.Combine(apppath, PLUGINS_DIR);
2007-10-05 07:19:57 +00:00
logfile = Path.Combine(settingspath, LOG_FILE);
2007-10-05 08:00:29 +00:00
// Make program settings directory if missing
if(!Directory.Exists(settingspath)) Directory.CreateDirectory(settingspath);
// Remove the previous log file and start logging
2007-10-05 08:00:29 +00:00
if(File.Exists(logfile)) File.Delete(logfile);
General.WriteLogLine("Doom Builder " + thisversion.Major + "." + thisversion.Minor + " startup");
General.WriteLogLine("Application path: " + apppath);
General.WriteLogLine("Temporary path: " + temppath);
General.WriteLogLine("Local settings path: " + settingspath);
General.WriteLogLine("Configurations path: " + configspath);
General.WriteLogLine("Compilers path: " + compilerspath);
General.WriteLogLine("Plugins path: " + pluginspath);
General.WriteLogLine("Command-line arguments: " + args.Length);
for(int i = 0; i < args.Length; i++)
General.WriteLogLine("Argument " + i + ": \"" + args[i] + "\"");
// Parse command-line arguments
ParseCommandLineArgs(args);
2007-06-13 19:39:38 +00:00
// Load configuration
General.WriteLogLine("Loading program configuration...");
2007-12-01 01:32:56 +00:00
settings = new ProgramConfiguration();
if(settings.Load(Path.Combine(settingspath, SETTINGS_FILE),
Path.Combine(apppath, SETTINGS_FILE)))
{
// Create action manager
actions = new ActionManager();
2008-01-13 21:23:59 +00:00
// Bind static methods to actions
General.Actions.BindMethods(typeof(General));
// Initialize static classes
MapSet.Initialize();
// Create main window
General.WriteLogLine("Loading main interface window...");
mainwindow = new MainForm();
2007-10-14 21:31:45 +00:00
mainwindow.UpdateInterface();
if(!delaymainwindow)
{
// Show main window
General.WriteLogLine("Showing main interface window...");
mainwindow.Show();
mainwindow.Update();
}
2007-11-04 22:19:30 +00:00
// Start Direct3D
General.WriteLogLine("Starting Direct3D graphics driver...");
try { D3DDevice.Startup(); }
catch(Direct3D9NotFoundException) { AskDownloadDirectX(); return; }
catch(Direct3DX9NotFoundException) { AskDownloadDirectX(); return; }
2007-11-04 22:19:30 +00:00
2008-01-02 21:49:43 +00:00
// Load plugin manager
General.WriteLogLine("Loading plugins...");
plugins = new PluginManager();
plugins.LoadAllPlugins();
// Now that all settings have been combined (core & plugins) apply the defaults
General.WriteLogLine("Applying configuration settings...");
actions.ApplyDefaultShortcutKeys();
2008-01-02 21:49:43 +00:00
// Load game configurations
General.WriteLogLine("Loading game configurations...");
LoadAllGameConfigurations();
// Load compiler configurations
General.WriteLogLine("Loading compiler configurations...");
LoadAllCompilerConfigurations();
// Load nodebuilder configurations
General.WriteLogLine("Loading nodebuilder configurations...");
LoadAllNodebuilderConfigurations();
// Load color settings
General.WriteLogLine("Loading color settings...");
2007-12-01 01:32:56 +00:00
colors = new ColorCollection(settings.Config);
2007-10-26 18:04:54 +00:00
// Create application clock
General.WriteLogLine("Creating application clock...");
clock = new Clock();
2008-05-29 16:44:20 +00:00
// Create types manager
General.WriteLogLine("Creating types manager...");
types = new TypesManager();
// Do auto map loading when window is delayed
if(delaymainwindow)
mainwindow.PerformAutoMapLoading();
// Run application from the main window
General.WriteLogLine("Startup done");
mainwindow.DisplayReady();
Application.Run(mainwindow);
}
else
{
// Terminate
Terminate(false);
}
}
// This handles DLL linking errors
private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Check if SlimDX failed loading
if(args.Name.Contains("SlimDX")) AskDownloadDirectX();
// Return null
return null;
}
// This asks the user to download DirectX
private static void AskDownloadDirectX()
{
// Cancel loading map from command-line parameters, if any.
// This causes problems, because when the window is shown, the map will
// be loaded and DirectX is initialized (which we seem to be missing)
autoloadfile = null;
// Ask the user to download DirectX
if(MessageBox.Show("This application requires the latest version of Microsoft DirectX installed on your computer." + Environment.NewLine +
2008-09-13 13:27:20 +00:00
"Do you want to install and/or update Microsoft DirectX now?", "DirectX Error", System.Windows.Forms.MessageBoxButtons.YesNo,
System.Windows.Forms.MessageBoxIcon.Exclamation) == System.Windows.Forms.DialogResult.Yes)
{
// Open DX web setup
//System.Diagnostics.Process.Start("http://www.microsoft.com/downloads/details.aspx?FamilyId=2DA43D38-DB71-4C1B-BC6A-9B6652CD92A3").WaitForExit(1000);
System.Diagnostics.Process.Start(Path.Combine(setuppath, "dxwebsetup.exe")).WaitForExit(1000);
}
// End program here
Terminate(false);
}
// This parses the command line arguments
private static void ParseCommandLineArgs(string[] args)
{
// Keep a copy
cmdargs = args;
// Make a queue so we can parse the values from left to right
Queue<string> argslist = new Queue<string>(args);
// Parse list
while(argslist.Count > 0)
{
// Get next arg
string curarg = argslist.Dequeue();
// Delay window?
if(string.Compare(curarg, "-DELAYWINDOW", true) == 0)
{
// Delay showing the main window
delaymainwindow = true;
}
// Map name info?
else if(string.Compare(curarg, "-MAP", true) == 0)
{
// Store next arg as map name information
autoloadmap = argslist.Dequeue();
}
// Config name info?
else if((string.Compare(curarg, "-CFG", true) == 0) ||
(string.Compare(curarg, "-CONFIG", true) == 0))
{
// Store next arg as config filename information
autoloadconfig = argslist.Dequeue();
}
// Every other arg
else
{
// No command to load file yet?
if(autoloadfile == null)
{
// Check if this is a file we can load
if(File.Exists(curarg))
{
// Load this file!
autoloadfile = curarg.Trim();
}
else
{
// Note in the log that we cannot find this file
General.WriteLogLine("WARNING: Cannot find the specified file \"" + curarg + "\"");
}
}
}
}
}
2007-06-13 19:39:38 +00:00
#endregion
#region ================== Terminate
// This is for plugins to use
public static void Exit(bool properexit)
{
// Plugin wants to exit nicely?
if(properexit)
{
// Close dialog forms first
while((Form.ActiveForm != mainwindow) && (Form.ActiveForm != null))
Form.ActiveForm.Close();
// Close main window
mainwindow.Close();
}
else
{
// Terminate, no questions asked
Terminate(true);
}
}
// This terminates the program
2008-01-02 21:49:43 +00:00
internal static void Terminate(bool properexit)
{
// Terminate properly?
if(properexit)
{
General.WriteLogLine("Termination requested");
// Unbind static methods from actions
General.Actions.UnbindMethods(typeof(General));
// Save colors
2007-12-01 01:32:56 +00:00
colors.SaveColors(settings.Config);
// Save action controls
actions.SaveSettings();
// Save game configuration settings
foreach(ConfigurationInfo ci in configs) ci.SaveSettings();
// Save settings configuration
General.WriteLogLine("Saving program configuration...");
2007-12-01 01:32:56 +00:00
settings.Save(Path.Combine(settingspath, SETTINGS_FILE));
// Clean up
if(map != null) map.Dispose(); map = null;
if(mainwindow != null) mainwindow.Dispose();
if(actions != null) actions.Dispose();
if(clock != null) clock.Dispose();
if(plugins != null) plugins.Dispose();
2008-05-29 16:44:20 +00:00
if(types != null) types.Dispose();
try { D3DDevice.Terminate(); } catch(Exception) { }
// Application ends here and now
General.WriteLogLine("Termination done");
Application.Exit();
}
else
{
// Just end now
General.WriteLogLine("Immediate program termination");
Application.Exit();
}
// Die.
Process.GetCurrentProcess().Kill();
}
#endregion
2007-06-14 23:31:57 +00:00
#region ================== Management
2008-09-23 10:04:10 +00:00
// This cancels a volatile mode, as if the user presses cancel
public static bool CancelVolatileMode()
{
// Volatile mode?
2008-09-23 10:04:10 +00:00
if((map != null) & (map.Mode != null) && map.Mode.Attributes.Volatile)
{
// Cancel
map.Mode.OnCancel();
return true;
}
else
{
// Mode is not volatile
return false;
}
}
2008-09-23 10:04:10 +00:00
// This disengages a volatile mode, leaving the choice to cancel or accept to the editing mode
public static bool DisengageVolatileMode()
{
// Volatile mode?
if((map != null) && (map.Mode != null) && map.Mode.Attributes.Volatile)
2008-09-23 10:04:10 +00:00
{
// Change back to normal mode
map.ChangeMode(map.PreviousStableMode.Name);
return true;
}
else
{
// Mode is not volatile
return false;
}
}
2007-06-14 23:31:57 +00:00
// This creates a new map
[BeginAction("newmap")]
2008-01-02 21:49:43 +00:00
internal static void NewMap()
2007-06-14 23:31:57 +00:00
{
MapOptions newoptions = new MapOptions();
2007-06-14 23:31:57 +00:00
MapOptionsForm optionswindow;
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Ask the user to save changes (if any)
if(General.AskSaveMap())
2007-06-16 19:53:51 +00:00
{
// Open map options dialog
optionswindow = new MapOptionsForm(newoptions);
optionswindow.IsForNewMap = true;
if(optionswindow.ShowDialog(mainwindow) == DialogResult.OK)
2007-06-14 23:31:57 +00:00
{
2007-06-15 10:18:03 +00:00
// Display status
mainwindow.DisplayStatus("Creating new map...");
2007-10-14 18:11:03 +00:00
Cursor.Current = Cursors.WaitCursor;
2007-06-16 19:53:51 +00:00
// Let the plugins know
plugins.OnMapNewBegin();
2007-06-15 10:18:03 +00:00
// Clear the display
mainwindow.ClearDisplay();
2007-06-16 19:53:51 +00:00
2007-06-15 10:18:03 +00:00
// Trash the current map, if any
if(map != null) map.Dispose();
// Create map manager with given options
2007-06-15 18:30:55 +00:00
map = new MapManager();
if(map.InitializeNewMap(newoptions))
{
// Done
}
else
2007-06-15 18:30:55 +00:00
{
// Unable to create map manager
map.Dispose();
map = null;
// Show splash logo on display
mainwindow.ShowSplashDisplay();
}
2007-10-14 18:11:03 +00:00
// Let the plugins know
plugins.OnMapNewEnd();
2007-10-14 18:11:03 +00:00
// All done
mainwindow.RedrawDisplay();
2007-10-14 21:31:45 +00:00
mainwindow.UpdateInterface();
mainwindow.HideInfo();
2007-10-14 18:11:03 +00:00
mainwindow.DisplayReady();
Cursor.Current = Cursors.Default;
2007-06-14 23:31:57 +00:00
}
2007-06-15 10:18:03 +00:00
}
}
2007-06-16 19:53:51 +00:00
// This closes the current map
[BeginAction("closemap")]
internal static void ActionCloseMap() { CloseMap(); }
internal static bool CloseMap()
{
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Ask the user to save changes (if any)
if(General.AskSaveMap())
{
// Display status
mainwindow.DisplayStatus("Closing map...");
2007-10-05 10:00:15 +00:00
General.WriteLogLine("Unloading map...");
2007-10-14 18:11:03 +00:00
Cursor.Current = Cursors.WaitCursor;
// Trash the current map
if(map != null) map.Dispose();
map = null;
// Show splash logo on display
mainwindow.ShowSplashDisplay();
// Done
2007-10-14 18:11:03 +00:00
Cursor.Current = Cursors.Default;
mainwindow.RedrawDisplay();
mainwindow.HideInfo();
2007-10-14 21:31:45 +00:00
mainwindow.UpdateInterface();
mainwindow.DisplayReady();
2007-10-05 10:00:15 +00:00
General.WriteLogLine("Map unload done");
return true;
}
else
{
// User cancelled
return false;
}
}
// This loads a map from file
[BeginAction("openmap")]
2008-01-02 21:49:43 +00:00
internal static void OpenMap()
{
OpenFileDialog openfile;
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Open map file dialog
openfile = new OpenFileDialog();
openfile.Filter = "Doom WAD Files (*.wad)|*.wad";
openfile.Title = "Open Map";
2007-10-14 15:44:55 +00:00
openfile.AddExtension = false;
openfile.CheckFileExists = true;
openfile.Multiselect = false;
openfile.ValidateNames = true;
if(openfile.ShowDialog(mainwindow) == DialogResult.OK)
{
// Update main window
mainwindow.Update();
// Open map file
OpenMapFile(openfile.FileName);
}
}
// This opens the specified file
2008-01-02 21:49:43 +00:00
internal static void OpenMapFile(string filename)
{
OpenMapOptionsForm openmapwindow;
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Ask the user to save changes (if any)
if(General.AskSaveMap())
{
// Open map options dialog
openmapwindow = new OpenMapOptionsForm(filename);
if(openmapwindow.ShowDialog(mainwindow) == DialogResult.OK)
OpenMapFileWithOptions(filename, openmapwindow.Options);
}
}
// This opens the specified file without dialog
internal static void OpenMapFileWithOptions(string filename, MapOptions options)
{
// Display status
mainwindow.DisplayStatus("Opening map file...");
Cursor.Current = Cursors.WaitCursor;
// Let the plugins know
plugins.OnMapOpenBegin();
// Clear the display
mainwindow.ClearDisplay();
// Trash the current map, if any
if(map != null) map.Dispose();
// Create map manager with given options
map = new MapManager();
if(map.InitializeOpenMap(filename, options))
{
// Add recent file
mainwindow.AddRecentFile(filename);
}
else
{
// Unable to create map manager
map.Dispose();
map = null;
2007-10-14 18:11:03 +00:00
// Show splash logo on display
mainwindow.ShowSplashDisplay();
}
// Let the plugins know
plugins.OnMapOpenEnd();
// All done
mainwindow.RedrawDisplay();
mainwindow.UpdateInterface();
mainwindow.HideInfo();
mainwindow.DisplayReady();
Cursor.Current = Cursors.Default;
2007-06-15 10:18:03 +00:00
}
// This saves the current map
// Returns tre when saved, false when cancelled or failed
[BeginAction("savemap")]
internal static void ActionSaveMap() { SaveMap(); }
internal static bool SaveMap()
{
bool result = false;
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Check if a wad file is known
if(map.FilePathName == "")
{
2007-10-14 15:44:55 +00:00
// Call to SaveMapAs
result = SaveMapAs();
}
else
{
2007-10-14 18:11:03 +00:00
// Display status
mainwindow.DisplayStatus("Saving map file...");
Cursor.Current = Cursors.WaitCursor;
// Save the map
2007-10-15 07:50:28 +00:00
if(map.SaveMap(map.FilePathName, MapManager.SAVE_NORMAL))
{
// Add recent file
mainwindow.AddRecentFile(map.FilePathName);
result = true;
2007-10-15 07:50:28 +00:00
}
2007-10-14 18:11:03 +00:00
// All done
2007-10-14 21:31:45 +00:00
mainwindow.UpdateInterface();
2007-10-14 18:11:03 +00:00
mainwindow.DisplayReady();
Cursor.Current = Cursors.Default;
}
return result;
}
2007-10-14 15:44:55 +00:00
2007-10-14 15:44:55 +00:00
// This saves the current map as a different file
// Returns tre when saved, false when cancelled or failed
[BeginAction("savemapas")]
internal static void ActionSaveMapAs() { SaveMapAs(); }
internal static bool SaveMapAs()
2007-10-14 15:44:55 +00:00
{
SaveFileDialog savefile;
bool result = false;
2007-10-14 15:44:55 +00:00
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
2007-10-14 15:44:55 +00:00
// Show save as dialog
savefile = new SaveFileDialog();
savefile.Filter = "Doom WAD Files (*.wad)|*.wad";
savefile.Title = "Save Map As";
savefile.AddExtension = true;
savefile.CheckPathExists = true;
savefile.OverwritePrompt = true;
savefile.ValidateNames = true;
if(savefile.ShowDialog(mainwindow) == DialogResult.OK)
{
2007-10-14 18:11:03 +00:00
// Display status
mainwindow.DisplayStatus("Saving map file...");
Cursor.Current = Cursors.WaitCursor;
2007-10-14 15:44:55 +00:00
// Save the map
2007-10-15 07:50:28 +00:00
if(map.SaveMap(savefile.FileName, MapManager.SAVE_AS))
{
// Add recent file
mainwindow.AddRecentFile(map.FilePathName);
result = true;
2007-10-15 07:50:28 +00:00
}
2007-10-14 18:11:03 +00:00
// All done
2007-10-14 21:31:45 +00:00
mainwindow.UpdateInterface();
2007-10-14 18:11:03 +00:00
mainwindow.DisplayReady();
Cursor.Current = Cursors.Default;
}
return result;
}
// This saves the current map as a different file
// Returns tre when saved, false when cancelled or failed
[BeginAction("savemapinto")]
internal static void ActionSaveMapInto() { SaveMapInto(); }
internal static bool SaveMapInto()
{
SaveFileDialog savefile;
bool result = false;
// Cancel volatile mode, if any
2008-09-23 10:04:10 +00:00
General.DisengageVolatileMode();
// Show save as dialog
savefile = new SaveFileDialog();
savefile.Filter = "Doom WAD Files (*.wad)|*.wad";
savefile.Title = "Save Map Into";
savefile.AddExtension = true;
savefile.CheckPathExists = true;
savefile.OverwritePrompt = false;
savefile.ValidateNames = true;
if(savefile.ShowDialog(mainwindow) == DialogResult.OK)
{
// Display status
mainwindow.DisplayStatus("Saving map file...");
Cursor.Current = Cursors.WaitCursor;
// Save the map
if(map.SaveMap(savefile.FileName, MapManager.SAVE_INTO))
{
// Add recent file
mainwindow.AddRecentFile(map.FilePathName);
result = true;
}
// All done
mainwindow.UpdateInterface();
mainwindow.DisplayReady();
2007-10-14 18:11:03 +00:00
Cursor.Current = Cursors.Default;
2007-10-14 15:44:55 +00:00
}
return result;
2007-10-14 15:44:55 +00:00
}
2007-06-15 10:18:03 +00:00
// This asks to save the map if needed
// Returns false when action was cancelled
2008-01-02 21:49:43 +00:00
internal static bool AskSaveMap()
2007-06-15 10:18:03 +00:00
{
DialogResult result;
// Map open and not saved?
if((map != null) && map.IsChanged)
{
// Ask to save changes
result = MessageBox.Show(mainwindow, "Do you want to save changes to " + map.FileTitle + " (" + map.Options.CurrentName + ")?", Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if(result == DialogResult.Yes)
{
// Save map and return true on success
return SaveMap();
2007-06-15 10:18:03 +00:00
}
else if(result == DialogResult.Cancel)
{
// Abort
return false;
}
}
// Continue
return true;
}
2007-06-14 23:31:57 +00:00
#endregion
#region ================== Debug
2007-06-24 18:56:43 +00:00
// This shows a major failure
public static void Fail(string message, string detailedmessage)
{
Debug.Fail(message, detailedmessage);
}
// This outputs log information
public static void WriteLogLine(string line)
{
// Output to console
Console.WriteLine(line);
// Write to log file
2007-12-27 01:24:11 +00:00
try { File.AppendAllText(logfile, line + Environment.NewLine); }
catch(Exception) { }
}
// This outputs log information
public static void WriteLog(string text)
{
// Output to console
Console.Write(text);
// Write to log file
2007-12-27 01:24:11 +00:00
try { File.AppendAllText(logfile, text); }
catch(Exception) { }
}
2007-12-04 19:22:14 +00:00
#endregion
2007-06-24 18:56:43 +00:00
#region ================== Tools
2007-12-26 00:31:32 +00:00
// This returns an element from a collection by index
public static T GetByIndex<T>(ICollection<T> collection, int index)
{
IEnumerator<T> e = collection.GetEnumerator();
for(int i = -1; i < index; i++) e.MoveNext();
return e.Current;
}
// This returns the next power of 2
public static int NextPowerOf2(int v)
{
int p = 0;
// Continue increasing until higher than v
while(Math.Pow(2, p) < v) p++;
// Return power
return (int)Math.Pow(2, p);
}
// Convert bool to integer
2008-01-02 21:49:43 +00:00
internal static int Bool2Int(bool v)
{
if(v) return 1; else return 0;
}
// Convert integer to bool
2008-01-02 21:49:43 +00:00
internal static bool Int2Bool(int v)
{
return (v != 0);
}
// This shows a message and logs the message
public static DialogResult ShowErrorMessage(string message, MessageBoxButtons buttons)
{
2007-10-14 18:11:03 +00:00
Cursor oldcursor;
DialogResult result;
// Log the message
WriteLogLine(message);
2007-10-14 18:11:03 +00:00
// Use normal cursor
oldcursor = Cursor.Current;
Cursor.Current = Cursors.Default;
// Show message
2007-10-14 18:11:03 +00:00
result = MessageBox.Show(Form.ActiveForm, message, Application.ProductName, buttons, MessageBoxIcon.Error);
// Restore old cursor
Cursor.Current = oldcursor;
// Return result
return result;
}
// This shows a message and logs the message
public static DialogResult ShowWarningMessage(string message, MessageBoxButtons buttons)
2007-10-14 21:31:45 +00:00
{
return ShowWarningMessage(message, buttons, MessageBoxDefaultButton.Button1);
}
// This shows a message and logs the message
public static DialogResult ShowWarningMessage(string message, MessageBoxButtons buttons, MessageBoxDefaultButton defaultbutton)
{
2007-10-14 18:11:03 +00:00
Cursor oldcursor;
DialogResult result;
// Log the message
WriteLogLine(message);
2007-06-24 18:56:43 +00:00
2007-10-14 18:11:03 +00:00
// Use normal cursor
oldcursor = Cursor.Current;
Cursor.Current = Cursors.Default;
// Show message
2007-10-14 21:31:45 +00:00
result = MessageBox.Show(Form.ActiveForm, message, Application.ProductName, buttons, MessageBoxIcon.Warning, defaultbutton);
2007-10-14 18:11:03 +00:00
// Restore old cursor
Cursor.Current = oldcursor;
// Return result
return result;
}
2007-06-24 18:56:43 +00:00
// This returns a unique temp filename
2008-01-02 21:49:43 +00:00
internal static string MakeTempFilename(string tempdir)
{
return MakeTempFilename(tempdir, "tmp");
}
// This returns a unique temp filename
internal static string MakeTempFilename(string tempdir, string extension)
2007-06-24 18:56:43 +00:00
{
string filename;
string chars = "abcdefghijklmnopqrstuvwxyz1234567890";
Random rnd = new Random();
int i;
do
{
// Generate a filename
filename = "";
for(i = 0; i < 8; i++) filename += chars[rnd.Next(chars.Length)];
filename = Path.Combine(tempdir, filename + "." + extension);
2007-06-24 18:56:43 +00:00
}
// Continue while file is not unique
while(File.Exists(filename) || Directory.Exists(filename));
2007-06-24 18:56:43 +00:00
// Return the filename
return filename;
}
// This returns a unique temp directory name
2008-01-02 21:49:43 +00:00
internal static string MakeTempDirname()
{
string dirname;
string chars = "abcdefghijklmnopqrstuvwxyz1234567890";
Random rnd = new Random();
int i;
do
{
// Generate a filename
dirname = "";
for(i = 0; i < 8; i++) dirname += chars[rnd.Next(chars.Length)];
dirname = Path.Combine(temppath, dirname);
}
// Continue while file is not unique
while(File.Exists(dirname) || Directory.Exists(dirname));
// Return the filename
return dirname;
}
2007-11-04 22:19:30 +00:00
// This shows an image in a panel either zoomed or centered depending on size
public static void DisplayZoomedImage(Panel panel, Image image)
{
// Set the image
panel.BackgroundImage = image;
// Image not null?
if(image != null)
{
// Small enough to fit in panel?
if((image.Size.Width < panel.ClientRectangle.Width) &&
(image.Size.Height < panel.ClientRectangle.Height))
{
// Display centered
panel.BackgroundImageLayout = ImageLayout.Center;
}
else
{
// Display zoomed
panel.BackgroundImageLayout = ImageLayout.Zoom;
}
}
}
// This calculates the new rectangle when one is scaled into another keeping aspect ratio
public static RectangleF MakeZoomedRect(Size source, RectangleF target)
{
return MakeZoomedRect(new SizeF((int)source.Width, (int)source.Height), target);
}
// This calculates the new rectangle when one is scaled into another keeping aspect ratio
public static RectangleF MakeZoomedRect(Size source, Rectangle target)
{
return MakeZoomedRect(new SizeF((int)source.Width, (int)source.Height),
new RectangleF((int)target.Left, (int)target.Top, (int)target.Width, (int)target.Height));
}
// This calculates the new rectangle when one is scaled into another keeping aspect ratio
public static RectangleF MakeZoomedRect(SizeF source, RectangleF target)
{
float scale;
// Image fits?
if((source.Width <= target.Width) &&
(source.Height <= target.Height))
{
// Just center
scale = 1.0f;
}
// Image is wider than tall?
else if((source.Width - target.Width) > (source.Height - target.Height))
{
// Scale down by width
scale = target.Width / source.Width;
}
else
{
// Scale down by height
scale = target.Height / source.Height;
}
// Return centered and scaled
return new RectangleF(target.Left + (target.Width - source.Width * scale) * 0.5f,
target.Top + (target.Height - source.Height * scale) * 0.5f,
source.Width * scale, source.Height * scale);
}
2007-06-24 18:56:43 +00:00
#endregion
[BeginAction("testaction")]
2008-01-02 21:49:43 +00:00
internal static void TestAction()
{
2008-10-26 23:10:48 +00:00
ScriptEditTestForm t = new ScriptEditTestForm();
t.ShowDialog(mainwindow);
t.Dispose();
}
2007-06-13 19:39:38 +00:00
}
}
2007-09-28 08:56:18 +00:00