shithub: choc

Download patch

ref: c139624650e69916e3a03dbce839d32bdf779b92
parent: b5d296d2ab1240287280938b84cd4a2a8d6ca3e2
parent: ec5b192d831ba72c4b4dcd9b0e1f2dce6396668d
author: Simon Howard <[email protected]>
date: Sat Jun 11 13:28:47 EDT 2016

Merge remote-tracking branch 'origin/master' into sdl2-branch

--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -11,7 +11,7 @@
 Before reporting a bug, it's worth checking if this really is a bug.
 Chocolate Doom's mission is to reproduce the Vanilla (DOS) versions of
 the Doom engine games, bugs and all. Check out the
-[NOT-BUGS](../NOT-BUGS) file for a list of common issues which aren't
+[NOT-BUGS](../NOT-BUGS.md) file for a list of common issues which aren't
 really bugs at all. You might also try searching [the GitHub issues
 list](https://github.com/chocolate-doom/chocolate-doom/issues) to see
 if your bug has already been reported.
@@ -39,7 +39,7 @@
 
 Chocolate Doom is always open to new feature requests; however, please
 be aware that the project is designed around a deliberately limited
-[philosophy](../PHILOSOPHY), and many features common in other source
+[philosophy](../PHILOSOPHY.md), and many features common in other source
 ports will not be accepted. Here are a few common requests which are
 often rejected:
 
@@ -68,7 +68,7 @@
   to license it under the GPL.
 
 * Please follow the coding style guidelines described in the
-  [HACKING](../HACKING) file.
+  [HACKING](../HACKING.md) file.
 
 * The guidelines given above in the "feature requests" section also
   apply here. New features which aren't in line with the project
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,7 @@
         - libsdl-net1.2-dev
         - libpng-dev
 
-script: ./autogen.sh && make
+script: ./autogen.sh && make && make install DESTDIR=/tmp/whatever && make dist
 
 branches:
     only:
--- a/HACKING
+++ /dev/null
@@ -1,213 +1,0 @@
-
-Coding style guidelines
-=======================
-
-The coding style guidelines for Chocolate Doom are designed to keep the
-style of the original source code.  This maintains consistency throughout
-the program, and does not require the original code to be changed. Some
-of these guidelines are stricter than what was done in the original
-source; follow these when writing new code only: there is no need to
-change existing code to fit them.
-
-You should set tabs to _display_ as eight spaces, not four.  However,
-_indentation_ should be four spaces.  If possible, do not use tab
-characters at all.  There is a utility called "expand" which will remove
-tab characters.  For the reasoning behind this, see:
-http://www.jwz.org/doc/tabs-vs-spaces.html
-
-Please write code to an 80 column limit so that it fits within a standard
-80 column terminal. Do not leave trailing whitespace at the end of lines.
-
-Functions should be named like this: 'AB_FunctionName'.  The 'AB' prefix
-denotes the subsystem (AM_ for automap, G_ for game, etc).  If a
-function is static, you can omit the prefix and just name it like
-'FunctionName'.  Functions and global variables should always be made
-static if possible.
-
-Put '_t' on the end of types created with typedef.  Type names like this
-should be all lowercase and have the subsystem name at the start. An
-example of this is 'txt_window_t'.  When creating structures, always
-typedef them.
-
-Do not use Hungarian notation.
-
-Do not use the goto statement.
-
-Use C++-style comments, ie. '//' comments, not '/* ... */' comments.
-I don't care that this isn't standard ANSI C.
-
-Variables should be named like this: 'my_variable_name', not like this:
-'MyVariableName'.  In pointer variable declarations, place the '*' next
-to the variable name, not the type.
-
-When using an if, do, while, or for statement, always use the { } braces
-even when they are not necessary.  For example, do this:
-
-    if (condition)
-    {
-        body;
-    }
-
-Not this:
-
-    if (condition)   // NO
-        body;
-
-Write code like this:
-
-typedef struct
-{
-    int member1;
-    char *member2;
-} my_structure_t;
-
-void FunctionName(int argument, int arg2, int arg3, int arg4, int arg5,
-                  int arg6, int arg7)
-{
-    int assign_var;
-
-    assign_var = arg2 + arg3 * arg4 * (arg5 + arg6);
-
-    if (foo && !bar || baz && qux || !(foo && bar && baz))
-    {
-        body;
-    }
-    else if (xyz + 4 < abc * 4 + 3)
-    {
-        body;
-    }
-    else
-    {
-        body;
-    }
-
-    if (very_long_condition_like_this_one_that_forces_a_line_break
-     && other_condition)
-    {
-        body;
-    }
-
-    switch (argument)
-    {
-        case FIRST:
-            code;
-            break;
-
-        case SECOND:
-            code;
-            break;
-
-        default:
-            break;
-    }
-
-    for (a = 0; a < 10; ++a)
-    {
-        FunctionCall(arg1, arg2, arg3, arg4,
-                     arg_split_onto_second_line);
-    }
-
-    while (a < 10)
-    {
-        loop_body;
-    }
-
-    do
-    {
-
-    } while (condition);
-}
-
-Security
-========
-
-The C standard library has a number of unsafe functions that should be
-avoided when writing code for Chocolate Doom. These are:
-
-    Unsafe function       Safer alternative
-    ---------------------------------------------
-    gets()                fgets(.., stdin)
-    sprintf               M_snprintf()
-    snprintf              M_snprintf()
-    vsprintf              M_vsnprintf()
-    vsnprintf             M_vsnprintf()
-    strcpy()              M_StringCopy()
-    strncpy()             M_StringCopy()
-    strcat()              M_StringConcat()
-    strncat()             M_StringConcat()
-    strdup()              M_StringDuplicate()
-
-Lots of the code includes calls to DEH_String() to simulate string
-replacement by the Dehacked tool. Be careful when using Dehacked
-replacements of printf format strings. For example, do not do this:
-
-    printf(DEH_String("foo %s"), s);
-    sprintf(mybuf, DEH_String("bar %s"), t);
-
-Instead do this:
-
-    DEH_printf("foo %s", s);
-    DEH_snprintf(mybuf, sizeof(mybuf), "bar %s", t);
-
-This does the format string replacement safely in a way that checks
-the arguments securely.
-
-
-Portability
-===========
-
-Chocolate Doom is designed to be cross-platform and work on different
-Operating Systems and processors.  Bear this in mind when writing code.
-
-Do not use the long type (its size differs across platforms; use
-int or int64_t depending on which you want).
-
-Use Doom's byte data type for byte data. 'int' is assumed to be a
-32-bit integer, and 'short' is a 16-bit integer. You can also use the
-ISO C99 data types: intN_t and uintN_t where N is 8,16,32,64.
-
-Be careful with platform dependencies: do not use Windows API
-functions, for example.  Use SDL where possible.
-
-Preprocessor #defines are set that can be used to identify the OS
-if necessary: _WIN32 for Windows and __MACOSX__ for MacOS X. Others
-are set through SDL.  Try to avoid this if possible.
-
-Be careful of endianness!  Doom has SHORT() and LONG() macros that
-do endianness conversion.  Never assume that integer types have a
-particular byte ordering.  Similarly, never assume that fields
-inside a structure are aligned in a particular way.  This is most
-relevant when reading or writing data to a file or a network pipe.
-
-For signed integers, you shouldn't assume that (i >> n) is the same as
-(i / (1 << n)).  However, most processors handle bitshifts of signed
-integers properly, so it's not a huge problem.
-
-
-GNU GPL and licensing
-=====================
-
-All code submitted to the project must be licensed under the GNU GPL or a
-compatible license.  If you use code that you haven't 100% written
-yourself, say so. Add a copyright header to the start of every file.  Use
-this template:
-
-//
-// Copyright(C) YEAR Author's name
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// 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.
-//
-//
-// *File description goes here*
-//
-
-# vim: tw=70
-
--- /dev/null
+++ b/HACKING.md
@@ -1,0 +1,215 @@
+# Coding style guidelines
+
+The coding style guidelines for Chocolate Doom are designed to keep the
+style of the original source code.  This maintains consistency throughout
+the program, and does not require the original code to be changed. Some
+of these guidelines are stricter than what was done in the original
+source; follow these when writing new code only: there is no need to
+change existing code to fit them.
+
+You should set tabs to *display* as eight spaces, not four.  However,
+*indentation* should be four spaces.  If possible, do not use tab
+characters at all.  There is a utility called “expand” which will remove
+tab characters.  For the reasoning behind this, see:
+http://www.jwz.org/doc/tabs-vs-spaces.html
+
+Please write code to an 80 column limit so that it fits within a standard
+80 column terminal. Do not leave trailing whitespace at the end of lines.
+
+Functions should be named like this: `AB_FunctionName`.  The `AB` prefix
+denotes the subsystem (`AM_` for automap, `G_` for game, etc).  If a
+function is static, you can omit the prefix and just name it like
+`FunctionName`.  Functions and global variables should always be made
+static if possible.
+
+Put `_t` on the end of types created with typedef.  Type names like this
+should be all lowercase and have the subsystem name at the start. An
+example of this is `txt_window_t`.  When creating structures, always
+typedef them.
+
+Do not use Hungarian notation.
+
+Do not use the goto statement.
+
+Use C++-style comments, ie. `//` comments, not `/* ... */` comments.
+I don’t care that this isn’t standard ANSI C.
+
+Variables should be named like this: `my_variable_name`, not like this:
+`MyVariableName`.  In pointer variable declarations, place the `*` next
+to the variable name, not the type.
+
+When using an if, do, while, or for statement, always use the { } braces
+even when they are not necessary.  For example, do this:
+
+```c
+if (condition)
+{
+    body;
+}
+```
+
+Not this:
+
+```c
+if (condition)   // NO
+    body;
+```
+
+Write code like this:
+
+```c
+typedef struct
+{
+    int member1;
+    char *member2;
+} my_structure_t;
+
+void FunctionName(int argument, int arg2, int arg3, int arg4, int arg5,
+                  int arg6, int arg7)
+{
+    int assign_var;
+
+    assign_var = arg2 + arg3 * arg4 * (arg5 + arg6);
+
+    if (foo && !bar || baz && qux || !(foo && bar && baz))
+    {
+        body;
+    }
+    else if (xyz + 4 < abc * 4 + 3)
+    {
+        body;
+    }
+    else
+    {
+        body;
+    }
+
+    if (very_long_condition_like_this_one_that_forces_a_line_break
+     && other_condition)
+    {
+        body;
+    }
+
+    switch (argument)
+    {
+        case FIRST:
+            code;
+            break;
+
+        case SECOND:
+            code;
+            break;
+
+        default:
+            break;
+    }
+
+    for (a = 0; a < 10; ++a)
+    {
+        FunctionCall(arg1, arg2, arg3, arg4,
+                     arg_split_onto_second_line);
+    }
+
+    while (a < 10)
+    {
+        loop_body;
+    }
+
+    do
+    {
+
+    } while (condition);
+}
+```
+
+## Security
+
+The C standard library has a number of unsafe functions that should be
+avoided when writing code for Chocolate Doom. These are:
+
+Unsafe function   |   Safer alternative
+------------------|------------------------
+`gets()`          |  `fgets(.., stdin)`
+`sprintf`         |  `M_snprintf()`
+`snprintf`        |  `M_snprintf()`
+`vsprintf`        |  `M_vsnprintf()`
+`vsnprintf`       |  `M_vsnprintf()`
+`strcpy()`        |  `M_StringCopy()`
+`strncpy()`       |  `M_StringCopy()`
+`strcat()`        |  `M_StringConcat()`
+`strncat()`       |  `M_StringConcat()`
+`strdup()`        |  `M_StringDuplicate()`
+
+Lots of the code includes calls to DEH_String() to simulate string
+replacement by the Dehacked tool. Be careful when using Dehacked
+replacements of printf format strings. For example, do not do this:
+
+```c
+printf(DEH_String("foo %s"), s);
+sprintf(mybuf, DEH_String("bar %s"), t);
+```
+
+Instead do this:
+
+```c
+DEH_printf("foo %s", s);
+DEH_snprintf(mybuf, sizeof(mybuf), "bar %s", t);
+```
+
+This does the format string replacement safely in a way that checks
+the arguments securely.
+
+## Portability
+
+Chocolate Doom is designed to be cross-platform and work on different
+Operating Systems and processors.  Bear this in mind when writing code.
+
+Do not use the `long` type (its size differs across platforms; use
+`int` or `int64_t` depending on which you want).
+
+Use Doom’s byte data type for byte data. `int` is assumed to be a
+32-bit integer, and `short` is a 16-bit integer. You can also use the
+ISO C99 data types: `intN_t` and `uintN_t` where N is 8, 16, 32, 64.
+
+Be careful with platform dependencies: do not use Windows API
+functions, for example.  Use SDL where possible.
+
+Preprocessor `#defines` are set that can be used to identify the OS
+if necessary: `_WIN32` for Windows and `__MACOSX__` for Mac OS X. Others
+are set through SDL.  Try to avoid this if possible.
+
+Be careful of endianness!  Doom has `SHORT()` and `LONG()` macros that
+do endianness conversion.  Never assume that integer types have a
+particular byte ordering.  Similarly, never assume that fields
+inside a structure are aligned in a particular way.  This is most
+relevant when reading or writing data to a file or a network pipe.
+
+For signed integers, you shouldn’t assume that `(i >> n)` is the same as
+`(i / (1 << n))`.  However, most processors handle bitshifts of signed
+integers properly, so it’s not a huge problem.
+
+## GNU GPL and licensing
+
+All code submitted to the project must be licensed under the GNU GPLv2 or a
+compatible license.  If you use code that you haven’t 100% written
+yourself, say so. Add a copyright header to the start of every file.  Use
+this template:
+
+```
+//
+// Copyright(C) YEAR Author's name
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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.
+//
+//
+// *File description goes here*
+//
+```
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,10 +38,10 @@
         codeblocks/setup-res.rc
 
 DOC_FILES=                              \
-        README                          \
-        README.Music                    \
-        NEWS                            \
-        PHILOSOPHY                      \
+        README.md                       \
+        README.Music.md                 \
+        NEWS.md                         \
+        PHILOSOPHY.md                   \
         ChangeLog
 
 EXTRA_DIST=                             \
@@ -49,15 +49,15 @@
         $(MSVC_FILES)                   \
         $(CODEBLOCKS_FILES)             \
         $(DOC_FILES)                    \
-        NOT-BUGS                        \
-        README.Strife                   \
+        NOT-BUGS.md                     \
+        README.Strife.md                \
         .lvimrc                         \
-        HACKING                         \
-        TODO                            \
+        HACKING.md                      \
+        TODO.md                         \
         rpm.spec
 
 doomdocsdir = ${docdir}/../${PROGRAM_PREFIX}doom
-doomdocs_DATA = $(DOC_FILES) NOT-BUGS
+doomdocs_DATA = $(DOC_FILES) NOT-BUGS.md
 
 hereticdocsdir = ${docdir}/../${PROGRAM_PREFIX}heretic
 hereticdocs_DATA = $(DOC_FILES)
@@ -66,7 +66,7 @@
 hexendocs_DATA = $(DOC_FILES)
 
 strifedocsdir = ${docdir}/../${PROGRAM_PREFIX}strife
-strifedocs_DATA = $(DOC_FILES) README.Strife
+strifedocs_DATA = $(DOC_FILES) README.Strife.md
 
 MAINTAINERCLEANFILES =  $(AUX_DIST_GEN)
 
--- a/NEWS
+++ /dev/null
@@ -1,1178 +1,0 @@
-HEAD:
-
-    General:
-    * Bash completion scripts are included. (thanks Fabian)
-    * Support the *.lmp file format in the OS X launcher (thanks Jon)
-    * Added emulation for pitch-shifting as in early versions of Doom,
-      Heretic, and Hexen. (thanks Jon)
-    * Write out aspect-correct 1600×1200 PNGs. (thanks Jon)
-    * OPL emulation is more accurate. (thanks Nuke.YKT)
-    * Futher emulation of DMX bugs with GUS cards. (thanks Nuke.YKT)
-    * Emulation of the disk icon has returned. (thanks Fabian, Jon)
-    * Checksum calculations were fixed on big endian systems, allowing
-      multiplayer games to be played in mixed little/big-endian
-      environments. (thanks GhostlyDeath, njankowski)
-
-    Build systems:
-    * Improved compatibility with BSD Make. (thanks R.Rebello)
-    * “./configure --with-PACKAGE” checks were repaired to behave
-      logically, rather than disabling the feature. (thanks R.Rebello)
-    * Default to installing the games to ${bindir}, such as /usr/local/bin,
-      rather than /usr/local/games. (thanks chungy)
-    * Support Visual Studio 2015. (thanks Azarien)
-    * Allow SDL headers and libraries to exist in the Microsoft Visual
-      Studio project directory. (thanks Quasar)
-    * Repaired the CodeBlocks projects by removing non-existent files from
-      the project files (thanks krystalgamer)
-
-    Doom:
-    * Chex Quest's level warp cheat (LEESNYDER##) was changed to behave
-      like the original EXE. (thanks Nuke.YKT)
-    * Allow starting multiplayer Chex Quest games.
-    * Allow Freedoom: Phase 1 ≤ 0.10.1 to be loaded with mods, with
-      -gameversion older than ultimate. (thanks Fabian, chungy)
-    * Added safety checks against write failures when saving a game,
-      such as when the directory is read-only.  Try falling back to a
-      temporary directory and reporting an error instead.
-      (thanks terrorcide)
-    * Versions 1.666, 1.7, and 1.8 are emulated. (thanks Nuke.YKT)
-
-    Heretic:
-    * Added map names for Episode 6, fixing a crash after completing a
-      level in this episode. (thanks J.Benaim)
-
-    Hexen:
-    * The MRJONES cheat code returns an identical string as vanilla,
-      and enables fully reproducable builds. (thanks Fabian)
-    * Fixed an issue where the game crashed while killing the Wraithverge
-      in 64-bit builds. (thanks J.Benaim)
-
-    Strife:
-    * Support added for automatic loading of the IWAD from the GOG.com
-      release of Strife: Veteran Edition on Windows. (thanks chungy)
-    * Jumping can be bound to a mouse button. (thanks Gez)
-    * Gibbing logic was changed to match vanilla behavior. (thanks Quasar)
-    * Several constants differences from vanilla were fixed. (thanks
-      Nuke.YKT, Quasar)
-    * When using -iwad, voices.wad from the IWAD's directory is prefered
-      over auto-detected DOS/Steam/GOG.com installs. (thanks Quasar)
-
-    libtextscreen:
-    * Simplified the API for creating and managing tables and columns.
-    * Allow cycling through tables with tab key.
-
-2.2.1 (2015-09-10):
-
-    Chocolate Doom has not seen a great deal of "stable" patch
-    releases in its history. While the development tree sees major new
-    features and changes, the purpose of this release, and hopefully
-    others to follow like it, is to repair some deficiencies that
-    existed in 2.2.0.
-
-    General:
-    * Preferences for the OS X launcher are now stored with a unique
-      name to not conflict with other applications. (thanks Xeriphas1994)
-    * Unix desktop entry files are now brought up to full desktop
-      entry specification compliance. (thanks chungy, Fabian)
-    * Unix AppData entries are now included, allowing software centers
-      to display detailed information about the engines. (thanks chungy)
-    * Partial XDG base directory specification compliance on Unix
-      systems now exist to search for IWAD paths.  One benefit is that
-      $HOME/.local/share/games/doom is now a valid location to store
-      and automatically find IWADs. (thanks chungy)
-
-    Build systems:
-    * The Microsoft Visual Studio build system was not fully
-      functional in 2.2.0 and has been fixed. (thanks Linguica)
-    * The autoconf build system checks for windres only for Windows
-      toolchains.  Some Linux distributions mistakingly include the
-      program in their native toolchains. (thanks Fabian)
-    * A compiler hint for packed structs has been added, which
-      otherwise broke the games when built under recent GCC releases
-      for Windows. (thanks Fabian)
-
-    Doom:
-    * The GOG.com releases of The Ultimate Doom, Doom II, and Final
-      Doom are now detected and supported on Windows. (thanks chungy)
-    * An integer overflow was used in spawn angle calculation,
-      undefined C behavior which broke with Clang optimization.
-      (thanks David Majnemer for insight)
-
-    Setup tool:
-    * The help URL for the level warp menu now points to the proper
-      wiki page, rather than the multiplayer page.
-    * The manifest has been updated for Windows 10 compatibility.
-      (thanks chungy)
-
-2.2.0 (2015-06-09):
-
-     * The Hexen four level demo IWAD is now supported. Thanks to
-       Fabian Greffrath for his careful investigation and emulation of
-       the demo game's behavior in developing this.
-     * OPL music playback has been improved in a number of ways to
-       match the behavior of Vanilla Doom's DMX library much more
-       closely. OPL3 playback is also now supported. Thanks go to
-       Alexey Khokholov for his excellent research into the Vanilla
-       DMX library that enabled these improvements.
-     * New gamepad configurations:
-        - PS4 DualShock 4 (thanks Matt '3nT' Davis).
-        - Xbox One controller on Linux (thanks chungy).
-        - "Super Joy Box 7" USB/PC gameport adapter.
-     * The Doom reload hack has been added back. See the wiki for more
-       context on this: http://doomwiki.org/wiki/Reload_hack
-     * The IWAD file from Strife: Veteran Edition is now detected
-       automatically (thanks chungy).
-     * It's now possible to build outside of the source directory
-       (thanks Dave Murphy).
-     * MSVC project files were brought up to date (thanks dbrackett16).
-     * M_StringDuplicate() has been added as a safer replacement for
-       strdup() (thanks Quasar). M_StringCopy() now handles short
-       buffers more gracefully.
-     * The netgame discrepancy window is now dismissed by pressing
-       enter to proceed, not escape (thanks Alexandre-Xavier).
-     * A couple of source files that were in the previous release and
-       were GPL3 have been replaced by GPL2 equivalents. Previous
-       releases that included these files should be retroactively
-       considered GPL3.
-
-    Bug fixes:
-     * A long-standing bug that could cause every display frame to be
-       rendered twice was fixed (thanks Linguica, Harha, Alexandre-
-       Xavier).
-     * Lots of endianness fixes were integrated that were found by
-       Ronald Lasmanowicz during development of his Wii port of
-       Chocolate Doom, including a fix for a bug that could cause
-       monsters to become partially invisible.
-     * DeHackEd files without a newline character at the EOF are now
-       correctly parsed (thanks Fabian).
-     * An infinite loop that could occur in the weapon cycling code
-       was fixed (thanks raithe, Fabian).
-     * Mouse input triggered by cursor warp was fixed (thanks Super6-4).
-     * Loop tags in substitute music files are ignored if both of the
-       loop tags are equal to zero. This makes us consistent with
-       other source ports that support the tags.
-     * It's now possible to more conveniently play back demo .lmp
-       files with names that end in the all-caps '.LMP' (thanks Ioan
-       Chera).
-     * Some code that accessed memory after freeing it was fixed. Two
-       new parameters, -zonezero and -zonescan, were added to try to
-       help detect these cases.
-     * Mistaken assumptions about representations of booleans that
-       affected some ARM systems were fixed (thanks floppes).
-     * memcpy() uses on overlapping memory were changed to use
-       memmove(), fixing abort traps on OpenBSD (thanks ryan-sg).
-     * Hyphens in manpages were fixed (thanks chungy, Fabian).
-     * Lots of compiler build warnings were fixed (thanks Fabian).
-
-    Setup tool:
-     * The setup tool now has help buttons for its various different
-       screens, which link to articles on the wiki that give more
-       information (thanks to chungy for helping to put the wiki pages
-       together).
-     * A fix was applied for a buffer overrun that could occur if the
-       user had lots of IWAD files installed (thanks Fabian).
-     * A crash related to username lookup was fixed.
-     * It's now possible to connect via the setup tool to multiplayer
-       servers that are not listening on the default port (thanks
-       Alexandre-Xavier).
-
-    Doom:
-     * Sky transitions when emulating the id anthology version of the
-       Final Doom executable were fixed (thanks Alexandre-Xavier,
-       Fabian, chungy).
-     * Structure fields in the stair-building functions were fixed to
-       be deterministic, fixing a desync in mm09-512.lmp (thanks
-       Fabian).
-
-    Hexen:
-     * A bug with texture names that had long names was fixed (thanks
-       ETTiNGRiNDER).
-     * Minotaur spawn time is now stored in little endian format,
-       fixing a bug that affected compatibility with Vanilla savegames
-       on big endian systems.
-     * Code that starts ACS scripts is no longer compiler-dependent.
-
-    Strife (all these are thanks to Quasar):
-     * Sound priority was changed, so that the ticking sound that
-       Stalker enemies make while active matches Vanilla behavior
-       (thanks GeoffLedak).
-     * Minor fixes to game behavior to match Vanilla, discovered
-       during development of Strife: Veteran edition.
-     * Behavior of descending stairs was fixed to match Vanilla.
-     * Inventory items beyond the 8-bit range are now allowed in
-       netgames.
-     * Automap behavior better matches Vanilla now.
-     * Multiplayer name changes were fixed.
-     * Sound origin behavior for switches was fixed.
-     * Teleport beacon behavior was fixed.
-     * Default Strife skill level and screen size were changed to
-       match Vanilla.
-     * Bug was fixed where Rowan would not always take Beldin's ring.
-     * Totally-invisible objects are now displayed correctly, and a
-       Vanilla glitch with Shadow Acolytes is correctly emulated.
-     * The level name for MAP29 (Entity's Lair) was fixed (thanks
-       chungy).
-
-    libtextscreen:
-     * The main loop now exits immediately once all windows are closed
-       (thanks Alexander-Xavier).
-     * The large font is no longer selected based entirely on screen
-       size.
-
-2.1.0 (2014-10-22):
-
-    Chocolate Doom now supports high-quality substitute music packs
-    that are used in place of the original MIDI music tracks. I'm
-    hoping to put together high-quality recordings of the music for
-    all supported games using the Roland SC-55 synthesizer
-    originally used to compose Doom's music (thanks twipley and
-    MusicallyInspired).
-
-    Support for joysticks and gamepads has been significantly
-    improved in this version. Most gamepads should now work; if they
-    don't, please report a bug. A number of gamepads are now
-    automatically detected and configured automatically; if yours is
-    not, you can help by sending in details. See the following page:
-
-      http://www.chocolate-doom.org/wiki/index.php/Adding_your_gamepad
-
-    OPL MIDI playback has been significantly improved, and problems
-    with most tracks should now be resolved. Multi-track MIDI files now
-    play back properly, MIDI tempo meta events are now supported and
-    problems with stuttering when playing certain tracks have been
-    fixed. If you still have problems with OPL playback, let me know.
-
-    Also of note is that Chocolate Doom now has a document that
-    describes the philosophy of the project and the reasoning behind
-    its design (see PHILOSOPHY distributed with the source).
-
-    Other new features:
-     * There is now a -dehlump command line parameter to load Dehacked
-       files contained inside WAD files (thanks Fabian Greffrath).
-     * PNG format screenshots are now supported, and there is a
-       dedicated key binding for taking screenshots without needing to
-       always use -devparm (thanks Fabian Greffrath). The PrintScreen
-       key can be used as a key binding (thanks Alexandre-Xavier).
-     * There is now a config file variable (snd_maxslicetime_ms) to
-       control the sound buffer size, and the default is more precise
-       to reduce sound latency (thanks Holering).
-     * You can now use an external command for music playback (thanks
-       Holering).
-     * All games now detect if you're tring to play using the wrong
-       type of IWAD (doom.wad with Hexen, etc.) and exit with a
-       helpful error message. A couple of users made this mistake
-       after the 2.0 release introduced support for the new games.
-     * The OS X app now associates with .hhe and .seh files.
-     * There is now a -nodes parameter that automatically starts a
-       netgame when a desired number of players have joined the game.
-     * There is now more extensive documentation about music
-       configuration (README.Music).
-     * On Linux, a GUI pop-up is used when the game quits with an
-       error to show the error message (thanks Willy Barro).
-     * There are now Linux .desktop files for all supported games
-       (thanks Mike Swanson).
-     * The -geometry command line parameter can now be used to specify
-       fullscreen or windowed modes, eg. -geometry 640x480w or
-       -geometry 1024x768f. (thanks Mike Swanson)
-
-    Doom:
-     * Minor workarounds were added to allow the BFG Edition IWADs to
-       be used without crashing the game (thanks Fabian Greffrath).
-     * GUS patch files included with the BFG Edition are now
-       automatically detected.
-     * The 'no fog on spawn west' Vanilla bug is now correctly
-       emulated (thanks xttl).
-     * Behavior of older versions of Doom back to v1.666 can now be
-       emulated.
-     * The new Freedoom IWAD names are now recognized and supported.
-     * Freedoom's DEHACKED lump can now be parsed and is automatically
-       loaded when a Freedoom IWAD file is used (thanks Fabian
-       Greffrath). A new command line parameter, -nodeh, can be used
-       to prevent this from being loaded.
-     * Behavior of the M_EPI4 menu item is now correctly emulated
-       based on game version (thanks Alexandre-Xavier).
-     * IDCLEV up to MAP40 is now supported, to match Vanilla (thanks
-       Alexandre-Xavier).
-     * Level warping on the command line (-warp) to episodes higher
-       than 4 is possible, matching Vanilla behavior (thanks plumsinus).
-     * The -cdrom command line parameter writes savegames to the
-       correct directory now, matching Vanilla Doom behavior (thanks
-       Alexandre-Xavier).
-     * The Doom II mission pack to use can now be specified manually on
-       the command line with the -pack parameter (thanks chungy)
-
-    Heretic:
-     * Weapon cycling keys for mouse and joystick were fixed (thanks
-       Sander van Dijk).
-     * The -timedemo parameter has been fixed, and -playdemo now
-       handles full paths correctly.
-     * A bug when panning the map was fixed (thanks Chris Fielder).
-     * A savegame bug where plat_t structures were not restored
-       correctly was fixed (thanks romeroyakovlev).
-     * Rebinding of the pause key was fixed (thanks Fabian Greffrath).
-
-    Hexen:
-     * Music workarounds have been added so that it is possible to
-       play using the Mac version of the Hexen IWAD file.
-     * Weapon cycling keys for mouse and joystick were fixed (thanks
-       Sander van Dijk).
-     * The -timedemo parameter has been fixed, and -playdemo now
-       handles full paths correctly.
-     * There are now key bindings to allow the artifact keys to be
-       rebound (thanks Fabian Greffrath).
-     * Rebinding of the pause key was fixed (thanks Fabian Greffrath).
-     * Maximum level number was extended to MAP60, allowing
-       multiplayer games using the Deathkings add-on.
-     * The startup screen can now be aborted by pressing escape, like
-       in Vanilla.
-     * Desync when playing back DEMO1 was fixed (thanks alexey.lysiuk).
-
-    Strife:
-     * 'Show mission' key is configured properly in setup (thanks
-       Sander van Dijk).
-     * Default music volume level now matches Vanilla (thanks
-       Alexandre-Xavier).
-     * Teleport beacon allegiance was fixed to match Vanilla (thanks
-       Quasar).
-     * The stair building code now more closely matches Vanilla
-       (thanks Quasar).
-     * Torpedo weapon changing behavior now matches Vanilla (thanks
-       Quasar).
-
-   Cleanups:
-     * The copyright headers at the top of all source files have been
-       vastly simplified.
-     * Unsafe string functions have been eliminated from the codebase.
-       Thanks to Theo de Raadt for calling out Chocolate Doom by name
-       (alongside many other packages) for still using unsafe functions
-       like strcpy: http://marc.info/?l=openbsd-tech&m=138733933417096
-     * vldoor_e enum values are now namespaced to avoid potential
-       conflicts with POSIX standard functions.
-
-   Bug fixes:
-     * WAD and Dehacked checksums are now sent to clients and checked
-       correctly when setting up netgames.
-     * A bug was fixed that caused sound not to work in multiplayer
-       games (thanks to everyone who reported this, and for
-       Alexandre-Xavier and Quasar for help in fixing it).
-     * The "D_DDTBLU disease" bug affecting certain MIDI files has
-       been fixed (thanks plumsinus, Brad Harding and Quasar).
-     * Calculation of the -devparm 'ticker' dots was fixed to match
-       Vanilla behavior (thanks _bruce_ and Alexandre-Xavier).
-     * The PC speaker code now supports the full range of sound
-       frequencies (thanks Gez).
-     * Annoying "jumping" behavior when grabbing the mouse cursor was
-       fixed.
-     * The screen is now initialized at the native bit depth by
-       default, to avoid problems with systems that don't handle 8-bit
-       screenbuffers very well any more.
-     * The --docdir argument to the configure script is now honored
-       (thanks Jan Engelhardt).
-     * Various issues with the build were fixed (thanks Jan
-       Engelhardt and Fabian Greffrath).
-     * Backwards parameters were fixed in the sound code (thanks
-       proteal).
-     * A crash was fixed when running fullscreen with the -2 parameter
-       (thanks Fabian Greffrath).
-     * A crash when using large values of snd_channels was fixed
-       (thanks Alexandre-Xavier).
-     * A resource leak in the BSD PC speaker code was fixed (thanks
-       Edward-san).
-     * Windows resource files were fixed for Windows 7 (thanks Brad
-       Harding).
-     * A hard to trigger crash caused by a realloc() in the WAD code
-       was fixed (thanks Fabian Greffrath for debugging).
-     * A bug has been fixed where Chocolate Doom would stay running
-       in the background on Windows after quitting. SDL_Quit() is
-       called now (thanks johnsirett, Brad Harding, Quasar).
-     * String replacements in dehacked lumps can now be overridden
-       if a subsequent dehacked patch replaces the same string.
-
-    libtextscreen:
-     * Clicking on scrollbars now jumps to the correct position
-       (thanks Alexandre-Xavier).
-     * A use-after-free bug has been fixed where a click in a window
-       that causes the window to close could lead to a crash (thanks
-       DuClare).
-     * Characters that are unprintable in the Extended ASCII chart
-       are just ignored when they're typed, rather than appearing as
-       an upside-down question mark (thanks Alexandre-Xavier).
-
-2.0.0 (2013-12-09):
-
-    This is version 2.0 of Chocolate Doom! This new major version is
-    released to celeberate the 20th anniversary of the first release
-    of Doom in 1993. Happy Birthday Doom!
-
-    This new version has some major changes compared to the 1.0 series:
-
-     * The codebase now includes Chocolate Heretic and Chocolate
-       Hexen. These are based on the GPL source code released by
-       Raven Software.
-     * Also included is Chocolate Strife. This was developed through a
-       mammoth four year reverse engineering project conducted by
-       James "Quasar" Haley and Samuel "Kaiser" Villareal. The result
-       is the most accurate reproduction of Strife to date, including
-       full demo and savegame compatibility. See README.Strife for
-       more information.
-
-    Minor features that are nonetheless worth mentioning:
-     * Chocolate Doom now includes a -statdump command line option,
-       which emulates the output of the statdump.exe tool. This is
-       used to implement a form of regression testing (statcheck) that
-       directly compares against the Vanilla behavior.
-     * Chocolate Heretic includes HHE patch file support, and I
-       believe is the first Heretic port to include this feature.
-     * GUS "pseudo-emulation" is now supported. This does not fully
-       emulate a GUS, but Doom's DMXGUS lump can be used to generate
-       a Timidity configuration file that plays music using the GUS
-       patch set.
-     * The setup tool now includes a built-in server browser, for use
-       when selecting a server to join.
-
-    Version 2.0 of Chocolate Doom has been in development for a long
-    time, and there have been many bugs fixed over this time, too many
-    to list here. Thanks to all the people who have tested it and
-    diligently reported bugs over this time, and to all the people who
-    have tested the beta releases over the past couple of months.
-    Your contributions have been essential and invaluable.
-
-1.7.0 (2012-06-09):
-
-     * Fixed gnome-screensaver desktop file (thanks Rahul Sundaram).
-     * Updated COPYING to current version of GPL2 (thanks Rahul
-       Sundaram).
-     * Running servers now re-resolve the address of the master server
-       occasionally, to adapt to DNS address changes.
-     * Error dialog is no longer shown on OS X when running from the
-       console.
-     * The Makefiles no longer use GNU make extensions, so the package
-       builds on OpenBSD.
-     * There is now an OPL MIDI debug option (-opldev), useful for
-       when developing GENMIDI lumps.
-     * A workaround for SDL mouse lag is now only used on Windows
-       (where it is needed), and not on other systems. This fixes
-       Chocolate Doom on AmigaOS (thanks Timo Sievänen).
-     * UTF-8 usernames are supported, and Windows usernames with
-       non-ASCII characters are now supported (thanks Alexandre
-       Xavier).
-
-    Compatibility:
-     * Palette accuracy is reduced to 6 bits per channel, to more
-       accurately emulate the PC VGA hardware (thanks GhostlyDeath).
-     * Fixed teleport behavior when emulating the alternate Final Doom
-       executable (-gameversion final2) (thanks xttl).
-
-    Bugs fixed:
-     * Fixed weapon cycling keys when playing in Shareware Doom and using
-       the IDKFA cheat (thanks Alexandre Xavier).
-     * Fixed the default mouse buttons in the setup tool (thanks
-       Alexandre Xavier).
-     * Chat macros now work when vanilla_keyboard_mapping is turned
-       off.
-     * Default chat macros were fixed in the setup tool.
-     * Ping time calculation was fixed for LAN search, and made more
-       accurate for all searches.
-     * Fixed bug with detection of IWAD type by filename (thanks mether).
-
-    libtextscreen:
-     * There is now limited UTF-8 text support in the textscreen
-       library, used in the label and input box widgets.
-     * Scroll bar behavior was fixed (thanks Alexandre Xavier).
-     * Input boxes stop editing and save when they lose their focus,
-       correcting a previous counterintuitive behavior (thanks
-       Twelve).
-     * The numeric keypad now works properly when entering text values
-       (thanks Twelve).
-
-1.6.0 (2011-05-17):
-
-     * The instructions in the INSTALL file are now customized for
-       different platforms, and each binary package contains a version
-       with instructions specific to the platform that it is
-       targetting.  This should help to avoid confusion that some
-       users have reported experiencing.
-     * The display settings window in the setup tool has been
-       reorganised to a better arrangement.
-     * It is now possible to load .lmp files (and play back demos)
-       with long filenames (thanks blzut3).
-     * In the setup tool, it is now possible to hold down shift when
-       changing key/mouse/joystick bindings to prevent other bindings
-       to the same key from being cleared (thanks myk).
-     * The joystick menu in the setup tool now has a test button
-       (thanks Alexandre Xavier).
-     * Specifying the -privateserver option implies -server (thanks
-       Porsche Monty).
-     * The Mac OS X .dmg package now has a background and looks generally
-       more polished.
-     * In Mac OS X, it is now possible to simply double click an IWAD
-       file in the Finder to configure its location within the launcher.
-     * Freedesktop.org desktop files are now installed for Doom and
-       the setup tool, which will appear in the main menu on desktop
-       environments such as Gnome and KDE (thanks Adrián Chaves
-       Fernández).
-     * The Chex Quest dehacked patch (chex.deh) will now be detected
-       if it is in the same directory as the IWAD file.
-
-    Compatibility:
-     * Added support for the alternate version of the Final Doom
-       executable included in some later versions of the Id Anthology.
-       This version fixed the demo loop crash that occurred with the
-       "original" Final Doom executable.
-
-       This executable can be selected on the command line with
-       -gameversion final2. It has been made the default when playing
-       with the Final Doom IWADs (the original behavior can be
-       selected with -gameversion final).  (thanks Porsche Monty,
-       Enjay).
-     * Very short sound effects are not played, to better emulate the
-       behavior of DMX in Vanilla Doom (thanks to Quasar for help in
-       investigating this).
-     * The null sector dereference emulation code has been imported
-       from Prboom+ - this fixes a desync with CLNJ-506.LMP (thanks
-       entryway).
-     * The IDMUS cheat doesn't work when emulating the v1.9 executable
-       (thanks Alexandre Xavier).
-
-    Bugs fixed:
-     * Menu navigation when using joystick/joypad (thanks Alexandre
-       Xavier).
-     * For configuration file value for shift keys, use scan code for
-       right shift, not left shift (thanks Alexandre Xavier).
-     * Default joystick buttons for the setup tool now match Vanilla
-       (thanks twipley).
-     * Visual Studio project files work again (thanks GhostlyDeath).
-     * The default sfx/music volume set by the setup tool is now 8
-       instead of 15, matching the game itself. (thanks Alexandre
-       Xavier).
-     * Weapon cycling from the shotgun to the chaingun in Doom 1 now
-       works properly (thanks Alexandre Xavier).
-     * MIDI playback that locked up when using an empty MUS / MIDI
-       file (thanks Alexandre Xavier).
-     * Default sampling rate used by setup tool changed to 44100Hz, to
-       match the game default (thanks Alexandre Xavier).
-     * Cheat codes and menu hot keys now work when shift is held down
-       or capslock turned on (thanks Alexandre Xavier).
-
-    libtextscreen:
-     * The background on GUI controls now lights up when hovering over
-       them, so that it is more obvious what you are selecting.
-     * It is now possible to type a '+' in input boxes (thanks
-       Alexandre Xavier).
-     * It is possible to use the mouse wheel to scroll through scroll
-       panes.
-     * Clicking on scroll bars now moves the scroll handle to a
-       matching location.
-     * Clicking outside a dropdown list popup window now dismisses the
-       window.
-     * Window hotkeys that are an alphabetical letter now work when
-       shift is held down or capslock turned on (thanks Alexandre
-       Xavier).
-
-1.5.0 (2011-01-02):
-
-    Big changes in this version:
-     * The DOSbox OPL emulator (DBOPL) has been imported to replace
-       the older FMOPL code.  The quality of OPL emulation is now
-       therefore much better.
-     * The game can now run in screen modes at any color depth (not
-       just 8-bit modes).  This is mainly to work around problems with
-       Windows Vista/7, where 8-bit color modes don't always work
-       properly.
-     * Multiplayer servers now register themselves with an Internet
-       master server.  Use the -search command line parameter to
-       find servers on the Internet to play on.  You can also use
-       DoomSeeker (http://skulltag.net/doomseeker/) which supports
-       this functionality.
-     * When running in windowed mode, it is now possible to
-       dynamically resize the window by dragging the window borders.
-     * Names can be specified for servers with the -servername command
-       line parameter.
-     * There are now keyboard, mouse and joystick bindings to cycle
-       through available weapons, making play with joypads or mobile
-       devices (ie. without a proper keyboard) much more practical.
-     * There is now a key binding to change the multiplayer spy key
-       (usually F12).
-     * The setup tool now has a "warp" button on the main menu, like
-       Vanilla setup.exe (thanks Proteh).
-     * Up to 8 mouse buttons are now supported (including the
-       mousewheel).
-     * A new command line parameter has been added (-solo-net) which
-       can be used to simulate being in a single player netgame.
-     * There is now a configuration file parameter to set the OPL I/O
-       port, for cards that don't use port 0x388.
-     * The Python scripts used for building Chocolate Doom now work
-       with Python 3 (but also continue to work with Python 2)
-       (thanks arin).
-     * There is now a NOT-BUGS file included that lists some common
-       Vanilla Doom bugs/limitations that you might encounter
-       (thanks to Sander van Dijk for feedback).
-
-    Compatibility:
-     * The -timer and -avg options now work the same as Vanilla when
-       playing back demos (thanks xttl)
-     * A texture lookup bug was fixed that caused the wrong sky to be
-       displayed in Spooky01.wad (thanks Porsche Monty).
-     * The HacX v1.2 IWAD file is now supported, and can be used
-       standalone without the need for the Doom II IWAD (thanks
-       atyth).
-     * The I_Error function doesn't display "Error:" before the error
-       message, matching the Vanilla behavior.  "Error" has also been
-       removed from the title of the dialog box that appears on
-       Windows when this happens.  This is desirable as not all such
-       messages are actually errors (thanks Proteh).
-     * The setup tool now passes through all command line arguments
-       when launching the game (thanks AlexXav).
-     * Demo loop behavior (ie. whether to play DEMO4) now depends on
-       the version being emulated.  When playing Final Doom the game
-       will exit unexpectedly as it tries to play the fourth demo -
-       this is Vanilla behaviour (thanks AlexXav).
-
-    Bugs fixed:
-     * A workaround has been a bug in old versions of SDL_mixer
-       (v1.2.8 and earlier) that could cause the game to lock up.
-       Please upgrade to a newer version if you haven't already.
-     * It is now possible to use OPL emulation at 11025Hz sound
-       sampling rate, due to the new OPL emulator (thanks Porsche
-       Monty).
-     * The span renderer function (used for drawing floors and
-       ceilings) now behaves the same as Vanilla Doom, so screenshots
-       are pixel-perfect identical to Vanilla Doom (thanks Porsche
-       Monty).
-     * The zone memory system now aligns allocated memory to 8-byte
-       boundaries on 64-bit systems, which may fix crashes on systems
-       such as sparc64 (thanks Ryan Freeman and Edd Barrett).
-     * The configure script now checks for libm, fixing compile
-       problems on Fedora Linux (thanks Sander van Dijk).
-     * Sound distortion with certain music files when played back
-       using OPL (eg. Heretic title screen).
-     * Error in Windows when reading response files (thanks Porsche
-       Monty, xttl, Janizdreg).
-     * Windows Vista/7 8-bit color mode issues (the default is now to
-       run in 32-bit color depth on these versions) (thanks to
-       everybody who reported this and helped test the fix).
-     * Screen borders no longer flash when running on widescreen
-       monitors, if you choose a true-color screen mode (thanks
-       exp(x)).
-     * The controller player in a netgame is the first player to join,
-       instead of just being someone who gets lucky.
-     * Command line arguments that take an option now check that an
-       option is provided (thanks Sander van Dijk).
-     * Skill level names in the setup tool are now written the same as
-       they are on the in-game "new game" menu (thanks AlexXav).
-     * There is no longer a limit on the lengths of filenames provided
-       to the -record command line parameter (thanks AlexXav).
-     * Window title is not lost in setup tool when changing video
-       driver (thanks AlexXav).
-
-    libtextscreen:
-     * The font used for the textscreen library can be forced by
-       setting the TEXTSCREEN_FONT environment variable to "small" or
-       "normal".
-     * Tables or scroll panes that don't contain any selectable widgets
-       are now themselves not selectable (thanks Proteh).
-     * The actions displayed at the bottom of windows are now laid out
-       in a more aesthetically pleasing way.
-
-1.4.0 (2010-07-10):
-
-     The biggest change in this version is the addition of OPL
-     emulation.  This emulates Vanilla Doom's MIDI playback when
-     using a Yamaha OPL synthesizer chip, as was found on
-     SoundBlaster compatible cards.
-
-     A software OPL emulator is included as most modern computers do
-     not have a hardware OPL chip any more.  If you do have one, you
-     can configure Chocolate Doom to use it; see README.OPL.
-
-     The OPL playback feature is not yet perfect or 100% complete,
-     but is judged to be good enough for general use.  If you find
-     music that does not play back properly, please report it as a
-     bug.
-
-     Other changes:
-     * The REJECT overflow emulation code from PrBoom+ has been
-       imported.  This fixes demo desync on some demos, although
-       others will still desync.
-     * Warnings are now generated for invalid dehacked replacements of
-       printf format strings.  Some potential buffer overflows are
-       also checked.
-     * The installation instructions (INSTALL file) have been
-       clarified and made more platform-agnostic.
-     * The mouse is no longer warped to the center of the screen when
-       the demo sequence advances.
-     * Key bindings can now be changed for the demo recording quit key
-       (normally 'q') and the multiplayer messaging keys (normally
-       't', 'g', 'i', 'b' and 'r').
-
-1.3.0 (2010-02-10):
-
-     * Chocolate Doom now runs on Windows Mobile/Windows CE!
-     * It is possible to rebind most/all of the keys that control the
-       menu, shortcuts, automap and weapon switching.  The main
-       reason for this is to support the Windows CE port and other
-       platforms where a full keyboard may not be present.
-     * Chocolate Doom now includes a proper Mac OS X package; it is
-       no longer necessary to compile binaries for this system by
-       hand.  The package includes a simple graphical launcher
-       program and can be installed simply by dragging the "Chocolate
-       Doom" icon to the Applications folder. (thanks to Rikard Lang
-       for extensive testing and feedback)
-     * The video mode auto-adjust code will automatically choose
-       windowed mode if no fullscreen video modes are available.
-     * The zone memory size is automatically reduced on systems with
-       a small amount of memory.
-     * The "join game" window in the setup tool now has an option to
-       automatically join a game on the local network.
-     * Chocolate Doom includes some initial hacks for compiling under
-       SDL 1.3.
-     * Recent versions of SDL_mixer include rewritten MIDI code on Mac
-       OS X.  If you are using a version of SDL_mixer with the new
-       code, music will now be enabled by default.
-     * Windows Vista and Windows 7 no longer prompt for elevated
-       privileges when running the setup tool (thanks hobbs and
-       MikeRS).
-     * The Windows binaries now have better looking icons (thanks
-       MikeRS).
-     * Magic values specified using the -spechit command line
-       parameter can now be hexadecimal.
-     * DOOMWADDIR/DOOMWADPATH can now specify the complete path to
-       IWAD files, rather than the path to the directory that contains
-       them.
-     * When recording shorttics demos, errors caused by the reduced
-       turning resolution are carried forward, possibly making turning
-       smoother.
-     * The source tarball can now be used to build an RPM package:
-         rpmbuild -tb chocolate-doom-VER.tar.gz
-
-    Compatibility:
-     * The A_BossDeath behavior in v1.9 emulation mode was fixed
-       (thanks entryway)
-     * The "loading" disk icon is drawn more like how it is drawn in
-       Vanilla Doom, also fixing a bug with chook3.wad.
-     * Desync on 64-bit systems with ep1-0500.lmp has (at long last)
-       been fixed (thanks exp(x)).
-     * Donut overrun emulation code imported from Prboom+ (thanks
-       entryway).
-     * The correct level name should now be shown in the automap for
-       pl2.wad MAP33 (thanks Janizdreg).
-     * In Chex Quest, the green radiation suit colormap is now used
-       instead of the red colormaps normally used when taking damage
-       or using the berserk pack.  This matches Vanilla chex.exe
-       behavior (thanks Fuzztooth).
-     * Impassible glass now displays and works the same as in Vanilla,
-       fixing wads such as OTTAWAU.WAD (thanks Never_Again).
-
-    Bugs fixed:
-     * Memory-mapped WAD I/O is disabled by default, as it caused
-       various issues, including a slowdown/crash with Plutonia 2
-       MAP23.  It can be explicitly re-enabled using the '-mmap'
-       command line parameter.
-     * Crash when saving games due to the ~/.chocolate-doom/savegames
-       directory not being created (thanks to everyone who reported
-       this).
-     * Chocolate Doom will now run under Win95/98, as the
-       SetProcessAffinityMask function is looked up dynamically.
-     * Compilation under Linux with older versions of libc will now
-       work (the semantics for sched_setaffinity were different in
-       older versions)
-     * Sound clipping when using libsamplerate was improved (thanks
-       David Flater)
-     * The audio buffer size is now calculated based on the sample
-       rate, so there is not a noticeable delay when using a lower
-       sample rate.
-     * The manpage documentation for the DOOMWADPATH variable was
-       fixed (thanks MikeRS).
-     * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND
-       disabled was fixed.
-     * Fixed crash when using the donut special type and the joining
-       linedef is one sided (thanks Alexander Waldmann).
-     * Key settings in a configuration file that are out of range
-       do not cause a crash (thanks entryway).
-     * Fix ear-piercing whistle when playing the MAP05 MIDI music
-       using timidity with EAWPATS (thanks entryway / HackNeyed).
-
-    libtextscreen:
-     * There is now a second, small textscreen font, so that the
-       ENDOOM screen and setup tool can be used on low resolution
-       devices (eg. PDAs/embedded devices)
-     * The textscreen library now has a scrollable pane widget. Thanks
-       to LionsPhil for contributing code to scroll up and down using
-       the keyboard.
-     * Doxygen documentation was added for the textscreen library.
-
-1.2.1 (2008-12-10):
-
-    This version just fixes a crash at the intermission screen when
-    playing Doom 1 levels.
-
-1.2.0 (2008-12-10):
-
-    Happy 15th Birthday, Doom!
-
-     * Chocolate Doom now has an icon that is not based on the proprietary
-       Doom artwork.
-     * There is now memory-mapped WAD I/O support, which should be useful
-       on some embedded systems.
-     * Chex quest emulation support is now included, although an
-       auxiliary dehacked patch is needed (chexdeh.zip in the idgames
-       archive).
-
-    Compatibility:
-     * The armor class is always set to 2 when picking up a megasphere
-       (thanks entryway).
-     * The quit screen prompts to quit "to dos" instead of just to quit
-       (thanks MikeRS)
-     * The "dimensional shambler" quit message was fixed.
-     * Fix crash related to A_BFGSpray with NULL target when using
-       dehacked patches - discovered with insaned2.deh
-       (thanks CSonicGo)
-     * NUL characters are stripped from dehacked files, to ensure correct
-       behavior with some dehacked patches (eg. the one with portal.wad).
-
-    Bugs fixed:
-     * "Python Image Library" should have been "Python Imaging Library"
-       (thanks exp(x)).
-     * The setup tool should no longer ask for elevated permissions
-       on Windows Vista (this fix possibly may not work).
-     * The application icon is set properly when running under Windows
-       XP with the "Luna" theme.
-     * Fix compilation under Cygwin to detect libraries and headers from
-       the correct environment.
-     * The video code does not try to read SDL events before SDL has
-       been properly initialised - this was causing problems with some
-       older versions of SDL.
-
-1.1.1 (2008-04-20):
-
-    The previous release (v1.1.0) included a bug that broke compilation
-    when libsamplerate support was enabled.  The only change in this 
-    version is to fix this bug.
-
-1.1.0 (2008-04-19):
-
-     * The video mode code has been radically restructured.  The video mode is
-       now chosen by directly specifying the mode to use; the scale factor is
-       then chosen to fit the screen.  This is helpful when using widescreen
-       monitors (thanks Linguica)
-     * MSVC build project files (thanks GhostlyDeath and entryway).
-     * Unix manpage improvements; the manpage now lists the environment
-       variables that Chocolate Doom uses.  Manpages have been added for
-       chocolate-setup and chocolate-server, from the versions for the Debian
-       Chocolate Doom package (thanks Jon Dowland).
-     * INSTALL file with installation instructions for installing Chocolate
-       Doom on Unix systems.
-     * Support for high quality resampling of sound effects using 
-       libsamplerate (thanks David Flater).
-     * A low pass filter is applied when doing sound resampling in an
-       attempt to filter out high frequency noise from the resampling
-       process.
-     * R_Main progress box is not displayed if stdout is a file (produces
-       cleaner output).
-     * Client/server version checking can be disabled to allow different
-       versions of Chocolate Doom to play together, or Chocolate Doom
-       clients to play with Strawberry Doom clients.
-     * Unix manpages are now generated for the Chocolate Doom 
-       configuration files.
-     * The BSD PC speaker driver now works on FreeBSD.
-
-    Compatibility:
-     * Use the same spechits compatibility value as PrBoom+, for consistency
-       (thanks Lemonzest).
-     * The intercepts overrun code has been refactored to work on big
-       endian machines.
-     * The default startup delay has been set to one second, to allow 
-       time for the screen to settle before starting the game (some 
-       monitors have a delay before they come back on after changing modes).
-     * If a savegame buffer overrun occurs, the savegame does not get saved
-       and existing savegames are not overwritten (same behaviour as 
-       Vanilla).
-
-    Bugs fixed:
-     * Desync with STRAIN demos and dehacked Misc values not being set
-       properly (thanks Lemonzest)
-     * Don't grab the mouse if the mouse is disabled via -nomouse or use_mouse
-       in the configuration file (thanks MikeRS).
-     * Don't center the mouse on startup if the mouse is disabled (thanks
-       Siggi).
-     * Reset the palette when the window is restored to clear any screen
-       corruption (thanks Catoptromancy).
-     * mus2mid.c should use MEM_SEEK_SET, not SEEK_SET (thanks Russell)
-     * Fast/Respawn options were not being exchanged when starting netgames
-       (thanks GhostlyDeath).
-     * Letterbox mode is more accurately described as "pillarboxed" or 
-       "windowboxed" where appropriate (thanks MikeRS)
-     * Process affinity mask is set to 1 on Windows, to work around a 
-       bug in SDL_mixer that can cause crashes on multi-core machines
-       (thanks entryway).
-     * Bugs in the joystick configuration dialog in the setup tool have
-       been fixed.
-
-1.0.0 (2007-12-10):
-
-    This release is dedicated to Dylan 'Toke' McIntosh, who was
-    tragically killed in a car crash in 2006.  I knew Dylan
-    from IRC and the Doomworld forums for several years, and he had
-    a deep passion for this game.  He was also a huge help for me while
-    developing Chocolate Doom, as he helped point out a lot of small
-    quirks in Vanilla Doom that I didn't know about. His death is a 
-    great loss.  RIP Toke.
-
-    This is the first release to reach full feature parity with 
-    Vanilla Doom.  As a result, I have made this version 1.0.0, so
-    Chocolate Doom is no longer beta!
-
-    Big new features:
-     * Multiplayer!  This version includes an entirely new multiplayer
-       engine, based on a packet server architecture.  I'd like to thank
-       joe, pritch, Meph and myk, and everyone else who has helped test
-       the new code for their support, feedback and help in testing this.  
-       The new code still needs more testing, and I'm eager to hear any 
-       feedback on this.
-     * A working setup tool.  This has the same look and feel as the 
-       original setup.exe.  I hope people like it!  Note that it has 
-       some advantages over the original setup.exe - for example, 
-       you can use the mouse.
-
-    Other new features:
-     * New mus conversion code thanks to Ben Ryves.  This converts the
-       Doom .mus format to .mid a lot better.  As one example, tnt.wad
-       Map02 is now a lot closer to how Vanilla says.  Also, the music 
-       on the deca.wad titlescreen now plays!
-     * x3, x4 and x5 display scale (thanks to MikeRS for x5 scale).
-     * Fullscreen "letterbox" mode allows Chocolate Doom to run on machines
-       where 1.6:1 aspect ratio modes are unavailable (320x200/640x400).
-       The game runs in 320x240/640x480 instead, with black borders.
-       The system automatically adjusts to this if closer modes are 
-       unavailable.
-     * Aspect ratio correction: you can (also) run at 640x480 without black 
-       borders at the top and bottom of the screen.
-     * PC speaker sound effect support.  Chocolate Doom can output real
-       PC speaker sounds on Linux, or emulate a PC speaker through the
-       sound card.
-     * Working three-screen mode, as seen in early versions of Doom!
-       To test this out, put three computers on a LAN and type:
-         chocolate-doom -server
-	 chocolate-doom -autojoin -left
-	 chocolate-doom -autojoin -right
-     * Allow a delay to be specified on startup, to allow the display to
-       settle after changing modes before starting the game.
-     * Allow the full path and filename to be specified when loading demos:
-       It is now possible to type 'chocolate-doom -playdemo /tmp/foo.lmp'
-       for example.
-     * Savegames are now stored in separate directories depending on
-       the IWAD: eg. the savegames for Doom II are stored in a different
-       place to those for Doom I, Final Doom, etc. (this does not affect
-       Windows).
-     * New mouse acceleration code works based on a threshold and 
-       acceleration.  Hopefully this should be closer to what the DOS
-       drivers do.  There is a 'test' feature in the setup tool to help 
-       in configuring this.
-     * New '-nwtmerge' command line option that emulates NWT's '-merge'
-       option.  This allows TiC's Obituary TC to be played.
-     * The ENDOOM screen no longer closes automatically, you have to click
-       the window to make it go away.
-     * Spechit overrun fixes and improvements.  Thanks to entryway for
-       his continued research on this topic (and because I stole your
-       improvements :-).  Thanks to Quasar for reporting a bug as well.
-     * Multiple dehacked patches can be specified on the command line,
-       in the same way as with WADs - eg. -deh foo.deh bar.deh baz.deh.
-     * Default zone memory size increased to 16MB; this can be controlled
-       using the -mb command-line option.
-     * It is now possible to record demos of unlimited length (by default, 
-       the Vanilla limit still applies, but it can now be disabled).
-     * Autoadjusting the screen mode can now be disabled.
-     * On Windows, the registry is queried to detect installed versions of
-       Doom and automatically locate IWAD files.  IWADs installed through
-       Steam are also autodetected.
-     * Added DOOMWADPATH that can be used like PATH to specify multiple 
-       locations in which to search for IWAD files.  Also, '-iwad' is 
-       now enhanced, so that eg. '-iwad doom.wad' will now search all 
-       IWAD search paths for 'doom.wad'.
-     * Improved mouse tracking that should no longer lag.  Thanks to 
-       entryway for research into this.
-     * The SDL driver can now be specified in the configuration file.  
-       The setup tool has an option on Windows to select between
-       DirectX and windib.
-     * Joystick support.
-     * Configuration file option to change the sound sample rate.
-     * More than three mouse buttons are now supported.
-     
-    Portability improvements: 
-     * Chocolate Doom now compiles and runs cleanly on MacOS X.  Huge
-       thanks go to Insomniak who kindly gave me an account on his machine
-       so that I could debug this remotely.  Big thanks also go to 
-       athanatos on the Doomworld forums for his patience in testing 
-       various ideas as I tried to get Chocolate Doom up and running
-       on MacOS.
-     * Chocolate Doom now compiles and runs natively on AMD64.
-     * Chocolate Doom now compiles and runs on Solaris/SPARC, including
-       the Sun compiler.  Thanks to Mike Spooner for some portability 
-       fixes.
-     * Improved audio rate conversion, so that sound should play properly
-       on machines that don't support low bitrate output.
-
-    Compatibility fixes:
-     * Check for IWADs in the same order as Vanilla Doom.
-     * Dehacked code will now not allow string replacements to be longer than
-       those possible through DOS dehacked.
-     * Fix sound effects playing too loud on level 8 (thanks to myk
-       for his continued persistence in getting me to fix this)
-     * Save demos when quitting normally - it is no longer necessary to
-       press 'q' to quit and save a demo.
-     * Fix spacing of -devparm mode dots.
-     * Fix sky behavior to be the same as Vanilla Doom - when playing in
-       Doom II, the skies never change from the sky on the first level
-       unless the player loads from a savegame. 
-     * Make -nomouse and config file use_mouse work again.
-     * Fix the -nomusic command-line parameter.  Make the snd_sfxdevice
-       snd_musicdevice values in the configuration file work, so that it
-       is possible to disable sound, as with Vanilla.
-     * Repeat key presses when the key is held down (this is the Vanilla 
-       behavior)  - thanks to Mad_Mac for pointing this out.
-     * Don't print a list of all arguments read from response files - Vanilla
-       doesn't do this.
-     * Autorun only when joyb_speed >= 10, not >= 4.  Thanks to Janizdreg 
-       for this.
-     * Emulate a bug in DOS dehacked that can overflow the dehacked
-       frame table and corrupt the weaponinfo table.  Note that this means
-       Batman Doom will no longer play properly (identical behavior
-       to Vanilla); vbatman.deh needs to also be applied to fix it.
-       (Thanks grazza)
-     * Allow dehacked 2.3 patches to be loaded.
-     * Add more dehacked string replacements.
-     * Compatibility option to enable or disable native key mappings.  This
-       means that people with non-US keyboards can decide whether to use
-       their correct native mapping or behave like Vanilla mapping (which
-       assumes all keyboards are US).
-     * Emulate overflow bug in P_FindNextHighestFloor.  Thanks to
-       entryway for the fix for this.
-     * Add -netdemo command line parameter, for playing back netgame
-       demos recorded with a single player.
-     * The numeric keypad now behaves like Vanilla Doom does.
-     * Fix some crashes when loading from savegames.
-     * Add intercepts overrun emulation from PrBoom-plus.  Thanks again
-       to entryway for his research on this subject.
-     * Add playeringame overrun emulation.
-
-    Bugs fixed:
-     * Fix crash when starting new levels due to the intermission screen
-       being drawn after the WI_ subsystem is shut down (thanks 
-       pritch and joe)
-     * Catch failures to initialise sound properly, and fail gracefully.
-     * Fix crasher in 1427uv01.lmp (thanks ultdoomer)
-     * Fix crash in udm1.wad.
-     * Fix crash when loading a savegame with revenant tracer missiles.
-     * Fix crash when loading a savegame when a mancubus was in the middle
-       of firing.
-     * Fix Doom 1 E1-3 intermission screen animations.
-     * Fix loading of dehacked "sound" sections.
-     * Make sure that modified copyright banners always end in a newline
-       - this fixes a bug with av.wad (thanks myk)
-     * Added missing quit message ("are you sure you want to quit this
-       great game?").
-     * Fix when playing long sound effects - the death sound in marina.wad
-       now plays properly, for example.
-     * Fix buffer overrun on the quicksave prompt screen that caused a
-       mysterious cycling character to appear.
-     * IDCLEV should not work in net games (thanks Janizdreg)
-     * Stop music playing at the ENDOOM screen.
-     * Fix sound sample rate conversion crash.
-     * Fix 'pop' heard at the end of sound effects.
-     * Fix crash when playing long sounds.
-     * Fix bug with -timedemo accuracy over multi-level demos.
-     * Fix bug with the automap always following player 1 in multiplayer
-       mode (thanks Janizdreg).
-
-0.1.4 (2006-02-13):
-
-    NWT-style merging command line options (allows Mordeth to be played)
-    Unix manpage (thanks Jon Dowland)
-    Dehacked improvements/fixes:
-     * Allow changing the names of graphic lumps used in menu, status bar
-       intermission screen, etc.
-     * Allow changing skies, animated flats + textures
-     * Allow changing more startup strings.
-     * Allow text replacements on music + sfx lump names
-    Fix for plutonia map12 crash.
-    Fix bug with playing long sfx at odd sample rates.
-    Big Endian fixes (for MacOS X).  Thanks to athanatos for helping
-        find some of these.
-    Install into /usr/games, rather than /usr/bin (thanks Jon Dowland)
-
-0.1.3 (2006-01-20):
-
-    Imported the spechit overrun emulation code from prboom-plus.  Thanks to
-         Andrey Budko for this.
-    New show_endoom option in the chocolate-doom.cfg config file allows
-         the ENDOOM screen to be disabled.
-    Chocolate Doom is now savegame-compatible with Vanilla Doom.
-
-    Fixes for big endian machines (thanks locust)
-    Fixed the behavior of the dehacked maximum health setting.
-    Fix the "-skill 0" hack to play without any items (thanks to Janizdreg
-        for pointing out that this was nonfunctional)
-    Fix playing of sounds at odd sample rates (again).  Sound effects at
-        any sample rate now play, but only sounds with valid headers.
-        This is the *real* way Vanilla Doom behaves.  Thanks to myk for
-        pointing out the incorrect behavior.
-
-0.1.2 (2005-10-29):
-
-    Silence sounds at odd sample rates (rather than bombing out); this
-        is the way Vanilla Doom behaves.
-    Handle multiple replacements of the same sprite in a PWAD.
-    Support specifying a specific version to emulate via the command line
-        (-gameversion)
-    Fix help screen orderings and skull positions.  Behave exactly as
-        the original executables do.
-
-0.1.1 (2005-10-18):
-    Display startup "banners" if they have been modified through 
-        dehacked.
-    Dehacked "Misc" section support.
-
-    Bugs fixed:
-     * Doom 1 skies always using Episode 1 sky
-     * Crash when switching applications while running fullscreen
-     * Lost soul bounce logic (do not bounce in Registered/Shareware)
-     * Mouse buttons mapped incorrectly (button 1 is right, 2 is middle)
-     * Music not pausing when game is paused, when using SDL_mixer's 
-       native MIDI playback.
-     * Pink icon on startup (palette should be fully set before anything is
-       loaded)
-
-0.1.0 (2005-10-09):
-    Dehacked support
-    WAD merging for TCs
-    ENDOOM display
-    Fix bug with invalid MUS files causing crashes
-    Final Doom fixes
-
-0.0.4 (2005-09-27):
-    Application icon and version info included in Windows .exe files
-    Fixes for non-x86 architectures
-    Fix uac_dead.wad (platform drop on e1m8 should occur when all
-        bosses die, not just barons)
-    Fix "loading" icon to work for all graphics modes
-
-0.0.3 (2005-09-17):
-    Mouse acceleration code to emulate the behaviour of old
-        DOS mouse drivers (thanks to Toke for information about 
-        this and suggestions)
-    Lock surfaces properly when we have to (fixes crash under
-        Windows 98)
-
-0.0.2 (2005-09-13):
-    Remove temporary MIDI files generated by sound code.
-    Fix sound not playing at the right volume
-    Allow alt-tab away while running in fullscreen under Windows
-    Add second configuration file (chocolate-doom.cfg) to allow 
-        chocolate-doom specific settings.
-    Fix switches not changing in Ultimate Doom
-
-0.0.1 (2005-09-07):
-    First beta release
-
-# vim: tw=70
-
--- /dev/null
+++ b/NEWS.md
@@ -1,0 +1,1164 @@
+## HEAD
+
+### General
+  * Bash completion scripts are included. (thanks Fabian)
+  * Support the *.lmp file format in the OS X launcher (thanks Jon)
+  * Added emulation for pitch-shifting as in early versions of Doom,
+    Heretic, and Hexen. (thanks Jon)
+  * Write out aspect-correct 1600×1200 PNGs. (thanks Jon)
+  * OPL emulation is more accurate. (thanks Nuke.YKT)
+  * Futher emulation of DMX bugs with GUS cards. (thanks Nuke.YKT)
+  * Emulation of the disk icon has returned. (thanks Fabian, Jon)
+  * Checksum calculations were fixed on big endian systems, allowing
+    multiplayer games to be played in mixed little/big-endian
+    environments. (thanks GhostlyDeath, njankowski)
+
+### Build systems
+  * Improved compatibility with BSD Make. (thanks R.Rebello)
+  * “./configure --with-PACKAGE” checks were repaired to behave
+    logically, rather than disabling the feature. (thanks R.Rebello)
+  * Default to installing the games to ${bindir}, such as
+    /usr/local/bin, rather than /usr/local/games. (thanks chungy)
+  * Support Visual Studio 2015. (thanks Azarien)
+  * Allow SDL headers and libraries to exist in the Microsoft Visual
+    Studio project directory. (thanks Quasar)
+  * Repaired the CodeBlocks projects by removing non-existent files
+    from the project files (thanks krystalgamer)
+
+### Doom
+  * Chex Quest’s level warp cheat (LEESNYDER##) was changed to behave
+    like the original EXE. (thanks Nuke.YKT)
+  * Allow starting multiplayer Chex Quest games.
+  * Allow Freedoom: Phase 1 ≤ 0.10.1 to be loaded with mods, with
+    -gameversion older than ultimate. (thanks Fabian, chungy)
+  * Added safety checks against write failures when saving a game,
+    such as when the directory is read-only.  Try falling back to a
+    temporary directory and reporting an error instead.  (thanks
+    terrorcide)
+  * Versions 1.666, 1.7, and 1.8 are emulated. (thanks Nuke.YKT)
+
+### Heretic
+  * Added map names for Episode 6, fixing a crash after completing a
+    level in this episode. (thanks J.Benaim)
+
+### Hexen
+  * The MRJONES cheat code returns an identical string as vanilla, and
+    enables fully reproducable builds. (thanks Fabian)
+  * Fixed an issue where the game crashed while killing the
+    Wraithverge in 64-bit builds. (thanks J.Benaim)
+
+### Strife
+  * Support added for automatic loading of the IWAD from the GOG.com
+    release of Strife: Veteran Edition on Windows. (thanks chungy)
+  * Jumping can be bound to a mouse button. (thanks Gez)
+  * Gibbing logic was changed to match vanilla behavior. (thanks Quasar)
+  * Several constants differences from vanilla were fixed. (thanks
+    Nuke.YKT, Quasar)
+  * When using -iwad, voices.wad from the IWAD’s directory is prefered
+    over auto-detected DOS/Steam/GOG.com installs. (thanks Quasar)
+
+### libtextscreen
+  * Simplified the API for creating and managing tables and columns.
+  * Allow cycling through tables with tab key.
+
+## 2.2.1 (2015-09-10)
+
+  Chocolate Doom has not seen a great deal of “stable” patch releases
+  in its history. While the development tree sees major new features
+  and changes, the purpose of this release, and hopefully others to
+  follow like it, is to repair some deficiencies that existed
+  in 2.2.0.
+
+### General
+  * Preferences for the OS X launcher are now stored with a unique
+    name to not conflict with other applications. (thanks
+    Xeriphas1994)
+  * Unix desktop entry files are now brought up to full desktop entry
+    specification compliance. (thanks chungy, Fabian)
+  * Unix AppData entries are now included, allowing software centers
+    to display detailed information about the engines. (thanks chungy)
+  * Partial XDG base directory specification compliance on Unix
+    systems now exist to search for IWAD paths.  One benefit is that
+    $HOME/.local/share/games/doom is now a valid location to store and
+    automatically find IWADs. (thanks chungy)
+
+### Build systems
+  * The Microsoft Visual Studio build system was not fully functional
+    in 2.2.0 and has been fixed. (thanks Linguica)
+  * The autoconf build system checks for windres only for Windows
+    toolchains.  Some Linux distributions mistakingly include the
+    program in their native toolchains. (thanks Fabian)
+  * A compiler hint for packed structs has been added, which otherwise
+    broke the games when built under recent GCC releases for
+    Windows. (thanks Fabian)
+
+### Doom
+  * The GOG.com releases of The Ultimate Doom, Doom II, and Final Doom
+    are now detected and supported on Windows. (thanks chungy)
+  * An integer overflow was used in spawn angle calculation, undefined
+    C behavior which broke with Clang optimization.  (thanks David
+    Majnemer for insight)
+
+### Setup tool
+  * The help URL for the level warp menu now points to the proper wiki
+    page, rather than the multiplayer page.
+  * The manifest has been updated for Windows 10 compatibility.
+    (thanks chungy)
+
+## 2.2.0 (2015-06-09)
+
+  * The Hexen four level demo IWAD is now supported. Thanks to Fabian
+    Greffrath for his careful investigation and emulation of the demo
+    game’s behavior in developing this.
+  * OPL music playback has been improved in a number of ways to match
+    the behavior of Vanilla Doom’s DMX library much more closely. OPL3
+    playback is also now supported. Thanks go to Alexey Khokholov for
+    his excellent research into the Vanilla DMX library that enabled
+    these improvements.
+  * New gamepad configurations:
+      - PS4 DualShock 4 (thanks Matt “3nT” Davis).
+      - Xbox One controller on Linux (thanks chungy).
+      - “Super Joy Box 7” USB/PC gameport adapter.
+  * The Doom reload hack has been added back. See the wiki for more
+    context on this: http://doomwiki.org/wiki/Reload_hack
+  * The IWAD file from Strife: Veteran Edition is now detected
+    automatically (thanks chungy).
+  * It’s now possible to build outside of the source directory (thanks
+    Dave Murphy).
+  * MSVC project files were brought up to date (thanks dbrackett16).
+  * M_StringDuplicate() has been added as a safer replacement for
+    strdup() (thanks Quasar). M_StringCopy() now handles short buffers
+    more gracefully.
+  * The netgame discrepancy window is now dismissed by pressing enter
+    to proceed, not escape (thanks Alexandre-Xavier).
+  * A couple of source files that were in the previous release and
+    were GPL3 have been replaced by GPL2 equivalents. Previous
+    releases that included these files should be retroactively
+    considered GPL3.
+
+### Bug fixes
+  * A long-standing bug that could cause every display frame to be
+    rendered twice was fixed (thanks Linguica, Harha, Alexandre-
+    Xavier).
+  * Lots of endianness fixes were integrated that were found by Ronald
+    Lasmanowicz during development of his Wii port of Chocolate Doom,
+    including a fix for a bug that could cause monsters to become
+    partially invisible.
+  * DeHackEd files without a newline character at the EOF are now
+    correctly parsed (thanks Fabian).
+  * An infinite loop that could occur in the weapon cycling code was
+    fixed (thanks raithe, Fabian).
+  * Mouse input triggered by cursor warp was fixed (thanks Super6-4).
+  * Loop tags in substitute music files are ignored if both of the
+    loop tags are equal to zero. This makes us consistent with other
+    source ports that support the tags.
+  * It’s now possible to more conveniently play back demo .lmp files
+    with names that end in the all-caps “.LMP” (thanks Ioan Chera).
+  * Some code that accessed memory after freeing it was fixed. Two new
+    parameters, -zonezero and -zonescan, were added to try to help
+    detect these cases.
+  * Mistaken assumptions about representations of booleans that
+    affected some ARM systems were fixed (thanks floppes).
+  * memcpy() uses on overlapping memory were changed to use memmove(),
+    fixing abort traps on OpenBSD (thanks ryan-sg).
+  * Hyphens in manpages were fixed (thanks chungy, Fabian).
+  * Lots of compiler build warnings were fixed (thanks Fabian).
+
+### Setup tool
+  * The setup tool now has help buttons for its various different
+    screens, which link to articles on the wiki that give more
+    information (thanks to chungy for helping to put the wiki pages
+    together).
+  * A fix was applied for a buffer overrun that could occur if the
+    user had lots of IWAD files installed (thanks Fabian).
+  * A crash related to username lookup was fixed.
+  * It’s now possible to connect via the setup tool to multiplayer
+    servers that are not listening on the default port (thanks
+    Alexandre-Xavier).
+
+### Doom
+  * Sky transitions when emulating the id anthology version of the
+    Final Doom executable were fixed (thanks Alexandre-Xavier, Fabian,
+    chungy).
+  * Structure fields in the stair-building functions were fixed to be
+    deterministic, fixing a desync in mm09-512.lmp (thanks Fabian).
+
+### Hexen
+  * A bug with texture names that had long names was fixed (thanks
+    ETTiNGRiNDER).
+  * Minotaur spawn time is now stored in little endian format, fixing
+    a bug that affected compatibility with Vanilla savegames on big
+    endian systems.
+  * Code that starts ACS scripts is no longer compiler-dependent.
+
+### Strife (all these are thanks to Quasar)
+  * Sound priority was changed, so that the ticking sound that Stalker
+    enemies make while active matches Vanilla behavior (thanks
+    GeoffLedak).
+  * Minor fixes to game behavior to match Vanilla, discovered during
+    development of Strife: Veteran edition.
+  * Behavior of descending stairs was fixed to match Vanilla.
+  * Inventory items beyond the 8-bit range are now allowed in
+    netgames.
+  * Automap behavior better matches Vanilla now.
+  * Multiplayer name changes were fixed.
+  * Sound origin behavior for switches was fixed.
+  * Teleport beacon behavior was fixed.
+  * Default Strife skill level and screen size were changed to match
+    Vanilla.
+  * Bug was fixed where Rowan would not always take Beldin’s ring.
+  * Totally-invisible objects are now displayed correctly, and a
+    Vanilla glitch with Shadow Acolytes is correctly emulated.
+  * The level name for MAP29 (Entity’s Lair) was fixed (thanks
+    chungy).
+
+### libtextscreen
+  * The main loop now exits immediately once all windows are closed
+    (thanks Alexander-Xavier).
+  * The large font is no longer selected based entirely on screen
+    size.
+
+## 2.1.0 (2014-10-22)
+
+  Chocolate Doom now supports high-quality substitute music packs that
+  are used in place of the original MIDI music tracks. I’m hoping to
+  put together high-quality recordings of the music for all supported
+  games using the Roland SC-55 synthesizer originally used to compose
+  Doom’s music (thanks twipley and MusicallyInspired).
+
+  Support for joysticks and gamepads has been significantly improved
+  in this version. Most gamepads should now work; if they don’t,
+  please report a bug. A number of gamepads are now automatically
+  detected and configured automatically; if yours is not, you can help
+  by sending in details. See the following page:
+
+  http://www.chocolate-doom.org/wiki/index.php/Adding_your_gamepad
+
+  OPL MIDI playback has been significantly improved, and problems with
+  most tracks should now be resolved. Multi-track MIDI files now play
+  back properly, MIDI tempo meta events are now supported and problems
+  with stuttering when playing certain tracks have been fixed. If you
+  still have problems with OPL playback, let me know.
+
+  Also of note is that Chocolate Doom now has a document that
+  describes the philosophy of the project and the reasoning behind its
+  design (see PHILOSOPHY distributed with the source).
+
+### Other new features
+  * There is now a -dehlump command line parameter to load Dehacked
+    files contained inside WAD files (thanks Fabian Greffrath).
+  * PNG format screenshots are now supported, and there is a dedicated
+    key binding for taking screenshots without needing to always use
+    -devparm (thanks Fabian Greffrath). The PrintScreen key can be
+    used as a key binding (thanks Alexandre-Xavier).
+  * There is now a config file variable (snd_maxslicetime_ms) to
+    control the sound buffer size, and the default is more precise to
+    reduce sound latency (thanks Holering).
+  * You can now use an external command for music playback (thanks
+    Holering).
+  * All games now detect if you’re tring to play using the wrong type
+    of IWAD (doom.wad with Hexen, etc.) and exit with a helpful error
+    message. A couple of users made this mistake after the 2.0 release
+    introduced support for the new games.
+  * The OS X app now associates with .hhe and .seh files.
+  * There is now a -nodes parameter that automatically starts a
+    netgame when a desired number of players have joined the game.
+  * There is now more extensive documentation about music
+    configuration (README.Music).
+  * On Linux, a GUI pop-up is used when the game quits with an error
+    to show the error message (thanks Willy Barro).
+  * There are now Linux .desktop files for all supported games (thanks
+    Mike Swanson).
+  * The -geometry command line parameter can now be used to specify
+    fullscreen or windowed modes, eg. -geometry 640x480w or -geometry
+    1024x768f. (thanks Mike Swanson)
+
+### Doom
+  * Minor workarounds were added to allow the BFG Edition IWADs to be
+    used without crashing the game (thanks Fabian Greffrath).
+  * GUS patch files included with the BFG Edition are now
+    automatically detected.
+  * The “no fog on spawn west” Vanilla bug is now correctly emulated
+    (thanks xttl).
+  * Behavior of older versions of Doom back to v1.666 can now be
+    emulated.
+  * The new Freedoom IWAD names are now recognized and supported.
+  * Freedoom’s DEHACKED lump can now be parsed and is automatically
+    loaded when a Freedoom IWAD file is used (thanks Fabian
+    Greffrath). A new command line parameter, -nodeh, can be used to
+    prevent this from being loaded.
+  * Behavior of the M_EPI4 menu item is now correctly emulated based
+    on game version (thanks Alexandre-Xavier).
+  * IDCLEV up to MAP40 is now supported, to match Vanilla (thanks
+    Alexandre-Xavier).
+  * Level warping on the command line (-warp) to episodes higher than
+    4 is possible, matching Vanilla behavior (thanks plumsinus).
+  * The -cdrom command line parameter writes savegames to the correct
+    directory now, matching Vanilla Doom behavior (thanks
+    Alexandre-Xavier).
+  * The Doom II mission pack to use can now be specified manually on
+    the command line with the -pack parameter (thanks chungy)
+
+### Heretic
+  * Weapon cycling keys for mouse and joystick were fixed (thanks
+    Sander van Dijk).
+  * The -timedemo parameter has been fixed, and -playdemo now handles
+    full paths correctly.
+  * A bug when panning the map was fixed (thanks Chris Fielder).
+  * A savegame bug where plat_t structures were not restored correctly
+    was fixed (thanks romeroyakovlev).
+  * Rebinding of the pause key was fixed (thanks Fabian Greffrath).
+
+### Hexen
+  * Music workarounds have been added so that it is possible to play
+    using the Mac version of the Hexen IWAD file.
+  * Weapon cycling keys for mouse and joystick were fixed (thanks
+    Sander van Dijk).
+  * The -timedemo parameter has been fixed, and -playdemo now handles
+    full paths correctly.
+  * There are now key bindings to allow the artifact keys to be
+    rebound (thanks Fabian Greffrath).
+  * Rebinding of the pause key was fixed (thanks Fabian Greffrath).
+  * Maximum level number was extended to MAP60, allowing multiplayer
+    games using the Deathkings add-on.
+  * The startup screen can now be aborted by pressing escape, like in
+    Vanilla.
+  * Desync when playing back DEMO1 was fixed (thanks alexey.lysiuk).
+
+### Strife
+  * “Show mission” key is configured properly in setup (thanks Sander
+    van Dijk).
+  * Default music volume level now matches Vanilla (thanks
+    Alexandre-Xavier).
+  * Teleport beacon allegiance was fixed to match Vanilla (thanks
+    Quasar).
+  * The stair building code now more closely matches Vanilla (thanks
+    Quasar).
+  * Torpedo weapon changing behavior now matches Vanilla (thanks
+    Quasar).
+
+### Cleanups
+  * The copyright headers at the top of all source files have been
+    vastly simplified.
+  * Unsafe string functions have been eliminated from the codebase.
+    Thanks to Theo de Raadt for calling out Chocolate Doom by name
+    (alongside many other packages) for still using unsafe functions
+    like strcpy: http://marc.info/?l=openbsd-tech&m=138733933417096
+  * vldoor_e enum values are now namespaced to avoid potential
+    conflicts with POSIX standard functions.
+
+### Bug fixes
+  * WAD and Dehacked checksums are now sent to clients and checked
+    correctly when setting up netgames.
+  * A bug was fixed that caused sound not to work in multiplayer games
+    (thanks to everyone who reported this, and for Alexandre-Xavier
+    and Quasar for help in fixing it).
+  * The “D_DDTBLU disease” bug affecting certain MIDI files has been
+    fixed (thanks plumsinus, Brad Harding and Quasar).
+  * Calculation of the -devparm “ticker” dots was fixed to match
+    Vanilla behavior (thanks _bruce_ and Alexandre-Xavier).
+  * The PC speaker code now supports the full range of sound
+    frequencies (thanks Gez).
+  * Annoying “jumping” behavior when grabbing the mouse cursor was
+    fixed.
+  * The screen is now initialized at the native bit depth by default,
+    to avoid problems with systems that don’t handle 8-bit
+    screenbuffers very well any more.
+  * The --docdir argument to the configure script is now honored
+    (thanks Jan Engelhardt).
+  * Various issues with the build were fixed (thanks Jan Engelhardt
+    and Fabian Greffrath).
+  * Backwards parameters were fixed in the sound code (thanks
+    proteal).
+  * A crash was fixed when running fullscreen with the -2 parameter
+    (thanks Fabian Greffrath).
+  * A crash when using large values of snd_channels was fixed (thanks
+    Alexandre-Xavier).
+  * A resource leak in the BSD PC speaker code was fixed (thanks
+    Edward-san).
+  * Windows resource files were fixed for Windows 7 (thanks Brad
+    Harding).
+  * A hard to trigger crash caused by a realloc() in the WAD code was
+    fixed (thanks Fabian Greffrath for debugging).
+  * A bug has been fixed where Chocolate Doom would stay running in
+    the background on Windows after quitting. SDL_Quit() is called now
+    (thanks johnsirett, Brad Harding, Quasar).
+  * String replacements in dehacked lumps can now be overridden if a
+    subsequent dehacked patch replaces the same string.
+
+### libtextscreen
+  * Clicking on scrollbars now jumps to the correct position (thanks
+    Alexandre-Xavier).
+  * A use-after-free bug has been fixed where a click in a window that
+    causes the window to close could lead to a crash (thanks DuClare).
+  * Characters that are unprintable in the Extended ASCII chart are
+    just ignored when they’re typed, rather than appearing as an
+    upside-down question mark (thanks Alexandre-Xavier).
+
+## 2.0.0 (2013-12-09)
+
+  This is version 2.0 of Chocolate Doom! This new major version is
+  released to celeberate the 20th anniversary of the first release of
+  Doom in 1993. Happy Birthday Doom!
+
+  This new version has some major changes compared to the 1.0 series:
+
+  * The codebase now includes Chocolate Heretic and Chocolate
+    Hexen. These are based on the GPL source code released by Raven
+    Software.
+  * Also included is Chocolate Strife. This was developed through a
+    mammoth four year reverse engineering project conducted by James
+    “Quasar” Haley and Samuel “Kaiser” Villareal. The result is the
+    most accurate reproduction of Strife to date, including full demo
+    and savegame compatibility. See README.Strife for more
+    information.
+
+### Minor features that are nonetheless worth mentioning
+  * Chocolate Doom now includes a -statdump command line option, which
+    emulates the output of the statdump.exe tool. This is used to
+    implement a form of regression testing (statcheck) that directly
+    compares against the Vanilla behavior.
+  * Chocolate Heretic includes HHE patch file support, and I believe
+    is the first Heretic port to include this feature.
+  * GUS “pseudo-emulation” is now supported. This does not fully
+    emulate a GUS, but Doom’s DMXGUS lump can be used to generate a
+    Timidity configuration file that plays music using the GUS patch
+    set.
+  * The setup tool now includes a built-in server browser, for use
+    when selecting a server to join.
+
+  Version 2.0 of Chocolate Doom has been in development for a long
+  time, and there have been many bugs fixed over this time, too many
+  to list here. Thanks to all the people who have tested it and
+  diligently reported bugs over this time, and to all the people who
+  have tested the beta releases over the past couple of months.  Your
+  contributions have been essential and invaluable.
+
+## 1.7.0 (2012-06-09)
+
+  * Fixed gnome-screensaver desktop file (thanks Rahul Sundaram).
+  * Updated COPYING to current version of GPL2 (thanks Rahul
+    Sundaram).
+  * Running servers now re-resolve the address of the master server
+    occasionally, to adapt to DNS address changes.
+  * Error dialog is no longer shown on OS X when running from the
+    console.
+  * The Makefiles no longer use GNU make extensions, so the package
+    builds on OpenBSD.
+  * There is now an OPL MIDI debug option (-opldev), useful for when
+    developing GENMIDI lumps.
+  * A workaround for SDL mouse lag is now only used on Windows (where
+    it is needed), and not on other systems. This fixes Chocolate Doom
+    on AmigaOS (thanks Timo Sievänen).
+  * UTF-8 usernames are supported, and Windows usernames with
+    non-ASCII characters are now supported (thanks Alexandre Xavier).
+
+### Compatibility
+  * Palette accuracy is reduced to 6 bits per channel, to more
+    accurately emulate the PC VGA hardware (thanks GhostlyDeath).
+  * Fixed teleport behavior when emulating the alternate Final Doom
+    executable (-gameversion final2) (thanks xttl).
+
+### Bugs fixed
+  * Fixed weapon cycling keys when playing in Shareware Doom and using
+    the IDKFA cheat (thanks Alexandre Xavier).
+  * Fixed the default mouse buttons in the setup tool (thanks
+    Alexandre Xavier).
+  * Chat macros now work when vanilla_keyboard_mapping is turned off.
+  * Default chat macros were fixed in the setup tool.
+  * Ping time calculation was fixed for LAN search, and made more
+    accurate for all searches.
+  * Fixed bug with detection of IWAD type by filename (thanks mether).
+
+### libtextscreen
+  * There is now limited UTF-8 text support in the textscreen library,
+    used in the label and input box widgets.
+  * Scroll bar behavior was fixed (thanks Alexandre Xavier).
+  * Input boxes stop editing and save when they lose their focus,
+    correcting a previous counterintuitive behavior (thanks Twelve).
+  * The numeric keypad now works properly when entering text values
+    (thanks Twelve).
+
+## 1.6.0 (2011-05-17)
+
+  * The instructions in the INSTALL file are now customized for
+    different platforms, and each binary package contains a version
+    with instructions specific to the platform that it is targetting.
+    This should help to avoid confusion that some users have reported
+    experiencing.
+  * The display settings window in the setup tool has been reorganised
+    to a better arrangement.
+  * It is now possible to load .lmp files (and play back demos) with
+    long filenames (thanks blzut3).
+  * In the setup tool, it is now possible to hold down shift when
+    changing key/mouse/joystick bindings to prevent other bindings to
+    the same key from being cleared (thanks myk).
+  * The joystick menu in the setup tool now has a test button (thanks
+    Alexandre Xavier).
+  * Specifying the -privateserver option implies -server (thanks
+    Porsche Monty).
+  * The Mac OS X .dmg package now has a background and looks generally
+    more polished.
+  * In Mac OS X, it is now possible to simply double click an IWAD
+    file in the Finder to configure its location within the launcher.
+  * Freedesktop.org desktop files are now installed for Doom and the
+    setup tool, which will appear in the main menu on desktop
+    environments such as Gnome and KDE (thanks Adrián Chaves
+    Fernández).
+  * The Chex Quest dehacked patch (chex.deh) will now be detected if
+    it is in the same directory as the IWAD file.
+
+### Compatibility
+  * Added support for the alternate version of the Final Doom
+    executable included in some later versions of the Id Anthology.
+    This version fixed the demo loop crash that occurred with the
+    “original” Final Doom executable.
+
+    This executable can be selected on the command line with
+    -gameversion final2. It has been made the default when playing
+    with the Final Doom IWADs (the original behavior can be selected
+    with -gameversion final).  (thanks Porsche Monty, Enjay).
+  * Very short sound effects are not played, to better emulate the
+    behavior of DMX in Vanilla Doom (thanks to Quasar for help in
+    investigating this).
+  * The null sector dereference emulation code has been imported from
+    Prboom+ - this fixes a desync with CLNJ-506.LMP (thanks entryway).
+  * The IDMUS cheat doesn’t work when emulating the v1.9 executable
+    (thanks Alexandre Xavier).
+
+### Bugs fixed
+  * Menu navigation when using joystick/joypad (thanks Alexandre
+    Xavier).
+  * For configuration file value for shift keys, use scan code for
+    right shift, not left shift (thanks Alexandre Xavier).
+  * Default joystick buttons for the setup tool now match Vanilla
+    (thanks twipley).
+  * Visual Studio project files work again (thanks GhostlyDeath).
+  * The default sfx/music volume set by the setup tool is now 8
+    instead of 15, matching the game itself. (thanks Alexandre
+    Xavier).
+  * Weapon cycling from the shotgun to the chaingun in Doom 1 now
+    works properly (thanks Alexandre Xavier).
+  * MIDI playback that locked up when using an empty MUS / MIDI file
+    (thanks Alexandre Xavier).
+  * Default sampling rate used by setup tool changed to 44100Hz, to
+    match the game default (thanks Alexandre Xavier).
+  * Cheat codes and menu hot keys now work when shift is held down or
+    capslock turned on (thanks Alexandre Xavier).
+
+### libtextscreen
+  * The background on GUI controls now lights up when hovering over
+    them, so that it is more obvious what you are selecting.
+  * It is now possible to type a “+” in input boxes (thanks Alexandre
+    Xavier).
+  * It is possible to use the mouse wheel to scroll through scroll
+    panes.
+  * Clicking on scroll bars now moves the scroll handle to a matching
+    location.
+  * Clicking outside a dropdown list popup window now dismisses the
+    window.
+  * Window hotkeys that are an alphabetical letter now work when shift
+    is held down or capslock turned on (thanks Alexandre Xavier).
+
+## 1.5.0 (2011-01-02)
+
+  Big changes in this version:
+
+  * The DOSbox OPL emulator (DBOPL) has been imported to replace the
+    older FMOPL code.  The quality of OPL emulation is now therefore
+    much better.
+  * The game can now run in screen modes at any color depth (not just
+    8-bit modes).  This is mainly to work around problems with Windows
+    Vista/7, where 8-bit color modes don’t always work properly.
+  * Multiplayer servers now register themselves with an Internet
+    master server.  Use the -search command line parameter to find
+    servers on the Internet to play on.  You can also use DoomSeeker
+    (http://skulltag.net/doomseeker/) which supports this
+    functionality.
+  * When running in windowed mode, it is now possible to dynamically
+    resize the window by dragging the window borders.
+  * Names can be specified for servers with the -servername command
+    line parameter.
+  * There are now keyboard, mouse and joystick bindings to cycle
+    through available weapons, making play with joypads or mobile
+    devices (ie. without a proper keyboard) much more practical.
+  * There is now a key binding to change the multiplayer spy key
+    (usually F12).
+  * The setup tool now has a “warp” button on the main menu, like
+    Vanilla setup.exe (thanks Proteh).
+  * Up to 8 mouse buttons are now supported (including the
+    mousewheel).
+  * A new command line parameter has been added (-solo-net) which can
+    be used to simulate being in a single player netgame.
+  * There is now a configuration file parameter to set the OPL I/O
+    port, for cards that don’t use port 0x388.
+  * The Python scripts used for building Chocolate Doom now work with
+    Python 3 (but also continue to work with Python 2) (thanks arin).
+  * There is now a NOT-BUGS file included that lists some common
+    Vanilla Doom bugs/limitations that you might encounter (thanks to
+    Sander van Dijk for feedback).
+
+### Compatibility
+  * The -timer and -avg options now work the same as Vanilla when
+    playing back demos (thanks xttl)
+  * A texture lookup bug was fixed that caused the wrong sky to be
+    displayed in Spooky01.wad (thanks Porsche Monty).
+  * The HacX v1.2 IWAD file is now supported, and can be used
+    standalone without the need for the Doom II IWAD (thanks atyth).
+  * The I_Error function doesn’t display “Error:” before the error
+    message, matching the Vanilla behavior.  “Error” has also been
+    removed from the title of the dialog box that appears on Windows
+    when this happens.  This is desirable as not all such messages are
+    actually errors (thanks Proteh).
+  * The setup tool now passes through all command line arguments when
+    launching the game (thanks AlexXav).
+  * Demo loop behavior (ie. whether to play DEMO4) now depends on the
+    version being emulated.  When playing Final Doom the game will
+    exit unexpectedly as it tries to play the fourth demo - this is
+    Vanilla behaviour (thanks AlexXav).
+
+### Bugs fixed
+  * A workaround has been a bug in old versions of SDL_mixer (v1.2.8
+    and earlier) that could cause the game to lock up.  Please upgrade
+    to a newer version if you haven’t already.
+  * It is now possible to use OPL emulation at 11025Hz sound sampling
+    rate, due to the new OPL emulator (thanks Porsche Monty).
+  * The span renderer function (used for drawing floors and ceilings)
+    now behaves the same as Vanilla Doom, so screenshots are
+    pixel-perfect identical to Vanilla Doom (thanks Porsche Monty).
+  * The zone memory system now aligns allocated memory to 8-byte
+    boundaries on 64-bit systems, which may fix crashes on systems
+    such as sparc64 (thanks Ryan Freeman and Edd Barrett).
+  * The configure script now checks for libm, fixing compile problems
+    on Fedora Linux (thanks Sander van Dijk).
+  * Sound distortion with certain music files when played back using
+    OPL (eg. Heretic title screen).
+  * Error in Windows when reading response files (thanks Porsche
+    Monty, xttl, Janizdreg).
+  * Windows Vista/7 8-bit color mode issues (the default is now to run
+    in 32-bit color depth on these versions) (thanks to everybody who
+    reported this and helped test the fix).
+  * Screen borders no longer flash when running on widescreen
+    monitors, if you choose a true-color screen mode (thanks exp(x)).
+  * The controller player in a netgame is the first player to join,
+    instead of just being someone who gets lucky.
+  * Command line arguments that take an option now check that an
+    option is provided (thanks Sander van Dijk).
+  * Skill level names in the setup tool are now written the same as
+    they are on the in-game “new game” menu (thanks AlexXav).
+  * There is no longer a limit on the lengths of filenames provided to
+    the -record command line parameter (thanks AlexXav).
+  * Window title is not lost in setup tool when changing video driver
+    (thanks AlexXav).
+
+### libtextscreen
+  * The font used for the textscreen library can be forced by setting
+    the TEXTSCREEN_FONT environment variable to “small” or “normal”.
+  * Tables or scroll panes that don’t contain any selectable widgets
+    are now themselves not selectable (thanks Proteh).
+  * The actions displayed at the bottom of windows are now laid out in
+    a more aesthetically pleasing way.
+
+## 1.4.0 (2010-07-10)
+
+  The biggest change in this version is the addition of OPL emulation.
+  This emulates Vanilla Doom’s MIDI playback when using a Yamaha OPL
+  synthesizer chip, as was found on SoundBlaster compatible cards.
+
+  A software OPL emulator is included as most modern computers do not
+  have a hardware OPL chip any more.  If you do have one, you can
+  configure Chocolate Doom to use it; see README.OPL.
+
+  The OPL playback feature is not yet perfect or 100% complete, but is
+  judged to be good enough for general use.  If you find music that
+  does not play back properly, please report it as a bug.
+
+### Other changes
+  * The REJECT overflow emulation code from PrBoom+ has been
+    imported.  This fixes demo desync on some demos, although
+    others will still desync.
+  * Warnings are now generated for invalid dehacked replacements of
+    printf format strings.  Some potential buffer overflows are also
+    checked.
+  * The installation instructions (INSTALL file) have been clarified
+    and made more platform-agnostic.
+  * The mouse is no longer warped to the center of the screen when the
+    demo sequence advances.
+  * Key bindings can now be changed for the demo recording quit key
+    (normally ‘q’) and the multiplayer messaging keys (normally ‘t’,
+    ‘g’, ‘i’, ‘b’ and ‘r’).
+
+## 1.3.0 (2010-02-10)
+
+  * Chocolate Doom now runs on Windows Mobile/Windows CE!
+  * It is possible to rebind most/all of the keys that control the
+    menu, shortcuts, automap and weapon switching.  The main reason
+    for this is to support the Windows CE port and other platforms
+    where a full keyboard may not be present.
+  * Chocolate Doom now includes a proper Mac OS X package; it is no
+    longer necessary to compile binaries for this system by hand.  The
+    package includes a simple graphical launcher program and can be
+    installed simply by dragging the “Chocolate Doom” icon to the
+    Applications folder. (thanks to Rikard Lang for extensive testing
+    and feedback)
+  * The video mode auto-adjust code will automatically choose windowed
+    mode if no fullscreen video modes are available.
+  * The zone memory size is automatically reduced on systems with a
+    small amount of memory.
+  * The “join game” window in the setup tool now has an option to
+    automatically join a game on the local network.
+  * Chocolate Doom includes some initial hacks for compiling under
+    SDL 1.3.
+  * Recent versions of SDL_mixer include rewritten MIDI code on Mac OS
+    X.  If you are using a version of SDL_mixer with the new code,
+    music will now be enabled by default.
+  * Windows Vista and Windows 7 no longer prompt for elevated
+    privileges when running the setup tool (thanks hobbs and MikeRS).
+  * The Windows binaries now have better looking icons (thanks
+    MikeRS).
+  * Magic values specified using the -spechit command line parameter
+    can now be hexadecimal.
+  * DOOMWADDIR/DOOMWADPATH can now specify the complete path to IWAD
+    files, rather than the path to the directory that contains them.
+  * When recording shorttics demos, errors caused by the reduced
+    turning resolution are carried forward, possibly making turning
+    smoother.
+  * The source tarball can now be used to build an RPM package:
+    rpmbuild -tb chocolate-doom-VER.tar.gz
+
+### Compatibility
+  * The A_BossDeath behavior in v1.9 emulation mode was fixed (thanks
+    entryway)
+  * The “loading” disk icon is drawn more like how it is drawn in
+    Vanilla Doom, also fixing a bug with chook3.wad.
+  * Desync on 64-bit systems with ep1-0500.lmp has (at long last) been
+    fixed (thanks exp(x)).
+  * Donut overrun emulation code imported from Prboom+ (thanks
+    entryway).
+  * The correct level name should now be shown in the automap for
+    pl2.wad MAP33 (thanks Janizdreg).
+  * In Chex Quest, the green radiation suit colormap is now used
+    instead of the red colormaps normally used when taking damage or
+    using the berserk pack.  This matches Vanilla chex.exe behavior
+    (thanks Fuzztooth).
+  * Impassible glass now displays and works the same as in Vanilla,
+    fixing wads such as OTTAWAU.WAD (thanks Never_Again).
+
+### Bugs fixed
+  * Memory-mapped WAD I/O is disabled by default, as it caused various
+    issues, including a slowdown/crash with Plutonia 2 MAP23.  It can
+    be explicitly re-enabled using the “-mmap” command line parameter.
+  * Crash when saving games due to the ~/.chocolate-doom/savegames
+    directory not being created (thanks to everyone who reported
+    this).
+  * Chocolate Doom will now run under Win95/98, as the
+    SetProcessAffinityMask function is looked up dynamically.
+  * Compilation under Linux with older versions of libc will now work
+    (the semantics for sched_setaffinity were different in older
+    versions)
+  * Sound clipping when using libsamplerate was improved (thanks David
+    Flater)
+  * The audio buffer size is now calculated based on the sample rate,
+    so there is not a noticeable delay when using a lower sample rate.
+  * The manpage documentation for the DOOMWADPATH variable was fixed
+    (thanks MikeRS).
+  * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND disabled
+    was fixed.
+  * Fixed crash when using the donut special type and the joining
+    linedef is one sided (thanks Alexander Waldmann).
+  * Key settings in a configuration file that are out of range do not
+    cause a crash (thanks entryway).
+  * Fix ear-piercing whistle when playing the MAP05 MIDI music using
+    timidity with EAWPATS (thanks entryway / HackNeyed).
+
+### libtextscreen
+  * There is now a second, small textscreen font, so that the ENDOOM
+    screen and setup tool can be used on low resolution devices
+    (eg. PDAs/embedded devices)
+  * The textscreen library now has a scrollable pane widget. Thanks to
+    LionsPhil for contributing code to scroll up and down using the
+    keyboard.
+  * Doxygen documentation was added for the textscreen library.
+
+## 1.2.1 (2008-12-10)
+
+  This version just fixes a crash at the intermission screen when
+  playing Doom 1 levels.
+
+## 1.2.0 (2008-12-10)
+
+  Happy 15th Birthday, Doom!
+
+  * Chocolate Doom now has an icon that is not based on the
+    proprietary Doom artwork.
+  * There is now memory-mapped WAD I/O support, which should be useful
+    on some embedded systems.
+  * Chex quest emulation support is now included, although an
+    auxiliary dehacked patch is needed (chexdeh.zip in the idgames
+    archive).
+
+### Compatibility
+  * The armor class is always set to 2 when picking up a megasphere
+    (thanks entryway).
+  * The quit screen prompts to quit “to dos” instead of just to quit
+    (thanks MikeRS)
+  * The “dimensional shambler” quit message was fixed.
+  * Fix crash related to A_BFGSpray with NULL target when using
+    dehacked patches - discovered with insaned2.deh (thanks CSonicGo)
+  * NUL characters are stripped from dehacked files, to ensure correct
+    behavior with some dehacked patches (eg. the one with portal.wad).
+
+### Bugs fixed
+  * “Python Image Library” should have been “Python Imaging Library”
+    (thanks exp(x)).
+  * The setup tool should no longer ask for elevated permissions on
+    Windows Vista (this fix possibly may not work).
+  * The application icon is set properly when running under Windows XP
+    with the “Luna” theme.
+  * Fix compilation under Cygwin to detect libraries and headers from
+    the correct environment.
+  * The video code does not try to read SDL events before SDL has been
+    properly initialised - this was causing problems with some older
+    versions of SDL.
+
+## 1.1.1 (2008-04-20)
+
+  The previous release (v1.1.0) included a bug that broke compilation
+  when libsamplerate support was enabled.  The only change in this
+  version is to fix this bug.
+
+## 1.1.0 (2008-04-19)
+
+  * The video mode code has been radically restructured.  The video
+    mode is now chosen by directly specifying the mode to use; the
+    scale factor is then chosen to fit the screen.  This is helpful
+    when using widescreen monitors (thanks Linguica)
+  * MSVC build project files (thanks GhostlyDeath and entryway).
+  * Unix manpage improvements; the manpage now lists the environment
+    variables that Chocolate Doom uses.  Manpages have been added for
+    chocolate-setup and chocolate-server, from the versions for the
+    Debian Chocolate Doom package (thanks Jon Dowland).
+  * INSTALL file with installation instructions for installing
+    Chocolate Doom on Unix systems.
+  * Support for high quality resampling of sound effects using
+    libsamplerate (thanks David Flater).
+  * A low pass filter is applied when doing sound resampling in an
+    attempt to filter out high frequency noise from the resampling
+    process.
+  * R_Main progress box is not displayed if stdout is a file (produces
+    cleaner output).
+  * Client/server version checking can be disabled to allow different
+    versions of Chocolate Doom to play together, or Chocolate Doom
+    clients to play with Strawberry Doom clients.
+  * Unix manpages are now generated for the Chocolate Doom
+    configuration files.
+  * The BSD PC speaker driver now works on FreeBSD.
+
+### Compatibility
+  * Use the same spechits compatibility value as PrBoom+, for
+    consistency (thanks Lemonzest).
+  * The intercepts overrun code has been refactored to work on big
+    endian machines.
+  * The default startup delay has been set to one second, to allow
+    time for the screen to settle before starting the game (some
+    monitors have a delay before they come back on after changing
+    modes).
+  * If a savegame buffer overrun occurs, the savegame does not get
+    saved and existing savegames are not overwritten (same behaviour
+    as Vanilla).
+
+### Bugs fixed
+  * Desync with STRAIN demos and dehacked Misc values not being set
+    properly (thanks Lemonzest)
+  * Don’t grab the mouse if the mouse is disabled via -nomouse or
+    use_mouse in the configuration file (thanks MikeRS).
+  * Don’t center the mouse on startup if the mouse is disabled (thanks
+    Siggi).
+  * Reset the palette when the window is restored to clear any screen
+    corruption (thanks Catoptromancy).
+  * mus2mid.c should use `MEM_SEEK_SET`, not `SEEK_SET` (thanks
+    Russell)
+  * Fast/Respawn options were not being exchanged when starting
+    netgames (thanks GhostlyDeath).
+  * Letterbox mode is more accurately described as “pillarboxed” or
+    “windowboxed” where appropriate (thanks MikeRS)
+  * Process affinity mask is set to 1 on Windows, to work around a bug
+    in SDL_mixer that can cause crashes on multi-core machines (thanks
+    entryway).
+  * Bugs in the joystick configuration dialog in the setup tool have
+    been fixed.
+
+## 1.0.0 (2007-12-10)
+
+  This release is dedicated to Dylan “Toke” McIntosh, who was
+  tragically killed in a car crash in 2006.  I knew Dylan from IRC and
+  the Doomworld forums for several years, and he had a deep passion
+  for this game.  He was also a huge help for me while developing
+  Chocolate Doom, as he helped point out a lot of small quirks in
+  Vanilla Doom that I didn’t know about. His death is a great loss.
+  RIP Toke.
+
+  This is the first release to reach full feature parity with Vanilla
+  Doom.  As a result, I have made this version 1.0.0, so Chocolate
+  Doom is no longer beta!
+
+### Big new features
+  * Multiplayer!  This version includes an entirely new multiplayer
+    engine, based on a packet server architecture.  I’d like to thank
+    joe, pritch, Meph and myk, and everyone else who has helped test
+    the new code for their support, feedback and help in testing this.
+    The new code still needs more testing, and I’m eager to hear any
+    feedback on this.
+  * A working setup tool.  This has the same look and feel as the
+    original setup.exe.  I hope people like it!  Note that it has some
+    advantages over the original setup.exe - for example, you can use
+    the mouse.
+
+### Other new features
+  * New mus conversion code thanks to Ben Ryves.  This converts the
+    Doom .mus format to .mid a lot better.  As one example, tnt.wad
+    Map02 is now a lot closer to how Vanilla says.  Also, the music on
+    the deca.wad titlescreen now plays!
+  * x3, x4 and x5 display scale (thanks to MikeRS for x5 scale).
+  * Fullscreen “letterbox” mode allows Chocolate Doom to run on
+    machines where 1.6:1 aspect ratio modes are unavailable
+    (320x200/640x400).  The game runs in 320x240/640x480 instead, with
+    black borders.  The system automatically adjusts to this if closer
+    modes are unavailable.
+  * Aspect ratio correction: you can (also) run at 640x480 without
+    black borders at the top and bottom of the screen.
+  * PC speaker sound effect support.  Chocolate Doom can output real
+    PC speaker sounds on Linux, or emulate a PC speaker through the
+    sound card.
+  * Working three-screen mode, as seen in early versions of Doom!  To
+    test this out, put three computers on a LAN and type:
+
+        chocolate-doom -server
+        chocolate-doom -autojoin -left
+        chocolate-doom -autojoin -right
+
+  * Allow a delay to be specified on startup, to allow the display to
+    settle after changing modes before starting the game.
+  * Allow the full path and filename to be specified when loading
+    demos: It is now possible to type “chocolate-doom -playdemo
+    /tmp/foo.lmp” for example.
+  * Savegames are now stored in separate directories depending on the
+    IWAD: eg. the savegames for Doom II are stored in a different
+    place to those for Doom I, Final Doom, etc. (this does not affect
+    Windows).
+  * New mouse acceleration code works based on a threshold and
+    acceleration.  Hopefully this should be closer to what the DOS
+    drivers do.  There is a ‘test’ feature in the setup tool to help
+    in configuring this.
+  * New “-nwtmerge” command line option that emulates NWT’s “-merge”
+    option.  This allows TiC’s Obituary TC to be played.
+  * The ENDOOM screen no longer closes automatically, you have to
+    click the window to make it go away.
+  * Spechit overrun fixes and improvements.  Thanks to entryway for
+    his continued research on this topic (and because I stole your
+    improvements :-).  Thanks to Quasar for reporting a bug as well.
+  * Multiple dehacked patches can be specified on the command line, in
+    the same way as with WADs - eg. -deh foo.deh bar.deh baz.deh.
+  * Default zone memory size increased to 16MB; this can be controlled
+    using the -mb command-line option.
+  * It is now possible to record demos of unlimited length (by
+    default, the Vanilla limit still applies, but it can now be
+    disabled).
+  * Autoadjusting the screen mode can now be disabled.
+  * On Windows, the registry is queried to detect installed versions
+    of Doom and automatically locate IWAD files.  IWADs installed
+    through Steam are also autodetected.
+  * Added DOOMWADPATH that can be used like PATH to specify multiple
+    locations in which to search for IWAD files.  Also, “-iwad” is now
+    enhanced, so that eg. “-iwad doom.wad” will now search all IWAD
+    search paths for “doom.wad”.
+  * Improved mouse tracking that should no longer lag.  Thanks to
+    entryway for research into this.
+  * The SDL driver can now be specified in the configuration file.
+    The setup tool has an option on Windows to select between DirectX
+    and windib.
+  * Joystick support.
+  * Configuration file option to change the sound sample rate.
+  * More than three mouse buttons are now supported.
+
+### Portability improvements
+  * Chocolate Doom now compiles and runs cleanly on MacOS X.  Huge
+    thanks go to Insomniak who kindly gave me an account on his
+    machine so that I could debug this remotely.  Big thanks also go
+    to athanatos on the Doomworld forums for his patience in testing
+    various ideas as I tried to get Chocolate Doom up and running on
+    MacOS.
+  * Chocolate Doom now compiles and runs natively on AMD64.
+  * Chocolate Doom now compiles and runs on Solaris/SPARC, including
+    the Sun compiler.  Thanks to Mike Spooner for some portability
+    fixes.
+  * Improved audio rate conversion, so that sound should play properly
+    on machines that don’t support low bitrate output.
+
+### Compatibility fixes
+  * Check for IWADs in the same order as Vanilla Doom.
+  * Dehacked code will now not allow string replacements to be longer
+    than those possible through DOS dehacked.
+  * Fix sound effects playing too loud on level 8 (thanks to myk for
+    his continued persistence in getting me to fix this)
+  * Save demos when quitting normally - it is no longer necessary to
+    press ‘q’ to quit and save a demo.
+  * Fix spacing of -devparm mode dots.
+  * Fix sky behavior to be the same as Vanilla Doom - when playing in
+    Doom II, the skies never change from the sky on the first level
+    unless the player loads from a savegame.
+  * Make -nomouse and config file use_mouse work again.
+  * Fix the -nomusic command-line parameter.  Make the snd_sfxdevice
+    snd_musicdevice values in the configuration file work, so that it
+    is possible to disable sound, as with Vanilla.
+  * Repeat key presses when the key is held down (this is the Vanilla
+    behavior) - thanks to Mad_Mac for pointing this out.
+  * Don’t print a list of all arguments read from response files -
+    Vanilla doesn’t do this.
+  * Autorun only when joyb_speed >= 10, not >= 4.  Thanks to Janizdreg
+    for this.
+  * Emulate a bug in DOS dehacked that can overflow the dehacked frame
+    table and corrupt the weaponinfo table.  Note that this means
+    Batman Doom will no longer play properly (identical behavior to
+    Vanilla); vbatman.deh needs to also be applied to fix it.  (Thanks
+    grazza)
+  * Allow dehacked 2.3 patches to be loaded.
+  * Add more dehacked string replacements.
+  * Compatibility option to enable or disable native key mappings.
+    This means that people with non-US keyboards can decide whether to
+    use their correct native mapping or behave like Vanilla mapping
+    (which assumes all keyboards are US).
+  * Emulate overflow bug in P_FindNextHighestFloor.  Thanks to
+    entryway for the fix for this.
+  * Add -netdemo command line parameter, for playing back netgame
+    demos recorded with a single player.
+  * The numeric keypad now behaves like Vanilla Doom does.
+  * Fix some crashes when loading from savegames.
+  * Add intercepts overrun emulation from PrBoom-plus.  Thanks again
+    to entryway for his research on this subject.
+  * Add playeringame overrun emulation.
+
+### Bugs fixed
+  * Fix crash when starting new levels due to the intermission screen
+    being drawn after the WI_ subsystem is shut down (thanks pritch
+    and joe)
+  * Catch failures to initialise sound properly, and fail gracefully.
+  * Fix crasher in 1427uv01.lmp (thanks ultdoomer)
+  * Fix crash in udm1.wad.
+  * Fix crash when loading a savegame with revenant tracer missiles.
+  * Fix crash when loading a savegame when a mancubus was in the
+    middle of firing.
+  * Fix Doom 1 E1-3 intermission screen animations.
+  * Fix loading of dehacked “sound” sections.
+  * Make sure that modified copyright banners always end in a newline
+    - this fixes a bug with av.wad (thanks myk)
+  * Added missing quit message (“are you sure you want to quit this
+    great game?”).
+  * Fix when playing long sound effects - the death sound in
+    marina.wad now plays properly, for example.
+  * Fix buffer overrun on the quicksave prompt screen that caused a
+    mysterious cycling character to appear.
+  * IDCLEV should not work in net games (thanks Janizdreg)
+  * Stop music playing at the ENDOOM screen.
+  * Fix sound sample rate conversion crash.
+  * Fix “pop” heard at the end of sound effects.
+  * Fix crash when playing long sounds.
+  * Fix bug with -timedemo accuracy over multi-level demos.
+  * Fix bug with the automap always following player 1 in multiplayer
+    mode (thanks Janizdreg).
+
+## 0.1.4 (2006-02-13)
+
+  * NWT-style merging command line options (allows Mordeth to be played)
+  * Unix manpage (thanks Jon Dowland)
+  * Dehacked improvements/fixes:
+     * Allow changing the names of graphic lumps used in menu, status bar
+       intermission screen, etc.
+     * Allow changing skies, animated flats + textures
+     * Allow changing more startup strings.
+     * Allow text replacements on music + sfx lump names
+  * Fix for plutonia map12 crash.
+  * Fix bug with playing long sfx at odd sample rates.
+  * Big Endian fixes (for MacOS X).  Thanks to athanatos for helping
+    find some of these.
+  * Install into /usr/games, rather than /usr/bin (thanks Jon Dowland)
+
+## 0.1.3 (2006-01-20)
+
+  * Imported the spechit overrun emulation code from prboom-plus.  Thanks to
+    Andrey Budko for this.
+  * New show_endoom option in the chocolate-doom.cfg config file allows
+    the ENDOOM screen to be disabled.
+  * Chocolate Doom is now savegame-compatible with Vanilla Doom.
+
+  * Fixes for big endian machines (thanks locust)
+  * Fixed the behavior of the dehacked maximum health setting.
+  * Fix the “-skill 0” hack to play without any items (thanks to Janizdreg
+    for pointing out that this was nonfunctional)
+  * Fix playing of sounds at odd sample rates (again).  Sound effects
+    at any sample rate now play, but only sounds with valid headers.
+    This is the *real* way Vanilla Doom behaves.  Thanks to myk for
+    pointing out the incorrect behavior.
+
+## 0.1.2 (2005-10-29)
+
+  * Silence sounds at odd sample rates (rather than bombing out); this
+    is the way Vanilla Doom behaves.
+  * Handle multiple replacements of the same sprite in a PWAD.
+  * Support specifying a specific version to emulate via the command line
+    (-gameversion)
+  * Fix help screen orderings and skull positions.  Behave exactly as
+    the original executables do.
+
+## 0.1.1 (2005-10-18)
+
+  * Display startup “banners” if they have been modified through
+    dehacked.
+  * Dehacked “Misc” section support.
+
+### Bugs fixed
+  * Doom 1 skies always using Episode 1 sky
+  * Crash when switching applications while running fullscreen
+  * Lost soul bounce logic (do not bounce in Registered/Shareware)
+  * Mouse buttons mapped incorrectly (button 1 is right, 2 is middle)
+  * Music not pausing when game is paused, when using SDL_mixer’s
+    native MIDI playback.
+  * Pink icon on startup (palette should be fully set before anything is
+    loaded)
+
+## 0.1.0 (2005-10-09)
+
+  * Dehacked support
+  * WAD merging for TCs
+  * ENDOOM display
+  * Fix bug with invalid MUS files causing crashes
+  * Final Doom fixes
+
+## 0.0.4 (2005-09-27)
+
+  * Application icon and version info included in Windows .exe files
+  * Fixes for non-x86 architectures
+  * Fix uac_dead.wad (platform drop on e1m8 should occur when all
+    bosses die, not just barons)
+  * Fix “loading” icon to work for all graphics modes
+
+## 0.0.3 (2005-09-17)
+
+  * Mouse acceleration code to emulate the behaviour of old DOS mouse
+    drivers (thanks to Toke for information about this and
+    suggestions)
+  * Lock surfaces properly when we have to (fixes crash under
+    Windows 98)
+
+## 0.0.2 (2005-09-13)
+
+  * Remove temporary MIDI files generated by sound code.
+  * Fix sound not playing at the right volume
+  * Allow alt-tab away while running in fullscreen under Windows
+  * Add second configuration file (chocolate-doom.cfg) to allow
+    chocolate-doom specific settings.
+  * Fix switches not changing in Ultimate Doom
+
+## 0.0.1 (2005-09-07)
+
+  First beta release
--- a/NOT-BUGS
+++ /dev/null
@@ -1,169 +1,0 @@
-
-The aim of Chocolate Doom is to behave as closely to Vanilla Doom as
-possible.  As a result, you may experience problems that you would
-also experience when using Vanilla Doom.  These are not "bugs" as
-Chocolate Doom is behaving as intended.
-
-This is not intended to be a comprehensive list of Vanilla Doom bugs.
-For more information, consult the "engine bugs" page of the Doom Wiki.
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game exits after title screen with message about game version ==
-
-The game may exit after the title screen is shown, with a message like
-the following:
-
-    Demo is from a different game version!
-    (read 106, should be 109)
-
-    *** You may need to upgrade your version of Doom to v1.9. ***
-        See: https://www.doomworld.com/classicdoom/info/patches.php
-        This appears to be v1.6/v1.666.
-
-This usually indicates that your IWAD file that you are using to play
-the game (usually named doom.wad or doom2.wad) is out of date.
-Chocolate Doom only supports the v1.9 IWAD file.
-
-To fix the problem, you must upgrade to the v1.9 IWAD file.  The URL
-in the message has downloadable upgrade patches that you can use to
-upgrade.
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game exits in demo loop when playing Final Doom ==
-
-When playing with the Final Doom IWAD files (tnt.wad, plutonia.wad),
-if you leave the game at the title screen to play through the demo
-loop, it will eventually exit with the following error message:
-
-    W_GetNumForName: demo4 not found!
-
-This is the same behavior as the Vanilla executables that were
-bundled with Final Doom.  When Ultimate Doom was developed, a fourth
-demo was added to the demo loop, and this change was retained in the
-Final Doom version of the executable.  However, the Final Doom IWADs
-do not include a fourth demo, so the game crashes.
-
-An alternate version of Final Doom was included in the Id Anthology
-boxed set, and this version of the game fixed this bug. However, this
-version also changes the teleport behavior, so the default is to
-emulate the most commonly distributed version of the game. To use
-the alternate version, run with:
-
-    chocolate-doom -gameversion final2
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game exits when accessing the options menu ==
-
-The game may exit with the message "Bad V_DrawPatch" when accessing
-the options menu, if you have your mouse sensitivity set high.
-
-The Doom options menu has a slider that allows the mouse sensitivity
-to be controlled; however, it has only a very limited range. It is
-common for experienced players to set a mouse sensitivity that is much
-higher than what can be set via the options menu. The setup program
-allows a larger range of values to be set.
-
-However, setting very high sensitivity values causes the game to exit
-when accessing the options menu under Vanilla Doom. Because Chocolate
-Doom aims to emulate Vanilla Doom as closely as possible, it does the
-same thing.
-
-One solution to the problem is to set a lower mouse sensitivity.
-Alternatively, all of the settings in the options menu can be
-controlled through Doom's key bindings anyway:
-
-    End game: F7
-    Messages on/off: F8
-    Graphic detail high/low: F5
-    Screen size smaller/larger: -/+
-    Sound volume menu: F4
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game exits with "Savegame buffer overrun" when saving the game ==
-
-If you are playing on a particularly large level, it is possible that
-when you save the game, the game will quit with the message "Savegame
-buffer overrun".
-
-Vanilla Doom has a limited size memory buffer that it uses for saving
-games.  If you are playing on a large level, the buffer may be too
-small for the entire savegame to fit.  Chocolate Doom allows the limit
-to be disabled: in the setup tool, go to the "compatibility" menu and
-disable the "Vanilla savegame limit" option.
-
-If this error happens to you, your game has not been lost!  A file
-named temp.dsg is saved; rename this to doomsav0.dsg to make it appear
-in the first slot in the "load game" menu.  (On Unix systems, you will
-need to look in the .chocolate-doom/savegames directory in your home
-directory)
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game ends suddenly when recording a demo ==
-
-If you are recording a very long demo, the game may exit suddenly.
-Vanilla Doom has a limited size memory buffer that it uses to save the
-demo into.  When the buffer is full, the game exits.  You can tell if
-this happens, as the demo file will be around 131,072 bytes in size.
-
-You can work around this by using the -maxdemo command line parameter
-to specify a larger buffer size.  Alternatively, the limit can be
-disabled: in the setup tool, go to the compatibility menu and disable
-the "Vanilla demo limit" option.
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Game exits with a message about "visplanes" ==
-
-The game may exit with one of these messages:
-
-    R_FindPlane: no more visplanes
-    R_DrawPlanes: visplane overflow (129)
-
-This is known as the "visplane overflow" limit and is one of the most
-well-known Vanilla Doom engine limits.  You should only ever experience
-this when trying to play an add-on level.  The level you are trying to
-play is too complex; it was most likely designed to work with a limit
-removing source port.
-
-More information can be found here (archived link):
-
-    https://archive.is/s6h7V
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== IDMUS## cheat doesn't work with shareware/registered Doom IWADs ==
-
-The IDMUS cheat allows the in-game music to be changed.  However, in
-the original v1.9 this cheat didn't work properly when playing with
-the Doom 1 (shareware and registered) IWADs.  This bug was fixed in
-the Ultimate Doom and Final Doom executables.
-
-Chocolate Doom emulates this bug.  When playing with the shareware or
-registered Doom IWADs, the IDMUS cheat therefore does not work
-properly.  If you are playing with the Ultimate Doom IWAD, the
-Ultimate Doom executable is emulated by default, so the cheat works
-properly.
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-== Some graphics are wrong when playing with BFG Edition IWADs ==
-
-If you are playing using the IWAD files from Doom 3: BFG Edition, you
-may notice that certain graphics appear strange or wrong. This
-includes the title screen, and parts of the options menu.
-
-The IWAD files in the new BFG Edition have had some significant
-changes from the IWAD files in older releases. Some of the graphics
-lumps have been removed or changed, and the Doom 2 secret levels are
-also censored. Chocolate Doom includes some small workarounds that
-allow the game to run, but for the best experience, it's best to get a
-copy of the classic versions of the IWADs. These are still available
-to buy from Steam or Id's online store.
-
-# vim: tw=70
-
--- /dev/null
+++ b/NOT-BUGS.md
@@ -1,0 +1,149 @@
+The aim of Chocolate Doom is to behave as closely to Vanilla Doom as
+possible.  As a result, you may experience problems that you would
+also experience when using Vanilla Doom.  These are not “bugs” as
+Chocolate Doom is behaving as intended.
+
+This is not intended to be a comprehensive list of Vanilla Doom bugs.
+For more information, consult the “engine bugs” page of the Doom Wiki.
+
+## Game exits after title screen with message about game version
+
+The game may exit after the title screen is shown, with a message like
+the following:
+
+    Demo is from a different game version!
+    (read 2, should be 109)
+
+    *** You may need to upgrade your version of Doom to v1.9. ***
+        See: https://www.doomworld.com/classicdoom/info/patches.php
+        This appears to be v1.0/v1.1/v1.2.
+
+This usually indicates that your IWAD file that you are using to play
+the game (usually named doom.wad or doom2.wad) is out of date.
+Chocolate Doom only supports versions 1.666 through 1.9.
+
+To fix the problem, you must upgrade your IWAD file, preferably
+to 1.9.  The URL in the message has downloadable upgrade patches that
+you can use to upgrade.
+
+## Game exits in demo loop when playing Final Doom
+
+When playing with the Final Doom IWAD files (tnt.wad, plutonia.wad),
+if you leave the game at the title screen to play through the demo
+loop, it will eventually exit with the following error message:
+
+    W_GetNumForName: demo4 not found!
+
+This is the same behavior as the Vanilla executables that were
+bundled with Final Doom.  When Ultimate Doom was developed, a fourth
+demo was added to the demo loop, and this change was retained in the
+Final Doom version of the executable.  However, the Final Doom IWADs
+do not include a fourth demo, so the game crashes.
+
+An alternate version of Final Doom was included in the Id Anthology
+boxed set, and this version of the game fixed this bug. However, this
+version also changes the teleport behavior, so the default is to
+emulate the most commonly distributed version of the game. To use
+the alternate version, run with:
+
+    chocolate-doom -gameversion final2
+
+## Game exits when accessing the options menu
+
+The game may exit with the message “Bad V_DrawPatch” when accessing
+the options menu, if you have your mouse sensitivity set high.
+
+The Doom options menu has a slider that allows the mouse sensitivity
+to be controlled; however, it has only a very limited range. It is
+common for experienced players to set a mouse sensitivity that is much
+higher than what can be set via the options menu. The setup program
+allows a larger range of values to be set.
+
+However, setting very high sensitivity values causes the game to exit
+when accessing the options menu under Vanilla Doom. Because Chocolate
+Doom aims to emulate Vanilla Doom as closely as possible, it does the
+same thing.
+
+One solution to the problem is to set a lower mouse sensitivity.
+Alternatively, all of the settings in the options menu can be
+controlled through Doom’s key bindings anyway:
+
+Option                     | Key
+---------------------------|-----
+End game                   | F7
+Messages on/off            | F8
+Graphic detail high/low    | F5
+Screen size smaller/larger | -/+
+Sound volume menu          | F4
+
+## Game exits with “Savegame buffer overrun” when saving the game
+
+If you are playing on a particularly large level, it is possible that
+when you save the game, the game will quit with the message “Savegame
+buffer overrun”.
+
+Vanilla Doom has a limited size memory buffer that it uses for saving
+games.  If you are playing on a large level, the buffer may be too
+small for the entire savegame to fit.  Chocolate Doom allows the limit
+to be disabled: in the setup tool, go to the “compatibility” menu and
+disable the “Vanilla savegame limit” option.
+
+If this error happens to you, your game has not been lost!  A file
+named temp.dsg is saved; rename this to doomsav0.dsg to make it appear
+in the first slot in the “load game” menu.  (On Unix systems, you will
+need to look in the .chocolate-doom/savegames directory in your home
+directory)
+
+## Game ends suddenly when recording a demo
+
+If you are recording a very long demo, the game may exit suddenly.
+Vanilla Doom has a limited size memory buffer that it uses to save the
+demo into.  When the buffer is full, the game exits.  You can tell if
+this happens, as the demo file will be around 131,072 bytes in size.
+
+You can work around this by using the -maxdemo command line parameter
+to specify a larger buffer size.  Alternatively, the limit can be
+disabled: in the setup tool, go to the compatibility menu and disable
+the “Vanilla demo limit” option.
+
+## Game exits with a message about “visplanes”
+
+The game may exit with one of these messages:
+
+    R_FindPlane: no more visplanes
+    R_DrawPlanes: visplane overflow (129)
+
+This is known as the “visplane overflow” limit and is one of the most
+well-known Vanilla Doom engine limits.  You should only ever experience
+this when trying to play an add-on level.  The level you are trying to
+play is too complex; it was most likely designed to work with a limit
+removing source port.
+
+More information can be found here (archived link): https://archive.is/s6h7V
+
+## IDMUS## cheat doesn’t work with shareware/registered Doom IWADs
+
+The IDMUS cheat allows the in-game music to be changed.  However, in
+the original v1.9 this cheat didn’t work properly when playing with
+the Doom 1 (shareware and registered) IWADs.  This bug was fixed in
+the Ultimate Doom and Final Doom executables.
+
+Chocolate Doom emulates this bug.  When playing with the shareware or
+registered Doom IWADs, the IDMUS cheat therefore does not work
+properly.  If you are playing with the Ultimate Doom IWAD, the
+Ultimate Doom executable is emulated by default, so the cheat works
+properly.
+
+## Some graphics are wrong when playing with BFG Edition IWADs
+
+If you are playing using the IWAD files from Doom 3: BFG Edition, you
+may notice that certain graphics appear strange or wrong. This
+includes the title screen, and parts of the options menu.
+
+The IWAD files in the new BFG Edition have had some significant
+changes from the IWAD files in older releases. Some of the graphics
+lumps have been removed or changed, and the Doom 2 secret levels are
+also censored. Chocolate Doom includes some small workarounds that
+allow the game to run, but for the best experience, it’s best to get a
+copy of the classic versions of the IWADs. These are still available
+to buy from Steam or GOG.com.
--- a/PHILOSOPHY
+++ /dev/null
@@ -1,200 +1,0 @@
-
-Chocolate Doom has been designed around a careful and deliberate
-philosophy that attempts to recreate the original ("Vanilla") DOS
-executables for Doom, Heretic, Hexen and Strife. This document
-describes some of that philosophy and the reasoning behind it.
-
-This document is descriptive, not proscriptive.
-
-== Vanilla behavior ==
-
-Ideally Chocolate Doom aims to recreate the behavior of the Vanilla
-binaries, but different aspects of Vanilla behavior are held to
-varying degrees of importance. It can be imagined as different "tiers"
-of compatibility:
-
- * The game and gameplay itself is of central importance. Here, the
-   Vanilla behavior ought to be maintained as accurately as possible.
-   This includes the look, feel and sound, and things like demo
-   compatibility.
- * The surrounding aspects of the game that aren't part of the central
-   gameplay experience can be extended as long as there's a good
-   reason and Vanilla behavior is respected.
- * The setup tool is not required to reproduce the behavior of the
-   Vanilla setup tool, even though it reproduces its look and feel.
-
-"Vanilla" is defined as:
-
- * DOS Doom 1.9 (although there are actually multiple "1.9"s).
- * DOS Heretic 1.3.
- * DOS Hexen 1.1.
- * DOS Strife 1.31.
-
-"Vanilla" does not include ports (either official or unofficial), such
-as console ports, Doom 95 or Doom 3: BFG Edition.
-
-== Compatibility ==
-
-Chocolate Doom aims to be compatible with Vanilla Doom in several
-different ways. Examples are:
-
- * Bug compatibility: the aim is to emulate compatibility of the
-   original game down to bugs that were present in the DOS
-   executables. This includes maintaining the limitations of the
-   original engine: for example, the infamous "visplane overflow" bug
-   is intentionally still present, where other source ports have
-   removed it; this allows mappers targeting Vanilla Doom to use
-   Chocolate Doom as a faithful substitute.
- * Demo compatibility: Doom was one of the first games to develop a
-   'speedrunning' community, and thousands of recordings of Doom
-   gameplay (.lmp demo files) exist in the Compet-N archive. Chocolate
-   Doom aims for the highest standard of demo compatibility with
-   Vanilla Doom, a goal that is often complicated by obscure behavior
-   that can be difficult to reproduce.
- * Configuration file compatibility: Chocolate Doom uses the same
-   configuration file format as Vanilla Doom, such that a user should
-   be able to reuse their existing Vanilla configuration file without
-   making any changes. Extra non-Vanilla options are stored in a
-   separate configuration file.
- * Savegame file compatibility: Chocolate Doom uses the same savegame
-   file format as Vanilla, such that it should be possible to import
-   and use existing savegame files.
-
-== DOS tools ==
-
-Chocolate Doom includes some features that aren't part of Vanilla Doom
-but exist for compatibility with DOS tools that interact with it.
-These are considered part of the Vanilla experience and ought to be
-treated as such. Some examples are:
-
- * The novert setting, which reproduces the functionality of
-   novert.exe.
- * The -deh parameter, which loads Dehacked patches like dehacked.exe
-   does under DOS. Chocolate Doom imposes the same limitations that
-   Vanilla Dehacked does.
-
-== Exceptions ==
-
-Chocolate Doom differs from Vanilla Doom in a number of ways. In most
-cases these are subtle, minor differences. Nonetheless they deserve
-some explanation and justification. Here are some examples of
-situations where changes are considered acceptable:
-
- 1. Vanilla behavior can be broken that is harmful, eg. can damage the
-    player's computer, or is just outright misleading. For example:
-
-    - Vanilla uses unbounded sprintf and strcpy (security issue).
-    - Vanilla has crashes that force the user to reboot the machine.
-    - Vanilla has an out of memory message that recommends tweaking
-      CONFIG.SYS. As Chocolate Doom doesn't run under DOS, reproducing
-      this message would not be helpful.
-
- 2. Subtly extending behavior is okay where it's not clear what the
-    Vanilla behavior is anyway. For example:
-
-    - Opening the menu releases mouse grab in Chocolate Doom.
-    - Chocolate Hexen's graphical startup screen runs in a window.
-
- 3. Supporting obsolete technology is not a goal: it's considered
-    acceptable that Chocolate Doom does not support every type of
-    hardware from 1993. However, Chocolate Doom should aim to recreate
-    the functionality in a modern way. Examples of technology that
-    isn't supported are:
-
-    - No support for IPX networks, but TCP/IP is supported instead.
-    - No support for dial-up/serial connections; modern operating
-      systems have features that do that for you.
-    - No MS-DOS version.
-
- 4. Changes are acceptable that allow the player to be able play the
-    game. For example:
-
-    - There are new key bindings for actions that can't be rebound with
-      Vanilla Doom, because it's useful for portability to machines
-      that don't have a full keyboard.
-    - There are additional mouse and joystick key bindings that let you
-      perform actions with them that can only be done with the keyboard
-      in Vanilla Doom.
-    - Chocolate Doom includes some hacks to support the Doom 3: BFG
-      Edition IWAD files. The assumption is that being able to at least
-      play is better than nothing, even if it's not Vanilla behavior.
-
- 5. Adding extra options to Vanilla functionality is acceptable as long
-    as the defaults match Vanilla, it doesn't change gameplay and
-    there's a good reason for it. For example:
-
-    - PNG screenshots are supported because PCX is an obsolete format.
-    - Chocolate Doom has the vanilla_keyboard_mapping option that
-      allows the user to use the native keyboard mapping for their
-      computer, rather than always assuming a US layout.
-
- 6. Changing configuration file defaults is acceptable where there's a
-    very good reason. For example:
-
-    - Vanilla Doom defaults to no sound or music if a configuration
-      file is not found. Chocolate Doom defaults to having sound
-      effects and music turned on by default, because modern computers
-      support these; there's no need to configure hardware IRQ settings
-      to get sound working.
-
- 7. Things can be changed if they're really just inconsequential. For
-    example:
-
-    - The startup messages in Chocolate Doom are not identical to
-      Vanilla Doom and are not necessarily in the same order.
-    - Vanilla Doom has command line options named -comdev, -shdev and
-      -regdev used by id internally for development; these have been
-      removed.
-
-A good litmus test of when it's acceptable to break from Vanilla
-behavior is to ask the question: "Although this is Vanilla behavior,
-is there anyone who would want this?".
-
-For example, emulating Vanilla bugs like the visplane overflow bug is
-something that is useful for people making Vanilla format maps. On the
-other hand, painstakingly emulating Vanilla Doom by starting with no
-sound or music by default is not helpful to anyone.
-
-== Minimalism ==
-
-Chocolate Doom aims to be minimalist and straightforward to configure;
-in particular, the setup tool should have a sane interface. Part of
-the inspiration for Chocolate Doom came from Boom's complicated maze
-of options menus (and a desire to avoid them). Too many preferences
-lead to a bad user interface; see Havoc Pennington's essay on Free
-Software UI:
-
-  http://ometer.com/free-software-ui.html
-
-Chocolate Doom has some options that are quite obscure and only really
-of interest to a small number of people. In these cases, the options
-are hidden away in configuration files and deliberately not exposed in
-the setup tool. The assumption is that if you care enough about those
-obscure features, editing a configuration file by hand should not be a
-huge problem for you.
-
-Also inspirational was the README file from Havoc's Metacity window
-manager, where the list of features begins:
-
-  Boring window manager for the adult in you. Many window managers
-  are like Marshmallow Froot Loops; Metacity is like Cheerios.
-
-I'd like to think that Chocolate Doom's philosophy towards features is
-similar. The idea is for a source port that is boring. I find the best
-software - both proprietary and open source - is software that is
-"egoless": it does a job well without pretentions about its importance
-or delusions of grandeur. A couple of other notable examples of
-software that I feel embody this spirit of design in a beautiful way
-are Marco Pesenti Gritti's Epiphany web browser and Evince PDF viewer.
-
-== Other philosophical aspects ==
-
-Chocolate Doom aims for maximal portability. That includes running on
-many different CPUs, different operating systems and different devices
-(ie. not just a desktop machine with a keyboard and mouse).
-
-Chocolate Doom is and will always remain Free Software. It will never
-include code that is not compatible with the GNU GPL.
-
-# vim: tw=70
-
--- /dev/null
+++ b/PHILOSOPHY.md
@@ -1,0 +1,200 @@
+Chocolate Doom has been designed around a careful and deliberate
+philosophy that attempts to recreate the original (“Vanilla”) DOS
+executables for Doom, Heretic, Hexen and Strife. This document
+describes some of that philosophy and the reasoning behind it.
+
+This document is descriptive, not proscriptive.
+
+# Vanilla behavior
+
+Ideally Chocolate Doom aims to recreate the behavior of the Vanilla
+binaries, but different aspects of Vanilla behavior are held to
+varying degrees of importance. It can be imagined as different “tiers”
+of compatibility:
+
+ * The game and gameplay itself is of central importance. Here, the
+   Vanilla behavior ought to be maintained as accurately as possible.
+   This includes the look, feel and sound, and things like demo
+   compatibility.
+ * The surrounding aspects of the game that aren’t part of the central
+   gameplay experience can be extended as long as there’s a good
+   reason and Vanilla behavior is respected.
+ * The setup tool is not required to reproduce the behavior of the
+   Vanilla setup tool, even though it reproduces its look and feel.
+
+“Vanilla” is defined as:
+
+ * DOS Doom 1.9 (although there are actually multiple “1.9”s).
+ * DOS Heretic 1.3.
+ * DOS Hexen 1.1.
+ * DOS Strife 1.31.
+
+“Vanilla” does not include ports (either official or unofficial), such
+as console ports, Doom 95 or Doom 3: BFG Edition.
+
+# Compatibility
+
+Chocolate Doom aims to be compatible with Vanilla Doom in several
+different ways. Examples are:
+
+ * Bug compatibility: the aim is to emulate compatibility of the
+   original game down to bugs that were present in the DOS
+   executables. This includes maintaining the limitations of the
+   original engine: for example, the infamous “visplane overflow” bug
+   is intentionally still present, where other source ports have
+   removed it; this allows mappers targeting Vanilla Doom to use
+   Chocolate Doom as a faithful substitute.
+ * Demo compatibility: Doom was one of the first games to develop a
+   ‘speedrunning’ community, and thousands of recordings of Doom
+   gameplay (.lmp demo files) exist in the Compet-N archive. Chocolate
+   Doom aims for the highest standard of demo compatibility with
+   Vanilla Doom, a goal that is often complicated by obscure behavior
+   that can be difficult to reproduce.
+ * Configuration file compatibility: Chocolate Doom uses the same
+   configuration file format as Vanilla Doom, such that a user should
+   be able to reuse their existing Vanilla configuration file without
+   making any changes. Extra non-Vanilla options are stored in a
+   separate configuration file.
+ * Savegame file compatibility: Chocolate Doom uses the same savegame
+   file format as Vanilla, such that it should be possible to import
+   and use existing savegame files.
+
+# DOS tools
+
+Chocolate Doom includes some features that aren’t part of Vanilla Doom
+but exist for compatibility with DOS tools that interact with it.
+These are considered part of the Vanilla experience and ought to be
+treated as such. Some examples are:
+
+ * The novert setting, which reproduces the functionality of
+   novert.exe.
+ * The -deh parameter, which loads Dehacked patches like dehacked.exe
+   does under DOS. Chocolate Doom imposes the same limitations that
+   Vanilla Dehacked does.
+
+# Exceptions
+
+Chocolate Doom differs from Vanilla Doom in a number of ways. In most
+cases these are subtle, minor differences. Nonetheless they deserve
+some explanation and justification. Here are some examples of
+situations where changes are considered acceptable:
+
+ 1. Vanilla behavior can be broken that is harmful, eg. can damage the
+    player’s computer, or is just outright misleading. For example:
+
+    - Vanilla uses unbounded sprintf and strcpy (security issue).
+    - Vanilla has crashes that force the user to reboot the machine.
+    - Vanilla has an out of memory message that recommends tweaking
+      CONFIG.SYS. As Chocolate Doom doesn’t run under DOS, reproducing
+      this message would not be helpful.
+
+ 2. Subtly extending behavior is okay where it’s not clear what the
+    Vanilla behavior is anyway. For example:
+
+    - Opening the menu releases mouse grab in Chocolate Doom.
+    - Chocolate Hexen’s graphical startup screen runs in a window.
+
+ 3. Supporting obsolete technology is not a goal: it’s considered
+    acceptable that Chocolate Doom does not support every type of
+    hardware from 1993. However, Chocolate Doom should aim to recreate
+    the functionality in a modern way. Examples of technology that
+    isn’t supported are:
+
+    - No support for IPX networks, but TCP/IP is supported instead.
+    - No support for dial-up/serial connections; modern operating
+      systems have features that do that for you.
+    - No MS-DOS version.
+
+ 4. Changes are acceptable that allow the player to be able play the
+    game. For example:
+
+    - There are new key bindings for actions that can’t be rebound with
+      Vanilla Doom, because it’s useful for portability to machines
+      that don’t have a full keyboard.
+    - There are additional mouse and joystick key bindings that let you
+      perform actions with them that can only be done with the keyboard
+      in Vanilla Doom.
+    - Chocolate Doom includes some hacks to support the Doom 3: BFG
+      Edition IWAD files. The assumption is that being able to at least
+      play is better than nothing, even if it’s not Vanilla behavior.
+    - Chocolate Strife does not emulate the save bug from
+      Vanilla 1.31, which could corrupt saves when overwriting a slot,
+      if the old slot was not part of the current game’s progression.
+      Vanilla behavior is unexpected and potentially devastating.
+
+ 5. Adding extra options to Vanilla functionality is acceptable as long
+    as the defaults match Vanilla, it doesn’t change gameplay and
+    there’s a good reason for it. For example:
+
+    - PNG screenshots are supported because PCX is an obsolete format.
+    - Chocolate Doom has the vanilla_keyboard_mapping option that
+      allows the user to use the native keyboard mapping for their
+      computer, rather than always assuming a US layout.
+
+ 6. Changing configuration file defaults is acceptable where there’s a
+    very good reason. For example:
+
+    - Vanilla Doom defaults to no sound or music if a configuration
+      file is not found. Chocolate Doom defaults to having sound
+      effects and music turned on by default, because modern computers
+      support these; there’s no need to configure hardware IRQ settings
+      to get sound working.
+
+ 7. Things can be changed if they’re really just inconsequential. For
+    example:
+
+    - The startup messages in Chocolate Doom are not identical to
+      Vanilla Doom and are not necessarily in the same order.
+    - Vanilla Doom has command line options named -comdev, -shdev and
+      -regdev used by id internally for development; these have been
+      removed.
+
+A good litmus test of when it’s acceptable to break from Vanilla
+behavior is to ask the question: “Although this is Vanilla behavior,
+is there anyone who would want this?”
+
+For example, emulating Vanilla bugs like the visplane overflow bug is
+something that is useful for people making Vanilla format maps. On the
+other hand, painstakingly emulating Vanilla Doom by starting with no
+sound or music by default is not helpful to anyone.
+
+# Minimalism
+
+Chocolate Doom aims to be minimalist and straightforward to configure;
+in particular, the setup tool should have a sane interface. Part of
+the inspiration for Chocolate Doom came from Boom’s complicated maze
+of options menus (and a desire to avoid them). Too many preferences
+lead to a bad user interface; see Havoc Pennington’s essay on Free
+Software UI:
+
+  http://ometer.com/free-software-ui.html
+
+Chocolate Doom has some options that are quite obscure and only really
+of interest to a small number of people. In these cases, the options
+are hidden away in configuration files and deliberately not exposed in
+the setup tool. The assumption is that if you care enough about those
+obscure features, editing a configuration file by hand should not be a
+huge problem for you.
+
+Also inspirational was the README file from Havoc’s Metacity window
+manager, where the list of features begins:
+
+  > Boring window manager for the adult in you. Many window managers
+  > are like Marshmallow Froot Loops; Metacity is like Cheerios.
+
+I’d like to think that Chocolate Doom’s philosophy towards features is
+similar. The idea is for a source port that is boring. I find the best
+software - both proprietary and open source - is software that is
+“egoless”: it does a job well without pretentions about its importance
+or delusions of grandeur. A couple of other notable examples of
+software that I feel embody this spirit of design in a beautiful way
+are Marco Pesenti Gritti’s Epiphany web browser and Evince PDF viewer.
+
+# Other philosophical aspects
+
+Chocolate Doom aims for maximal portability. That includes running on
+many different CPUs, different operating systems and different devices
+(ie. not just a desktop machine with a keyboard and mouse).
+
+Chocolate Doom is and will always remain Free Software. It will never
+include code that is not compatible with the GNU GPL.
--- a/README
+++ /dev/null
@@ -1,102 +1,0 @@
-
-Chocolate Doom aims to accurately reproduce the original DOS version of
-Doom and other games based on the Doom engine in a form that can be
-run on modern computers.
-
-Originally, Chocolate Doom was only a Doom source port. The project
-now includes ports of Heretic and Hexen, and Strife.
-
-Chocolate Doom's aims are:
-
- * To always be 100% Free and Open Source software.
- * Portability to as many different operating systems as possible.
- * Accurate reproduction of the original DOS versions of the games,
-   including bugs.
- * Compatibility with the DOS demo, configuration and savegame files.
- * To provide an accurate retro "feel" (display and input should
-   behave the same).
-
-More information about the philosophy and design behind Chocolate Doom
-can be found in the PHILOSOPHY file distributed with the source code.
-
-== Setting up gameplay ==
-
-For instructions on how to set up Chocolate Doom for play, see the
-INSTALL file.
-
-== Configuration File ==
-
-Chocolate Doom is compatible with the DOS Doom configuration file
-(normally named 'default.cfg'). Existing configuration files for DOS
-Doom should therefore simply work out of the box. However, Chocolate
-Doom also provides some extra settings. These are stored in a
-separate file named 'chocolate-doom.cfg'.
-
-The configuration can be edited using the chocolate-setup tool.
-
-== Command line options ==
-
-Chocolate Doom supports a number of command line parameters, including
-some extras that were not originally suported by the DOS versions. For
-binary distributions, see the CMDLINE file included with your
-download; more information is also available on the Chocolate Doom
-website.
-
-== Playing TCs ==
-
-With Vanilla Doom there is no way to include sprites in PWAD files.
-Chocolate Doom's '-file' command line option behaves exactly the same
-as Vanilla Doom, and trying to play TCs by adding the WAD files using
-'-file' will not work.
-
-Many Total Conversions (TCs) are distributed as a PWAD file which must
-be merged into the main IWAD. Typically a copy of DEUSF.EXE is
-included which performs this merge. Chocolate Doom includes a new
-option, '-merge', which will simulate this merge. Essentially, the
-WAD directory is merged in memory, removing the need to modify the
-IWAD on disk.
-
-To play TCs using Chocolate Doom, run like this:
-
-  chocolate-doom -merge thetc.wad
-
-Here are some examples:
-
-  chocolate-doom -merge batman.wad -deh batman.deh vbatman.deh  (Batman Doom)
-  chocolate-doom -merge aoddoom1.wad -deh aoddoom1.deh  (Army of Darkness Doom)
-
-== Other information ==
-
- * Chocolate Doom includes a number of different options for music
-   playback. See the README.Music file for more details.
-
- * More information, including information about how to play various
-   classic TCs, is available on the Chocolate Doom website:
-
-     https://www.chocolate-doom.org/
-
-   You are encouraged to sign up and contribute any useful information
-   you may have regarding the port!
-
- * Chocolate Doom is not perfect. Although it aims to accurately
-   emulate reproduce the DOS executables, some behavior can be very
-   difficult to reproduce. Because of the nature of the project, you
-   may also encounter Vanilla Doom bugs; these are intentionally
-   present; see the NOT-BUGS file for more information.
-
-   New bug reports can be submitted to the issue tracker on Github:
-
-     https://github.com/chocolate-doom/chocolate-doom/issues
-
- * Source code patches are welcome, but please follow the style
-   guidelines - see the file named HACKING included with the source
-   distribution.
-
- * Chocolate Doom is distributed under the GNU GPL. See the COPYING
-   file for more information.
-
- * Please send any feedback, questions or suggestions to
-   [email protected]. Thanks!
-
-# vim: tw=70
-
--- a/README.Music
+++ /dev/null
@@ -1,171 +1,0 @@
-
-Doom has a memorable and atmospheric soundtrack. Like many games of
-the era, it is MIDI-based. Chocolate Doom includes a number of
-different options for music playback, detailed below.
-
-== Native MIDI playback ==
-
-Most modern operating systems have some kind of built-in support for
-MIDI playback; some have very good quality MIDI playback (Mac OS X for
-example). To use this, choose "Native MIDI" in the sound configuration
-dialog in the setup tool.
-
-== Timidity ==
-
-Timidity is a software-based MIDI synthesizer, and a version of it is
-included in the SDL2_mixer library used by Chocolate Doom. To use
-Timidity for MIDI playback, first download a sound font. An example of
-a good quality sound font is the eawpats font, which can be downloaded
-from the idgames archive as sounds/eawpats.zip:
-
-  https://www.doomworld.com/idgames/sounds/eawpats
-
-Having installed a sound font, select "Native MIDI" in the sound
-configuration dialog in the setup tool, and use the "Timidity
-configuration file" widget below to enter the path to the Timidity
-configuration file (normally named timidity.cfg).
-
-== Gravis Ultrasound (GUS) ==
-
-The Gravis Ultrasound (GUS) was a PC sound card popular in the '90s,
-notable for having wavetable synthesis that provided MIDI playback
-that was superior to most other cards of the era. Chocolate Doom
-includes a "pseudo-GUS emulation" feature that simulates the GUS
-(using Timidity, under the hood).
-
-To use this feature you need a copy of the GUS patch files that were
-distributed with the original GUS patches. If you have Doom 3: BFG
-Edition, these patches are included with its version of classic Doom,
-and are automatically detected. Otherwise, they can be downloaded
-from the idgames archive as music/dgguspat.zip:
-
-  https://www.doomworld.com/idgames/music/dgguspat
-
-Having downloaded the patches, select "GUS (emulated)" in the sound
-configuration dialog in the setup tool, and use the "GUS patch path"
-widget to enter the path to the directory containing the patch files.
-
-By default a GUS card with 1024KB is simulated; to simulate a 256KB,
-512KB or 768KB card instead, change the gus_ram_kb option in
-chocolate-doom.cfg.
-
-== OPL (Soundblaster / Adlib) ==
-
-Most people playing Doom in the '90s had Soundblaster-compatible sound
-cards, which used the Yamaha OPL series of chips for FM-based MIDI
-synthesis. Chocolate Doom includes the ability to emulate these chips
-for a retro experience. OPL emulation is the default MIDI playback,
-but can be selected in the setup tool as "OPL (Adlib/SB)".
-
-Most modern computers do not include an OPL chip any more, as CPUs are
-fast enough to do decent software MIDI synthesis. However, no software
-emulator sounds exactly like a real (hardware) OPL chip, and a few
-cards do have real hardware OPL. If you have such a card, here's how
-to configure Chocolate Doom to use it.
-
-=== Sound cards with OPL chips ===
-
-If you have an ISA sound card, it almost certainly includes an OPL
-chip. Modern computers don't have slots for ISA cards though, so you
-must be running a pretty old machine.
-
-If you have a PCI sound card, you probably don't have an OPL chip.
-However, there are some exceptions to this. The following cards are
-known to include "legacy" OPL support:
-
-  * C-Media CMI8738 (*)
-  * Forte Media FM801
-  * Cards based on the Yamaha YMF724 (*)
-
-Other cards that apparently have OPL support but have not been tested:
-
-  * S3 SonicVibes
-  * AZTech PCI 168 (AZT 3328 chipset)
-  * ESS Solo-1 sound cards (ES1938, ES1946, ES1969 chipset)
-  * Conexant Riptide Audio/Modem combo cards
-  * Cards based on the Crystal Semiconductors CS4281
-  * Cards based on the Avance Logic ALS300
-  * Cards based on the Avance Logic ALS4000
-
-If you desperately want hardware OPL music, you may be able to find
-one of these cards for sale cheap on eBay.
-
-For the cards listed above with (*) next to them, OPL support is
-disabled by default and must be explictly enabled in software.
-
-If your machine is not a PC, you don't have an OPL chip, and you will
-have to use the software OPL.
-
-=== Operating System support ===
-
-If you're certain that you have a sound card with hardware OPL, you
-may need to take extra steps to configure your operating system to
-allow access to it. To do hardware OPL, Chocolate Doom must access
-the chip directly, which is usually not possible in modern operating
-systems unless you are running as the superuser (root/Administrator).
-
-=== Windows 9x ===
-
-If you're running Windows 95, 98 or Me, there is no need to configure
-anything. Windows allows direct access to the OPL chip. You can
-confirm that hardware OPL is working by checking for this message in
-stdout.txt:
-
-  OPL_Init: Using driver 'Win32'.
-
-=== Windows NT (including 2000, XP and later) ===
-
-If you're running an NT-based system, it is not possible to directly
-access the OPL chip, even when running as Administrator. Fortunately,
-it is possible to use the "ioperm.sys" driver developed for Cygwin:
-
-  http://openwince.sourceforge.net/ioperm/
-
-It is not necessary to have Cygwin installed to use this. Copy the
-ioperm.sys file into the same directory as the Chocolate Doom
-executable and it should be automatically loaded.
-
-You can confirm that hardware OPL is working by checking for this
-message in stdout.txt:
-
-  OPL_Init: Using driver 'Win32'.
-
-=== Linux ===
-
-If you are using a system based on the Linux kernel, you can access
-the OPL chip directly, but you must be running as root. You can
-confirm that hardware OPL is working, by checking for this message on
-startup:
-
-  OPL_Init: Using driver 'Linux'.
-
-If you are using one of the PCI cards in the list above with a (*)
-next to it, you may need to manually enable FM legacy support. Add
-the following to your /etc/modprobe.conf file to do this:
-
-  options snd-ymfpci fm_port=0x388
-  options snd-cmipci fm_port=0x388
-
-=== OpenBSD/NetBSD ===
-
-You must be running as root to access the hardware OPL directly. You
-can confirm that hardware OPL is working by checking for this message
-on startup:
-
-  OPL_Init: Using driver 'OpenBSD'.
-
-There is no native OPL backend for FreeBSD yet. Sorry!
-
-== Other options ==
-
-If you have some other favorite MIDI playback option that isn't
-listed above, you can set a hook to invoke an external command for
-MIDI playback using the 'snd_musiccmd' configuration file option. For
-example, set:
-
-  snd_musiccmd    "aplaymidi -p 128:0"
-
-in your chocolate-doom.cfg file.
-
-# vim: set tw=70:
-
--- /dev/null
+++ b/README.Music.md
@@ -1,0 +1,167 @@
+Doom has a memorable and atmospheric soundtrack. Like many games of
+the era, it is MIDI-based. Chocolate Doom includes a number of
+different options for music playback, detailed below.
+
+## Native MIDI playback
+
+Most modern operating systems have some kind of built-in support for
+MIDI playback; some have very good quality MIDI playback (Mac OS X for
+example). To use this, choose “Native MIDI” in the sound configuration
+dialog in the setup tool.
+
+## Timidity
+
+Timidity is a software-based MIDI synthesizer, and a version of it is
+included in the SDL2_mixer library used by Chocolate Doom. To use
+Timidity for MIDI playback, first download a sound font. An example of
+a good quality sound font is the eawpats font, which can be downloaded
+from the idgames archive as sounds/eawpats.zip:
+
+  https://www.doomworld.com/idgames/sounds/eawpats
+
+Having installed a sound font, select “Native MIDI” in the sound
+configuration dialog in the setup tool, and use the “Timidity
+configuration file” widget below to enter the path to the Timidity
+configuration file (normally named timidity.cfg).
+
+## Gravis Ultrasound (GUS)
+
+The Gravis Ultrasound (GUS) was a PC sound card popular in the ’90s,
+notable for having wavetable synthesis that provided MIDI playback
+that was superior to most other cards of the era. Chocolate Doom
+includes a “pseudo-GUS emulation” feature that simulates the GUS
+(using Timidity, under the hood).
+
+To use this feature you need a copy of the GUS patch files that were
+distributed with the original GUS patches. If you have Doom 3: BFG
+Edition, these patches are included with its version of classic Doom,
+and are automatically detected. Otherwise, they can be downloaded
+from the idgames archive as music/dgguspat.zip:
+
+  https://www.doomworld.com/idgames/music/dgguspat
+
+Having downloaded the patches, select “GUS (emulated)” in the sound
+configuration dialog in the setup tool, and use the “GUS patch path”
+widget to enter the path to the directory containing the patch files.
+
+By default a GUS card with 1024KB is simulated; to simulate a 256KB,
+512KB or 768KB card instead, change the gus_ram_kb option in
+chocolate-doom.cfg.
+
+## OPL (Soundblaster / Adlib)
+
+Most people playing Doom in the ’90s had Soundblaster-compatible sound
+cards, which used the Yamaha OPL series of chips for FM-based MIDI
+synthesis. Chocolate Doom includes the ability to emulate these chips
+for a retro experience. OPL emulation is the default MIDI playback,
+but can be selected in the setup tool as “OPL (Adlib/SB)”.
+
+Most modern computers do not include an OPL chip any more, as CPUs are
+fast enough to do decent software MIDI synthesis. However, no software
+emulator sounds exactly like a real (hardware) OPL chip, and a few
+cards do have real hardware OPL. If you have such a card, here’s how
+to configure Chocolate Doom to use it.
+
+# Sound cards with OPL chips
+
+If you have an ISA sound card, it almost certainly includes an OPL
+chip. Modern computers don’t have slots for ISA cards though, so you
+must be running a pretty old machine.
+
+If you have a PCI sound card, you probably don’t have an OPL chip.
+However, there are some exceptions to this. The following cards are
+known to include “legacy” OPL support:
+
+  * C-Media CMI8738 (*)
+  * Forte Media FM801
+  * Cards based on the Yamaha YMF724 (*)
+
+Other cards that apparently have OPL support but have not been tested:
+
+  * S3 SonicVibes
+  * AZTech PCI 168 (AZT 3328 chipset)
+  * ESS Solo-1 sound cards (ES1938, ES1946, ES1969 chipset)
+  * Conexant Riptide Audio/Modem combo cards
+  * Cards based on the Crystal Semiconductors CS4281
+  * Cards based on the Avance Logic ALS300
+  * Cards based on the Avance Logic ALS4000
+
+If you desperately want hardware OPL music, you may be able to find
+one of these cards for sale cheap on eBay.
+
+For the cards listed above with (*) next to them, OPL support is
+disabled by default and must be explictly enabled in software.
+
+If your machine is not a PC, you don’t have an OPL chip, and you will
+have to use the software OPL.
+
+# Operating System support
+
+If you’re certain that you have a sound card with hardware OPL, you
+may need to take extra steps to configure your operating system to
+allow access to it. To do hardware OPL, Chocolate Doom must access
+the chip directly, which is usually not possible in modern operating
+systems unless you are running as the superuser (root/Administrator).
+
+## Windows 9x
+
+If you’re running Windows 95, 98 or Me, there is no need to configure
+anything. Windows allows direct access to the OPL chip. You can
+confirm that hardware OPL is working by checking for this message in
+stdout.txt:
+
+    OPL_Init: Using driver 'Win32'.
+
+## Windows NT (including 2000, XP and later)
+
+If you’re running an NT-based system, it is not possible to directly
+access the OPL chip, even when running as Administrator. Fortunately,
+it is possible to use the “ioperm.sys” driver developed for Cygwin:
+
+  http://openwince.sourceforge.net/ioperm/
+
+It is not necessary to have Cygwin installed to use this. Copy the
+ioperm.sys file into the same directory as the Chocolate Doom
+executable and it should be automatically loaded.
+
+You can confirm that hardware OPL is working by checking for this
+message in stdout.txt:
+
+    OPL_Init: Using driver 'Win32'.
+
+## Linux
+
+If you are using a system based on the Linux kernel, you can access
+the OPL chip directly, but you must be running as root. You can
+confirm that hardware OPL is working, by checking for this message on
+startup:
+
+    OPL_Init: Using driver 'Linux'.
+
+If you are using one of the PCI cards in the list above with a (*)
+next to it, you may need to manually enable FM legacy support. Add
+the following to your /etc/modprobe.conf file to do this:
+
+    options snd-ymfpci fm_port=0x388
+    options snd-cmipci fm_port=0x388
+
+## OpenBSD/NetBSD
+
+You must be running as root to access the hardware OPL directly. You
+can confirm that hardware OPL is working by checking for this message
+on startup:
+
+    OPL_Init: Using driver 'OpenBSD'.
+
+There is no native OPL backend for FreeBSD yet. Sorry!
+
+# Other options
+
+If you have some other favorite MIDI playback option that isn’t
+listed above, you can set a hook to invoke an external command for
+MIDI playback using the ‘snd_musiccmd’ configuration file option. For
+example, set:
+
+    snd_musiccmd    "aplaymidi -p 128:0"
+
+in your chocolate-doom.cfg file.
--- a/README.Strife
+++ /dev/null
@@ -1,121 +1,0 @@
-===============================================================================
-
-          Samuel 'Kaiser' Villarreal and James 'Quasar' Haley Present
-
-           C      H      O      C      O      L      A      T      E
-            ______________________________._________________________
-           /   _____/\__    ___/\______   \   \_   _____/\_   _____/
-           \_____  \   |    |    |       _/   ||    __)   |    __)_
-           /        \  |    |    |    |   \   ||     \    |        \
-          /_______  /  |____|    |____|_  /___|\___  /   /_______  /
-                  \/                    \/         \/            \/
-
-===============================================================================
-
-* What is it? *
-
-Chocolate Strife is the most accurate and complete recreation of Rogue
-Entertainment's "Strife: Quest for the Sigil." It was created through more than
-four years of reverse engineering effort with the blessings of the original
-programmers of the game.
-
-
-* Why? *
-
-The source code for Strife was lost, which means, unlike the code for all the
-other commercial DOOM-engine games, it cannot be released. The only access we
-have to the code is the binary executable file. Tools such as IDA Pro have
-been employed to disassemble and decompile the executable, which was cross-
-referenced against the Linux DOOM and DOS Heretic sources and painstakingly
-combed over multiple times, instruction-by-instruction, to ensure that the
-resulting Chocolate Doom-based executable is as close as possible to the
-original.
-
-
-* Is it Legal? *
-
-Chocolate Strife was originally reverse-engineered from the DOS Strife
-binaries. Although reverse engineering is legally a protected activity, this
-nonetheless left some open questions about its legal status.
-
-In 2014, a new commercial release of Strife was published (Strife: Veteran
-Edition) based on the Chocolate Strife code, and developed by the authors of
-Chocolate Strife under commercial license. The release of Strife: Veteran
-Edition, along with its GPL-licensed source code, constitutes tacit approval
-for the legal status of Chocolate Strife by its current copyright holder.
-
-
-* Is it Perfect? *
-
-Almost, but not entirely! That's where you come in. Help us by reporting any
-discrepancies you may notice between this executable and the vanilla DOS
-program!
-
-However, do *not* report any glitch that you can replicate in the vanilla EXE
-as a bug. The point of Chocolate Strife, like Chocolate Doom before it, is to
-be as bug-compatible with the original game as possible. Also be aware that
-some glitches are impossible to compatibly recreate, and wherever this is the
-case, Chocolate Strife has erred on the side of not crashing the program,
-for example by initializing pointers to NULL rather than using them without
-setting a value first.
-
-
-* What are some known problems? *
-
-- The demo version is *not* supported, and there are not any current plans
-  to support it in the future, due to the vast number of differences (the
-  demo version of Strife is based on a much earlier beta version of Rogue's
-  codebase). You should use a commercial Strife IWAD file, preferably of
-  version 1.2 or later.
-
-
-* How do I use it? *
-
-From the Run box or a command line, issue a command to Chocolate Strife just
-like you would run Chocolate Doom. Most of the same command line parameters
-are supported.
-
-voices.wad will be read from the same directory as the IWAD, if it can be
-found. If it is not found, then voices will be disabled just as would happen
-with the vanilla executable. Do not add voices.wad using -file, as that is
-redundant and unnecessary.
-
-Some new command-line parameters in Chocolate Strife include the following:
-
--nograph
-  Disables the graphical introduction sequence. -devparm implies this.
-
--novoice
-  Disables voices even if voices.wad can be found.
-
--work
-  Enables Rogue's playtesting mode. Automatic godmode, and pressing the
-  inventory drop key will toggle noclipping.
-
--flip
-  Flips player gun graphics. This is buggy, however, because it does not
-  reverse the graphics' x offsets (this is an accurate emulation of the
-  vanilla engine's behavior).
-
--random
-  Randomizes the timing and location of item respawns in deathmatch, when
-  item respawning is enabled.
-
-
-* Copyright *
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; either version 2 of the License, or (at your option) any later
-version.
-
-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.
-
-See the "COPYING" file for the full license text. The source code for this
-program is available from the same location where you downloaded this package.
-
-Aside from Chocolate Doom, portions of the code are derived from the Eternity
-Engine, Copyright 2011 Team Eternity, as published under the GNU GPL.
-
--- /dev/null
+++ b/README.Strife.md
@@ -1,0 +1,124 @@
+````````````````````````````````````````````````````````````````````````
+
+          Samuel ‘Kaiser’ Villarreal and James ‘Quasar’ Haley Present
+
+           C      H      O      C      O      L      A      T      E
+            ______________________________._________________________
+           /   _____/\__    ___/\______   \   \_   _____/\_   _____/
+           \_____  \   |    |    |       _/   ||    __)   |    __)_
+           /        \  |    |    |    |   \   ||     \    |        \
+          /_______  /  |____|    |____|_  /___|\___  /   /_______  /
+                  \/                    \/         \/            \/
+
+````````````````````````````````````````````````````````````````````````
+
+## What is it?
+
+Chocolate Strife is the most accurate and complete recreation of Rogue
+Entertainment’s “Strife: Quest for the Sigil.”  It was created through more
+than four years of reverse engineering effort with the blessings of the
+original programmers of the game.
+
+
+## Why?
+
+The source code for Strife was lost, which means, unlike the code for all the
+other commercial DOOM-engine games, it cannot be released. The only access we
+have to the code is the binary executable file. Tools such as IDA Pro have
+been employed to disassemble and decompile the executable, which was cross-
+referenced against the Linux DOOM and DOS Heretic sources and painstakingly
+combed over multiple times, instruction-by-instruction, to ensure that the
+resulting Chocolate Doom-based executable is as close as possible to the
+original.
+
+
+## Is it Legal?
+
+Chocolate Strife was originally reverse-engineered from the DOS Strife
+binaries. Although reverse engineering is legally a protected activity, this
+nonetheless left some open questions about its legal status.
+
+In 2014, a new commercial release of Strife was published (Strife: Veteran
+Edition) based on the Chocolate Strife code, and developed by the authors of
+Chocolate Strife under commercial license. The release of Strife: Veteran
+Edition, along with its GPL-licensed source code, constitutes tacit approval
+for the legal status of Chocolate Strife by its current copyright holder.
+
+
+## Is it Perfect?
+
+Almost, but not entirely! That’s where you come in. Help us by reporting any
+discrepancies you may notice between this executable and the vanilla DOS
+program!
+
+However, do *not* report any glitch that you can replicate in the vanilla EXE
+as a bug. The point of Chocolate Strife, like Chocolate Doom before it, is to
+be as bug-compatible with the original game as possible. Also be aware that
+some glitches are impossible to compatibly recreate, and wherever this is the
+case, Chocolate Strife has erred on the side of not crashing the program,
+for example by initializing pointers to NULL rather than using them without
+setting a value first.
+
+
+## What are some known problems?
+
+The demo version is *not* supported, and there are not any current plans to
+support it in the future, due to the vast number of differences (the demo
+version of Strife is based on an earlier version of Rogue’s
+codebase).
+
+The commercial Strife IWAD version 1.1 may run, but also exhibit issues.  Like
+the demo version, there are no current plans to fully support it.  Make sure
+your copy is updated to at least 1.2.  Strife: Veteran Edition already
+includes the required version.
+
+
+## How do I use it?
+
+From the Run box or a command line, issue a command to Chocolate Strife just
+like you would run Chocolate Doom. Most of the same command line parameters
+are supported.
+
+voices.wad will be read from the same directory as the IWAD, if it can be
+found. If it is not found, then voices will be disabled just as would happen
+with the vanilla executable. Do not add voices.wad using -file, as that is
+redundant and unnecessary.
+
+Some new command-line parameters in Chocolate Strife include the following:
+
+  - -nograph
+    - Disables the graphical introduction sequence. -devparm implies this.
+
+  - -novoice
+    - Disables voices even if voices.wad can be found.
+
+  - -work
+    - Enables Rogue’s playtesting mode. Automatic godmode, and pressing the
+      inventory drop key will toggle noclipping.
+
+  - -flip
+    - Flips player gun graphics. This is buggy, however, because it does not
+      reverse the graphics’ x offsets (this is an accurate emulation of the
+      vanilla engine’s behavior).
+
+  - -random
+    - Randomizes the timing and location of item respawns in deathmatch, when
+      item respawning is enabled.
+
+
+## Copyright
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+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.
+
+See the “COPYING” file for the full license text. The source code for this
+program is available from the same location where you downloaded this package.
+
+Aside from Chocolate Doom, portions of the code are derived from the Eternity
+Engine, Copyright 2011 Team Eternity, as published under the GNU GPL.
--- /dev/null
+++ b/README.md
@@ -1,0 +1,104 @@
+# Chocolate Doom
+
+Chocolate Doom aims to accurately reproduce the original DOS version of
+Doom and other games based on the Doom engine in a form that can be
+run on modern computers.
+
+Originally, Chocolate Doom was only a Doom source port. The project
+now includes ports of Heretic and Hexen, and Strife.
+
+Chocolate Doom’s aims are:
+
+ * To always be 100% Free and Open Source software.
+ * Portability to as many different operating systems as possible.
+ * Accurate reproduction of the original DOS versions of the games,
+   including bugs.
+ * Compatibility with the DOS demo, configuration and savegame files.
+ * To provide an accurate retro “feel” (display and input should
+   behave the same).
+
+More information about the philosophy and design behind Chocolate Doom
+can be found in the PHILOSOPHY file distributed with the source code.
+
+## Setting up gameplay
+
+For instructions on how to set up Chocolate Doom for play, see the
+INSTALL file.
+
+## Configuration File
+
+Chocolate Doom is compatible with the DOS Doom configuration file
+(normally named `default.cfg`). Existing configuration files for DOS
+Doom should therefore simply work out of the box. However, Chocolate
+Doom also provides some extra settings. These are stored in a
+separate file named `chocolate-doom.cfg`.
+
+The configuration can be edited using the chocolate-setup tool.
+
+## Command line options
+
+Chocolate Doom supports a number of command line parameters, including
+some extras that were not originally suported by the DOS versions. For
+binary distributions, see the CMDLINE file included with your
+download; more information is also available on the Chocolate Doom
+website.
+
+## Playing TCs
+
+With Vanilla Doom there is no way to include sprites in PWAD files.
+Chocolate Doom’s ‘-file’ command line option behaves exactly the same
+as Vanilla Doom, and trying to play TCs by adding the WAD files using
+‘-file’ will not work.
+
+Many Total Conversions (TCs) are distributed as a PWAD file which must
+be merged into the main IWAD. Typically a copy of DEUSF.EXE is
+included which performs this merge. Chocolate Doom includes a new
+option, ‘-merge’, which will simulate this merge. Essentially, the
+WAD directory is merged in memory, removing the need to modify the
+IWAD on disk.
+
+To play TCs using Chocolate Doom, run like this:
+
+```
+chocolate-doom -merge thetc.wad
+```
+
+Here are some examples:
+
+```
+chocolate-doom -merge batman.wad -deh batman.deh vbatman.deh  (Batman Doom)
+chocolate-doom -merge aoddoom1.wad -deh aoddoom1.deh  (Army of Darkness Doom)
+```
+
+## Other information
+
+ * Chocolate Doom includes a number of different options for music
+   playback. See the README.Music file for more details.
+
+ * More information, including information about how to play various
+   classic TCs, is available on the Chocolate Doom website:
+
+     https://www.chocolate-doom.org/
+
+   You are encouraged to sign up and contribute any useful information
+   you may have regarding the port!
+
+ * Chocolate Doom is not perfect. Although it aims to accurately
+   emulate reproduce the DOS executables, some behavior can be very
+   difficult to reproduce. Because of the nature of the project, you
+   may also encounter Vanilla Doom bugs; these are intentionally
+   present; see the NOT-BUGS file for more information.
+
+   New bug reports can be submitted to the issue tracker on Github:
+
+     https://github.com/chocolate-doom/chocolate-doom/issues
+
+ * Source code patches are welcome, but please follow the style
+   guidelines - see the file named HACKING included with the source
+   distribution.
+
+ * Chocolate Doom is distributed under the GNU GPL. See the COPYING
+   file for more information.
+
+ * Please send any feedback, questions or suggestions to
+   [email protected]. Thanks!
--- a/TODO
+++ /dev/null
@@ -1,56 +1,0 @@
-To do:
-
-* Multiplayer:
-  - Use UPnP to automatically configure port forwarding for NATted
-    networks.
-  - Multiplayer options and configuration file (server name, etc)
-* Improve multiplayer startup:
-  - Select an IWAD automatically from the server's game type rather than
-    all players having to specify -iwad.
-  - Send list of WADs to load instead of all clients having to specify -file.
-  - Same applies to dehacked patches and wad merging parameters.
-* Portability improvements:
-  - Test on and fix for architectures where ((-2) >> 1) != -1
-  - Use size-specific types (eg. int32_t instead of int)
-  - Don't make structure packing assumptions when loading levels.
-  - Port to every OS and architecture under the sun
-
-Heretic/Hexen:
- * Frequency shifted sounds.
- * Check for endianness assumptions - mostly done now
- * Structure packing macros for structures read from disk
- * Merge r_draw.c to common version and delete duplicate
- * Heretic v1.2 emulation (if possible)
- * Hexen v1.0 emulation (if possible/necessary)
- * Screensaver mode
-
-Crazy pie in the sky ideas:
-
-* Automatic WAD installer - download and run TCs from a list automatically
-  (automating the current "instructions on wiki" system).
-* Textscreen interface to the Compet-N database: menu driven system to
-  automatically download and play speedruns.
-* DWANGO-like interface for finding players and setting up games.
-* Video capture mode?
-
-== OPL TODO list ==
-
-Needs research:
-
- * Strategy when no more voices are available is still wrong
- * Scale levels don't exactly match Vanilla (off-by-one?)
-
-Bad MIDIs:
-
- * doom2.wad MAP01
- * gothicdm MAP05
- * tnt.wad MAP30
- * Alien Vendetta (title screen, MAP01, etc)
-
-Other tasks:
-
- * Get a better software OPL emulator
- * DMXOPTIONS opl3/phase option support.
-
-# vim: tw=70
-
--- /dev/null
+++ b/TODO.md
@@ -1,0 +1,36 @@
+This is Chocolate Doom’s “to do” list. Note that this is kind of an arbitrary
+and unstructured wish list of features and improvements. The bug tracker
+(http://chocolate-doom.org/bugs) has more feature requests.
+
+* Multiplayer:
+  - Use UPnP to automatically configure port forwarding for NATed
+    networks.
+  - Multiplayer options and configuration file (server name, etc)
+* Improve multiplayer startup:
+  - Select an IWAD automatically from the server’s game type rather than
+    all players having to specify -iwad.
+  - Send list of WADs to load instead of all clients having to specify -file.
+  - Same applies to dehacked patches and wad merging parameters.
+* Portability improvements:
+  - Test on and fix for architectures where `((-2) >> 1) != -1`
+  - Use size-specific types (eg. `int32_t` instead of int)
+  - Don’t make structure packing assumptions when loading levels.
+  - Port to every OS and architecture under the sun
+  - Port to Emscripten and release a web-based version.
+* Video capture mode
+  - Real-time recording of gameplay
+  - Batch conversion of demos into videos
+* Heretic/Hexen/Strife:
+  - Merge r_draw.c to common version and delete duplicates
+  - Heretic v1.2 emulation (if possible)
+  - Hexen v1.0 emulation (if possible/necessary)
+  - Strife v1.1 emulation (for demo IWAD support)
+  - Screensaver mode
+
+Crazy pie in the sky ideas:
+
+* Automatic WAD installer - download and run TCs from a list automatically
+  (automating the current “instructions on wiki” system).
+* Textscreen interface to the Compet-N database: menu driven system to
+  automatically download and play speedruns.
+* DWANGO-like interface for finding players and setting up games.
--- a/opl/opl3.c
+++ b/opl/opl3.c
@@ -21,38 +21,8 @@
 //      OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
 //          OPL2 ROMs.
 //
-// version: 1.7
+// version: 1.7.2
 //
-//  Changelog:
-//
-//  v1.1:
-//      Vibrato's sign fix.
-//  v1.2:
-//      Operator key fix.
-//      Corrected 4-operator mode.
-//      Corrected rhythm mode.
-//      Some small fixes.
-//  v1.2.1:
-//      Small envelope generator fix.
-//      Removed EX_Get function(not used)
-//  v1.3:
-//      Complete rewrite.
-//  v1.4:
-//      New envelope and waveform generator.
-//      Some small fixes.
-//  v1.4.1:
-//      Envelope generator rate calculation fix.
-//  v1.4.2:
-//      Version for ZDoom.
-//  v1.5:
-//      Optimizations.
-//  v1.6:
-//      Improved emulation output.
-//  v1.6.1:
-//      Simple YMF289(OPL3-L) emulation.
-//  v1.7:
-//      Version for Chocolate Doom.
-//
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -537,16 +507,13 @@
     if (!slot->key)
     {
         slot->eg_gen = envelope_gen_num_attack;
-        if ((slot->eg_rate >> 2) != 0x0f)
+        OPL3_EnvelopeUpdateRate(slot);
+        if ((slot->eg_rate >> 2) == 0x0f)
         {
-            slot->eg_gen = envelope_gen_num_attack;
-        }
-        else
-        {
             slot->eg_gen = envelope_gen_num_decay;
+            OPL3_EnvelopeUpdateRate(slot);
             slot->eg_rout = 0x00;
         }
-        OPL3_EnvelopeUpdateRate(slot);
         slot->pg_phase = 0x00;
     }
     slot->key |= type;
@@ -683,7 +650,7 @@
 
 static void OPL3_SlotGenerateZM(opl3_slot *slot)
 {
-    OPL3_SlotGeneratePhase(slot, 0);
+    OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9));
 }
 
 static void OPL3_SlotCalcFB(opl3_slot *slot)
@@ -789,6 +756,8 @@
         {
             chip->channel[chnum].chtype = ch_2op;
             OPL3_ChannelSetupAlg(&chip->channel[chnum]);
+            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum);
+            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum);
         }
     }
 }
@@ -1084,7 +1053,7 @@
              | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00;
     //hh
     phase = (phasebit << 9)
-          | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1)));
+          | (0x34 << ((phasebit ^ (chip->noise & 0x01)) << 1));
     OPL3_SlotGeneratePhase(channel7->slots[0], phase);
     //tt
     OPL3_SlotGenerateZM(channel8->slots[0]);
--- a/opl/opl3.h
+++ b/opl/opl3.h
@@ -21,7 +21,7 @@
 //      OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
 //          OPL2 ROMs.
 //
-// version: 1.7
+// version: 1.7.2
 //
 
 #ifndef OPL_OPL3_H
--- a/pkg/config.make.in
+++ b/pkg/config.make.in
@@ -19,9 +19,8 @@
 
 # Documentation files to distribute with packages.
 
-DOC_FILES = README        \
-            README.Music  \
-            COPYING       \
-            ChangeLog     \
-            NEWS
+DOC_FILES = README.md        \
+            README.Music.md  \
+            COPYING          \
+            NEWS.md
 
--- a/pkg/osx/GNUmakefile
+++ b/pkg/osx/GNUmakefile
@@ -6,7 +6,7 @@
 
 include ../config.make
 
-DOC_FILES += README.Strife NOT-BUGS
+DOC_FILES += README.Strife.md NOT-BUGS.md
 
 export MACOSX_DEPLOYMENT_TARGET=10.7
 
@@ -71,6 +71,7 @@
 	mkdir -p "$(APP_DOC_DIR)"
 	cp $(TOPLEVEL_DOCS) "$(APP_DOC_DIR)"
 
+	mv "$(APP_DOC_DIR)/README.md" "$(APP_DOC_DIR)/README"
 	ln -s "$(APP_DOC_RELDIR)/COPYING" "$(STAGING_DIR)/Software License"
 	ln -s "$(APP_DOC_RELDIR)/README" "$(STAGING_DIR)/README"
 	ln -s /Applications "$(STAGING_DIR)"
--- a/pkg/win32/GNUmakefile
+++ b/pkg/win32/GNUmakefile
@@ -27,12 +27,12 @@
 # Special hooks to custom modify files for particular games.
 
 hook-doom: staging-doom
-	cp $(TOPLEVEL)/NOT-BUGS $</NOT-BUGS.txt
+	cp $(TOPLEVEL)/NOT-BUGS.md $</NOT-BUGS.txt
 
 # Chocolate Strife has its own custom README file:
 
 hook-strife: staging-strife
-	cp $(TOPLEVEL)/README.Strife $</README.txt
+	cp $(TOPLEVEL)/README.Strife.md $</README.txt
 
 # Build up a staging dir for a particular game.
 
@@ -45,8 +45,8 @@
 	   $@/$(PROGRAM_PREFIX)$*-setup.exe
 	$(STRIP) $@/*.exe
 	
-	for f in $(DOC_FILES); do                    \
-		cp $(TOPLEVEL)/$$f $@/$$f.txt;       \
+	for f in $(DOC_FILES); do                                \
+		cp $(TOPLEVEL)/$$f $@/$$(basename $$f .md).txt;  \
 	done
 	cp $(TOPLEVEL)/man/CMDLINE.$* $@/CMDLINE.txt
 	
--- a/rpm.spec.in
+++ b/rpm.spec.in
@@ -42,7 +42,7 @@
 rm -rf $RPM_BUILD_ROOT
 
 %description
-%(sed -n "/==/ q; p " < README)
+%(sed -n "/##/ q; p " < README.md)
 
 See @PACKAGE_URL@ for more information.
 
@@ -65,7 +65,7 @@
 /usr/share/applications/*
 
 %description -n @PROGRAM_PREFIX@heretic
-%(sed -n "/==/ q; p " < README)
+%(sed -n "/##/ q; p " < README.md)
 
 These are the Heretic binaries.
 
@@ -85,7 +85,7 @@
 Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
 
 %description -n @PROGRAM_PREFIX@hexen
-%(sed -n "/==/ q; p " < README)
+%(sed -n "/##/ q; p " < README.md)
 
 These are the Hexen binaries.
 
@@ -105,7 +105,7 @@
 Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
 
 %description -n @PROGRAM_PREFIX@strife
-%(sed -n "/==/ q; p " < README)
+%(sed -n "/##/ q; p " < README.md)
 
 These are the Strife binaries.
 
--- a/src/doom/am_map.c
+++ b/src/doom/am_map.c
@@ -697,11 +697,12 @@
             rc = false;
         }
 
-	if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2))
-	{
-	    rc = false;
-	    cheating = (cheating+1) % 3;
-	}
+        if ((!deathmatch || gameversion <= exe_doom_1_8)
+         && cht_CheckCheat(&cheat_amap, ev->data2))
+        {
+            rc = false;
+            cheating = (cheating + 1) % 3;
+        }
     }
     else if (ev->type == ev_keyup)
     {
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -583,7 +583,7 @@
 	{
 	    pagetic = 200;
 
-	    if ( gamemode == retail )
+	    if (gameversion >= exe_ultimate)
 	      pagename = DEH_String("CREDIT");
 	    else
 	      pagename = DEH_String("HELP2");
--- a/src/doom/f_finale.c
+++ b/src/doom/f_finale.c
@@ -671,7 +671,7 @@
         switch (gameepisode)
         {
             case 1:
-                if (gamemode == retail)
+                if (gameversion >= exe_ultimate)
                 {
                     lumpname = "CREDIT";
                 }
--- a/src/doom/m_menu.c
+++ b/src/doom/m_menu.c
@@ -750,74 +750,9 @@
 //
 void M_DrawReadThis1(void)
 {
-    char *lumpname = "CREDIT";
-    int skullx = 330, skully = 175;
-
     inhelpscreens = true;
-    
-    // Different versions of Doom 1.9 work differently
 
-    switch (gameversion)
-    {
-        case exe_doom_1_666:
-        case exe_doom_1_7:
-        case exe_doom_1_8:
-        case exe_doom_1_9:
-        case exe_hacx:
-
-            if (gamemode == commercial)
-            {
-                // Doom 2
-
-                lumpname = "HELP";
-
-                skullx = 330;
-                skully = 165;
-            }
-            else
-            {
-                // Doom 1
-                // HELP2 is the first screen shown in Doom 1
-                
-                lumpname = "HELP2";
-
-                skullx = 280;
-                skully = 185;
-            }
-            break;
-
-        case exe_ultimate:
-        case exe_chex:
-
-            // Ultimate Doom always displays "HELP1".
-
-            // Chex Quest version also uses "HELP1", even though it is based
-            // on Final Doom.
-
-            lumpname = "HELP1";
-
-            break;
-
-        case exe_final:
-        case exe_final2:
-
-            // Final Doom always displays "HELP".
-
-            lumpname = "HELP";
-
-            break;
-
-        default:
-            I_Error("Unhandled game version");
-            break;
-    }
-
-    lumpname = DEH_String(lumpname);
-    
-    V_DrawPatchDirect (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
-
-    ReadDef1.x = skullx;
-    ReadDef1.y = skully;
+    V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP2"), PU_CACHE));
 }
 
 
@@ -835,7 +770,14 @@
     V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
 }
 
+void M_DrawReadThisCommercial(void)
+{
+    inhelpscreens = true;
 
+    V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP"), PU_CACHE));
+}
+
+
 //
 // Change Sfx & Music volumes
 //
@@ -971,15 +913,6 @@
 	return;
     }
 
-    // Yet another hack...
-    if ( (gamemode == registered)
-	 && (choice > 2))
-    {
-      fprintf( stderr,
-	       "M_Episode: 4th episode requires UltimateDOOM\n");
-      choice = 0;
-    }
-	 
     epi = choice;
     M_SetupNextMenu(&NewDef);
 }
@@ -1082,20 +1015,8 @@
 
 void M_ReadThis2(int choice)
 {
-    // Doom 1.9 had two menus when playing Doom 1
-    // All others had only one
-
-    if (gameversion <= exe_doom_1_9 && gamemode != commercial)
-    {
-        choice = 0;
-        M_SetupNextMenu(&ReadDef2);
-    }
-    else
-    {
-        // Close the menu
-
-        M_FinishReadThis(0);
-    }
+    choice = 0;
+    M_SetupNextMenu(&ReadDef2);
 }
 
 void M_FinishReadThis(int choice)
@@ -1692,7 +1613,7 @@
         {
 	    M_StartControlPanel ();
 
-	    if ( gamemode == retail )
+	    if (gameversion >= exe_ultimate)
 	      currentMenu = &ReadDef2;
 	    else
 	      currentMenu = &ReadDef1;
@@ -2107,27 +2028,31 @@
     // Here we could catch other version dependencies,
     //  like HELP1/2, and four episodes.
 
-  
-    switch ( gamemode )
+    // The same hacks were used in the original Doom EXEs.
+
+    if (gameversion >= exe_ultimate)
     {
-      case commercial:
-        // Commercial has no "read this" entry.
-	MainMenu[readthis] = MainMenu[quitdoom];
-	MainDef.numitems--;
-	MainDef.y += 8;
-	NewDef.prevMenu = &MainDef;
-	break;
-      case shareware:
-	// Episode 2 and 3 are handled,
-	//  branching to an ad screen.
-      case registered:
-	break;
-      case retail:
-	// We are fine.
-      default:
-	break;
+        MainMenu[readthis].routine = M_ReadThis2;
+        ReadDef2.prevMenu = NULL;
     }
 
+    if (gameversion >= exe_final && gameversion <= exe_final2)
+    {
+        ReadDef2.routine = M_DrawReadThisCommercial;
+    }
+
+    if (gamemode == commercial)
+    {
+        MainMenu[readthis] = MainMenu[quitdoom];
+        MainDef.numitems--;
+        MainDef.y += 8;
+        NewDef.prevMenu = &MainDef;
+        ReadDef1.routine = M_DrawReadThisCommercial;
+        ReadDef1.x = 330;
+        ReadDef1.y = 165;
+        ReadMenu1[rdthsempty1].routine = M_FinishReadThis;
+    }
+
     // Versions of doom.exe before the Ultimate Doom release only had
     // three episodes; if we're emulating one of those then don't try
     // to show episode four. If we are, then do show episode four
@@ -2134,7 +2059,12 @@
     // (should crash if missing).
     if (gameversion < exe_ultimate)
     {
-	EpiDef.numitems--;
+        EpiDef.numitems--;
+    }
+    // chex.exe shows only one episode.
+    else if (gameversion == exe_chex)
+    {
+        EpiDef.numitems = 1;
     }
 
     opldev = M_CheckParm("-opldev") > 0;
--- a/src/doom/statdump.c
+++ b/src/doom/statdump.c
@@ -1,356 +1,356 @@
- /*
-
- Copyright(C) 2005-2014 Simon Howard
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- 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.
-
- --
-
- Functions for presenting the information captured from the statistics
- buffer to a file.
-
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "d_player.h"
-#include "d_mode.h"
-#include "m_argv.h"
-
-#include "statdump.h"
-
-/* Par times for E1M1-E1M9. */
-static const int doom1_par_times[] =
-{
-    30, 75, 120, 90, 165, 180, 180, 30, 165,
-};
-
-/* Par times for MAP01-MAP09. */
-static const int doom2_par_times[] =
-{
-    30, 90, 120, 120, 90, 150, 120, 120, 270,
-};
-
-/* Player colors. */
-static const char *player_colors[] =
-{
-    "Green", "Indigo", "Brown", "Red"
-};
-
-// Array of end-of-level statistics that have been captured.
-
-#define MAX_CAPTURES 32
-static wbstartstruct_t captured_stats[MAX_CAPTURES];
-static int num_captured_stats = 0;
-
-static GameMission_t discovered_gamemission = none;
-
-/* Try to work out whether this is a Doom 1 or Doom 2 game, by looking
- * at the episode and map, and the par times.  This is used to decide
- * how to format the level name.  Unfortunately, in some cases it is
- * impossible to determine whether this is Doom 1 or Doom 2. */
-
-static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats)
-{
-    int partime;
-    int level;
-    int i;
-
-    if (discovered_gamemission != none)
-    {
-        return;
-    }
-
-    for (i=0; i<num_stats; ++i)
-    {
-        level = stats[i].last;
-
-        /* If episode 2, 3 or 4, this is Doom 1. */
-
-        if (stats[i].epsd > 0)
-        {
-            discovered_gamemission = doom;
-            return;
-        }
-
-        /* This is episode 1.  If this is level 10 or higher,
-           it must be Doom 2. */
-
-        if (level >= 9)
-        {
-            discovered_gamemission = doom2;
-            return;
-        }
-
-        /* Try to work out if this is Doom 1 or Doom 2 by looking
-           at the par time. */
-
-        partime = stats[i].partime;
-
-        if (partime == doom1_par_times[level] * TICRATE
-         && partime != doom2_par_times[level] * TICRATE)
-        {
-            discovered_gamemission = doom;
-            return;
-        }
-
-        if (partime != doom1_par_times[level] * TICRATE
-         && partime == doom2_par_times[level] * TICRATE)
-        {
-            discovered_gamemission = doom2;
-            return;
-        }
-    }
-}
-
-/* Returns the number of players active in the given stats buffer. */
-
-static int GetNumPlayers(wbstartstruct_t *stats)
-{
-    int i;
-    int num_players = 0;
-
-    for (i=0; i<MAXPLAYERS; ++i)
-    {
-        if (stats->plyr[i].in)
-        {
-            ++num_players;
-        }
-    }
-
-    return num_players;
-}
-
-static void PrintBanner(FILE *stream)
-{
-    fprintf(stream, "===========================================\n");
-}
-
-static void PrintPercentage(FILE *stream, int amount, int total)
-{
-    if (total == 0)
-    {
-        fprintf(stream, "0");
-    }
-    else
-    {
-        fprintf(stream, "%i / %i", amount, total);
-
-        // statdump.exe is a 16-bit program, so very occasionally an
-        // integer overflow can occur when doing this calculation with
-        // a large value. Therefore, cast to short to give the same
-        // output.
-
-        fprintf(stream, " (%i%%)", (short) (amount * 100) / total);
-    }
-}
-
-/* Display statistics for a single player. */
-
-static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats,
-        int player_num)
-{
-    wbplayerstruct_t *player = &stats->plyr[player_num];
-
-    fprintf(stream, "Player %i (%s):\n", player_num + 1,
-            player_colors[player_num]);
-
-    /* Kills percentage */
-
-    fprintf(stream, "\tKills: ");
-    PrintPercentage(stream, player->skills, stats->maxkills);
-    fprintf(stream, "\n");
-
-    /* Items percentage */
-
-    fprintf(stream, "\tItems: ");
-    PrintPercentage(stream, player->sitems, stats->maxitems);
-    fprintf(stream, "\n");
-
-    /* Secrets percentage */
-
-    fprintf(stream, "\tSecrets: ");
-    PrintPercentage(stream, player->ssecret, stats->maxsecret);
-    fprintf(stream, "\n");
-}
-
-/* Frags table for multiplayer games. */
-
-static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats)
-{
-    int x, y;
-
-    fprintf(stream, "Frags:\n");
-
-    /* Print header */
-
-    fprintf(stream, "\t\t");
-
-    for (x=0; x<MAXPLAYERS; ++x)
-    {
-
-        if (!stats->plyr[x].in)
-        {
-            continue;
-        }
-
-        fprintf(stream, "%s\t", player_colors[x]);
-    }
-
-    fprintf(stream, "\n");
-
-    fprintf(stream, "\t\t-------------------------------- VICTIMS\n");
-
-    /* Print table */
-
-    for (y=0; y<MAXPLAYERS; ++y)
-    {
-        if (!stats->plyr[y].in)
-        {
-            continue;
-        }
-
-        fprintf(stream, "\t%s\t|", player_colors[y]);
-
-        for (x=0; x<MAXPLAYERS; ++x)
-        {
-            if (!stats->plyr[x].in)
-            {
-                continue;
-            }
-
-            fprintf(stream, "%i\t", stats->plyr[y].frags[x]);
-        }
-
-        fprintf(stream, "\n");
-    }
-
-    fprintf(stream, "\t\t|\n");
-    fprintf(stream, "\t     KILLERS\n");
-}
-
-/* Displays the level name: MAPxy or ExMy, depending on game mode. */
-
-static void PrintLevelName(FILE *stream, int episode, int level)
-{
-    PrintBanner(stream);
-
-    switch (discovered_gamemission)
-    {
-
-        case doom:
-            fprintf(stream, "E%iM%i\n", episode + 1, level + 1);
-            break;
-        case doom2:
-            fprintf(stream, "MAP%02i\n", level + 1);
-            break;
-        default:
-        case none:
-            fprintf(stream, "E%iM%i / MAP%02i\n", 
-                    episode + 1, level + 1, level + 1);
-            break;
-    }
-
-    PrintBanner(stream);
-}
-
-/* Print details of a statistics buffer to the given file. */
-
-static void PrintStats(FILE *stream, wbstartstruct_t *stats)
-{
-    int leveltime, partime;
-    int i;
-
-    PrintLevelName(stream, stats->epsd, stats->last);
-    fprintf(stream, "\n");
-
-    leveltime = stats->plyr[0].stime / TICRATE;
-    partime = stats->partime / TICRATE;
-    fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60);
-    fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60);
-    fprintf(stream, "\n");
-
-    for (i=0; i<MAXPLAYERS; ++i)
-    {
-        if (stats->plyr[i].in)
-        {
-            PrintPlayerStats(stream, stats, i);
-        }
-    }
-
-    if (GetNumPlayers(stats) >= 2)
-    {
-        PrintFragsTable(stream, stats);
-    }
-
-    fprintf(stream, "\n");
-}
-
-void StatCopy(wbstartstruct_t *stats)
-{
-    if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES)
-    {
-        memcpy(&captured_stats[num_captured_stats], stats,
-               sizeof(wbstartstruct_t));
-        ++num_captured_stats;
-    }
-}
-
-void StatDump(void)
-{
-    FILE *dumpfile;
-    int i;
-
-    //!
-    // @category compat
-    // @arg <filename>
-    //
-    // Dump statistics information to the specified file on the levels
-    // that were played. The output from this option matches the output
-    // from statdump.exe (see ctrlapi.zip in the /idgames archive).
-    //
-
-    i = M_CheckParmWithArgs("-statdump", 1);
-
-    if (i > 0)
-    {
-        printf("Statistics captured for %i level(s)\n", num_captured_stats);
-
-        // We actually know what the real gamemission is, but this has
-        // to match the output from statdump.exe.
-
-        DiscoverGamemode(captured_stats, num_captured_stats);
-
-        // Allow "-" as output file, for stdout.
-
-        if (strcmp(myargv[i + 1], "-") != 0)
-        {
-            dumpfile = fopen(myargv[i + 1], "w");
-        }
-        else
-        {
-            dumpfile = NULL;
-        }
-
-        for (i = 0; i < num_captured_stats; ++i)
-        {
-            PrintStats(dumpfile, &captured_stats[i]);
-        }
-
-        if (dumpfile != NULL)
-        {
-            fclose(dumpfile);
-        }
-    }
-}
-
+ /*
+
+ Copyright(C) 2005-2014 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ 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.
+
+ --
+
+ Functions for presenting the information captured from the statistics
+ buffer to a file.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "d_player.h"
+#include "d_mode.h"
+#include "m_argv.h"
+
+#include "statdump.h"
+
+/* Par times for E1M1-E1M9. */
+static const int doom1_par_times[] =
+{
+    30, 75, 120, 90, 165, 180, 180, 30, 165,
+};
+
+/* Par times for MAP01-MAP09. */
+static const int doom2_par_times[] =
+{
+    30, 90, 120, 120, 90, 150, 120, 120, 270,
+};
+
+/* Player colors. */
+static const char *player_colors[] =
+{
+    "Green", "Indigo", "Brown", "Red"
+};
+
+// Array of end-of-level statistics that have been captured.
+
+#define MAX_CAPTURES 32
+static wbstartstruct_t captured_stats[MAX_CAPTURES];
+static int num_captured_stats = 0;
+
+static GameMission_t discovered_gamemission = none;
+
+/* Try to work out whether this is a Doom 1 or Doom 2 game, by looking
+ * at the episode and map, and the par times.  This is used to decide
+ * how to format the level name.  Unfortunately, in some cases it is
+ * impossible to determine whether this is Doom 1 or Doom 2. */
+
+static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats)
+{
+    int partime;
+    int level;
+    int i;
+
+    if (discovered_gamemission != none)
+    {
+        return;
+    }
+
+    for (i=0; i<num_stats; ++i)
+    {
+        level = stats[i].last;
+
+        /* If episode 2, 3 or 4, this is Doom 1. */
+
+        if (stats[i].epsd > 0)
+        {
+            discovered_gamemission = doom;
+            return;
+        }
+
+        /* This is episode 1.  If this is level 10 or higher,
+           it must be Doom 2. */
+
+        if (level >= 9)
+        {
+            discovered_gamemission = doom2;
+            return;
+        }
+
+        /* Try to work out if this is Doom 1 or Doom 2 by looking
+           at the par time. */
+
+        partime = stats[i].partime;
+
+        if (partime == doom1_par_times[level] * TICRATE
+         && partime != doom2_par_times[level] * TICRATE)
+        {
+            discovered_gamemission = doom;
+            return;
+        }
+
+        if (partime != doom1_par_times[level] * TICRATE
+         && partime == doom2_par_times[level] * TICRATE)
+        {
+            discovered_gamemission = doom2;
+            return;
+        }
+    }
+}
+
+/* Returns the number of players active in the given stats buffer. */
+
+static int GetNumPlayers(wbstartstruct_t *stats)
+{
+    int i;
+    int num_players = 0;
+
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        if (stats->plyr[i].in)
+        {
+            ++num_players;
+        }
+    }
+
+    return num_players;
+}
+
+static void PrintBanner(FILE *stream)
+{
+    fprintf(stream, "===========================================\n");
+}
+
+static void PrintPercentage(FILE *stream, int amount, int total)
+{
+    if (total == 0)
+    {
+        fprintf(stream, "0");
+    }
+    else
+    {
+        fprintf(stream, "%i / %i", amount, total);
+
+        // statdump.exe is a 16-bit program, so very occasionally an
+        // integer overflow can occur when doing this calculation with
+        // a large value. Therefore, cast to short to give the same
+        // output.
+
+        fprintf(stream, " (%i%%)", (short) (amount * 100) / total);
+    }
+}
+
+/* Display statistics for a single player. */
+
+static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats,
+        int player_num)
+{
+    wbplayerstruct_t *player = &stats->plyr[player_num];
+
+    fprintf(stream, "Player %i (%s):\n", player_num + 1,
+            player_colors[player_num]);
+
+    /* Kills percentage */
+
+    fprintf(stream, "\tKills: ");
+    PrintPercentage(stream, player->skills, stats->maxkills);
+    fprintf(stream, "\n");
+
+    /* Items percentage */
+
+    fprintf(stream, "\tItems: ");
+    PrintPercentage(stream, player->sitems, stats->maxitems);
+    fprintf(stream, "\n");
+
+    /* Secrets percentage */
+
+    fprintf(stream, "\tSecrets: ");
+    PrintPercentage(stream, player->ssecret, stats->maxsecret);
+    fprintf(stream, "\n");
+}
+
+/* Frags table for multiplayer games. */
+
+static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats)
+{
+    int x, y;
+
+    fprintf(stream, "Frags:\n");
+
+    /* Print header */
+
+    fprintf(stream, "\t\t");
+
+    for (x=0; x<MAXPLAYERS; ++x)
+    {
+
+        if (!stats->plyr[x].in)
+        {
+            continue;
+        }
+
+        fprintf(stream, "%s\t", player_colors[x]);
+    }
+
+    fprintf(stream, "\n");
+
+    fprintf(stream, "\t\t-------------------------------- VICTIMS\n");
+
+    /* Print table */
+
+    for (y=0; y<MAXPLAYERS; ++y)
+    {
+        if (!stats->plyr[y].in)
+        {
+            continue;
+        }
+
+        fprintf(stream, "\t%s\t|", player_colors[y]);
+
+        for (x=0; x<MAXPLAYERS; ++x)
+        {
+            if (!stats->plyr[x].in)
+            {
+                continue;
+            }
+
+            fprintf(stream, "%i\t", stats->plyr[y].frags[x]);
+        }
+
+        fprintf(stream, "\n");
+    }
+
+    fprintf(stream, "\t\t|\n");
+    fprintf(stream, "\t     KILLERS\n");
+}
+
+/* Displays the level name: MAPxy or ExMy, depending on game mode. */
+
+static void PrintLevelName(FILE *stream, int episode, int level)
+{
+    PrintBanner(stream);
+
+    switch (discovered_gamemission)
+    {
+
+        case doom:
+            fprintf(stream, "E%iM%i\n", episode + 1, level + 1);
+            break;
+        case doom2:
+            fprintf(stream, "MAP%02i\n", level + 1);
+            break;
+        default:
+        case none:
+            fprintf(stream, "E%iM%i / MAP%02i\n", 
+                    episode + 1, level + 1, level + 1);
+            break;
+    }
+
+    PrintBanner(stream);
+}
+
+/* Print details of a statistics buffer to the given file. */
+
+static void PrintStats(FILE *stream, wbstartstruct_t *stats)
+{
+    int leveltime, partime;
+    int i;
+
+    PrintLevelName(stream, stats->epsd, stats->last);
+    fprintf(stream, "\n");
+
+    leveltime = stats->plyr[0].stime / TICRATE;
+    partime = stats->partime / TICRATE;
+    fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60);
+    fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60);
+    fprintf(stream, "\n");
+
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        if (stats->plyr[i].in)
+        {
+            PrintPlayerStats(stream, stats, i);
+        }
+    }
+
+    if (GetNumPlayers(stats) >= 2)
+    {
+        PrintFragsTable(stream, stats);
+    }
+
+    fprintf(stream, "\n");
+}
+
+void StatCopy(wbstartstruct_t *stats)
+{
+    if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES)
+    {
+        memcpy(&captured_stats[num_captured_stats], stats,
+               sizeof(wbstartstruct_t));
+        ++num_captured_stats;
+    }
+}
+
+void StatDump(void)
+{
+    FILE *dumpfile;
+    int i;
+
+    //!
+    // @category compat
+    // @arg <filename>
+    //
+    // Dump statistics information to the specified file on the levels
+    // that were played. The output from this option matches the output
+    // from statdump.exe (see ctrlapi.zip in the /idgames archive).
+    //
+
+    i = M_CheckParmWithArgs("-statdump", 1);
+
+    if (i > 0)
+    {
+        printf("Statistics captured for %i level(s)\n", num_captured_stats);
+
+        // We actually know what the real gamemission is, but this has
+        // to match the output from statdump.exe.
+
+        DiscoverGamemode(captured_stats, num_captured_stats);
+
+        // Allow "-" as output file, for stdout.
+
+        if (strcmp(myargv[i + 1], "-") != 0)
+        {
+            dumpfile = fopen(myargv[i + 1], "w");
+        }
+        else
+        {
+            dumpfile = NULL;
+        }
+
+        for (i = 0; i < num_captured_stats; ++i)
+        {
+            PrintStats(dumpfile, &captured_stats[i]);
+        }
+
+        if (dumpfile != NULL)
+        {
+            fclose(dumpfile);
+        }
+    }
+}
+
--- a/src/doom/statdump.h
+++ b/src/doom/statdump.h
@@ -1,23 +1,23 @@
- /*
-
- Copyright(C) 2005-2014 Simon Howard
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- 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.
-
- */
-
-#ifndef DOOM_STATDUMP_H
-#define DOOM_STATDUMP_H
-
-void StatCopy(wbstartstruct_t *stats);
-void StatDump(void);
-
-#endif /* #ifndef DOOM_STATDUMP_H */
+ /*
+
+ Copyright(C) 2005-2014 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ 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.
+
+ */
+
+#ifndef DOOM_STATDUMP_H
+#define DOOM_STATDUMP_H
+
+void StatCopy(wbstartstruct_t *stats);
+void StatDump(void);
+
+#endif /* #ifndef DOOM_STATDUMP_H */
--- a/src/doom/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@ -1687,7 +1687,7 @@
     {
         M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
     }
-    else if (gamemode == retail && wbs->epsd == 3)
+    else if (gameversion >= exe_ultimate && wbs->epsd == 3)
     {
         M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
     }
@@ -1781,7 +1781,7 @@
 #ifdef RANGECHECKING
     if (gamemode != commercial)
     {
-      if ( gamemode == retail )
+      if (gameversion >= exe_ultimate)
 	RNGCHECK(wbs->epsd, 0, 3);
       else
 	RNGCHECK(wbs->epsd, 0, 2);
--- a/src/strife/m_saves.c
+++ b/src/strife/m_saves.c
@@ -1,528 +1,528 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villarreal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// 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.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Strife Hub Saving Code
-//
-
-// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
-// Visual C++, we need to include the win_opendir module.
-#if defined(_MSC_VER)
-#include <win_opendir.h>
-#elif defined(__GNUC__) || defined(POSIX)
-#include <dirent.h>
-#else
-#error Need an include for dirent.h!
-#endif
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "z_zone.h"
-#include "i_system.h"
-#include "d_player.h"
-#include "deh_str.h"
-#include "doomstat.h"
-#include "m_misc.h"
-#include "m_saves.h"
-#include "p_dialog.h"
-
-//
-// File Paths
-//
-// Strife maintains multiple file paths related to savegames.
-//
-char *savepath;     // The actual path of the selected saveslot
-char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
-char *loadpath;     // Path used while loading the game
-
-char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
-
-//
-// ClearTmp
-//
-// Clear the temporary save directory
-//
-void ClearTmp(void)
-{
-    DIR *sp2dir = NULL;
-    struct dirent *f = NULL;
-
-    if(savepathtemp == NULL)
-        I_Error("you fucked up savedir man!");
-
-    if(!(sp2dir = opendir(savepathtemp)))
-        I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
-
-    while((f = readdir(sp2dir)))
-    {
-        char *filepath = NULL;
-
-        // haleyjd: skip "." and ".." without assuming they're the
-        // first two entries like the original code did.
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, not sprintf
-        filepath = M_SafeFilePath(savepathtemp, f->d_name);
-        remove(filepath);
-
-        Z_Free(filepath);
-    }
-
-    closedir(sp2dir);
-}
-
-//
-// ClearSlot
-//
-// Clear a single save slot folder
-//
-void ClearSlot(void)
-{
-    DIR *spdir = NULL;
-    struct dirent *f = NULL;
-
-    if(savepath == NULL)
-        I_Error("userdir is fucked up man!");
-
-    if(!(spdir = opendir(savepath)))
-        I_Error("ClearSlot: Couldn't open dir %s", savepath);
-
-    while((f = readdir(spdir)))
-    {
-        char *filepath = NULL;
-
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-        
-        // haleyjd: use M_SafeFilePath, not sprintf
-        filepath = M_SafeFilePath(savepath, f->d_name);
-        remove(filepath);
-
-        Z_Free(filepath);
-    }
-
-    closedir(spdir);
-}
-
-//
-// FromCurr
-//
-// Copying files from savepathtemp to savepath
-//
-void FromCurr(void)
-{
-    DIR *sp2dir = NULL;
-    struct dirent *f = NULL;
-
-    if(!(sp2dir = opendir(savepathtemp)))
-        I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
-
-    while((f = readdir(sp2dir)))
-    {
-        byte *filebuffer  = NULL;
-        int   filelen     = 0;
-        char *srcfilename = NULL;
-        char *dstfilename = NULL;
-
-        // haleyjd: skip "." and ".." without assuming they're the
-        // first two entries like the original code did.
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
-        dstfilename = M_SafeFilePath(savepath,     f->d_name);
-
-        filelen = M_ReadFile(srcfilename, &filebuffer);
-        M_WriteFile(dstfilename, filebuffer, filelen);
-
-        Z_Free(filebuffer);
-        Z_Free(srcfilename);
-        Z_Free(dstfilename);
-    }
-
-    closedir(sp2dir);
-}
-
-//
-// ToCurr
-//
-// Copying files from savepath to savepathtemp
-//
-void ToCurr(void)
-{
-    DIR *spdir = NULL;
-    struct dirent *f = NULL;
-
-    ClearTmp();
-
-    // BUG: Rogue copypasta'd this error message, which is why we don't know
-    // the real original name of this function.
-    if(!(spdir = opendir(savepath)))
-        I_Error("ClearSlot: Couldn't open dir %s", savepath);
-
-    while((f = readdir(spdir)))
-    {
-        byte *filebuffer  = NULL;
-        int   filelen     = 0;
-        char *srcfilename = NULL;
-        char *dstfilename = NULL;
-
-        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
-            continue;
-
-        // haleyjd: use M_SafeFilePath, NOT sprintf.
-        srcfilename = M_SafeFilePath(savepath,     f->d_name);
-        dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
-
-        filelen = M_ReadFile(srcfilename, &filebuffer);
-        M_WriteFile(dstfilename, filebuffer, filelen);
-
-        Z_Free(filebuffer);
-        Z_Free(srcfilename);
-        Z_Free(dstfilename);
-    }
-
-    closedir(spdir);
-}
-
-//
-// M_SaveMoveMapToHere
-//
-// Moves a map to the "HERE" save.
-//
-void M_SaveMoveMapToHere(void)
-{
-    char *mapsave  = NULL;
-    char *heresave = NULL;
-    char tmpnum[33];
-
-    // haleyjd: no itoa available...
-    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
-
-    // haleyjd: use M_SafeFilePath, not sprintf
-    mapsave  = M_SafeFilePath(savepath, tmpnum);
-    heresave = M_SafeFilePath(savepath, "here");
-
-    // haleyjd: use M_FileExists, not access
-    if(M_FileExists(mapsave))
-    {
-        remove(heresave);
-        rename(mapsave, heresave);
-    }
-
-    Z_Free(mapsave);
-    Z_Free(heresave);
-}
-
-//
-// M_SaveMoveHereToMap
-//
-// Moves the "HERE" save to a map.
-//
-void M_SaveMoveHereToMap(void)
-{
-    char *mapsave  = NULL;
-    char *heresave = NULL;
-    char tmpnum[33];
-
-    // haleyjd: no itoa available...
-    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
-
-    mapsave  = M_SafeFilePath(savepathtemp, tmpnum);
-    heresave = M_SafeFilePath(savepathtemp, "here");
-
-    if(M_FileExists(heresave))
-    {
-        remove(mapsave);
-        rename(heresave, mapsave);
-    }
-
-    Z_Free(mapsave);
-    Z_Free(heresave);
-}
-
-//
-// M_SaveMisObj
-//
-// Writes the mission objective into the MIS_OBJ file.
-//
-boolean M_SaveMisObj(const char *path)
-{
-    boolean result;
-    char *destpath = NULL;
-
-    // haleyjd 20110210: use M_SafeFilePath, not sprintf
-    destpath = M_SafeFilePath(path, "mis_obj");
-    result   = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
-
-    Z_Free(destpath);
-    return result;
-}
-
-//
-// M_ReadMisObj
-//
-// Reads the mission objective from the MIS_OBJ file.
-//
-void M_ReadMisObj(void)
-{
-    FILE *f = NULL;
-    char *srcpath = NULL;
-
-    // haleyjd: use M_SafeFilePath, not sprintf
-    srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
-
-    if((f = fopen(srcpath, "rb")))
-    {
-        fread(mission_objective, 1, OBJECTIVE_LEN, f);
-        fclose(f);
-    }
-
-    Z_Free(srcpath);
-}
-
-//=============================================================================
-//
-// Original Routines
-//
-// haleyjd - None of the below code is derived from Strife itself, but has been
-// adapted or created in order to provide secure, portable filepath handling
-// for the purposes of savegame support. This is partially needed to allow for
-// differences in Choco due to it being multiplatform. The rest exists because
-// I cannot stand programming in an impoverished ANSI C environment that
-// calls sprintf on fixed-size buffers. :P
-//
-
-//
-// M_Calloc
-//
-// haleyjd 20110210 - original routine
-// Because Choco doesn't have Z_Calloc O_o
-//
-void *M_Calloc(size_t n1, size_t n2)
-{
-    return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
-}
-
-//
-// M_StringAlloc
-//
-// haleyjd: This routine takes any number of strings and a number of extra
-// characters, calculates their combined length, and calls Z_Alloca to create
-// a temporary buffer of that size. This is extremely useful for allocation of
-// file paths, and is used extensively in d_main.c.  The pointer returned is
-// to a temporary Z_Alloca buffer, which lives until the next main loop
-// iteration, so don't cache it. Note that this idiom is not possible with the
-// normal non-standard alloca function, which allocates stack space.
-//
-// [STRIFE] - haleyjd 20110210
-// This routine is taken from the Eternity Engine and adapted to do without
-// Z_Alloca. I need secure string concatenation for filepath handling. The
-// only difference from use in EE is that the pointer returned in *str must
-// be manually freed.
-//
-int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
-{
-    va_list args;
-    size_t len = extra;
-
-    if(numstrs < 1)
-        I_Error("M_StringAlloc: invalid input\n");
-
-    len += strlen(str1);
-
-    --numstrs;
-
-    if(numstrs != 0)
-    {   
-        va_start(args, str1);
-
-        while(numstrs != 0)
-        {
-            const char *argstr = va_arg(args, const char *);
-
-            len += strlen(argstr);
-
-            --numstrs;
-        }
-
-        va_end(args);
-    }
-
-    ++len;
-
-    *str = (char *)(M_Calloc(1, len));
-
-    return len;
-}
-
-//
-// M_NormalizeSlashes
-//
-// Remove trailing slashes, translate backslashes to slashes
-// The string to normalize is passed and returned in str
-//
-// killough 11/98: rewritten
-//
-// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect 
-// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
-// BOOM.
-//
-void M_NormalizeSlashes(char *str)
-{
-    char *p;
-   
-    // Convert all slashes/backslashes to DIR_SEPARATOR
-    for(p = str; *p; p++)
-    {
-        if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
-            *p = DIR_SEPARATOR;
-    }
-
-    // Remove trailing slashes
-    while(p > str && *--p == DIR_SEPARATOR)
-        *p = 0;
-
-    // Collapse multiple slashes
-    for(p = str; (*str++ = *p); )
-        if(*p++ == DIR_SEPARATOR)
-            while(*p == DIR_SEPARATOR)
-                p++;
-}
-
-//
-// M_SafeFilePath
-//
-// haleyjd 20110210 - original routine.
-// This routine performs safe, portable concatenation of a base file path
-// with another path component or file name. The returned string is Z_Malloc'd
-// and should be freed when it has exhausted its usefulness.
-//
-char *M_SafeFilePath(const char *basepath, const char *newcomponent)
-{
-    int   newstrlen = 0;
-    char *newstr = NULL;
-
-    if (!strcmp(basepath, ""))
-    {
-        basepath = ".";
-    }
-
-    // Always throw in a slash. M_NormalizeSlashes will remove it in the case
-    // that either basepath or newcomponent includes a redundant slash at the
-    // end or beginning respectively.
-    newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
-    M_snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
-    M_NormalizeSlashes(newstr);
-
-    return newstr;
-}
-
-//
-// M_CreateSaveDirs
-//
-// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
-// of save folders which were created externally by the installer. fraggle says
-// that's no good for Choco purposes, and I agree, so this routine will create
-// the full set of folders under the configured savegamedir.
-//
-void M_CreateSaveDirs(const char *savedir)
-{
-    int i;
-
-    for(i = 0; i < 7; i++)
-    {
-        char *compositedir;
-
-        // compose the full path by concatenating with savedir
-        compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
-
-        M_MakeDirectory(compositedir);
-
-        Z_Free(compositedir);
-    }
-}
-
-//
-// M_MakeStrifeSaveDir
-//
-// haleyjd 20110211: Convenience routine
-//
-char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
-{
-    static char tmpbuffer[32];
-
-    M_snprintf(tmpbuffer, sizeof(tmpbuffer),
-               "strfsav%d.ssg%s", slotnum, extra);
-
-    return tmpbuffer;
-}
-
-// 
-// M_GetFilePath
-//
-// haleyjd: STRIFE-FIXME: Temporary?
-// Code borrowed from Eternity, and modified to return separator char
-//
-char M_GetFilePath(const char *fn, char *dest, size_t len)
-{
-    boolean found_slash = false;
-    char *p;
-    char sepchar = '\0';
-
-    memset(dest, 0, len);
-
-    p = dest + len - 1;
-
-    M_StringCopy(dest, fn, len);
-
-    while(p >= dest)
-    {
-        if(*p == '/' || *p == '\\')
-        {
-            sepchar = *p;
-            found_slash = true; // mark that the path ended with a slash
-            *p = '\0';
-            break;
-        }
-        *p = '\0';
-        p--;
-    }
-
-    // haleyjd: in the case that no slash was ever found, yet the
-    // path string is empty, we are dealing with a file local to the
-    // working directory. The proper path to return for such a string is
-    // not "", but ".", since the format strings add a slash now. When
-    // the string is empty but a slash WAS found, we really do want to
-    // return the empty string, since the path is relative to the root.
-    if(!found_slash && *dest == '\0')
-        *dest = '.';
-
-    // if a separator is not found, default to forward, because Windows 
-    // supports that too.
-    if(sepchar == '\0') 
-        sepchar = '/';
-
-    return sepchar;
-}
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+
+// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
+// Visual C++, we need to include the win_opendir module.
+#if defined(_MSC_VER)
+#include <win_opendir.h>
+#elif defined(__GNUC__) || defined(POSIX)
+#include <dirent.h>
+#else
+#error Need an include for dirent.h!
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "z_zone.h"
+#include "i_system.h"
+#include "d_player.h"
+#include "deh_str.h"
+#include "doomstat.h"
+#include "m_misc.h"
+#include "m_saves.h"
+#include "p_dialog.h"
+
+//
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath;     // The actual path of the selected saveslot
+char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
+char *loadpath;     // Path used while loading the game
+
+char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
+
+//
+// ClearTmp
+//
+// Clear the temporary save directory
+//
+void ClearTmp(void)
+{
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(savepathtemp == NULL)
+        I_Error("you fucked up savedir man!");
+
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
+
+    while((f = readdir(sp2dir)))
+    {
+        char *filepath = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, not sprintf
+        filepath = M_SafeFilePath(savepathtemp, f->d_name);
+        remove(filepath);
+
+        Z_Free(filepath);
+    }
+
+    closedir(sp2dir);
+}
+
+//
+// ClearSlot
+//
+// Clear a single save slot folder
+//
+void ClearSlot(void)
+{
+    DIR *spdir = NULL;
+    struct dirent *f = NULL;
+
+    if(savepath == NULL)
+        I_Error("userdir is fucked up man!");
+
+    if(!(spdir = opendir(savepath)))
+        I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+    while((f = readdir(spdir)))
+    {
+        char *filepath = NULL;
+
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+        
+        // haleyjd: use M_SafeFilePath, not sprintf
+        filepath = M_SafeFilePath(savepath, f->d_name);
+        remove(filepath);
+
+        Z_Free(filepath);
+    }
+
+    closedir(spdir);
+}
+
+//
+// FromCurr
+//
+// Copying files from savepathtemp to savepath
+//
+void FromCurr(void)
+{
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(!(sp2dir = opendir(savepathtemp)))
+        I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
+
+    while((f = readdir(sp2dir)))
+    {
+        byte *filebuffer  = NULL;
+        int   filelen     = 0;
+        char *srcfilename = NULL;
+        char *dstfilename = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, NOT sprintf.
+        srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
+        dstfilename = M_SafeFilePath(savepath,     f->d_name);
+
+        filelen = M_ReadFile(srcfilename, &filebuffer);
+        M_WriteFile(dstfilename, filebuffer, filelen);
+
+        Z_Free(filebuffer);
+        Z_Free(srcfilename);
+        Z_Free(dstfilename);
+    }
+
+    closedir(sp2dir);
+}
+
+//
+// ToCurr
+//
+// Copying files from savepath to savepathtemp
+//
+void ToCurr(void)
+{
+    DIR *spdir = NULL;
+    struct dirent *f = NULL;
+
+    ClearTmp();
+
+    // BUG: Rogue copypasta'd this error message, which is why we don't know
+    // the real original name of this function.
+    if(!(spdir = opendir(savepath)))
+        I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+    while((f = readdir(spdir)))
+    {
+        byte *filebuffer  = NULL;
+        int   filelen     = 0;
+        char *srcfilename = NULL;
+        char *dstfilename = NULL;
+
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, NOT sprintf.
+        srcfilename = M_SafeFilePath(savepath,     f->d_name);
+        dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
+
+        filelen = M_ReadFile(srcfilename, &filebuffer);
+        M_WriteFile(dstfilename, filebuffer, filelen);
+
+        Z_Free(filebuffer);
+        Z_Free(srcfilename);
+        Z_Free(dstfilename);
+    }
+
+    closedir(spdir);
+}
+
+//
+// M_SaveMoveMapToHere
+//
+// Moves a map to the "HERE" save.
+//
+void M_SaveMoveMapToHere(void)
+{
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    mapsave  = M_SafeFilePath(savepath, tmpnum);
+    heresave = M_SafeFilePath(savepath, "here");
+
+    // haleyjd: use M_FileExists, not access
+    if(M_FileExists(mapsave))
+    {
+        remove(heresave);
+        rename(mapsave, heresave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
+}
+
+//
+// M_SaveMoveHereToMap
+//
+// Moves the "HERE" save to a map.
+//
+void M_SaveMoveHereToMap(void)
+{
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    M_snprintf(tmpnum, sizeof(tmpnum), "%d", gamemap);
+
+    mapsave  = M_SafeFilePath(savepathtemp, tmpnum);
+    heresave = M_SafeFilePath(savepathtemp, "here");
+
+    if(M_FileExists(heresave))
+    {
+        remove(mapsave);
+        rename(heresave, mapsave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
+}
+
+//
+// M_SaveMisObj
+//
+// Writes the mission objective into the MIS_OBJ file.
+//
+boolean M_SaveMisObj(const char *path)
+{
+    boolean result;
+    char *destpath = NULL;
+
+    // haleyjd 20110210: use M_SafeFilePath, not sprintf
+    destpath = M_SafeFilePath(path, "mis_obj");
+    result   = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+
+    Z_Free(destpath);
+    return result;
+}
+
+//
+// M_ReadMisObj
+//
+// Reads the mission objective from the MIS_OBJ file.
+//
+void M_ReadMisObj(void)
+{
+    FILE *f = NULL;
+    char *srcpath = NULL;
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
+
+    if((f = fopen(srcpath, "rb")))
+    {
+        fread(mission_objective, 1, OBJECTIVE_LEN, f);
+        fclose(f);
+    }
+
+    Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+    return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c.  The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+    va_list args;
+    size_t len = extra;
+
+    if(numstrs < 1)
+        I_Error("M_StringAlloc: invalid input\n");
+
+    len += strlen(str1);
+
+    --numstrs;
+
+    if(numstrs != 0)
+    {   
+        va_start(args, str1);
+
+        while(numstrs != 0)
+        {
+            const char *argstr = va_arg(args, const char *);
+
+            len += strlen(argstr);
+
+            --numstrs;
+        }
+
+        va_end(args);
+    }
+
+    ++len;
+
+    *str = (char *)(M_Calloc(1, len));
+
+    return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect 
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+    char *p;
+   
+    // Convert all slashes/backslashes to DIR_SEPARATOR
+    for(p = str; *p; p++)
+    {
+        if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+            *p = DIR_SEPARATOR;
+    }
+
+    // Remove trailing slashes
+    while(p > str && *--p == DIR_SEPARATOR)
+        *p = 0;
+
+    // Collapse multiple slashes
+    for(p = str; (*str++ = *p); )
+        if(*p++ == DIR_SEPARATOR)
+            while(*p == DIR_SEPARATOR)
+                p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+    int   newstrlen = 0;
+    char *newstr = NULL;
+
+    if (!strcmp(basepath, ""))
+    {
+        basepath = ".";
+    }
+
+    // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+    // that either basepath or newcomponent includes a redundant slash at the
+    // end or beginning respectively.
+    newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+    M_snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+    M_NormalizeSlashes(newstr);
+
+    return newstr;
+}
+
+//
+// M_CreateSaveDirs
+//
+// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
+// of save folders which were created externally by the installer. fraggle says
+// that's no good for Choco purposes, and I agree, so this routine will create
+// the full set of folders under the configured savegamedir.
+//
+void M_CreateSaveDirs(const char *savedir)
+{
+    int i;
+
+    for(i = 0; i < 7; i++)
+    {
+        char *compositedir;
+
+        // compose the full path by concatenating with savedir
+        compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
+
+        M_MakeDirectory(compositedir);
+
+        Z_Free(compositedir);
+    }
+}
+
+//
+// M_MakeStrifeSaveDir
+//
+// haleyjd 20110211: Convenience routine
+//
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
+{
+    static char tmpbuffer[32];
+
+    M_snprintf(tmpbuffer, sizeof(tmpbuffer),
+               "strfsav%d.ssg%s", slotnum, extra);
+
+    return tmpbuffer;
+}
+
+// 
+// M_GetFilePath
+//
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
+//
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+    boolean found_slash = false;
+    char *p;
+    char sepchar = '\0';
+
+    memset(dest, 0, len);
+
+    p = dest + len - 1;
+
+    M_StringCopy(dest, fn, len);
+
+    while(p >= dest)
+    {
+        if(*p == '/' || *p == '\\')
+        {
+            sepchar = *p;
+            found_slash = true; // mark that the path ended with a slash
+            *p = '\0';
+            break;
+        }
+        *p = '\0';
+        p--;
+    }
+
+    // haleyjd: in the case that no slash was ever found, yet the
+    // path string is empty, we are dealing with a file local to the
+    // working directory. The proper path to return for such a string is
+    // not "", but ".", since the format strings add a slash now. When
+    // the string is empty but a slash WAS found, we really do want to
+    // return the empty string, since the path is relative to the root.
+    if(!found_slash && *dest == '\0')
+        *dest = '.';
+
+    // if a separator is not found, default to forward, because Windows 
+    // supports that too.
+    if(sepchar == '\0') 
+        sepchar = '/';
+
+    return sepchar;
+}
+
+// EOF
+
+
--- a/src/strife/m_saves.h
+++ b/src/strife/m_saves.h
@@ -1,56 +1,56 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villareal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// 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.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Strife Hub Saving Code
-//
-
-#ifndef M_SAVES_H__
-#define M_SAVES_H__
-
-#define CHARACTER_NAME_LEN 32
-
-extern char *savepath;
-extern char *savepathtemp;
-extern char *loadpath;
-extern char character_name[CHARACTER_NAME_LEN];
-
-// Strife Savegame Functions
-void ClearTmp(void);
-void ClearSlot(void);
-void FromCurr(void);
-void ToCurr(void);
-void M_SaveMoveMapToHere(void);
-void M_SaveMoveHereToMap(void);
-
-boolean M_SaveMisObj(const char *path);
-void    M_ReadMisObj(void);
-
-// Custom Utilities for Filepath Handling
-void *M_Calloc(size_t n1, size_t n2);
-void  M_NormalizeSlashes(char *str);
-int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
-char *M_SafeFilePath(const char *basepath, const char *newcomponent);
-char  M_GetFilePath(const char *fn, char *dest, size_t len);
-char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
-void  M_CreateSaveDirs(const char *savedir);
-
-#endif
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+
+#ifndef M_SAVES_H__
+#define M_SAVES_H__
+
+#define CHARACTER_NAME_LEN 32
+
+extern char *savepath;
+extern char *savepathtemp;
+extern char *loadpath;
+extern char character_name[CHARACTER_NAME_LEN];
+
+// Strife Savegame Functions
+void ClearTmp(void);
+void ClearSlot(void);
+void FromCurr(void);
+void ToCurr(void);
+void M_SaveMoveMapToHere(void);
+void M_SaveMoveHereToMap(void);
+
+boolean M_SaveMisObj(const char *path);
+void    M_ReadMisObj(void);
+
+// Custom Utilities for Filepath Handling
+void *M_Calloc(size_t n1, size_t n2);
+void  M_NormalizeSlashes(char *str);
+int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
+char *M_SafeFilePath(const char *basepath, const char *newcomponent);
+char  M_GetFilePath(const char *fn, char *dest, size_t len);
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
+void  M_CreateSaveDirs(const char *savedir);
+
+#endif
+
+// EOF
+
+
--- a/src/strife/p_dialog.c
+++ b/src/strife/p_dialog.c
@@ -1,1413 +1,1413 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villarreal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// 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.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Dialog Engine for Strife
-//
-
-#include <stdlib.h>
-
-#include "z_zone.h"
-#include "w_wad.h"
-#include "deh_str.h"
-#include "d_main.h"
-#include "d_mode.h"
-#include "d_player.h"
-#include "doomstat.h"
-#include "m_random.h"
-#include "m_menu.h"
-#include "m_misc.h"
-#include "r_main.h"
-#include "v_video.h"
-#include "p_local.h"
-#include "sounds.h"
-#include "p_dialog.h"
-#include "s_sound.h"
-#include "p_local.h"
-#include "p_inter.h"
-
-//
-// Defines and Macros
-//
-
-// haleyjd: size of the original Strife mapdialog_t structure.
-#define ORIG_MAPDIALOG_SIZE 0x5EC
-
-#define DIALOG_INT(field, ptr)    \
-    field = ((int)ptr[0]        | \
-            ((int)ptr[1] <<  8) | \
-            ((int)ptr[2] << 16) | \
-            ((int)ptr[3] << 24)); \
-    ptr += 4;
-
-#define DIALOG_STR(field, ptr, len) \
-    memcpy(field, ptr, len);        \
-    ptr += len;
-
-//
-// Globals
-//
-
-// This can be toggled at runtime to determine if the full dialog messages
-// are subtitled on screen or not. Defaults to off.
-int dialogshowtext = false;
-
-// The global mission objective buffer. This gets written to and read from file,
-// and is set by dialogs and line actions.
-char mission_objective[OBJECTIVE_LEN];
-
-//
-// Static Globals
-//
-
-// True if SCRIPT00 is loaded.
-static boolean script0loaded;
-
-// Number of dialogs defined in the current level's script.
-static int numleveldialogs;
-
-// The actual level dialogs. This didn't exist in Strife, but is new to account
-// for structure alignment/packing concerns, given that Chocolate Doom is
-// multiplatform.
-static mapdialog_t *leveldialogs;
-
-// The actual script00 dialogs. As above.
-static mapdialog_t *script0dialogs;
-
-// Number of dialogs defined in the SCRIPT00 lump.
-static int numscript0dialogs;
-
-// The player engaged in dialog. This is always player 1, though, since Rogue
-// never completed the ability to use dialog outside of single-player mode.
-static player_t *dialogplayer;
-
-// The object to which the player is speaking.
-static mobj_t   *dialogtalker;
-
-// The talker's current angle
-static angle_t dialogtalkerangle;
-
-// The currently active mapdialog object.
-static mapdialog_t *currentdialog;
-
-// Text at the end of the choices
-static char dialoglastmsgbuffer[48];
-
-// Item to display to player when picked up or recieved
-static char pickupstring[46];
-
-// Health based on gameskill given by the front's medic
-static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
-
-//=============================================================================
-//
-// Dialog State Sets
-//
-// These are used to animate certain actors in response to what happens in
-// their dialog sequences.
-//
-
-typedef struct dialogstateset_s
-{
-    mobjtype_t type;  // the type of object
-    statenum_t greet; // greeting state, for start of dialog
-    statenum_t yes;   // "yes" state, for an affirmative response
-    statenum_t no;    // "no" state, when you don't have the right items
-} dialogstateset_t;
-
-static dialogstateset_t dialogstatesets[] =
-{
-    { MT_PLAYER,       S_NULL,    S_NULL,    S_NULL    },
-    { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
-    { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
-};
-
-// Rogue stored this in a static global rather than making it a define...
-static int numdialogstatesets = arrlen(dialogstatesets);
-
-// Current dialog talker state
-static dialogstateset_t *dialogtalkerstates;
-
-//=============================================================================
-//
-// Random Messages
-//
-// Rogue hard-coded these so they wouldn't have to repeat them several times
-// in the SCRIPT00 lump, apparently.
-//
-
-#define MAXRNDMESSAGES 10
-
-typedef struct rndmessage_s
-{
-    const char *type_name;
-    int nummessages;
-    char *messages[MAXRNDMESSAGES];
-} rndmessage_t;
-
-static rndmessage_t rndMessages[] = 
-{
-    // Peasants
-    {
-        "PEASANT",
-        10,
-        {
-            "PLEASE DON'T HURT ME.",
-            
-            "IF YOU'RE LOOKING TO HURT ME, I'M \n"
-            "NOT REALLY WORTH THE EFFORT.",
-            
-            "I DON'T KNOW ANYTHING.",
-            
-            "GO AWAY OR I'LL CALL THE GUARDS!",
-            
-            "I WISH SOMETIMES THAT ALL THESE \n"
-            "REBELS WOULD JUST LEARN THEIR \n"
-            "PLACE AND STOP THIS NONSENSE.",
-
-            "JUST LEAVE ME ALONE, OK?",
-
-            "I'M NOT SURE, BUT SOMETIMES I THINK \n"
-            "THAT I KNOW SOME OF THE ACOLYTES.",
-
-            "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
-
-            "THERE'S NO WAY THAT THIS IS JUST A \n"
-            "SECURITY FORCE.",
-
-            "I'VE HEARD THAT THE ORDER IS REALLY \n"
-            "NERVOUS ABOUT THE FRONT'S \n"
-            "ACTIONS AROUND HERE."
-        }
-    },
-    // Rebel
-    {
-        "REBEL",
-        10,
-        {
-            "THERE'S NO WAY THE ORDER WILL \n"
-            "STAND AGAINST US.",
-
-            "WE'RE ALMOST READY TO STRIKE. \n"
-            "MACIL'S PLANS ARE FALLING IN PLACE.",
-
-            "WE'RE ALL BEHIND YOU, DON'T WORRY.",
-
-            "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
-            "FOR SCRAP!",
-
-            "THE DAY OF OUR GLORY WILL SOON \n"
-            "COME, AND THOSE WHO OPPOSE US WILL \n"
-            "BE CRUSHED!",
-
-            "DON'T GET TOO COMFORTABLE. WE'VE \n"
-            "STILL GOT OUR WORK CUT OUT FOR US.",
-
-            "MACIL SAYS THAT YOU'RE THE NEW \n"
-            "HOPE. BEAR THAT IN MIND.",
-
-            "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
-            "WORLD AS IT SHOULD BE.",
-
-            "REMEMBER THAT YOU AREN'T FIGHTING \n"
-            "JUST FOR YOURSELF, BUT FOR \n"
-            "EVERYONE HERE AND OUTSIDE.",
-
-            "AS LONG AS ONE OF US STILL STANDS, \n"
-            "WE WILL WIN."
-        }
-    },
-    // Acolyte
-    {
-        "AGUARD",
-        10,
-        {
-            "MOVE ALONG,  PEASANT.",
-
-            "FOLLOW THE TRUE FAITH, ONLY THEN \n"
-            "WILL YOU BEGIN TO UNDERSTAND.",
-
-            "ONLY THROUGH DEATH CAN ONE BE \n"
-            "TRULY REBORN.",
-
-            "I'M NOT INTERESTED IN YOUR USELESS \n"
-            "DRIVEL.",
-
-            "IF I HAD WANTED TO TALK TO YOU I \n"
-            "WOULD HAVE TOLD YOU SO.",
-
-            "GO AND ANNOY SOMEONE ELSE!",
-
-            "KEEP MOVING!",
-
-            "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
-
-            "THE ORDER WILL CLEANSE THE WORLD \n"
-            "AND USHER IT INTO THE NEW ERA.",
-
-            "PROBLEM?  NO, I THOUGHT NOT.",
-        }
-    },
-    // Beggar
-    {
-        "BEGGAR",
-        10,
-        {
-            "ALMS FOR THE POOR?",
-
-            "WHAT ARE YOU LOOKING AT, SURFACER?",
-
-            "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
-
-            "YOU  SURFACE PEOPLE WILL NEVER \n"
-            "                                                                 "
-            "                                      UNDERSTAND US.",
-
-            "HA, THE GUARDS CAN'T FIND US.  THOSE \n"
-            "IDIOTS DON'T EVEN KNOW WE EXIST.",
-
-            "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
-            "  JOIN US.",
-
-            "STARE NOW,  BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
-
-            // Note: "NOTHING THING" is an authentic typo
-            "THERE'S NOTHING THING MORE \n"
-            "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
-
-            "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
-
-            "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
-        }
-    },
-    // Templar
-    {
-        "PGUARD",
-        10,
-        {
-            "WE ARE THE HANDS OF FATE. TO EARN \n"
-            "OUR WRATH IS TO FIND OBLIVION!",
-
-            "THE ORDER WILL CLEANSE THE WORLD \n"
-            "OF THE WEAK AND CORRUPT!",
-
-            "OBEY THE WILL OF THE MASTERS!",
-
-            "LONG LIFE TO THE BROTHERS OF THE \n"
-            "ORDER!",
-
-            "FREE WILL IS AN ILLUSION THAT BINDS \n"
-            "THE WEAK MINDED.",
-
-            "POWER IS THE PATH TO GLORY. TO \n"
-            "FOLLOW THE ORDER IS TO WALK THAT \n"
-            "PATH!",
-
-            "TAKE YOUR PLACE AMONG THE \n"
-            "RIGHTEOUS, JOIN US!",
-
-            "THE ORDER PROTECTS ITS OWN.",
-
-            "ACOLYTES?  THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
-
-            "IF THERE IS ANY HONOR INSIDE THAT \n"
-            "PATHETIC SHELL OF A BODY, \n"
-            "YOU'LL ENTER INTO THE ARMS OF THE \n"
-            "ORDER."
-        }
-    }
-};
-
-// And again, this could have been a define, but was a variable.
-static int numrndmessages = arrlen(rndMessages);
-
-//=============================================================================
-//
-// Dialog Menu Structure
-//
-// The Strife dialog system is actually just a serious abuse of the DOOM menu
-// engine. Hence why it doesn't work in multiplayer games or during demo
-// recording.
-//
-
-#define NUMDIALOGMENUITEMS 6
-
-static void P_DialogDrawer(void);
-
-static menuitem_t dialogmenuitems[] =
-{
-    { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
-    { 1, "", P_DialogDoChoice, '2' },
-    { 1, "", P_DialogDoChoice, '3' },
-    { 1, "", P_DialogDoChoice, '4' },
-    { 1, "", P_DialogDoChoice, '5' },
-    { 1, "", P_DialogDoChoice, '6' }  // Item 6 is always the dismissal item
-};
-
-static menu_t dialogmenu =
-{
-    NUMDIALOGMENUITEMS, 
-    NULL, 
-    dialogmenuitems, 
-    P_DialogDrawer, 
-    42, 
-    75, 
-    0
-};
-
-// Lump number of the dialog background picture, if any.
-static int dialogbgpiclumpnum;
-
-// Name of current speaking character.
-static char *dialogname;
-
-// Current dialog text.
-static const char *dialogtext;
-
-//=============================================================================
-//
-// Routines
-//
-
-//
-// P_ParseDialogLump
-//
-// haleyjd 09/02/10: This is an original function added to parse out the 
-// dialogs from the dialog lump rather than reading them raw from the lump 
-// pointer. This avoids problems with structure packing.
-//
-static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs, 
-                              int numdialogs, int tag)
-{
-    int i;
-    byte *rover = lump;
-
-    *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
-
-    for(i = 0; i < numdialogs; i++)
-    {
-        int j;
-        mapdialog_t *curdialog = &((*dialogs)[i]);
-
-        DIALOG_INT(curdialog->speakerid,    rover);
-        DIALOG_INT(curdialog->dropitem,     rover);
-        DIALOG_INT(curdialog->checkitem[0], rover);
-        DIALOG_INT(curdialog->checkitem[1], rover);
-        DIALOG_INT(curdialog->checkitem[2], rover);
-        DIALOG_INT(curdialog->jumptoconv,   rover);
-        DIALOG_STR(curdialog->name,         rover, MDLG_NAMELEN);
-        DIALOG_STR(curdialog->voice,        rover, MDLG_LUMPLEN);
-        DIALOG_STR(curdialog->backpic,      rover, MDLG_LUMPLEN);
-        DIALOG_STR(curdialog->text,         rover, MDLG_TEXTLEN);
-
-        // copy choices
-        for(j = 0; j < 5; j++)
-        {
-            mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
-            DIALOG_INT(curchoice->giveitem,         rover);
-            DIALOG_INT(curchoice->needitems[0],     rover);
-            DIALOG_INT(curchoice->needitems[1],     rover);
-            DIALOG_INT(curchoice->needitems[2],     rover);
-            DIALOG_INT(curchoice->needamounts[0],   rover);
-            DIALOG_INT(curchoice->needamounts[1],   rover);
-            DIALOG_INT(curchoice->needamounts[2],   rover);
-            DIALOG_STR(curchoice->text,             rover, MDLG_CHOICELEN);
-            DIALOG_STR(curchoice->textok,           rover, MDLG_MSGLEN);
-            DIALOG_INT(curchoice->next,             rover);
-            DIALOG_INT(curchoice->objective,        rover);
-            DIALOG_STR(curchoice->textno,           rover, MDLG_MSGLEN);
-        }
-    }
-}
-
-//
-// P_DialogLoad
-//
-// [STRIFE] New function
-// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads 
-// SCRIPT00 if it has not yet been loaded.
-//
-void P_DialogLoad(void)
-{
-    char lumpname[9];
-    int  lumpnum;
-
-    // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
-    DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
-    if((lumpnum = W_CheckNumForName(lumpname)) == -1)
-        numleveldialogs = 0;
-    else
-    {
-        byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
-        numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
-        P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs, 
-                          PU_LEVEL);
-        Z_Free(leveldialogptr); // haleyjd: free the original lump
-    }
-
-    // also load SCRIPT00 if it has not been loaded yet
-    if(!script0loaded)
-    {
-        byte *script0ptr;
-
-        script0loaded = true; 
-        // BUG: Rogue should have used W_GetNumForName here...
-        lumpnum = W_CheckNumForName(DEH_String("script00")); 
-        script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
-        numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
-        P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
-                          PU_STATIC);
-        Z_Free(script0ptr); // haleyjd: free the original lump
-    }
-}
-
-//
-// P_PlayerHasItem
-//
-// [STRIFE] New function
-// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
-// Returns the amount possessed, or 0 if none.
-//
-int P_PlayerHasItem(player_t *player, mobjtype_t type)
-{
-    int i;
-
-    if(type > 0)
-    {
-        // check keys
-        if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
-            return (player->cards[type - MT_KEY_BASE]);
-
-        // check sigil pieces
-        if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
-            return (type - MT_SIGIL_A <= player->sigiltype);
-
-        // check quest tokens
-        if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
-            return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
-
-        // check inventory
-        for(i = 0; i < 32; i++)
-        {
-            if(type == player->inventory[i].type)
-                return player->inventory[i].amount;
-        }
-    }
-    return 0;
-}
-
-//
-// P_DialogFind
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Looks for a dialog definition matching the given 
-// Script ID # for an mobj.
-//
-mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
-{
-    int i;
-
-    // check the map-specific dialogs first
-    for(i = 0; i < numleveldialogs; i++)
-    {
-        if(type == leveldialogs[i].speakerid)
-        {
-            if(jumptoconv <= 1)
-                return &leveldialogs[i];
-            else
-                --jumptoconv;
-        }
-    }
-
-    // check SCRIPT00 dialogs next
-    for(i = 0; i < numscript0dialogs; i++)
-    {
-        if(type == script0dialogs[i].speakerid)
-            return &script0dialogs[i];
-    }
-
-    // the default dialog is script 0 in the SCRIPT00 lump.
-    return &script0dialogs[0];
-}
-
-//
-// P_DialogGetStates
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
-// for a particular thing type.
-//
-static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
-{
-    int i;
-
-    // look for a match by type
-    for(i = 0; i < numdialogstatesets; i++)
-    {
-        if(type == dialogstatesets[i].type)
-            return &dialogstatesets[i];
-    }
-
-    // return the default 0 record if no match.
-    return &dialogstatesets[0];
-}
-
-//
-// P_DialogGetMsg
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
-// the actor should use a random message stored in the executable instead.
-//
-static const char *P_DialogGetMsg(const char *message)
-{
-    // if the message starts with "RANDOM"...
-    if(!strncasecmp(message, DEH_String("RANDOM"), 6))
-    {
-        int i;
-        const char *nameloc = message + 7;
-
-        // look for a match in rndMessages for the string starting 
-        // 7 chars after "RANDOM_"
-        for(i = 0; i < numrndmessages; i++)
-        {
-            if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
-            {
-                // found a match, so return a random message
-                int rnd = M_Random();
-                int nummessages = rndMessages[i].nummessages;
-                return DEH_String(rndMessages[i].messages[rnd % nummessages]);
-            }
-        }
-    }
-
-    // otherwise, just return the message passed in.
-    return message;
-}
-
-//
-// P_GiveInventoryItem
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Give an inventory item to the player, if possible.
-// villsa 09/09/10: Fleshed out routine
-//
-boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
-{
-    int curinv = 0;
-    int i;
-    boolean ok = false;
-    mobjtype_t item = 0;
-    inventory_t* invtail;
-
-    // repaint the status bar due to inventory changing
-    player->st_update = true;
-
-    while(1)
-    {
-        // inventory is full
-        if(curinv > player->numinventory)
-            return true;
-
-        item = player->inventory[curinv].type;
-        if(type < item)
-        {
-            if(curinv != MAXINVENTORYSLOTS)
-            {
-                // villsa - sort inventory item if needed
-                invtail = &player->inventory[player->numinventory - 1];
-                if(player->numinventory >= (curinv + 1))
-                {
-                    for(i = player->numinventory; i >= (curinv + 1); --i)    
-                    {
-                        invtail[1].sprite   = invtail[0].sprite;
-                        invtail[1].type     = invtail[0].type;
-                        invtail[1].amount   = invtail[0].amount;
-
-                        invtail--;
-                    }
-                }
-
-                // villsa - add inventory item
-                player->inventory[curinv].amount = 1;
-                player->inventory[curinv].sprite = sprnum;
-                player->inventory[curinv].type = type;
-
-                // sort cursor if needed
-                if(player->numinventory)
-                {
-                    if(curinv <= player->inventorycursor)
-                        player->inventorycursor++;
-                }
-
-                player->numinventory++;
-
-                return true;
-            }
-
-            return false;
-        }
-
-        if(type == item)
-            break;
-
-        curinv++;
-    }
-
-    // check amount of inventory item by using the mass from mobjinfo
-    if(player->inventory[curinv].amount < mobjinfo[item].mass)
-    {
-        player->inventory[curinv].amount++;
-        ok = true;
-    }
-    else
-        ok = false;
-
-    return ok;
-}
-
-//
-// P_GiveItemToPlayer
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Sorts out how to give something to the player.
-// Not strictly just for inventory items.
-// villsa 09/09/10: Fleshed out function
-//
-boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
-{
-    int i = 0;
-    line_t junk;
-    int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
-
-    // set quest if mf_givequest flag is set
-    if(mobjinfo[type].flags & MF_GIVEQUEST)
-        player->questflags |= 1 << (mobjinfo[type].speed - 1);
-
-    // check for keys
-    if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
-    {
-        P_GiveCard(player, type - MT_KEY_BASE);
-        return true;
-    }
-
-    // check for quest tokens
-    if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
-    {
-        if(mobjinfo[type].name)
-        {
-            M_StringCopy(pickupstring, DEH_String(mobjinfo[type].name), 39);
-            player->message = pickupstring;
-        }
-        player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
-
-        if(player == &players[consoleplayer])
-            S_StartSound(NULL, sound);
-        return true;
-    }
-
-    // haleyjd 09/22/10: Refactored to give sprites higher priority than
-    // mobjtypes and to implement missing logic.
-    switch(sprnum)
-    {
-    case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
-        P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
-        P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
-
-        // [STRIFE] Bizarre...
-        for(i = 0; i < 5 * player->accuracy + 300; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_ARM1: // Armor 1
-        if(!P_GiveArmor(player, -2))
-            P_GiveInventoryItem(player, sprnum, type);
-        break;
-
-    case SPR_ARM2: // Armor 2
-        if(!P_GiveArmor(player, -1))
-            P_GiveInventoryItem(player, sprnum, type);
-        break;
-
-    case SPR_COIN: // 1 Gold
-        P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_CRED: // 10 Gold
-        for(i = 0; i < 10; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_SACK: // 25 gold
-        for(i = 0; i < 25; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break;
-
-    case SPR_CHST: // 50 gold
-        for(i = 0; i < 50; i++)
-            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-        break; // haleyjd 20141215: missing break, caused Rowan to not take ring from you.
-
-    case SPR_BBOX: // Box of Bullets
-        if(!P_GiveAmmo(player, am_bullets, 5))
-            return false;
-        break;
-
-    case SPR_BLIT: // Bullet Clip
-        if(!P_GiveAmmo(player, am_bullets, 1))
-            return false;
-        break;
-
-    case SPR_PMAP: // Map powerup
-        if(!P_GivePower(player, pw_allmap))
-            return false;
-        sound = sfx_yeah; // bluh-doop!
-        break;
-
-    case SPR_COMM: // Communicator
-        if(!P_GivePower(player, pw_communicator))
-            return false;
-        sound = sfx_yeah; // bluh-doop!
-        break;
-
-    case SPR_MSSL: // Mini-missile
-        if(!P_GiveAmmo(player, am_missiles, 1))
-            return false;
-        break;
-
-    case SPR_ROKT: // Crate of missiles
-        if(!P_GiveAmmo(player, am_missiles, 5))
-            return false;
-        break;
-
-    case SPR_BRY1: // Battery cell
-        if(!P_GiveAmmo(player, am_cell, 1))
-            return false;
-        break;
-
-    case SPR_CPAC: // Cell pack
-        if(!P_GiveAmmo(player, am_cell, 5))
-            return false;
-        break;
-
-    case SPR_PQRL: // Poison bolts
-        if(!P_GiveAmmo(player, am_poisonbolts, 5))
-            return false;
-        break;
-
-    case SPR_XQRL: // Electric bolts
-        if(!P_GiveAmmo(player, am_elecbolts, 5))
-            return false;
-        break;
-
-    case SPR_GRN1: // HE Grenades
-        if(!P_GiveAmmo(player, am_hegrenades, 1))
-            return false;
-        break;
-
-    case SPR_GRN2: // WP Grenades
-        if(!P_GiveAmmo(player, am_wpgrenades, 1))
-            return false;
-        break;
-
-    case SPR_BKPK: // Backpack (aka Ammo Satchel)
-        if(!player->backpack)
-        {
-            for(i = 0; i < NUMAMMO; i++)
-                player->maxammo[i] *= 2;
-
-            player->backpack = true;
-        }
-        for(i = 0; i < NUMAMMO; i++)
-            P_GiveAmmo(player, i, 1);
-        break;
-
-    case SPR_RIFL: // Assault Rifle
-        if(player->weaponowned[wp_rifle])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_rifle, false))
-            return false;
-        
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_FLAM: // Flamethrower
-        if(player->weaponowned[wp_flame])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_flame, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_MMSL: // Mini-missile Launcher
-        if(player->weaponowned[wp_missile])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_missile, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_TRPD: // Mauler
-        if(player->weaponowned[wp_mauler])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_mauler, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
-        if(player->weaponowned[wp_elecbow])
-            return false;
-
-        if(!P_GiveWeapon(player, wp_elecbow, false))
-            return false;
-
-        sound = sfx_wpnup; // SHK-CHK!
-        break;
-
-    case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
-        switch(type)
-        {
-        case MT_KEY_HAND: // Severed hand
-            P_GiveCard(player, key_SeveredHand);
-            break;
-
-        case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
-            for(i = 0; i < 300; i++)
-                P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
-            break;
-
-        case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
-            if(player->ammo[am_bullets] >= 50)
-                return false;
-
-            player->ammo[am_bullets] = 50;
-            break;
-
-        case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
-            if(!P_GiveBody(player, healthamounts[gameskill]))
-                return false;
-            break;
-
-        case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
-            P_NoiseAlert(player->mo, player->mo);
-            A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
-            break;
-
-        case MT_TOKEN_DOOR1: // Door special 1
-            junk.tag = 222;
-            EV_DoDoor(&junk, vld_open);
-            break;
-
-        case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
-            junk.tag = 223;
-            EV_DoDoor(&junk, vld_open);
-            if(gamemap == 2) // If on Tarnhill, give Prison pass object
-                P_GiveInventoryItem(player, sprnum, type);
-            break;
-
-        case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
-            junk.tag = 222;
-            EV_DoDoor(&junk, vld_close);
-            break;
-
-        case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P ) 
-            junk.tag = 224;
-            EV_DoDoor(&junk, vld_close);
-            break;
-
-        case MT_TOKEN_STAMINA: // Stamina upgrade
-            if(player->stamina >= 100)
-                return false;
-
-            player->stamina += 10;
-            P_GiveBody(player, 200); // full healing
-            break;
-
-        case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
-            if(player->accuracy >= 100)
-                return false;
-
-            player->accuracy += 10;
-            break;
-
-        case MT_SLIDESHOW: // Slideshow (start a finale)
-            gameaction = ga_victory;
-            if(gamemap == 10)
-                P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
-            break;
-        
-        default: // The default is to just give it as an inventory item.
-            P_GiveInventoryItem(player, sprnum, type);
-            break;
-        }
-        break;
-
-    default: // The ultimate default: Give it as an inventory item.
-        if(!P_GiveInventoryItem(player, sprnum, type))
-            return false;
-        break;
-    }
-
-    // Play sound.
-    if(player == &players[consoleplayer])
-        S_StartSound(NULL, sound);
-
-    return true;
-}
-
-//
-// P_TakeDialogItem
-//
-// [STRIFE] New function
-// haleyjd 09/03/10: Removes needed items from the player's inventory.
-//
-static void P_TakeDialogItem(player_t *player, int type, int amount)
-{
-    int i;
-
-    if(amount <= 0)
-        return;
-
-    for(i = 0; i < player->numinventory; i++)
-    {
-        // find a matching item
-        if(type != player->inventory[i].type)
-            continue;
-
-        // if there is none left...
-        if((player->inventory[i].amount -= amount) < 1)
-        {
-            // ...shift everything above it down
-            int j;
-
-            // BUG: They should have stopped at j < numinventory. This
-            // seems to implicitly assume that numinventory is always at
-            // least one less than the max # of slots, otherwise it 
-            // pulls in data from the following player_t fields:
-            // st_update, numinventory, inventorycursor, accuracy, stamina
-            for(j = i + 1; j <= player->numinventory; j++)
-            {
-                inventory_t *item1 = &(player->inventory[j - 1]);
-                inventory_t *item2 = &(player->inventory[j]);
-
-                *item1 = *item2;
-            }
-
-            // blank the topmost slot
-            // BUG: This will overwrite the aforementioned fields if
-            // numinventory is equal to the number of slots!
-            // STRIFE-TODO: Overflow emulation?
-            player->inventory[player->numinventory].type = NUMMOBJTYPES;
-            player->inventory[player->numinventory].sprite = -1;
-            player->numinventory--;
-
-            // update cursor position
-            if(player->inventorycursor >= player->numinventory)
-            {
-                if(player->inventorycursor)
-                    player->inventorycursor--;
-            }
-        } // end if
-        
-        return; // done!
-
-    } // end for
-}
-
-//
-// P_DialogDrawer
-//
-// This function is set as the drawer callback for the dialog menu.
-//
-static void P_DialogDrawer(void)
-{
-    angle_t angle;
-    int y;
-    int i;
-    int height;
-    int finaly;
-    char choicetext[64];
-    char choicetext2[64];
-
-    // Run down bonuscount faster than usual so that flashes from being given
-    // items are less obvious.
-    if(dialogplayer->bonuscount)
-    {
-        dialogplayer->bonuscount -= 3;
-        if(dialogplayer->bonuscount < 0)
-            dialogplayer->bonuscount = 0;
-    }
-
-    angle = R_PointToAngle2(dialogplayer->mo->x,
-                            dialogplayer->mo->y,
-                            dialogtalker->x,
-                            dialogtalker->y);
-    angle -= dialogplayer->mo->angle;
-
-    // Dismiss the dialog if the player is out of alignment, or the thing he was
-    // talking to is now engaged in battle.
-    if ((angle > ANG45 && angle < (ANG270+ANG45))
-     || (dialogtalker->flags & MF_NODIALOG) != 0)
-    {
-        P_DialogDoChoice(dialogmenu.numitems - 1);
-    }
-
-    dialogtalker->reactiontime = 2;
-
-    // draw background
-    if(dialogbgpiclumpnum != -1)
-    {
-        patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
-        V_DrawPatchDirect(0, 0, patch);
-    }
-
-    // if there's a valid background pic, delay drawing the rest of the menu 
-    // for a while; otherwise, it will appear immediately
-    if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
-    {
-        if(menuindialog)
-        {
-            // time to pause the game?
-            if(menupausetime + 3 < gametic)
-                menupause = true;
-        }
-
-        // draw character name
-        M_WriteText(12, 18, dialogname);
-        y = 28;
-
-        // show text (optional for dialogs with voices)
-        if(dialogshowtext || currentdialog->voice[0] == '\0')
-            y = M_WriteText(20, 28, dialogtext);
-
-        height = 20 * dialogmenu.numitems;
-
-        finaly = 175 - height;     // preferred height
-        if(y > finaly)
-            finaly = 199 - height; // height it will bump down to if necessary.
-
-        // draw divider
-        M_WriteText(42, finaly - 6, DEH_String("______________________________"));
-
-        dialogmenu.y = finaly + 6;
-        y = 0;
-
-        // draw the menu items
-        for(i = 0; i < dialogmenu.numitems - 1; i++)
-        {
-            DEH_snprintf(choicetext, sizeof(choicetext),
-                         "%d) %s", i + 1, currentdialog->choices[i].text);
-            
-            // alternate text for items that need money
-            if(currentdialog->choices[i].needamounts[0] > 0)
-            {
-                // haleyjd 20120401: necessary to avoid undefined behavior:
-                M_StringCopy(choicetext2, choicetext, sizeof(choicetext2));
-                DEH_snprintf(choicetext, sizeof(choicetext),
-                             "%s for %d", choicetext2,
-                             currentdialog->choices[i].needamounts[0]);
-            }
-
-            M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
-            y += 19;
-        }
-
-        // draw the final item for dismissing the dialog
-        M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
-    }
-}
-
-//
-// P_DialogDoChoice
-//
-// [STRIFE] New function
-// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
-// callback for all items in the dialogmenu structure.
-//
-void P_DialogDoChoice(int choice)
-{
-    int i = 0, nextdialog = 0;
-    boolean candochoice = true;
-    char *message = NULL;
-    mapdlgchoice_t *currentchoice;
-
-    if(choice == -1)
-        choice = dialogmenu.numitems - 1;
-
-    currentchoice = &(currentdialog->choices[choice]);
-
-    I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe)
-
-    // villsa 09/08/10: converted into for loop
-    for(i = 0; i < MDLG_MAXITEMS; i++)
-    {
-        if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
-                                         currentchoice->needamounts[i])
-        {
-            candochoice = false; // nope, missing something
-        }
-    }
-
-    if(choice != dialogmenu.numitems - 1 && candochoice)
-    {
-        int item;
-
-        message = currentchoice->textok;
-        if(dialogtalkerstates->yes)
-            P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
-
-        item = currentchoice->giveitem;
-        if(item < 0 || 
-           P_GiveItemToPlayer(dialogplayer, 
-                              states[mobjinfo[item].spawnstate].sprite, 
-                              item))
-        {
-            // if successful, take needed items
-            int count = 0;
-            // villsa 09/08/10: converted into for loop
-            for(count = 0; count < MDLG_MAXITEMS; count++)
-            {
-                P_TakeDialogItem(dialogplayer, 
-                                 currentchoice->needitems[count],
-                                 currentchoice->needamounts[count]);
-            }
-        }
-        else
-            message = DEH_String("You seem to have enough!");
-
-        // store next dialog into the talking actor
-        nextdialog = currentchoice->next;
-        if(nextdialog != 0)
-            dialogtalker->miscdata = (byte)(abs(nextdialog));
-    }
-    else
-    {
-        // not successful
-        message = currentchoice->textno;
-        if(dialogtalkerstates->no)
-            P_SetMobjState(dialogtalker, dialogtalkerstates->no);
-    }
-    
-    if(choice != dialogmenu.numitems - 1)
-    {
-        int objective;
-        char *objlump;
-
-        if((objective = currentchoice->objective))
-        {
-            DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
-            objlump = W_CacheLumpName(mission_objective, PU_CACHE);
-            M_StringCopy(mission_objective, objlump, OBJECTIVE_LEN);
-        }
-        // haleyjd 20130301: v1.31 hack: if first char of message is a period,
-        // clear the player's message. Is this actually used anywhere?
-        if(gameversion == exe_strife_1_31 && message[0] == '.')
-            message = NULL;
-        dialogplayer->message = message;
-    }
-
-    dialogtalker->angle = dialogtalkerangle;
-    dialogplayer->st_update = true;
-    M_ClearMenus(0);
-
-    if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
-        menuindialog = false;
-    else
-        P_DialogStart(dialogplayer);
-}
-
-//
-// P_DialogStartP1
-//
-// [STRIFE] New function
-// haleyjd 09/13/10: This is a hack used by the finale system.
-//
-void P_DialogStartP1(void)
-{
-    P_DialogStart(&players[0]);
-}
-
-//
-// P_DialogStart
-//
-// villsa [STRIFE] New function
-//
-void P_DialogStart(player_t *player)
-{
-    int i = 0;
-    int pic;
-    int rnd = 0;
-    char* byetext;
-    int jumptoconv;
-
-    if(menuactive || netgame)
-        return;
-
-    // are we facing towards our NPC?
-    P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
-    if(!linetarget)
-    {
-        P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
-        if(!linetarget)
-            P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
-    }
-
-    if(!linetarget)
-       return;
-
-    // already in combat, can't talk to it
-    if(linetarget->flags & MF_NODIALOG)
-       return;
-
-    // set pointer to the character talking
-    dialogtalker = linetarget;
-
-    // play a sound
-    if(player == &players[consoleplayer])
-       S_StartSound(0, sfx_radio);
-
-    linetarget->target = player->mo;         // target the player
-    dialogtalker->reactiontime = 2;          // set reactiontime
-    dialogtalkerangle = dialogtalker->angle; // remember original angle
-
-    // face talker towards player
-    A_FaceTarget(dialogtalker);
-
-    // face towards NPC's direction
-    player->mo->angle = R_PointToAngle2(player->mo->x,
-                                        player->mo->y,
-                                        dialogtalker->x,
-                                        dialogtalker->y);
-    // set pointer to player talking
-    dialogplayer = player;
-
-    // haleyjd 09/08/10: get any stored dialog state from this object
-    jumptoconv = linetarget->miscdata;
-
-    // check item requirements
-    while(1)
-    {
-        int i = 0;
-        currentdialog = P_DialogFind(linetarget->type, jumptoconv);
-
-        // dialog's jumptoconv equal to 0? There's nothing to jump to.
-        if(currentdialog->jumptoconv == 0)
-            break;
-
-        // villsa 09/08/10: converted into for loop
-        for(i = 0; i < MDLG_MAXITEMS; i++)
-        {
-            // if the item is non-zero, the player must have at least one in his
-            // or her inventory
-            if(currentdialog->checkitem[i] != 0 &&
-                P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
-                break;
-        }
-
-        if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
-            break;
-
-        jumptoconv = currentdialog->jumptoconv;
-    }
-
-    M_DialogDimMsg(20, 28, currentdialog->text, false);
-    dialogtext = P_DialogGetMsg(currentdialog->text);
-
-    // get states
-    dialogtalkerstates = P_DialogGetStates(linetarget->type);
-
-    // have talker greet the player
-    if(dialogtalkerstates->greet)
-        P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
-
-    // get talker's name
-    if(currentdialog->name[0])
-        dialogname = currentdialog->name;
-    else
-    {
-        // use a fallback:
-        if(mobjinfo[linetarget->type].name)
-            dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
-        else
-            dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
-    }
-
-    // setup number of choices to choose from
-    for(i = 0; i < MDLG_MAXCHOICES; i++)
-    {
-        if(!currentdialog->choices[i].giveitem)
-            break;
-    }
-
-    // set number of choices to menu
-    dialogmenu.numitems = i + 1;
-
-    rnd = M_Random() % 3;
-
-    // setup dialog menu
-    M_StartControlPanel();
-    menupause = false;
-    menuindialog = true;
-    menupausetime = gametic + 17;
-    currentMenu = &dialogmenu;
-
-    if(i >= dialogmenu.lastOn)
-        itemOn = dialogmenu.lastOn;
-    else
-        itemOn = 0;
-
-    // get backdrop
-    pic = W_CheckNumForName(currentdialog->backpic);
-    dialogbgpiclumpnum = pic;
-    if(pic != -1)
-        V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
-
-    // get voice
-    I_StartVoice(currentdialog->voice);
-
-    // get bye text
-    switch(rnd)
-    {
-    case 2:
-        byetext = DEH_String("BYE!");
-        break;
-    case 1:
-        byetext = DEH_String("Thanks, Bye!");
-        break;
-    default:
-    case 0:
-        byetext = DEH_String("See you later!");
-        break;
-    }
-
-    DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
-                 "%d) %s", i + 1, byetext);
-}
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+
+#include <stdlib.h>
+
+#include "z_zone.h"
+#include "w_wad.h"
+#include "deh_str.h"
+#include "d_main.h"
+#include "d_mode.h"
+#include "d_player.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "m_menu.h"
+#include "m_misc.h"
+#include "r_main.h"
+#include "v_video.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "p_dialog.h"
+#include "s_sound.h"
+#include "p_local.h"
+#include "p_inter.h"
+
+//
+// Defines and Macros
+//
+
+// haleyjd: size of the original Strife mapdialog_t structure.
+#define ORIG_MAPDIALOG_SIZE 0x5EC
+
+#define DIALOG_INT(field, ptr)    \
+    field = ((int)ptr[0]        | \
+            ((int)ptr[1] <<  8) | \
+            ((int)ptr[2] << 16) | \
+            ((int)ptr[3] << 24)); \
+    ptr += 4;
+
+#define DIALOG_STR(field, ptr, len) \
+    memcpy(field, ptr, len);        \
+    ptr += len;
+
+//
+// Globals
+//
+
+// This can be toggled at runtime to determine if the full dialog messages
+// are subtitled on screen or not. Defaults to off.
+int dialogshowtext = false;
+
+// The global mission objective buffer. This gets written to and read from file,
+// and is set by dialogs and line actions.
+char mission_objective[OBJECTIVE_LEN];
+
+//
+// Static Globals
+//
+
+// True if SCRIPT00 is loaded.
+static boolean script0loaded;
+
+// Number of dialogs defined in the current level's script.
+static int numleveldialogs;
+
+// The actual level dialogs. This didn't exist in Strife, but is new to account
+// for structure alignment/packing concerns, given that Chocolate Doom is
+// multiplatform.
+static mapdialog_t *leveldialogs;
+
+// The actual script00 dialogs. As above.
+static mapdialog_t *script0dialogs;
+
+// Number of dialogs defined in the SCRIPT00 lump.
+static int numscript0dialogs;
+
+// The player engaged in dialog. This is always player 1, though, since Rogue
+// never completed the ability to use dialog outside of single-player mode.
+static player_t *dialogplayer;
+
+// The object to which the player is speaking.
+static mobj_t   *dialogtalker;
+
+// The talker's current angle
+static angle_t dialogtalkerangle;
+
+// The currently active mapdialog object.
+static mapdialog_t *currentdialog;
+
+// Text at the end of the choices
+static char dialoglastmsgbuffer[48];
+
+// Item to display to player when picked up or recieved
+static char pickupstring[46];
+
+// Health based on gameskill given by the front's medic
+static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
+
+//=============================================================================
+//
+// Dialog State Sets
+//
+// These are used to animate certain actors in response to what happens in
+// their dialog sequences.
+//
+
+typedef struct dialogstateset_s
+{
+    mobjtype_t type;  // the type of object
+    statenum_t greet; // greeting state, for start of dialog
+    statenum_t yes;   // "yes" state, for an affirmative response
+    statenum_t no;    // "no" state, when you don't have the right items
+} dialogstateset_t;
+
+static dialogstateset_t dialogstatesets[] =
+{
+    { MT_PLAYER,       S_NULL,    S_NULL,    S_NULL    },
+    { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+    { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
+};
+
+// Rogue stored this in a static global rather than making it a define...
+static int numdialogstatesets = arrlen(dialogstatesets);
+
+// Current dialog talker state
+static dialogstateset_t *dialogtalkerstates;
+
+//=============================================================================
+//
+// Random Messages
+//
+// Rogue hard-coded these so they wouldn't have to repeat them several times
+// in the SCRIPT00 lump, apparently.
+//
+
+#define MAXRNDMESSAGES 10
+
+typedef struct rndmessage_s
+{
+    const char *type_name;
+    int nummessages;
+    char *messages[MAXRNDMESSAGES];
+} rndmessage_t;
+
+static rndmessage_t rndMessages[] = 
+{
+    // Peasants
+    {
+        "PEASANT",
+        10,
+        {
+            "PLEASE DON'T HURT ME.",
+            
+            "IF YOU'RE LOOKING TO HURT ME, I'M \n"
+            "NOT REALLY WORTH THE EFFORT.",
+            
+            "I DON'T KNOW ANYTHING.",
+            
+            "GO AWAY OR I'LL CALL THE GUARDS!",
+            
+            "I WISH SOMETIMES THAT ALL THESE \n"
+            "REBELS WOULD JUST LEARN THEIR \n"
+            "PLACE AND STOP THIS NONSENSE.",
+
+            "JUST LEAVE ME ALONE, OK?",
+
+            "I'M NOT SURE, BUT SOMETIMES I THINK \n"
+            "THAT I KNOW SOME OF THE ACOLYTES.",
+
+            "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
+
+            "THERE'S NO WAY THAT THIS IS JUST A \n"
+            "SECURITY FORCE.",
+
+            "I'VE HEARD THAT THE ORDER IS REALLY \n"
+            "NERVOUS ABOUT THE FRONT'S \n"
+            "ACTIONS AROUND HERE."
+        }
+    },
+    // Rebel
+    {
+        "REBEL",
+        10,
+        {
+            "THERE'S NO WAY THE ORDER WILL \n"
+            "STAND AGAINST US.",
+
+            "WE'RE ALMOST READY TO STRIKE. \n"
+            "MACIL'S PLANS ARE FALLING IN PLACE.",
+
+            "WE'RE ALL BEHIND YOU, DON'T WORRY.",
+
+            "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
+            "FOR SCRAP!",
+
+            "THE DAY OF OUR GLORY WILL SOON \n"
+            "COME, AND THOSE WHO OPPOSE US WILL \n"
+            "BE CRUSHED!",
+
+            "DON'T GET TOO COMFORTABLE. WE'VE \n"
+            "STILL GOT OUR WORK CUT OUT FOR US.",
+
+            "MACIL SAYS THAT YOU'RE THE NEW \n"
+            "HOPE. BEAR THAT IN MIND.",
+
+            "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
+            "WORLD AS IT SHOULD BE.",
+
+            "REMEMBER THAT YOU AREN'T FIGHTING \n"
+            "JUST FOR YOURSELF, BUT FOR \n"
+            "EVERYONE HERE AND OUTSIDE.",
+
+            "AS LONG AS ONE OF US STILL STANDS, \n"
+            "WE WILL WIN."
+        }
+    },
+    // Acolyte
+    {
+        "AGUARD",
+        10,
+        {
+            "MOVE ALONG,  PEASANT.",
+
+            "FOLLOW THE TRUE FAITH, ONLY THEN \n"
+            "WILL YOU BEGIN TO UNDERSTAND.",
+
+            "ONLY THROUGH DEATH CAN ONE BE \n"
+            "TRULY REBORN.",
+
+            "I'M NOT INTERESTED IN YOUR USELESS \n"
+            "DRIVEL.",
+
+            "IF I HAD WANTED TO TALK TO YOU I \n"
+            "WOULD HAVE TOLD YOU SO.",
+
+            "GO AND ANNOY SOMEONE ELSE!",
+
+            "KEEP MOVING!",
+
+            "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
+
+            "THE ORDER WILL CLEANSE THE WORLD \n"
+            "AND USHER IT INTO THE NEW ERA.",
+
+            "PROBLEM?  NO, I THOUGHT NOT.",
+        }
+    },
+    // Beggar
+    {
+        "BEGGAR",
+        10,
+        {
+            "ALMS FOR THE POOR?",
+
+            "WHAT ARE YOU LOOKING AT, SURFACER?",
+
+            "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
+
+            "YOU  SURFACE PEOPLE WILL NEVER \n"
+            "                                                                 "
+            "                                      UNDERSTAND US.",
+
+            "HA, THE GUARDS CAN'T FIND US.  THOSE \n"
+            "IDIOTS DON'T EVEN KNOW WE EXIST.",
+
+            "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
+            "  JOIN US.",
+
+            "STARE NOW,  BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
+
+            // Note: "NOTHING THING" is an authentic typo
+            "THERE'S NOTHING THING MORE \n"
+            "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
+
+            "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
+
+            "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
+        }
+    },
+    // Templar
+    {
+        "PGUARD",
+        10,
+        {
+            "WE ARE THE HANDS OF FATE. TO EARN \n"
+            "OUR WRATH IS TO FIND OBLIVION!",
+
+            "THE ORDER WILL CLEANSE THE WORLD \n"
+            "OF THE WEAK AND CORRUPT!",
+
+            "OBEY THE WILL OF THE MASTERS!",
+
+            "LONG LIFE TO THE BROTHERS OF THE \n"
+            "ORDER!",
+
+            "FREE WILL IS AN ILLUSION THAT BINDS \n"
+            "THE WEAK MINDED.",
+
+            "POWER IS THE PATH TO GLORY. TO \n"
+            "FOLLOW THE ORDER IS TO WALK THAT \n"
+            "PATH!",
+
+            "TAKE YOUR PLACE AMONG THE \n"
+            "RIGHTEOUS, JOIN US!",
+
+            "THE ORDER PROTECTS ITS OWN.",
+
+            "ACOLYTES?  THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
+
+            "IF THERE IS ANY HONOR INSIDE THAT \n"
+            "PATHETIC SHELL OF A BODY, \n"
+            "YOU'LL ENTER INTO THE ARMS OF THE \n"
+            "ORDER."
+        }
+    }
+};
+
+// And again, this could have been a define, but was a variable.
+static int numrndmessages = arrlen(rndMessages);
+
+//=============================================================================
+//
+// Dialog Menu Structure
+//
+// The Strife dialog system is actually just a serious abuse of the DOOM menu
+// engine. Hence why it doesn't work in multiplayer games or during demo
+// recording.
+//
+
+#define NUMDIALOGMENUITEMS 6
+
+static void P_DialogDrawer(void);
+
+static menuitem_t dialogmenuitems[] =
+{
+    { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
+    { 1, "", P_DialogDoChoice, '2' },
+    { 1, "", P_DialogDoChoice, '3' },
+    { 1, "", P_DialogDoChoice, '4' },
+    { 1, "", P_DialogDoChoice, '5' },
+    { 1, "", P_DialogDoChoice, '6' }  // Item 6 is always the dismissal item
+};
+
+static menu_t dialogmenu =
+{
+    NUMDIALOGMENUITEMS, 
+    NULL, 
+    dialogmenuitems, 
+    P_DialogDrawer, 
+    42, 
+    75, 
+    0
+};
+
+// Lump number of the dialog background picture, if any.
+static int dialogbgpiclumpnum;
+
+// Name of current speaking character.
+static char *dialogname;
+
+// Current dialog text.
+static const char *dialogtext;
+
+//=============================================================================
+//
+// Routines
+//
+
+//
+// P_ParseDialogLump
+//
+// haleyjd 09/02/10: This is an original function added to parse out the 
+// dialogs from the dialog lump rather than reading them raw from the lump 
+// pointer. This avoids problems with structure packing.
+//
+static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs, 
+                              int numdialogs, int tag)
+{
+    int i;
+    byte *rover = lump;
+
+    *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
+
+    for(i = 0; i < numdialogs; i++)
+    {
+        int j;
+        mapdialog_t *curdialog = &((*dialogs)[i]);
+
+        DIALOG_INT(curdialog->speakerid,    rover);
+        DIALOG_INT(curdialog->dropitem,     rover);
+        DIALOG_INT(curdialog->checkitem[0], rover);
+        DIALOG_INT(curdialog->checkitem[1], rover);
+        DIALOG_INT(curdialog->checkitem[2], rover);
+        DIALOG_INT(curdialog->jumptoconv,   rover);
+        DIALOG_STR(curdialog->name,         rover, MDLG_NAMELEN);
+        DIALOG_STR(curdialog->voice,        rover, MDLG_LUMPLEN);
+        DIALOG_STR(curdialog->backpic,      rover, MDLG_LUMPLEN);
+        DIALOG_STR(curdialog->text,         rover, MDLG_TEXTLEN);
+
+        // copy choices
+        for(j = 0; j < 5; j++)
+        {
+            mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
+            DIALOG_INT(curchoice->giveitem,         rover);
+            DIALOG_INT(curchoice->needitems[0],     rover);
+            DIALOG_INT(curchoice->needitems[1],     rover);
+            DIALOG_INT(curchoice->needitems[2],     rover);
+            DIALOG_INT(curchoice->needamounts[0],   rover);
+            DIALOG_INT(curchoice->needamounts[1],   rover);
+            DIALOG_INT(curchoice->needamounts[2],   rover);
+            DIALOG_STR(curchoice->text,             rover, MDLG_CHOICELEN);
+            DIALOG_STR(curchoice->textok,           rover, MDLG_MSGLEN);
+            DIALOG_INT(curchoice->next,             rover);
+            DIALOG_INT(curchoice->objective,        rover);
+            DIALOG_STR(curchoice->textno,           rover, MDLG_MSGLEN);
+        }
+    }
+}
+
+//
+// P_DialogLoad
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads 
+// SCRIPT00 if it has not yet been loaded.
+//
+void P_DialogLoad(void)
+{
+    char lumpname[9];
+    int  lumpnum;
+
+    // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
+    DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
+    if((lumpnum = W_CheckNumForName(lumpname)) == -1)
+        numleveldialogs = 0;
+    else
+    {
+        byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+        numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+        P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs, 
+                          PU_LEVEL);
+        Z_Free(leveldialogptr); // haleyjd: free the original lump
+    }
+
+    // also load SCRIPT00 if it has not been loaded yet
+    if(!script0loaded)
+    {
+        byte *script0ptr;
+
+        script0loaded = true; 
+        // BUG: Rogue should have used W_GetNumForName here...
+        lumpnum = W_CheckNumForName(DEH_String("script00")); 
+        script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+        numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+        P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
+                          PU_STATIC);
+        Z_Free(script0ptr); // haleyjd: free the original lump
+    }
+}
+
+//
+// P_PlayerHasItem
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
+// Returns the amount possessed, or 0 if none.
+//
+int P_PlayerHasItem(player_t *player, mobjtype_t type)
+{
+    int i;
+
+    if(type > 0)
+    {
+        // check keys
+        if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
+            return (player->cards[type - MT_KEY_BASE]);
+
+        // check sigil pieces
+        if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
+            return (type - MT_SIGIL_A <= player->sigiltype);
+
+        // check quest tokens
+        if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+            return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
+
+        // check inventory
+        for(i = 0; i < 32; i++)
+        {
+            if(type == player->inventory[i].type)
+                return player->inventory[i].amount;
+        }
+    }
+    return 0;
+}
+
+//
+// P_DialogFind
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Looks for a dialog definition matching the given 
+// Script ID # for an mobj.
+//
+mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
+{
+    int i;
+
+    // check the map-specific dialogs first
+    for(i = 0; i < numleveldialogs; i++)
+    {
+        if(type == leveldialogs[i].speakerid)
+        {
+            if(jumptoconv <= 1)
+                return &leveldialogs[i];
+            else
+                --jumptoconv;
+        }
+    }
+
+    // check SCRIPT00 dialogs next
+    for(i = 0; i < numscript0dialogs; i++)
+    {
+        if(type == script0dialogs[i].speakerid)
+            return &script0dialogs[i];
+    }
+
+    // the default dialog is script 0 in the SCRIPT00 lump.
+    return &script0dialogs[0];
+}
+
+//
+// P_DialogGetStates
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
+// for a particular thing type.
+//
+static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
+{
+    int i;
+
+    // look for a match by type
+    for(i = 0; i < numdialogstatesets; i++)
+    {
+        if(type == dialogstatesets[i].type)
+            return &dialogstatesets[i];
+    }
+
+    // return the default 0 record if no match.
+    return &dialogstatesets[0];
+}
+
+//
+// P_DialogGetMsg
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
+// the actor should use a random message stored in the executable instead.
+//
+static const char *P_DialogGetMsg(const char *message)
+{
+    // if the message starts with "RANDOM"...
+    if(!strncasecmp(message, DEH_String("RANDOM"), 6))
+    {
+        int i;
+        const char *nameloc = message + 7;
+
+        // look for a match in rndMessages for the string starting 
+        // 7 chars after "RANDOM_"
+        for(i = 0; i < numrndmessages; i++)
+        {
+            if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
+            {
+                // found a match, so return a random message
+                int rnd = M_Random();
+                int nummessages = rndMessages[i].nummessages;
+                return DEH_String(rndMessages[i].messages[rnd % nummessages]);
+            }
+        }
+    }
+
+    // otherwise, just return the message passed in.
+    return message;
+}
+
+//
+// P_GiveInventoryItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Give an inventory item to the player, if possible.
+// villsa 09/09/10: Fleshed out routine
+//
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
+{
+    int curinv = 0;
+    int i;
+    boolean ok = false;
+    mobjtype_t item = 0;
+    inventory_t* invtail;
+
+    // repaint the status bar due to inventory changing
+    player->st_update = true;
+
+    while(1)
+    {
+        // inventory is full
+        if(curinv > player->numinventory)
+            return true;
+
+        item = player->inventory[curinv].type;
+        if(type < item)
+        {
+            if(curinv != MAXINVENTORYSLOTS)
+            {
+                // villsa - sort inventory item if needed
+                invtail = &player->inventory[player->numinventory - 1];
+                if(player->numinventory >= (curinv + 1))
+                {
+                    for(i = player->numinventory; i >= (curinv + 1); --i)    
+                    {
+                        invtail[1].sprite   = invtail[0].sprite;
+                        invtail[1].type     = invtail[0].type;
+                        invtail[1].amount   = invtail[0].amount;
+
+                        invtail--;
+                    }
+                }
+
+                // villsa - add inventory item
+                player->inventory[curinv].amount = 1;
+                player->inventory[curinv].sprite = sprnum;
+                player->inventory[curinv].type = type;
+
+                // sort cursor if needed
+                if(player->numinventory)
+                {
+                    if(curinv <= player->inventorycursor)
+                        player->inventorycursor++;
+                }
+
+                player->numinventory++;
+
+                return true;
+            }
+
+            return false;
+        }
+
+        if(type == item)
+            break;
+
+        curinv++;
+    }
+
+    // check amount of inventory item by using the mass from mobjinfo
+    if(player->inventory[curinv].amount < mobjinfo[item].mass)
+    {
+        player->inventory[curinv].amount++;
+        ok = true;
+    }
+    else
+        ok = false;
+
+    return ok;
+}
+
+//
+// P_GiveItemToPlayer
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Sorts out how to give something to the player.
+// Not strictly just for inventory items.
+// villsa 09/09/10: Fleshed out function
+//
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
+{
+    int i = 0;
+    line_t junk;
+    int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
+
+    // set quest if mf_givequest flag is set
+    if(mobjinfo[type].flags & MF_GIVEQUEST)
+        player->questflags |= 1 << (mobjinfo[type].speed - 1);
+
+    // check for keys
+    if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
+    {
+        P_GiveCard(player, type - MT_KEY_BASE);
+        return true;
+    }
+
+    // check for quest tokens
+    if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+    {
+        if(mobjinfo[type].name)
+        {
+            M_StringCopy(pickupstring, DEH_String(mobjinfo[type].name), 39);
+            player->message = pickupstring;
+        }
+        player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
+
+        if(player == &players[consoleplayer])
+            S_StartSound(NULL, sound);
+        return true;
+    }
+
+    // haleyjd 09/22/10: Refactored to give sprites higher priority than
+    // mobjtypes and to implement missing logic.
+    switch(sprnum)
+    {
+    case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
+        P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
+        P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
+
+        // [STRIFE] Bizarre...
+        for(i = 0; i < 5 * player->accuracy + 300; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_ARM1: // Armor 1
+        if(!P_GiveArmor(player, -2))
+            P_GiveInventoryItem(player, sprnum, type);
+        break;
+
+    case SPR_ARM2: // Armor 2
+        if(!P_GiveArmor(player, -1))
+            P_GiveInventoryItem(player, sprnum, type);
+        break;
+
+    case SPR_COIN: // 1 Gold
+        P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_CRED: // 10 Gold
+        for(i = 0; i < 10; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_SACK: // 25 gold
+        for(i = 0; i < 25; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break;
+
+    case SPR_CHST: // 50 gold
+        for(i = 0; i < 50; i++)
+            P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+        break; // haleyjd 20141215: missing break, caused Rowan to not take ring from you.
+
+    case SPR_BBOX: // Box of Bullets
+        if(!P_GiveAmmo(player, am_bullets, 5))
+            return false;
+        break;
+
+    case SPR_BLIT: // Bullet Clip
+        if(!P_GiveAmmo(player, am_bullets, 1))
+            return false;
+        break;
+
+    case SPR_PMAP: // Map powerup
+        if(!P_GivePower(player, pw_allmap))
+            return false;
+        sound = sfx_yeah; // bluh-doop!
+        break;
+
+    case SPR_COMM: // Communicator
+        if(!P_GivePower(player, pw_communicator))
+            return false;
+        sound = sfx_yeah; // bluh-doop!
+        break;
+
+    case SPR_MSSL: // Mini-missile
+        if(!P_GiveAmmo(player, am_missiles, 1))
+            return false;
+        break;
+
+    case SPR_ROKT: // Crate of missiles
+        if(!P_GiveAmmo(player, am_missiles, 5))
+            return false;
+        break;
+
+    case SPR_BRY1: // Battery cell
+        if(!P_GiveAmmo(player, am_cell, 1))
+            return false;
+        break;
+
+    case SPR_CPAC: // Cell pack
+        if(!P_GiveAmmo(player, am_cell, 5))
+            return false;
+        break;
+
+    case SPR_PQRL: // Poison bolts
+        if(!P_GiveAmmo(player, am_poisonbolts, 5))
+            return false;
+        break;
+
+    case SPR_XQRL: // Electric bolts
+        if(!P_GiveAmmo(player, am_elecbolts, 5))
+            return false;
+        break;
+
+    case SPR_GRN1: // HE Grenades
+        if(!P_GiveAmmo(player, am_hegrenades, 1))
+            return false;
+        break;
+
+    case SPR_GRN2: // WP Grenades
+        if(!P_GiveAmmo(player, am_wpgrenades, 1))
+            return false;
+        break;
+
+    case SPR_BKPK: // Backpack (aka Ammo Satchel)
+        if(!player->backpack)
+        {
+            for(i = 0; i < NUMAMMO; i++)
+                player->maxammo[i] *= 2;
+
+            player->backpack = true;
+        }
+        for(i = 0; i < NUMAMMO; i++)
+            P_GiveAmmo(player, i, 1);
+        break;
+
+    case SPR_RIFL: // Assault Rifle
+        if(player->weaponowned[wp_rifle])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_rifle, false))
+            return false;
+        
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_FLAM: // Flamethrower
+        if(player->weaponowned[wp_flame])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_flame, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_MMSL: // Mini-missile Launcher
+        if(player->weaponowned[wp_missile])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_missile, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_TRPD: // Mauler
+        if(player->weaponowned[wp_mauler])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_mauler, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
+        if(player->weaponowned[wp_elecbow])
+            return false;
+
+        if(!P_GiveWeapon(player, wp_elecbow, false))
+            return false;
+
+        sound = sfx_wpnup; // SHK-CHK!
+        break;
+
+    case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
+        switch(type)
+        {
+        case MT_KEY_HAND: // Severed hand
+            P_GiveCard(player, key_SeveredHand);
+            break;
+
+        case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
+            for(i = 0; i < 300; i++)
+                P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+            break;
+
+        case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
+            if(player->ammo[am_bullets] >= 50)
+                return false;
+
+            player->ammo[am_bullets] = 50;
+            break;
+
+        case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
+            if(!P_GiveBody(player, healthamounts[gameskill]))
+                return false;
+            break;
+
+        case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
+            P_NoiseAlert(player->mo, player->mo);
+            A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
+            break;
+
+        case MT_TOKEN_DOOR1: // Door special 1
+            junk.tag = 222;
+            EV_DoDoor(&junk, vld_open);
+            break;
+
+        case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
+            junk.tag = 223;
+            EV_DoDoor(&junk, vld_open);
+            if(gamemap == 2) // If on Tarnhill, give Prison pass object
+                P_GiveInventoryItem(player, sprnum, type);
+            break;
+
+        case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
+            junk.tag = 222;
+            EV_DoDoor(&junk, vld_close);
+            break;
+
+        case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P ) 
+            junk.tag = 224;
+            EV_DoDoor(&junk, vld_close);
+            break;
+
+        case MT_TOKEN_STAMINA: // Stamina upgrade
+            if(player->stamina >= 100)
+                return false;
+
+            player->stamina += 10;
+            P_GiveBody(player, 200); // full healing
+            break;
+
+        case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
+            if(player->accuracy >= 100)
+                return false;
+
+            player->accuracy += 10;
+            break;
+
+        case MT_SLIDESHOW: // Slideshow (start a finale)
+            gameaction = ga_victory;
+            if(gamemap == 10)
+                P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
+            break;
+        
+        default: // The default is to just give it as an inventory item.
+            P_GiveInventoryItem(player, sprnum, type);
+            break;
+        }
+        break;
+
+    default: // The ultimate default: Give it as an inventory item.
+        if(!P_GiveInventoryItem(player, sprnum, type))
+            return false;
+        break;
+    }
+
+    // Play sound.
+    if(player == &players[consoleplayer])
+        S_StartSound(NULL, sound);
+
+    return true;
+}
+
+//
+// P_TakeDialogItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Removes needed items from the player's inventory.
+//
+static void P_TakeDialogItem(player_t *player, int type, int amount)
+{
+    int i;
+
+    if(amount <= 0)
+        return;
+
+    for(i = 0; i < player->numinventory; i++)
+    {
+        // find a matching item
+        if(type != player->inventory[i].type)
+            continue;
+
+        // if there is none left...
+        if((player->inventory[i].amount -= amount) < 1)
+        {
+            // ...shift everything above it down
+            int j;
+
+            // BUG: They should have stopped at j < numinventory. This
+            // seems to implicitly assume that numinventory is always at
+            // least one less than the max # of slots, otherwise it 
+            // pulls in data from the following player_t fields:
+            // st_update, numinventory, inventorycursor, accuracy, stamina
+            for(j = i + 1; j <= player->numinventory; j++)
+            {
+                inventory_t *item1 = &(player->inventory[j - 1]);
+                inventory_t *item2 = &(player->inventory[j]);
+
+                *item1 = *item2;
+            }
+
+            // blank the topmost slot
+            // BUG: This will overwrite the aforementioned fields if
+            // numinventory is equal to the number of slots!
+            // STRIFE-TODO: Overflow emulation?
+            player->inventory[player->numinventory].type = NUMMOBJTYPES;
+            player->inventory[player->numinventory].sprite = -1;
+            player->numinventory--;
+
+            // update cursor position
+            if(player->inventorycursor >= player->numinventory)
+            {
+                if(player->inventorycursor)
+                    player->inventorycursor--;
+            }
+        } // end if
+        
+        return; // done!
+
+    } // end for
+}
+
+//
+// P_DialogDrawer
+//
+// This function is set as the drawer callback for the dialog menu.
+//
+static void P_DialogDrawer(void)
+{
+    angle_t angle;
+    int y;
+    int i;
+    int height;
+    int finaly;
+    char choicetext[64];
+    char choicetext2[64];
+
+    // Run down bonuscount faster than usual so that flashes from being given
+    // items are less obvious.
+    if(dialogplayer->bonuscount)
+    {
+        dialogplayer->bonuscount -= 3;
+        if(dialogplayer->bonuscount < 0)
+            dialogplayer->bonuscount = 0;
+    }
+
+    angle = R_PointToAngle2(dialogplayer->mo->x,
+                            dialogplayer->mo->y,
+                            dialogtalker->x,
+                            dialogtalker->y);
+    angle -= dialogplayer->mo->angle;
+
+    // Dismiss the dialog if the player is out of alignment, or the thing he was
+    // talking to is now engaged in battle.
+    if ((angle > ANG45 && angle < (ANG270+ANG45))
+     || (dialogtalker->flags & MF_NODIALOG) != 0)
+    {
+        P_DialogDoChoice(dialogmenu.numitems - 1);
+    }
+
+    dialogtalker->reactiontime = 2;
+
+    // draw background
+    if(dialogbgpiclumpnum != -1)
+    {
+        patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
+        V_DrawPatchDirect(0, 0, patch);
+    }
+
+    // if there's a valid background pic, delay drawing the rest of the menu 
+    // for a while; otherwise, it will appear immediately
+    if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
+    {
+        if(menuindialog)
+        {
+            // time to pause the game?
+            if(menupausetime + 3 < gametic)
+                menupause = true;
+        }
+
+        // draw character name
+        M_WriteText(12, 18, dialogname);
+        y = 28;
+
+        // show text (optional for dialogs with voices)
+        if(dialogshowtext || currentdialog->voice[0] == '\0')
+            y = M_WriteText(20, 28, dialogtext);
+
+        height = 20 * dialogmenu.numitems;
+
+        finaly = 175 - height;     // preferred height
+        if(y > finaly)
+            finaly = 199 - height; // height it will bump down to if necessary.
+
+        // draw divider
+        M_WriteText(42, finaly - 6, DEH_String("______________________________"));
+
+        dialogmenu.y = finaly + 6;
+        y = 0;
+
+        // draw the menu items
+        for(i = 0; i < dialogmenu.numitems - 1; i++)
+        {
+            DEH_snprintf(choicetext, sizeof(choicetext),
+                         "%d) %s", i + 1, currentdialog->choices[i].text);
+            
+            // alternate text for items that need money
+            if(currentdialog->choices[i].needamounts[0] > 0)
+            {
+                // haleyjd 20120401: necessary to avoid undefined behavior:
+                M_StringCopy(choicetext2, choicetext, sizeof(choicetext2));
+                DEH_snprintf(choicetext, sizeof(choicetext),
+                             "%s for %d", choicetext2,
+                             currentdialog->choices[i].needamounts[0]);
+            }
+
+            M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
+            y += 19;
+        }
+
+        // draw the final item for dismissing the dialog
+        M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
+    }
+}
+
+//
+// P_DialogDoChoice
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
+// callback for all items in the dialogmenu structure.
+//
+void P_DialogDoChoice(int choice)
+{
+    int i = 0, nextdialog = 0;
+    boolean candochoice = true;
+    char *message = NULL;
+    mapdlgchoice_t *currentchoice;
+
+    if(choice == -1)
+        choice = dialogmenu.numitems - 1;
+
+    currentchoice = &(currentdialog->choices[choice]);
+
+    I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe)
+
+    // villsa 09/08/10: converted into for loop
+    for(i = 0; i < MDLG_MAXITEMS; i++)
+    {
+        if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
+                                         currentchoice->needamounts[i])
+        {
+            candochoice = false; // nope, missing something
+        }
+    }
+
+    if(choice != dialogmenu.numitems - 1 && candochoice)
+    {
+        int item;
+
+        message = currentchoice->textok;
+        if(dialogtalkerstates->yes)
+            P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
+
+        item = currentchoice->giveitem;
+        if(item < 0 || 
+           P_GiveItemToPlayer(dialogplayer, 
+                              states[mobjinfo[item].spawnstate].sprite, 
+                              item))
+        {
+            // if successful, take needed items
+            int count = 0;
+            // villsa 09/08/10: converted into for loop
+            for(count = 0; count < MDLG_MAXITEMS; count++)
+            {
+                P_TakeDialogItem(dialogplayer, 
+                                 currentchoice->needitems[count],
+                                 currentchoice->needamounts[count]);
+            }
+        }
+        else
+            message = DEH_String("You seem to have enough!");
+
+        // store next dialog into the talking actor
+        nextdialog = currentchoice->next;
+        if(nextdialog != 0)
+            dialogtalker->miscdata = (byte)(abs(nextdialog));
+    }
+    else
+    {
+        // not successful
+        message = currentchoice->textno;
+        if(dialogtalkerstates->no)
+            P_SetMobjState(dialogtalker, dialogtalkerstates->no);
+    }
+    
+    if(choice != dialogmenu.numitems - 1)
+    {
+        int objective;
+        char *objlump;
+
+        if((objective = currentchoice->objective))
+        {
+            DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
+            objlump = W_CacheLumpName(mission_objective, PU_CACHE);
+            M_StringCopy(mission_objective, objlump, OBJECTIVE_LEN);
+        }
+        // haleyjd 20130301: v1.31 hack: if first char of message is a period,
+        // clear the player's message. Is this actually used anywhere?
+        if(gameversion == exe_strife_1_31 && message[0] == '.')
+            message = NULL;
+        dialogplayer->message = message;
+    }
+
+    dialogtalker->angle = dialogtalkerangle;
+    dialogplayer->st_update = true;
+    M_ClearMenus(0);
+
+    if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
+        menuindialog = false;
+    else
+        P_DialogStart(dialogplayer);
+}
+
+//
+// P_DialogStartP1
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is a hack used by the finale system.
+//
+void P_DialogStartP1(void)
+{
+    P_DialogStart(&players[0]);
+}
+
+//
+// P_DialogStart
+//
+// villsa [STRIFE] New function
+//
+void P_DialogStart(player_t *player)
+{
+    int i = 0;
+    int pic;
+    int rnd = 0;
+    char* byetext;
+    int jumptoconv;
+
+    if(menuactive || netgame)
+        return;
+
+    // are we facing towards our NPC?
+    P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
+    if(!linetarget)
+    {
+        P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
+        if(!linetarget)
+            P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
+    }
+
+    if(!linetarget)
+       return;
+
+    // already in combat, can't talk to it
+    if(linetarget->flags & MF_NODIALOG)
+       return;
+
+    // set pointer to the character talking
+    dialogtalker = linetarget;
+
+    // play a sound
+    if(player == &players[consoleplayer])
+       S_StartSound(0, sfx_radio);
+
+    linetarget->target = player->mo;         // target the player
+    dialogtalker->reactiontime = 2;          // set reactiontime
+    dialogtalkerangle = dialogtalker->angle; // remember original angle
+
+    // face talker towards player
+    A_FaceTarget(dialogtalker);
+
+    // face towards NPC's direction
+    player->mo->angle = R_PointToAngle2(player->mo->x,
+                                        player->mo->y,
+                                        dialogtalker->x,
+                                        dialogtalker->y);
+    // set pointer to player talking
+    dialogplayer = player;
+
+    // haleyjd 09/08/10: get any stored dialog state from this object
+    jumptoconv = linetarget->miscdata;
+
+    // check item requirements
+    while(1)
+    {
+        int i = 0;
+        currentdialog = P_DialogFind(linetarget->type, jumptoconv);
+
+        // dialog's jumptoconv equal to 0? There's nothing to jump to.
+        if(currentdialog->jumptoconv == 0)
+            break;
+
+        // villsa 09/08/10: converted into for loop
+        for(i = 0; i < MDLG_MAXITEMS; i++)
+        {
+            // if the item is non-zero, the player must have at least one in his
+            // or her inventory
+            if(currentdialog->checkitem[i] != 0 &&
+                P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
+                break;
+        }
+
+        if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
+            break;
+
+        jumptoconv = currentdialog->jumptoconv;
+    }
+
+    M_DialogDimMsg(20, 28, currentdialog->text, false);
+    dialogtext = P_DialogGetMsg(currentdialog->text);
+
+    // get states
+    dialogtalkerstates = P_DialogGetStates(linetarget->type);
+
+    // have talker greet the player
+    if(dialogtalkerstates->greet)
+        P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
+
+    // get talker's name
+    if(currentdialog->name[0])
+        dialogname = currentdialog->name;
+    else
+    {
+        // use a fallback:
+        if(mobjinfo[linetarget->type].name)
+            dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
+        else
+            dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
+    }
+
+    // setup number of choices to choose from
+    for(i = 0; i < MDLG_MAXCHOICES; i++)
+    {
+        if(!currentdialog->choices[i].giveitem)
+            break;
+    }
+
+    // set number of choices to menu
+    dialogmenu.numitems = i + 1;
+
+    rnd = M_Random() % 3;
+
+    // setup dialog menu
+    M_StartControlPanel();
+    menupause = false;
+    menuindialog = true;
+    menupausetime = gametic + 17;
+    currentMenu = &dialogmenu;
+
+    if(i >= dialogmenu.lastOn)
+        itemOn = dialogmenu.lastOn;
+    else
+        itemOn = 0;
+
+    // get backdrop
+    pic = W_CheckNumForName(currentdialog->backpic);
+    dialogbgpiclumpnum = pic;
+    if(pic != -1)
+        V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
+
+    // get voice
+    I_StartVoice(currentdialog->voice);
+
+    // get bye text
+    switch(rnd)
+    {
+    case 2:
+        byetext = DEH_String("BYE!");
+        break;
+    case 1:
+        byetext = DEH_String("Thanks, Bye!");
+        break;
+    default:
+    case 0:
+        byetext = DEH_String("See you later!");
+        break;
+    }
+
+    DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
+                 "%d) %s", i + 1, byetext);
+}
+
+// EOF
+
+
--- a/src/strife/p_dialog.h
+++ b/src/strife/p_dialog.h
@@ -1,102 +1,102 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
-// Copyright(C) 2010 James Haley, Samuel Villareal
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// 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.
-//
-// DESCRIPTION:
-//
-// [STRIFE] New Module
-//
-// Dialog Engine for Strife
-//
-
-#ifndef P_DIALOG_H__
-#define P_DIALOG_H__
-
-#define OBJECTIVE_LEN       300
-
-#define MAXINVENTORYSLOTS   30
-
-#define MDLG_CHOICELEN      32
-#define MDLG_MSGLEN         80
-#define MDLG_NAMELEN        16
-#define MDLG_LUMPLEN        8
-#define MDLG_TEXTLEN        320
-#define MDLG_MAXCHOICES     5
-#define MDLG_MAXITEMS       3
-
-extern char mission_objective[OBJECTIVE_LEN];
-
-extern int dialogshowtext;
-
-// villsa - convenient macro for giving objective logs to player
-#define GiveObjective(x, minlumpnum) \
-do { \
-  int obj_ln  = W_CheckNumForName(DEH_String(x)); \
-  if(obj_ln > minlumpnum) \
-    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
-                 OBJECTIVE_LEN);\
-} while(0)
-
-// haleyjd - voice and objective in one
-#define GiveVoiceObjective(voice, log, minlumpnum) \
-do { \
-  int obj_ln = W_CheckNumForName(DEH_String(log)); \
-  I_StartVoice(DEH_String(voice)); \
-  if(obj_ln > minlumpnum) \
-    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
-                 OBJECTIVE_LEN);\
-} while(0)
-
-typedef struct mapdlgchoice_s
-{
-    int  giveitem;                      // item given when successful
-    int  needitems[MDLG_MAXITEMS];      // item needed for success
-    int  needamounts[MDLG_MAXITEMS];    // amount of items needed
-    char text[MDLG_CHOICELEN];          // normal text
-    char textok[MDLG_MSGLEN];           // message given on success
-    int next;                           // next dialog?
-    int objective;                      // ???
-    char textno[MDLG_MSGLEN];           // message given on failure
-} mapdlgchoice_t;
-
-typedef struct mapdialog_s
-{
-    int speakerid;                      // script ID# for mobjtype that will use this dialog
-    int dropitem;                       // item to drop if that thingtype is killed
-    int checkitem[MDLG_MAXITEMS];       // item(s) needed to see this dialog
-    int jumptoconv;                     // conversation to jump to when... ?
-    char name[MDLG_NAMELEN];            // name of speaker
-    char voice[MDLG_LUMPLEN];           // voice file to play
-    char backpic[MDLG_LUMPLEN];         // backdrop pic for character, if any
-    char text[MDLG_TEXTLEN];            // main message text
-    
-    // options that this dialog gives the player
-    mapdlgchoice_t choices[MDLG_MAXCHOICES];
-} mapdialog_t;
-
-void         P_DialogLoad(void);
-void         P_DialogStart(player_t *player);
-void         P_DialogDoChoice(int choice);
-boolean      P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
-boolean      P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
-boolean      P_UseInventoryItem(player_t* player, int item);
-void         P_DialogStartP1(void);
-mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
-int          P_PlayerHasItem(player_t *player, mobjtype_t type);
-
-#endif
-
-// EOF
-
-
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// 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.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+
+#ifndef P_DIALOG_H__
+#define P_DIALOG_H__
+
+#define OBJECTIVE_LEN       300
+
+#define MAXINVENTORYSLOTS   30
+
+#define MDLG_CHOICELEN      32
+#define MDLG_MSGLEN         80
+#define MDLG_NAMELEN        16
+#define MDLG_LUMPLEN        8
+#define MDLG_TEXTLEN        320
+#define MDLG_MAXCHOICES     5
+#define MDLG_MAXITEMS       3
+
+extern char mission_objective[OBJECTIVE_LEN];
+
+extern int dialogshowtext;
+
+// villsa - convenient macro for giving objective logs to player
+#define GiveObjective(x, minlumpnum) \
+do { \
+  int obj_ln  = W_CheckNumForName(DEH_String(x)); \
+  if(obj_ln > minlumpnum) \
+    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
+                 OBJECTIVE_LEN);\
+} while(0)
+
+// haleyjd - voice and objective in one
+#define GiveVoiceObjective(voice, log, minlumpnum) \
+do { \
+  int obj_ln = W_CheckNumForName(DEH_String(log)); \
+  I_StartVoice(DEH_String(voice)); \
+  if(obj_ln > minlumpnum) \
+    M_StringCopy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), \
+                 OBJECTIVE_LEN);\
+} while(0)
+
+typedef struct mapdlgchoice_s
+{
+    int  giveitem;                      // item given when successful
+    int  needitems[MDLG_MAXITEMS];      // item needed for success
+    int  needamounts[MDLG_MAXITEMS];    // amount of items needed
+    char text[MDLG_CHOICELEN];          // normal text
+    char textok[MDLG_MSGLEN];           // message given on success
+    int next;                           // next dialog?
+    int objective;                      // ???
+    char textno[MDLG_MSGLEN];           // message given on failure
+} mapdlgchoice_t;
+
+typedef struct mapdialog_s
+{
+    int speakerid;                      // script ID# for mobjtype that will use this dialog
+    int dropitem;                       // item to drop if that thingtype is killed
+    int checkitem[MDLG_MAXITEMS];       // item(s) needed to see this dialog
+    int jumptoconv;                     // conversation to jump to when... ?
+    char name[MDLG_NAMELEN];            // name of speaker
+    char voice[MDLG_LUMPLEN];           // voice file to play
+    char backpic[MDLG_LUMPLEN];         // backdrop pic for character, if any
+    char text[MDLG_TEXTLEN];            // main message text
+    
+    // options that this dialog gives the player
+    mapdlgchoice_t choices[MDLG_MAXCHOICES];
+} mapdialog_t;
+
+void         P_DialogLoad(void);
+void         P_DialogStart(player_t *player);
+void         P_DialogDoChoice(int choice);
+boolean      P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
+boolean      P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
+boolean      P_UseInventoryItem(player_t* player, int item);
+void         P_DialogStartP1(void);
+mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
+int          P_PlayerHasItem(player_t *player, mobjtype_t type);
+
+#endif
+
+// EOF
+
+
--- a/src/strife/p_plats.c
+++ b/src/strife/p_plats.c
@@ -325,13 +325,15 @@
     int i;
 
     for(i = 0; i < MAXPLATS; i++)
+    {
         if (activeplats[i] == NULL)
         {
             activeplats[i] = plat;
             return;
         }
+    }
 
-        I_Error("P_AddActivePlat: no more plats!");
+    I_Error("P_AddActivePlat: no more plats!");
 }
 
 //
@@ -341,6 +343,7 @@
 {
     int i;
     for(i = 0; i < MAXPLATS; i++)
+    {
         if(plat == activeplats[i])
         {
             (activeplats[i])->sector->specialdata = NULL;
@@ -349,6 +352,7 @@
 
             return;
         }
+    }
 
-        I_Error("P_RemoveActivePlat: can't find plat!");
+    I_Error("P_RemoveActivePlat: can't find plat!");
 }