shithub: choc

Download patch

ref: 1430facdb3ae25a92d515bc1daf71c860ef20f1e
parent: 42445b60eda121966524c4533d070c56f69e1844
parent: f30f390e513e456c2bdec64726469a50097e4371
author: Simon Howard <fraggle@soulsphere.org>
date: Thu Jun 4 17:07:07 EDT 2015

Merge branch 'master' into sdl2-branch

Conflicts:
	src/i_video.c
	src/setup/display.c
	textscreen/txt_sdl.c

--- a/HACKING
+++ b/HACKING
@@ -64,11 +64,15 @@
 void FunctionName(int argument, int arg2, int arg3, int arg4, int arg5,
                   int arg6, int arg7)
 {
-    if (condition)
+    int assign_var;
+
+    assign_var = arg2 + arg3 * arg4 * (arg5 + arg6);
+
+    if (foo && !bar || baz && qux || !(foo && bar && baz))
     {
         body;
     }
-    else if (condition)
+    else if (xyz + 4 < abc * 4 + 3)
     {
         body;
     }
@@ -97,9 +101,10 @@
             break;
     }
 
-    for (a=0; a<10; ++a)
+    for (a = 0; a < 10; ++a)
     {
-        loop_body;
+        FunctionCall(arg1, arg2, arg3, arg4,
+                     arg_split_onto_second_line);
     }
 
     while (a < 10)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,119 @@
 
+2.2.0 (2015-05-??):
+
+     * 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
--- a/PHILOSOPHY
+++ b/PHILOSOPHY
@@ -155,15 +155,8 @@
 other hand, painstakingly emulating Vanilla Doom by starting with no
 sound or music by default is not helpful to anyone.
 
-== Other philosophical aspects ==
+== Minimalism ==
 
-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.
-
 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
@@ -179,6 +172,29 @@
 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
 
--- a/codeblocks/doom.cbp
+++ b/codeblocks/doom.cbp
@@ -114,6 +114,9 @@
 		<Unit filename="../src/doom/deh_ammo.c">
 			<Option compilerVar="CC" />
 		</Unit>
+		<Unit filename="../src/doom/deh_bexstr.c">
+			<Option compilerVar="CC" />
+		</Unit>
 		<Unit filename="../src/doom/deh_cheat.c">
 			<Option compilerVar="CC" />
 		</Unit>
--- a/configure.ac
+++ b/configure.ac
@@ -94,7 +94,7 @@
     AC_CHECK_LIB(m, log)
 
     AC_CHECK_HEADERS([linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h])
-    AC_CHECK_FUNCS(mmap sched_setaffinity ioperm)
+    AC_CHECK_FUNCS(mmap ioperm)
 
     # OpenBSD I/O i386 library for I/O port access.
     # (64 bit has the same thing with a different name!)
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -14,9 +14,9 @@
              @PROGRAM_PREFIX@setup.png
 
 @PROGRAM_PREFIX@doom.png : doom.png
-	cp doom.png $@
+	cp $(top_srcdir)/data/doom.png $@
 
 @PROGRAM_PREFIX@setup.png : setup.png
-	cp setup.png $@
+	cp $(top_srcdir)/data/setup.png $@
 
 CLEANFILES = $(icons_DATA)
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -47,85 +47,87 @@
 CLEANFILES = $(GENERATED_MAN_PAGES) $(SETUP_MAN_PAGES) \
              $(doomdocs_DATA) $(hereticdocs_DATA) \
              $(hexendocs_DATA) $(strifedocs_DATA)
+MANDIR = $(top_srcdir)/man
+DOCGEN = $(MANDIR)/docgen
 
 $(SETUP_MAN_PAGES): chocolate-setup.6
 	cp $< $@
 
 @PROGRAM_PREFIX@doom.6: ../src $(MANPAGE_GEN_FILES)
-	./docgen -g doom -m doom.template ../src ../src/doom > $@
+	$(DOCGEN) -g doom -m doom.template $(top_srcdir)/src $(top_srcdir)/src/doom > $@
 
-default.cfg.5: ../src default.cfg.template
-	./docgen -g doom -m default.cfg.template \
-                 -c default ../src/m_config.c > $@
+default.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template
+	$(DOCGEN) -g doom -m $(MANDIR)/default.cfg.template \
+                 -c default $(top_srcdir)/src/m_config.c > $@
 
 @PROGRAM_PREFIX@doom.cfg.5: ../src extra.cfg.template
-	./docgen -g doom -m extra.cfg.template \
-                 -c extended ../src/m_config.c > $@
+	$(DOCGEN) -g doom -m extra.cfg.template \
+                 -c extended $(top_srcdir)/src/m_config.c > $@
 
-CMDLINE.doom : CMDLINE.template ../src ../src/doom
-	./docgen -p CMDLINE.template ../src/ ../src/doom/ > $@
+CMDLINE.doom : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/doom
+	$(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/doom/ > $@
 
-INSTALL.doom: INSTALL.template
-	./simplecpp -DDOOM -DPRECOMPILED < INSTALL.template > $@
+INSTALL.doom: $(MANDIR)/INSTALL.template
+	$(MANDIR)/simplecpp -DDOOM -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@
 
 
-@PROGRAM_PREFIX@heretic.6: ../src $(MANPAGE_GEN_FILES)
-	./docgen -g heretic -m heretic.template ../src ../src/heretic > $@
+@PROGRAM_PREFIX@heretic.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES)
+	$(DOCGEN) -g heretic -m $(top_srcdir)/man/heretic.template $(top_srcdir)/src $(top_srcdir)/src/heretic > $@
 
-heretic.cfg.5: ../src default.cfg.template
-	./docgen -g heretic -m default.cfg.template \
-                 -c default ../src/m_config.c > $@
+heretic.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template
+	$(DOCGEN) -g heretic -m $(MANDIR)/default.cfg.template \
+                 -c default $(top_srcdir)/src/m_config.c > $@
 
-@PROGRAM_PREFIX@heretic.cfg.5: ../src extra.cfg.template
-	./docgen -g heretic -m extra.cfg.template \
-                 -c extended ../src/m_config.c > $@
+@PROGRAM_PREFIX@heretic.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template
+	$(DOCGEN) -g heretic -m $(MANDIR)/extra.cfg.template \
+                 -c extended $(top_srcdir)/src/m_config.c > $@
 
-CMDLINE.heretic : CMDLINE.template ../src ../src/heretic
-	./docgen -p CMDLINE.template ../src/ ../src/heretic/ > $@
+CMDLINE.heretic : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/heretic
+	$(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/heretic/ > $@
 
-INSTALL.heretic: INSTALL.template
-	./simplecpp -DHERETIC -DPRECOMPILED < INSTALL.template > $@
+INSTALL.heretic: $(MANDIR)/INSTALL.template
+	$(MANDIR)/simplecpp -DHERETIC -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@
 
 
-@PROGRAM_PREFIX@hexen.6: ../src $(MANPAGE_GEN_FILES)
-	./docgen -g hexen -m hexen.template ../src ../src/hexen > $@
+@PROGRAM_PREFIX@hexen.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES)
+	$(DOCGEN) -g hexen -m $(MANDIR)/hexen.template $(top_srcdir)/src $(top_srcdir)/src/hexen > $@
 
-hexen.cfg.5: ../src default.cfg.template
-	./docgen -g hexen -m default.cfg.template \
-                 -c default ../src/m_config.c > $@
+hexen.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template
+	$(DOCGEN) -g hexen -m $(MANDIR)/default.cfg.template \
+                 -c default $(top_srcdir)/src/m_config.c > $@
 
-@PROGRAM_PREFIX@hexen.cfg.5: ../src extra.cfg.template
-	./docgen -g hexen -m extra.cfg.template \
-                 -c extended ../src/m_config.c > $@
+@PROGRAM_PREFIX@hexen.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template
+	$(DOCGEN) -g hexen -m $(MANDIR)/extra.cfg.template \
+                 -c extended $(top_srcdir)/src/m_config.c > $@
 
-CMDLINE.hexen : CMDLINE.template ../src ../src/hexen
-	./docgen -p CMDLINE.template ../src/ ../src/hexen/ > $@
+CMDLINE.hexen : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/hexen
+	$(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/hexen/ > $@
 
-INSTALL.hexen: INSTALL.template
-	./simplecpp -DHEXEN -DPRECOMPILED < INSTALL.template > $@
+INSTALL.hexen: $(MANDIR)/INSTALL.template
+	$(MANDIR)/simplecpp -DHEXEN -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@
 
 
-@PROGRAM_PREFIX@strife.6: ../src $(MANPAGE_GEN_FILES)
-	./docgen -g strife -m strife.template ../src ../src/strife > $@
+@PROGRAM_PREFIX@strife.6: $(top_srcdir)/src $(MANPAGE_GEN_FILES)
+	$(DOCGEN) -g strife -m $(MANDIR)/strife.template $(top_srcdir)/src $(top_srcdir)/src/strife > $@
 
-strife.cfg.5: ../src default.cfg.template
-	./docgen -g strife -m default.cfg.template \
-                 -c default ../src/m_config.c > $@
+strife.cfg.5: $(top_srcdir)/src $(MANDIR)/default.cfg.template
+	$(DOCGEN) -g strife -m $(MANDIR)/default.cfg.template \
+                 -c default $(top_srcdir)/src/m_config.c > $@
 
-@PROGRAM_PREFIX@strife.cfg.5: ../src extra.cfg.template
-	./docgen -g strife -m extra.cfg.template \
-                 -c extended ../src/m_config.c > $@
+@PROGRAM_PREFIX@strife.cfg.5: $(top_srcdir)/src $(MANDIR)/extra.cfg.template
+	$(DOCGEN) -g strife -m $(MANDIR)/extra.cfg.template \
+                 -c extended $(top_srcdir)/src/m_config.c > $@
 
-CMDLINE.strife : CMDLINE.template ../src ../src/strife
-	./docgen -p CMDLINE.template ../src/ ../src/strife/ > $@
+CMDLINE.strife : $(MANDIR)/CMDLINE.template $(top_srcdir)/src $(top_srcdir)/src/strife
+	$(DOCGEN) -p $(MANDIR)/CMDLINE.template $(top_srcdir)/src/ $(top_srcdir)/src/strife/ > $@
 
 INSTALL.strife: INSTALL.template
-	./simplecpp -DSTRIFE -DPRECOMPILED < INSTALL.template > $@
+	$(MANDIR)/simplecpp -DSTRIFE -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@
 
 
-INSTALL: INSTALL.template
-	./simplecpp -DDOOM -DHERETIC -DHEXEN -DSTRIFE \
-	            -DPRECOMPILED < INSTALL.template > $@
+INSTALL: $(MANDIR)/INSTALL.template
+	$(MANDIR)//simplecpp -DDOOM -DHERETIC -DHEXEN -DSTRIFE \
+	            -DPRECOMPILED < $(MANDIR)/INSTALL.template > $@
 
 endif
 
--- a/man/chocolate-server.6
+++ b/man/chocolate-server.6
@@ -13,7 +13,7 @@
 is a dedicated server for Chocolate Doom. It is equivalent to 
 running 
 .B chocolate\-doom
-with the "-dedicated" option.
+with the "\-dedicated" option.
 .PP
 Game options are not specified to the server, which merely acts to
 retransmit data between players in the game; parameters for the
--- a/man/docgen
+++ b/man/docgen
@@ -425,6 +425,8 @@
     for t in targets:
         content += t.manpage_output() + "\n"
 
+    content = content.replace("-", "\\-")
+
     print_template(template_file, content)
 
 def wiki_output(targets, template):
--- a/man/environ.man
+++ b/man/environ.man
@@ -1,7 +1,7 @@
 .TP
 \fBDOOMWADDIR\fR, \fBDOOMWADPATH\fR
 These environment variables provide paths to search for Doom .WAD files when
-looking for a game IWAD file or a PWAD file specified with the `-file' option.
+looking for a game IWAD file or a PWAD file specified with the `\-file' option.
 \fBDOOMWADDIR\fR specifies a single path in which to look for WAD files,
 while \fBDOOMWWADPATH\fR specifies a colon-separated list of paths to search.
 .TP
--- a/opl/examples/Makefile.am
+++ b/opl/examples/Makefile.am
@@ -1,5 +1,5 @@
 
-AM_CFLAGS = -I..
+AM_CFLAGS = -I$(top_srcdir)/opl
 
 noinst_PROGRAMS=droplay
 
--- a/opl/examples/droplay.c
+++ b/opl/examples/droplay.c
@@ -19,6 +19,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "SDL.h"
 
--- a/opl/opl.c
+++ b/opl/opl.c
@@ -67,6 +67,8 @@
 
 static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
 {
+    int result1, result2;
+
     // Initialize the driver.
 
     if (!_driver->init_func(port_base))
@@ -82,7 +84,9 @@
     driver = _driver;
     init_stage_reg_writes = 1;
 
-    if (!OPL_Detect() || !OPL_Detect())
+    result1 = OPL_Detect();
+    result2 = OPL_Detect();
+    if (!result1 || !result2)
     {
         printf("OPL_Init: No OPL detected using '%s' driver.\n", _driver->name);
         _driver->shutdown_func();
@@ -90,15 +94,11 @@
         return 0;
     }
 
-    // Initialize all registers.
-
-    OPL_InitRegisters();
-
     init_stage_reg_writes = 0;
 
     printf("OPL_Init: Using driver '%s'.\n", driver->name);
 
-    return 1;
+    return result2;
 }
 
 // Find a driver automatically by trying each in the list.
@@ -106,12 +106,14 @@
 static int AutoSelectDriver(unsigned int port_base)
 {
     int i;
+    int result;
 
     for (i=0; drivers[i] != NULL; ++i)
     {
-        if (InitDriver(drivers[i], port_base))
+        result = InitDriver(drivers[i], port_base);
+        if (result)
         {
-            return 1;
+            return result;
         }
     }
 
@@ -127,6 +129,7 @@
 {
     char *driver_name;
     int i;
+    int result;
 
     driver_name = getenv("OPL_DRIVER");
 
@@ -138,9 +141,10 @@
         {
             if (!strcmp(driver_name, drivers[i]->name))
             {
-                if (InitDriver(drivers[i], port_base))
+                result = InitDriver(drivers[i], port_base);
+                if (result)
                 {
-                    return 1;
+                    return result;
                 }
                 else
                 {
@@ -233,7 +237,14 @@
 {
     int i;
 
-    OPL_WritePort(OPL_REGISTER_PORT, reg);
+    if (reg & 0x100)
+    {
+        OPL_WritePort(OPL_REGISTER_PORT_OPL3, reg);
+    }
+    else
+    {
+        OPL_WritePort(OPL_REGISTER_PORT, reg);
+    }
 
     // For timing, read the register port six times after writing the
     // register number to cause the appropriate delay
@@ -306,13 +317,22 @@
     // Enable interrupts:
     OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
 
-    return (result1 & 0xe0) == 0x00
-        && (result2 & 0xe0) == 0xc0;
+    if ((result1 & 0xe0) == 0x00 && (result2 & 0xe0) == 0xc0)
+    {
+        result1 = OPL_ReadPort(OPL_REGISTER_PORT);
+        result2 = OPL_ReadPort(OPL_REGISTER_PORT_OPL3);
+        if (result1 == 0x00)
+        {
+            return 2;
+        }
+        return 1;
+    }
+    return 0;
 }
 
 // Initialize registers on startup
 
-void OPL_InitRegisters(void)
+void OPL_InitRegisters(int opl3)
 {
     int r;
 
@@ -349,8 +369,42 @@
     // "Allow FM chips to control the waveform of each operator":
     OPL_WriteRegister(OPL_REG_WAVEFORM_ENABLE, 0x20);
 
+    if (opl3)
+    {
+        OPL_WriteRegister(OPL_REG_NEW, 0x01);
+
+        // Initialize level registers
+
+        for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
+        {
+            OPL_WriteRegister(r | 0x100, 0x3f);
+        }
+
+        // Initialize other registers
+        // These two loops write to registers that actually don't exist,
+        // but this is what Doom does ...
+        // Similarly, the <= is also intenational.
+
+        for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r)
+        {
+            OPL_WriteRegister(r | 0x100, 0x00);
+        }
+
+        // More registers ...
+
+        for (r=1; r < OPL_REGS_LEVEL; ++r)
+        {
+            OPL_WriteRegister(r | 0x100, 0x00);
+        }
+    }
+
     // Keyboard split point on (?)
     OPL_WriteRegister(OPL_REG_FM_MODE,         0x40);
+
+    if (opl3)
+    {
+        OPL_WriteRegister(OPL_REG_NEW, 0x01);
+    }
 }
 
 //
--- a/opl/opl.h
+++ b/opl/opl.h
@@ -26,7 +26,8 @@
 typedef enum
 {
     OPL_REGISTER_PORT = 0,
-    OPL_DATA_PORT = 1
+    OPL_DATA_PORT = 1,
+    OPL_REGISTER_PORT_OPL3 = 2
 } opl_port_t;
 
 #define OPL_NUM_OPERATORS   21
@@ -37,6 +38,7 @@
 #define OPL_REG_TIMER2            0x03
 #define OPL_REG_TIMER_CTRL        0x04
 #define OPL_REG_FM_MODE           0x08
+#define OPL_REG_NEW               0x105
 
 // Operator registers (21 of each):
 
@@ -101,7 +103,7 @@
 
 // Initialize all registers, performed on startup.
 
-void OPL_InitRegisters(void);
+void OPL_InitRegisters(int opl3);
 
 //
 // Timer callback functions.
--- a/opl/opl_sdl.c
+++ b/opl/opl_sdl.c
@@ -71,6 +71,7 @@
 // OPL software emulator structure.
 
 static Chip opl_chip;
+static int opl_opl3mode;
 
 // Temporary mixing buffer used by the mixing callback.
 
@@ -164,14 +165,29 @@
 
     assert(nsamples < mixing_freq);
 
-    Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
+    if (opl_opl3mode)
+    {
+        Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer);
 
-    // Mix into the destination buffer, doubling up into stereo.
+        // Mix into the destination buffer, doubling up into stereo.
 
-    for (i=0; i<nsamples; ++i)
+        for (i=0; i<nsamples; ++i)
+        {
+            buffer[i * 2] = (int16_t) mix_buffer[i * 2];
+            buffer[i * 2 + 1] = (int16_t) mix_buffer[i * 2 + 1];
+        }
+    }
+    else
     {
-        buffer[i * 2] = (int16_t) mix_buffer[i];
-        buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
+        Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
+
+        // Mix into the destination buffer, doubling up into stereo.
+
+        for (i=0; i<nsamples; ++i)
+        {
+            buffer[i * 2] = (int16_t) mix_buffer[i];
+            buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
+        }
     }
 }
 
@@ -351,7 +367,7 @@
 
     // Mix buffer:
 
-    mix_buffer = malloc(mixing_freq * sizeof(uint32_t));
+    mix_buffer = malloc(mixing_freq * sizeof(uint32_t) * 2);
 
     // Create the emulator structure:
 
@@ -358,6 +374,7 @@
     DBOPL_InitTables();
     Chip__Chip(&opl_chip);
     Chip__Setup(&opl_chip, mixing_freq);
+    opl_opl3mode = 0;
 
     callback_mutex = SDL_CreateMutex();
     callback_queue_mutex = SDL_CreateMutex();
@@ -372,6 +389,11 @@
 {
     unsigned int result = 0;
 
+    if (port == OPL_REGISTER_PORT_OPL3)
+    {
+        return 0xff;
+    }
+
     if (timer1.enabled && current_time > timer1.expire_time)
     {
         result |= 0x80;   // Either have expired
@@ -439,6 +461,9 @@
 
             break;
 
+        case OPL_REG_NEW:
+            opl_opl3mode = value & 0x01;
+
         default:
             Chip__WriteReg(&opl_chip, reg_num, value);
             break;
@@ -450,6 +475,10 @@
     if (port == OPL_REGISTER_PORT)
     {
         register_num = value;
+    }
+    else if (port == OPL_REGISTER_PORT_OPL3)
+    {
+        register_num = value | 0x100;
     }
     else if (port == OPL_DATA_PORT)
     {
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,9 +18,9 @@
 
 execgames_SCRIPTS = $(SETUP_BINARIES)
 
-AM_CFLAGS = -I$(top_builddir)/textscreen            \
-            -I$(top_builddir)/opl                   \
-            -I$(top_builddir)/pcsound               \
+AM_CFLAGS = -I$(top_srcdir)/textscreen            \
+            -I$(top_srcdir)/opl                   \
+            -I$(top_srcdir)/pcsound               \
             @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 # Common source files used by absolutely everything:
--- a/src/aes_prng.c
+++ b/src/aes_prng.c
@@ -20,920 +20,868 @@
 // effective PRNG (see: Empirical Evidence concerning AES, Hellekalek
 // & Wegenkittl, 2003).
 //
-// The AES implementation is from GnuPG. Original copyright notice is
-// below.
+// AES implementation is taken from the Linux kernel's AES
+// implementation, found in crypto/aes_generic.c. It has been hacked
+// up to work independently.
 //
 
-/* Rijndael (AES) for GnuPG
- *	Copyright (C) 2000, 2001, 2008 Free Software Foundation, Inc.
+#include <stdint.h>
+
+#include "aes_prng.h"
+#include "doomtype.h"
+#include "i_swap.h"
+
+/*
+ * Cryptographic API.
  *
- * This file is part of GnuPG.
+ * AES Cipher Algorithm.
  *
- * GnuPG is free software; you can redistribute it and/or modify
+ * Based on Brian Gladman's code.
+ *
+ * Linux developers:
+ *  Alexander Kjeldaas <astor@fast.no>
+ *  Herbert Valerio Riedel <hvr@hvrlab.org>
+ *  Kyle McMartin <kyle@debian.org>
+ *  Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
+ *
+ * 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 3 of the License, or
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GnuPG 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.
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ * All rights reserved.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *******************************************************************
- * The code here is based on the optimized implementation taken from
- * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000,
- * which carries this notice:
- *------------------------------------------
- * rijndael-alg-fst.c   v2.3   April '2000
+ * LICENSE TERMS
  *
- * Optimised ANSI C code
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
  *
- * authors: v1.0: Antoon Bosselaers
- *          v2.0: Vincent Rijmen
- *          v2.3: Paulo Barreto
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
  *
- * This code is placed in the public domain.
- *------------------------------------------
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
  */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> /* for memcmp() */
 
-#include "aes_prng.h"
-#include "doomtype.h"
-#include "i_system.h"
+#define AES_MIN_KEY_SIZE        16
+#define AES_MAX_KEY_SIZE        32
+#define AES_KEYSIZE_128         16
+#define AES_KEYSIZE_192         24
+#define AES_KEYSIZE_256         32
+#define AES_BLOCK_SIZE          16
+#define AES_MAX_KEYLENGTH       (15 * 16)
+#define AES_MAX_KEYLENGTH_U32   (AES_MAX_KEYLENGTH / sizeof(uint32_t))
 
-#define MAXKC			(256/32)
-#define MAXROUNDS		14
-
-
+/*
+ * Please ensure that the first two fields are 16-byte aligned
+ * relative to the start of the structure, i.e., don't move them!
+ */
 typedef struct
 {
-    int  ROUNDS;                   /* key-length-dependent number of rounds */
-    uint32_t keySched[MAXROUNDS+1][4];	/* key schedule		*/
-} RIJNDAEL_context;
+    uint32_t key_enc[AES_MAX_KEYLENGTH_U32];
+    uint32_t key_dec[AES_MAX_KEYLENGTH_U32];
+    uint32_t key_length;
+} aes_context_t;
 
-static const byte S[256] =
+static inline uint8_t get_byte(const uint32_t x, const unsigned n)
 {
-    99, 124, 119, 123, 242, 107, 111, 197,
-    48,   1, 103,  43, 254, 215, 171, 118,
-    202, 130, 201, 125, 250,  89,  71, 240,
-    173, 212, 162, 175, 156, 164, 114, 192,
-    183, 253, 147,  38,  54,  63, 247, 204,
-    52, 165, 229, 241, 113, 216,  49,  21,
-    4, 199,  35, 195,  24, 150,   5, 154,
-    7,  18, 128, 226, 235,  39, 178, 117,
-    9, 131,  44,  26,  27, 110,  90, 160,
-    82,  59, 214, 179,  41, 227,  47, 132,
-    83, 209,   0, 237,  32, 252, 177,  91,
-    106, 203, 190,  57,  74,  76,  88, 207,
-    208, 239, 170, 251,  67,  77,  51, 133,
-    69, 249,   2, 127,  80,  60, 159, 168,
-    81, 163,  64, 143, 146, 157,  56, 245,
-    188, 182, 218,  33,  16, 255, 243, 210,
-    205,  12,  19, 236,  95, 151,  68,  23,
-    196, 167, 126,  61, 100,  93,  25, 115,
-    96, 129,  79, 220,  34,  42, 144, 136,
-    70, 238, 184,  20, 222,  94,  11, 219,
-    224,  50,  58,  10,  73,   6,  36,  92,
-    194, 211, 172,  98, 145, 149, 228, 121,
-    231, 200,  55, 109, 141, 213,  78, 169,
-    108,  86, 244, 234, 101, 122, 174,   8,
-    186, 120,  37,  46,  28, 166, 180, 198,
-    232, 221, 116,  31,  75, 189, 139, 138,
-    112,  62, 181, 102,  72,   3, 246,  14,
-    97,  53,  87, 185, 134, 193,  29, 158,
-    225, 248, 152,  17, 105, 217, 142, 148,
-    155,  30, 135, 233, 206,  85,  40, 223,
-    140, 161, 137,  13, 191, 230,  66, 104,
-    65, 153,  45,  15, 176,  84, 187,  22
+    return x >> (n << 3);
+}
+
+static const uint32_t rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
+
+static const uint32_t crypto_ft_tab[4][256] = {
+    {
+        0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
+        0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
+        0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+        0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
+        0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+        0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+        0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
+        0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
+        0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+        0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+        0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
+        0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+        0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
+        0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
+        0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+        0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
+        0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
+        0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+        0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
+        0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+        0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+        0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
+        0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
+        0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+        0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+        0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
+        0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+        0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
+        0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
+        0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+        0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
+        0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
+        0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+        0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
+        0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+        0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+        0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
+        0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
+        0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+        0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+        0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
+        0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+        0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
+        0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
+        0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+        0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
+        0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
+        0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+        0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
+        0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+        0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+        0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
+        0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
+        0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+        0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+        0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
+        0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+        0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
+        0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
+        0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+        0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
+        0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
+        0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+        0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
+    }, {
+        0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
+        0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
+        0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
+        0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
+        0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+        0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
+        0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
+        0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
+        0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
+        0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+        0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
+        0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
+        0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
+        0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
+        0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+        0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
+        0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
+        0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
+        0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
+        0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+        0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
+        0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
+        0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
+        0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
+        0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+        0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
+        0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
+        0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
+        0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
+        0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+        0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
+        0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
+        0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
+        0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
+        0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+        0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
+        0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
+        0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
+        0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
+        0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+        0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
+        0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
+        0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
+        0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
+        0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+        0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
+        0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
+        0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
+        0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
+        0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+        0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
+        0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
+        0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
+        0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
+        0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+        0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
+        0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
+        0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
+        0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
+        0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+        0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
+        0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
+        0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
+        0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a,
+    }, {
+        0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
+        0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
+        0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
+        0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
+        0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+        0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
+        0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
+        0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
+        0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
+        0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+        0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
+        0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
+        0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
+        0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
+        0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+        0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
+        0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
+        0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
+        0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
+        0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+        0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
+        0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
+        0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
+        0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
+        0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+        0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
+        0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
+        0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
+        0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
+        0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+        0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
+        0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
+        0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
+        0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
+        0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+        0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
+        0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
+        0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
+        0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
+        0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+        0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
+        0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
+        0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
+        0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
+        0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+        0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
+        0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
+        0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
+        0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
+        0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+        0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
+        0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
+        0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
+        0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
+        0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+        0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
+        0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
+        0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
+        0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
+        0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+        0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
+        0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
+        0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
+        0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16,
+    }, {
+        0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
+        0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
+        0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
+        0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
+        0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+        0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
+        0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
+        0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
+        0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
+        0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+        0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
+        0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
+        0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
+        0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
+        0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+        0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
+        0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
+        0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
+        0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
+        0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+        0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
+        0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
+        0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
+        0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
+        0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+        0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
+        0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
+        0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
+        0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
+        0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+        0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
+        0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
+        0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
+        0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
+        0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+        0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
+        0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
+        0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
+        0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
+        0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+        0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
+        0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
+        0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
+        0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
+        0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+        0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
+        0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
+        0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
+        0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
+        0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+        0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
+        0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
+        0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
+        0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
+        0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+        0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
+        0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
+        0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
+        0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
+        0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+        0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
+        0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
+        0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
+        0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616,
+    }
+};
+
+static const uint32_t crypto_fl_tab[4][256] = {
+    {
+        0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
+        0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
+        0x00000030, 0x00000001, 0x00000067, 0x0000002b,
+        0x000000fe, 0x000000d7, 0x000000ab, 0x00000076,
+        0x000000ca, 0x00000082, 0x000000c9, 0x0000007d,
+        0x000000fa, 0x00000059, 0x00000047, 0x000000f0,
+        0x000000ad, 0x000000d4, 0x000000a2, 0x000000af,
+        0x0000009c, 0x000000a4, 0x00000072, 0x000000c0,
+        0x000000b7, 0x000000fd, 0x00000093, 0x00000026,
+        0x00000036, 0x0000003f, 0x000000f7, 0x000000cc,
+        0x00000034, 0x000000a5, 0x000000e5, 0x000000f1,
+        0x00000071, 0x000000d8, 0x00000031, 0x00000015,
+        0x00000004, 0x000000c7, 0x00000023, 0x000000c3,
+        0x00000018, 0x00000096, 0x00000005, 0x0000009a,
+        0x00000007, 0x00000012, 0x00000080, 0x000000e2,
+        0x000000eb, 0x00000027, 0x000000b2, 0x00000075,
+        0x00000009, 0x00000083, 0x0000002c, 0x0000001a,
+        0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0,
+        0x00000052, 0x0000003b, 0x000000d6, 0x000000b3,
+        0x00000029, 0x000000e3, 0x0000002f, 0x00000084,
+        0x00000053, 0x000000d1, 0x00000000, 0x000000ed,
+        0x00000020, 0x000000fc, 0x000000b1, 0x0000005b,
+        0x0000006a, 0x000000cb, 0x000000be, 0x00000039,
+        0x0000004a, 0x0000004c, 0x00000058, 0x000000cf,
+        0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb,
+        0x00000043, 0x0000004d, 0x00000033, 0x00000085,
+        0x00000045, 0x000000f9, 0x00000002, 0x0000007f,
+        0x00000050, 0x0000003c, 0x0000009f, 0x000000a8,
+        0x00000051, 0x000000a3, 0x00000040, 0x0000008f,
+        0x00000092, 0x0000009d, 0x00000038, 0x000000f5,
+        0x000000bc, 0x000000b6, 0x000000da, 0x00000021,
+        0x00000010, 0x000000ff, 0x000000f3, 0x000000d2,
+        0x000000cd, 0x0000000c, 0x00000013, 0x000000ec,
+        0x0000005f, 0x00000097, 0x00000044, 0x00000017,
+        0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d,
+        0x00000064, 0x0000005d, 0x00000019, 0x00000073,
+        0x00000060, 0x00000081, 0x0000004f, 0x000000dc,
+        0x00000022, 0x0000002a, 0x00000090, 0x00000088,
+        0x00000046, 0x000000ee, 0x000000b8, 0x00000014,
+        0x000000de, 0x0000005e, 0x0000000b, 0x000000db,
+        0x000000e0, 0x00000032, 0x0000003a, 0x0000000a,
+        0x00000049, 0x00000006, 0x00000024, 0x0000005c,
+        0x000000c2, 0x000000d3, 0x000000ac, 0x00000062,
+        0x00000091, 0x00000095, 0x000000e4, 0x00000079,
+        0x000000e7, 0x000000c8, 0x00000037, 0x0000006d,
+        0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9,
+        0x0000006c, 0x00000056, 0x000000f4, 0x000000ea,
+        0x00000065, 0x0000007a, 0x000000ae, 0x00000008,
+        0x000000ba, 0x00000078, 0x00000025, 0x0000002e,
+        0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6,
+        0x000000e8, 0x000000dd, 0x00000074, 0x0000001f,
+        0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a,
+        0x00000070, 0x0000003e, 0x000000b5, 0x00000066,
+        0x00000048, 0x00000003, 0x000000f6, 0x0000000e,
+        0x00000061, 0x00000035, 0x00000057, 0x000000b9,
+        0x00000086, 0x000000c1, 0x0000001d, 0x0000009e,
+        0x000000e1, 0x000000f8, 0x00000098, 0x00000011,
+        0x00000069, 0x000000d9, 0x0000008e, 0x00000094,
+        0x0000009b, 0x0000001e, 0x00000087, 0x000000e9,
+        0x000000ce, 0x00000055, 0x00000028, 0x000000df,
+        0x0000008c, 0x000000a1, 0x00000089, 0x0000000d,
+        0x000000bf, 0x000000e6, 0x00000042, 0x00000068,
+        0x00000041, 0x00000099, 0x0000002d, 0x0000000f,
+        0x000000b0, 0x00000054, 0x000000bb, 0x00000016,
+    }, {
+        0x00006300, 0x00007c00, 0x00007700, 0x00007b00,
+        0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500,
+        0x00003000, 0x00000100, 0x00006700, 0x00002b00,
+        0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600,
+        0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00,
+        0x0000fa00, 0x00005900, 0x00004700, 0x0000f000,
+        0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00,
+        0x00009c00, 0x0000a400, 0x00007200, 0x0000c000,
+        0x0000b700, 0x0000fd00, 0x00009300, 0x00002600,
+        0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00,
+        0x00003400, 0x0000a500, 0x0000e500, 0x0000f100,
+        0x00007100, 0x0000d800, 0x00003100, 0x00001500,
+        0x00000400, 0x0000c700, 0x00002300, 0x0000c300,
+        0x00001800, 0x00009600, 0x00000500, 0x00009a00,
+        0x00000700, 0x00001200, 0x00008000, 0x0000e200,
+        0x0000eb00, 0x00002700, 0x0000b200, 0x00007500,
+        0x00000900, 0x00008300, 0x00002c00, 0x00001a00,
+        0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000,
+        0x00005200, 0x00003b00, 0x0000d600, 0x0000b300,
+        0x00002900, 0x0000e300, 0x00002f00, 0x00008400,
+        0x00005300, 0x0000d100, 0x00000000, 0x0000ed00,
+        0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00,
+        0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900,
+        0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00,
+        0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00,
+        0x00004300, 0x00004d00, 0x00003300, 0x00008500,
+        0x00004500, 0x0000f900, 0x00000200, 0x00007f00,
+        0x00005000, 0x00003c00, 0x00009f00, 0x0000a800,
+        0x00005100, 0x0000a300, 0x00004000, 0x00008f00,
+        0x00009200, 0x00009d00, 0x00003800, 0x0000f500,
+        0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100,
+        0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200,
+        0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00,
+        0x00005f00, 0x00009700, 0x00004400, 0x00001700,
+        0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00,
+        0x00006400, 0x00005d00, 0x00001900, 0x00007300,
+        0x00006000, 0x00008100, 0x00004f00, 0x0000dc00,
+        0x00002200, 0x00002a00, 0x00009000, 0x00008800,
+        0x00004600, 0x0000ee00, 0x0000b800, 0x00001400,
+        0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00,
+        0x0000e000, 0x00003200, 0x00003a00, 0x00000a00,
+        0x00004900, 0x00000600, 0x00002400, 0x00005c00,
+        0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200,
+        0x00009100, 0x00009500, 0x0000e400, 0x00007900,
+        0x0000e700, 0x0000c800, 0x00003700, 0x00006d00,
+        0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900,
+        0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00,
+        0x00006500, 0x00007a00, 0x0000ae00, 0x00000800,
+        0x0000ba00, 0x00007800, 0x00002500, 0x00002e00,
+        0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600,
+        0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00,
+        0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00,
+        0x00007000, 0x00003e00, 0x0000b500, 0x00006600,
+        0x00004800, 0x00000300, 0x0000f600, 0x00000e00,
+        0x00006100, 0x00003500, 0x00005700, 0x0000b900,
+        0x00008600, 0x0000c100, 0x00001d00, 0x00009e00,
+        0x0000e100, 0x0000f800, 0x00009800, 0x00001100,
+        0x00006900, 0x0000d900, 0x00008e00, 0x00009400,
+        0x00009b00, 0x00001e00, 0x00008700, 0x0000e900,
+        0x0000ce00, 0x00005500, 0x00002800, 0x0000df00,
+        0x00008c00, 0x0000a100, 0x00008900, 0x00000d00,
+        0x0000bf00, 0x0000e600, 0x00004200, 0x00006800,
+        0x00004100, 0x00009900, 0x00002d00, 0x00000f00,
+        0x0000b000, 0x00005400, 0x0000bb00, 0x00001600,
+    }, {
+        0x00630000, 0x007c0000, 0x00770000, 0x007b0000,
+        0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000,
+        0x00300000, 0x00010000, 0x00670000, 0x002b0000,
+        0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000,
+        0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000,
+        0x00fa0000, 0x00590000, 0x00470000, 0x00f00000,
+        0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000,
+        0x009c0000, 0x00a40000, 0x00720000, 0x00c00000,
+        0x00b70000, 0x00fd0000, 0x00930000, 0x00260000,
+        0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000,
+        0x00340000, 0x00a50000, 0x00e50000, 0x00f10000,
+        0x00710000, 0x00d80000, 0x00310000, 0x00150000,
+        0x00040000, 0x00c70000, 0x00230000, 0x00c30000,
+        0x00180000, 0x00960000, 0x00050000, 0x009a0000,
+        0x00070000, 0x00120000, 0x00800000, 0x00e20000,
+        0x00eb0000, 0x00270000, 0x00b20000, 0x00750000,
+        0x00090000, 0x00830000, 0x002c0000, 0x001a0000,
+        0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000,
+        0x00520000, 0x003b0000, 0x00d60000, 0x00b30000,
+        0x00290000, 0x00e30000, 0x002f0000, 0x00840000,
+        0x00530000, 0x00d10000, 0x00000000, 0x00ed0000,
+        0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000,
+        0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000,
+        0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000,
+        0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000,
+        0x00430000, 0x004d0000, 0x00330000, 0x00850000,
+        0x00450000, 0x00f90000, 0x00020000, 0x007f0000,
+        0x00500000, 0x003c0000, 0x009f0000, 0x00a80000,
+        0x00510000, 0x00a30000, 0x00400000, 0x008f0000,
+        0x00920000, 0x009d0000, 0x00380000, 0x00f50000,
+        0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000,
+        0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000,
+        0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000,
+        0x005f0000, 0x00970000, 0x00440000, 0x00170000,
+        0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000,
+        0x00640000, 0x005d0000, 0x00190000, 0x00730000,
+        0x00600000, 0x00810000, 0x004f0000, 0x00dc0000,
+        0x00220000, 0x002a0000, 0x00900000, 0x00880000,
+        0x00460000, 0x00ee0000, 0x00b80000, 0x00140000,
+        0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000,
+        0x00e00000, 0x00320000, 0x003a0000, 0x000a0000,
+        0x00490000, 0x00060000, 0x00240000, 0x005c0000,
+        0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000,
+        0x00910000, 0x00950000, 0x00e40000, 0x00790000,
+        0x00e70000, 0x00c80000, 0x00370000, 0x006d0000,
+        0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000,
+        0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000,
+        0x00650000, 0x007a0000, 0x00ae0000, 0x00080000,
+        0x00ba0000, 0x00780000, 0x00250000, 0x002e0000,
+        0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000,
+        0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000,
+        0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000,
+        0x00700000, 0x003e0000, 0x00b50000, 0x00660000,
+        0x00480000, 0x00030000, 0x00f60000, 0x000e0000,
+        0x00610000, 0x00350000, 0x00570000, 0x00b90000,
+        0x00860000, 0x00c10000, 0x001d0000, 0x009e0000,
+        0x00e10000, 0x00f80000, 0x00980000, 0x00110000,
+        0x00690000, 0x00d90000, 0x008e0000, 0x00940000,
+        0x009b0000, 0x001e0000, 0x00870000, 0x00e90000,
+        0x00ce0000, 0x00550000, 0x00280000, 0x00df0000,
+        0x008c0000, 0x00a10000, 0x00890000, 0x000d0000,
+        0x00bf0000, 0x00e60000, 0x00420000, 0x00680000,
+        0x00410000, 0x00990000, 0x002d0000, 0x000f0000,
+        0x00b00000, 0x00540000, 0x00bb0000, 0x00160000,
+    }, {
+        0x63000000, 0x7c000000, 0x77000000, 0x7b000000,
+        0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000,
+        0x30000000, 0x01000000, 0x67000000, 0x2b000000,
+        0xfe000000, 0xd7000000, 0xab000000, 0x76000000,
+        0xca000000, 0x82000000, 0xc9000000, 0x7d000000,
+        0xfa000000, 0x59000000, 0x47000000, 0xf0000000,
+        0xad000000, 0xd4000000, 0xa2000000, 0xaf000000,
+        0x9c000000, 0xa4000000, 0x72000000, 0xc0000000,
+        0xb7000000, 0xfd000000, 0x93000000, 0x26000000,
+        0x36000000, 0x3f000000, 0xf7000000, 0xcc000000,
+        0x34000000, 0xa5000000, 0xe5000000, 0xf1000000,
+        0x71000000, 0xd8000000, 0x31000000, 0x15000000,
+        0x04000000, 0xc7000000, 0x23000000, 0xc3000000,
+        0x18000000, 0x96000000, 0x05000000, 0x9a000000,
+        0x07000000, 0x12000000, 0x80000000, 0xe2000000,
+        0xeb000000, 0x27000000, 0xb2000000, 0x75000000,
+        0x09000000, 0x83000000, 0x2c000000, 0x1a000000,
+        0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000,
+        0x52000000, 0x3b000000, 0xd6000000, 0xb3000000,
+        0x29000000, 0xe3000000, 0x2f000000, 0x84000000,
+        0x53000000, 0xd1000000, 0x00000000, 0xed000000,
+        0x20000000, 0xfc000000, 0xb1000000, 0x5b000000,
+        0x6a000000, 0xcb000000, 0xbe000000, 0x39000000,
+        0x4a000000, 0x4c000000, 0x58000000, 0xcf000000,
+        0xd0000000, 0xef000000, 0xaa000000, 0xfb000000,
+        0x43000000, 0x4d000000, 0x33000000, 0x85000000,
+        0x45000000, 0xf9000000, 0x02000000, 0x7f000000,
+        0x50000000, 0x3c000000, 0x9f000000, 0xa8000000,
+        0x51000000, 0xa3000000, 0x40000000, 0x8f000000,
+        0x92000000, 0x9d000000, 0x38000000, 0xf5000000,
+        0xbc000000, 0xb6000000, 0xda000000, 0x21000000,
+        0x10000000, 0xff000000, 0xf3000000, 0xd2000000,
+        0xcd000000, 0x0c000000, 0x13000000, 0xec000000,
+        0x5f000000, 0x97000000, 0x44000000, 0x17000000,
+        0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000,
+        0x64000000, 0x5d000000, 0x19000000, 0x73000000,
+        0x60000000, 0x81000000, 0x4f000000, 0xdc000000,
+        0x22000000, 0x2a000000, 0x90000000, 0x88000000,
+        0x46000000, 0xee000000, 0xb8000000, 0x14000000,
+        0xde000000, 0x5e000000, 0x0b000000, 0xdb000000,
+        0xe0000000, 0x32000000, 0x3a000000, 0x0a000000,
+        0x49000000, 0x06000000, 0x24000000, 0x5c000000,
+        0xc2000000, 0xd3000000, 0xac000000, 0x62000000,
+        0x91000000, 0x95000000, 0xe4000000, 0x79000000,
+        0xe7000000, 0xc8000000, 0x37000000, 0x6d000000,
+        0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000,
+        0x6c000000, 0x56000000, 0xf4000000, 0xea000000,
+        0x65000000, 0x7a000000, 0xae000000, 0x08000000,
+        0xba000000, 0x78000000, 0x25000000, 0x2e000000,
+        0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000,
+        0xe8000000, 0xdd000000, 0x74000000, 0x1f000000,
+        0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000,
+        0x70000000, 0x3e000000, 0xb5000000, 0x66000000,
+        0x48000000, 0x03000000, 0xf6000000, 0x0e000000,
+        0x61000000, 0x35000000, 0x57000000, 0xb9000000,
+        0x86000000, 0xc1000000, 0x1d000000, 0x9e000000,
+        0xe1000000, 0xf8000000, 0x98000000, 0x11000000,
+        0x69000000, 0xd9000000, 0x8e000000, 0x94000000,
+        0x9b000000, 0x1e000000, 0x87000000, 0xe9000000,
+        0xce000000, 0x55000000, 0x28000000, 0xdf000000,
+        0x8c000000, 0xa1000000, 0x89000000, 0x0d000000,
+        0xbf000000, 0xe6000000, 0x42000000, 0x68000000,
+        0x41000000, 0x99000000, 0x2d000000, 0x0f000000,
+        0xb0000000, 0x54000000, 0xbb000000, 0x16000000,
+    }
 };
 
+/* initialise the key schedule from the user supplied key */
 
-static const byte T1[256][4] =
+static uint32_t aes_ror32(uint32_t word, unsigned int shift)
 {
-    { 0xc6,0x63,0x63,0xa5 }, { 0xf8,0x7c,0x7c,0x84 },
-    { 0xee,0x77,0x77,0x99 }, { 0xf6,0x7b,0x7b,0x8d },
-    { 0xff,0xf2,0xf2,0x0d }, { 0xd6,0x6b,0x6b,0xbd },
-    { 0xde,0x6f,0x6f,0xb1 }, { 0x91,0xc5,0xc5,0x54 },
-    { 0x60,0x30,0x30,0x50 }, { 0x02,0x01,0x01,0x03 },
-    { 0xce,0x67,0x67,0xa9 }, { 0x56,0x2b,0x2b,0x7d },
-    { 0xe7,0xfe,0xfe,0x19 }, { 0xb5,0xd7,0xd7,0x62 },
-    { 0x4d,0xab,0xab,0xe6 }, { 0xec,0x76,0x76,0x9a },
-    { 0x8f,0xca,0xca,0x45 }, { 0x1f,0x82,0x82,0x9d },
-    { 0x89,0xc9,0xc9,0x40 }, { 0xfa,0x7d,0x7d,0x87 },
-    { 0xef,0xfa,0xfa,0x15 }, { 0xb2,0x59,0x59,0xeb },
-    { 0x8e,0x47,0x47,0xc9 }, { 0xfb,0xf0,0xf0,0x0b },
-    { 0x41,0xad,0xad,0xec }, { 0xb3,0xd4,0xd4,0x67 },
-    { 0x5f,0xa2,0xa2,0xfd }, { 0x45,0xaf,0xaf,0xea },
-    { 0x23,0x9c,0x9c,0xbf }, { 0x53,0xa4,0xa4,0xf7 },
-    { 0xe4,0x72,0x72,0x96 }, { 0x9b,0xc0,0xc0,0x5b },
-    { 0x75,0xb7,0xb7,0xc2 }, { 0xe1,0xfd,0xfd,0x1c },
-    { 0x3d,0x93,0x93,0xae }, { 0x4c,0x26,0x26,0x6a },
-    { 0x6c,0x36,0x36,0x5a }, { 0x7e,0x3f,0x3f,0x41 },
-    { 0xf5,0xf7,0xf7,0x02 }, { 0x83,0xcc,0xcc,0x4f },
-    { 0x68,0x34,0x34,0x5c }, { 0x51,0xa5,0xa5,0xf4 },
-    { 0xd1,0xe5,0xe5,0x34 }, { 0xf9,0xf1,0xf1,0x08 },
-    { 0xe2,0x71,0x71,0x93 }, { 0xab,0xd8,0xd8,0x73 },
-    { 0x62,0x31,0x31,0x53 }, { 0x2a,0x15,0x15,0x3f },
-    { 0x08,0x04,0x04,0x0c }, { 0x95,0xc7,0xc7,0x52 },
-    { 0x46,0x23,0x23,0x65 }, { 0x9d,0xc3,0xc3,0x5e },
-    { 0x30,0x18,0x18,0x28 }, { 0x37,0x96,0x96,0xa1 },
-    { 0x0a,0x05,0x05,0x0f }, { 0x2f,0x9a,0x9a,0xb5 },
-    { 0x0e,0x07,0x07,0x09 }, { 0x24,0x12,0x12,0x36 },
-    { 0x1b,0x80,0x80,0x9b }, { 0xdf,0xe2,0xe2,0x3d },
-    { 0xcd,0xeb,0xeb,0x26 }, { 0x4e,0x27,0x27,0x69 },
-    { 0x7f,0xb2,0xb2,0xcd }, { 0xea,0x75,0x75,0x9f },
-    { 0x12,0x09,0x09,0x1b }, { 0x1d,0x83,0x83,0x9e },
-    { 0x58,0x2c,0x2c,0x74 }, { 0x34,0x1a,0x1a,0x2e },
-    { 0x36,0x1b,0x1b,0x2d }, { 0xdc,0x6e,0x6e,0xb2 },
-    { 0xb4,0x5a,0x5a,0xee }, { 0x5b,0xa0,0xa0,0xfb },
-    { 0xa4,0x52,0x52,0xf6 }, { 0x76,0x3b,0x3b,0x4d },
-    { 0xb7,0xd6,0xd6,0x61 }, { 0x7d,0xb3,0xb3,0xce },
-    { 0x52,0x29,0x29,0x7b }, { 0xdd,0xe3,0xe3,0x3e },
-    { 0x5e,0x2f,0x2f,0x71 }, { 0x13,0x84,0x84,0x97 },
-    { 0xa6,0x53,0x53,0xf5 }, { 0xb9,0xd1,0xd1,0x68 },
-    { 0x00,0x00,0x00,0x00 }, { 0xc1,0xed,0xed,0x2c },
-    { 0x40,0x20,0x20,0x60 }, { 0xe3,0xfc,0xfc,0x1f },
-    { 0x79,0xb1,0xb1,0xc8 }, { 0xb6,0x5b,0x5b,0xed },
-    { 0xd4,0x6a,0x6a,0xbe }, { 0x8d,0xcb,0xcb,0x46 },
-    { 0x67,0xbe,0xbe,0xd9 }, { 0x72,0x39,0x39,0x4b },
-    { 0x94,0x4a,0x4a,0xde }, { 0x98,0x4c,0x4c,0xd4 },
-    { 0xb0,0x58,0x58,0xe8 }, { 0x85,0xcf,0xcf,0x4a },
-    { 0xbb,0xd0,0xd0,0x6b }, { 0xc5,0xef,0xef,0x2a },
-    { 0x4f,0xaa,0xaa,0xe5 }, { 0xed,0xfb,0xfb,0x16 },
-    { 0x86,0x43,0x43,0xc5 }, { 0x9a,0x4d,0x4d,0xd7 },
-    { 0x66,0x33,0x33,0x55 }, { 0x11,0x85,0x85,0x94 },
-    { 0x8a,0x45,0x45,0xcf }, { 0xe9,0xf9,0xf9,0x10 },
-    { 0x04,0x02,0x02,0x06 }, { 0xfe,0x7f,0x7f,0x81 },
-    { 0xa0,0x50,0x50,0xf0 }, { 0x78,0x3c,0x3c,0x44 },
-    { 0x25,0x9f,0x9f,0xba }, { 0x4b,0xa8,0xa8,0xe3 },
-    { 0xa2,0x51,0x51,0xf3 }, { 0x5d,0xa3,0xa3,0xfe },
-    { 0x80,0x40,0x40,0xc0 }, { 0x05,0x8f,0x8f,0x8a },
-    { 0x3f,0x92,0x92,0xad }, { 0x21,0x9d,0x9d,0xbc },
-    { 0x70,0x38,0x38,0x48 }, { 0xf1,0xf5,0xf5,0x04 },
-    { 0x63,0xbc,0xbc,0xdf }, { 0x77,0xb6,0xb6,0xc1 },
-    { 0xaf,0xda,0xda,0x75 }, { 0x42,0x21,0x21,0x63 },
-    { 0x20,0x10,0x10,0x30 }, { 0xe5,0xff,0xff,0x1a },
-    { 0xfd,0xf3,0xf3,0x0e }, { 0xbf,0xd2,0xd2,0x6d },
-    { 0x81,0xcd,0xcd,0x4c }, { 0x18,0x0c,0x0c,0x14 },
-    { 0x26,0x13,0x13,0x35 }, { 0xc3,0xec,0xec,0x2f },
-    { 0xbe,0x5f,0x5f,0xe1 }, { 0x35,0x97,0x97,0xa2 },
-    { 0x88,0x44,0x44,0xcc }, { 0x2e,0x17,0x17,0x39 },
-    { 0x93,0xc4,0xc4,0x57 }, { 0x55,0xa7,0xa7,0xf2 },
-    { 0xfc,0x7e,0x7e,0x82 }, { 0x7a,0x3d,0x3d,0x47 },
-    { 0xc8,0x64,0x64,0xac }, { 0xba,0x5d,0x5d,0xe7 },
-    { 0x32,0x19,0x19,0x2b }, { 0xe6,0x73,0x73,0x95 },
-    { 0xc0,0x60,0x60,0xa0 }, { 0x19,0x81,0x81,0x98 },
-    { 0x9e,0x4f,0x4f,0xd1 }, { 0xa3,0xdc,0xdc,0x7f },
-    { 0x44,0x22,0x22,0x66 }, { 0x54,0x2a,0x2a,0x7e },
-    { 0x3b,0x90,0x90,0xab }, { 0x0b,0x88,0x88,0x83 },
-    { 0x8c,0x46,0x46,0xca }, { 0xc7,0xee,0xee,0x29 },
-    { 0x6b,0xb8,0xb8,0xd3 }, { 0x28,0x14,0x14,0x3c },
-    { 0xa7,0xde,0xde,0x79 }, { 0xbc,0x5e,0x5e,0xe2 },
-    { 0x16,0x0b,0x0b,0x1d }, { 0xad,0xdb,0xdb,0x76 },
-    { 0xdb,0xe0,0xe0,0x3b }, { 0x64,0x32,0x32,0x56 },
-    { 0x74,0x3a,0x3a,0x4e }, { 0x14,0x0a,0x0a,0x1e },
-    { 0x92,0x49,0x49,0xdb }, { 0x0c,0x06,0x06,0x0a },
-    { 0x48,0x24,0x24,0x6c }, { 0xb8,0x5c,0x5c,0xe4 },
-    { 0x9f,0xc2,0xc2,0x5d }, { 0xbd,0xd3,0xd3,0x6e },
-    { 0x43,0xac,0xac,0xef }, { 0xc4,0x62,0x62,0xa6 },
-    { 0x39,0x91,0x91,0xa8 }, { 0x31,0x95,0x95,0xa4 },
-    { 0xd3,0xe4,0xe4,0x37 }, { 0xf2,0x79,0x79,0x8b },
-    { 0xd5,0xe7,0xe7,0x32 }, { 0x8b,0xc8,0xc8,0x43 },
-    { 0x6e,0x37,0x37,0x59 }, { 0xda,0x6d,0x6d,0xb7 },
-    { 0x01,0x8d,0x8d,0x8c }, { 0xb1,0xd5,0xd5,0x64 },
-    { 0x9c,0x4e,0x4e,0xd2 }, { 0x49,0xa9,0xa9,0xe0 },
-    { 0xd8,0x6c,0x6c,0xb4 }, { 0xac,0x56,0x56,0xfa },
-    { 0xf3,0xf4,0xf4,0x07 }, { 0xcf,0xea,0xea,0x25 },
-    { 0xca,0x65,0x65,0xaf }, { 0xf4,0x7a,0x7a,0x8e },
-    { 0x47,0xae,0xae,0xe9 }, { 0x10,0x08,0x08,0x18 },
-    { 0x6f,0xba,0xba,0xd5 }, { 0xf0,0x78,0x78,0x88 },
-    { 0x4a,0x25,0x25,0x6f }, { 0x5c,0x2e,0x2e,0x72 },
-    { 0x38,0x1c,0x1c,0x24 }, { 0x57,0xa6,0xa6,0xf1 },
-    { 0x73,0xb4,0xb4,0xc7 }, { 0x97,0xc6,0xc6,0x51 },
-    { 0xcb,0xe8,0xe8,0x23 }, { 0xa1,0xdd,0xdd,0x7c },
-    { 0xe8,0x74,0x74,0x9c }, { 0x3e,0x1f,0x1f,0x21 },
-    { 0x96,0x4b,0x4b,0xdd }, { 0x61,0xbd,0xbd,0xdc },
-    { 0x0d,0x8b,0x8b,0x86 }, { 0x0f,0x8a,0x8a,0x85 },
-    { 0xe0,0x70,0x70,0x90 }, { 0x7c,0x3e,0x3e,0x42 },
-    { 0x71,0xb5,0xb5,0xc4 }, { 0xcc,0x66,0x66,0xaa },
-    { 0x90,0x48,0x48,0xd8 }, { 0x06,0x03,0x03,0x05 },
-    { 0xf7,0xf6,0xf6,0x01 }, { 0x1c,0x0e,0x0e,0x12 },
-    { 0xc2,0x61,0x61,0xa3 }, { 0x6a,0x35,0x35,0x5f },
-    { 0xae,0x57,0x57,0xf9 }, { 0x69,0xb9,0xb9,0xd0 },
-    { 0x17,0x86,0x86,0x91 }, { 0x99,0xc1,0xc1,0x58 },
-    { 0x3a,0x1d,0x1d,0x27 }, { 0x27,0x9e,0x9e,0xb9 },
-    { 0xd9,0xe1,0xe1,0x38 }, { 0xeb,0xf8,0xf8,0x13 },
-    { 0x2b,0x98,0x98,0xb3 }, { 0x22,0x11,0x11,0x33 },
-    { 0xd2,0x69,0x69,0xbb }, { 0xa9,0xd9,0xd9,0x70 },
-    { 0x07,0x8e,0x8e,0x89 }, { 0x33,0x94,0x94,0xa7 },
-    { 0x2d,0x9b,0x9b,0xb6 }, { 0x3c,0x1e,0x1e,0x22 },
-    { 0x15,0x87,0x87,0x92 }, { 0xc9,0xe9,0xe9,0x20 },
-    { 0x87,0xce,0xce,0x49 }, { 0xaa,0x55,0x55,0xff },
-    { 0x50,0x28,0x28,0x78 }, { 0xa5,0xdf,0xdf,0x7a },
-    { 0x03,0x8c,0x8c,0x8f }, { 0x59,0xa1,0xa1,0xf8 },
-    { 0x09,0x89,0x89,0x80 }, { 0x1a,0x0d,0x0d,0x17 },
-    { 0x65,0xbf,0xbf,0xda }, { 0xd7,0xe6,0xe6,0x31 },
-    { 0x84,0x42,0x42,0xc6 }, { 0xd0,0x68,0x68,0xb8 },
-    { 0x82,0x41,0x41,0xc3 }, { 0x29,0x99,0x99,0xb0 },
-    { 0x5a,0x2d,0x2d,0x77 }, { 0x1e,0x0f,0x0f,0x11 },
-    { 0x7b,0xb0,0xb0,0xcb }, { 0xa8,0x54,0x54,0xfc },
-    { 0x6d,0xbb,0xbb,0xd6 }, { 0x2c,0x16,0x16,0x3a }
-};
+    return (word >> shift) | (word << (32 - shift));
+}
 
-static const byte T2[256][4] =
-{
-    { 0xa5,0xc6,0x63,0x63 }, { 0x84,0xf8,0x7c,0x7c },
-    { 0x99,0xee,0x77,0x77 }, { 0x8d,0xf6,0x7b,0x7b },
-    { 0x0d,0xff,0xf2,0xf2 }, { 0xbd,0xd6,0x6b,0x6b },
-    { 0xb1,0xde,0x6f,0x6f }, { 0x54,0x91,0xc5,0xc5 },
-    { 0x50,0x60,0x30,0x30 }, { 0x03,0x02,0x01,0x01 },
-    { 0xa9,0xce,0x67,0x67 }, { 0x7d,0x56,0x2b,0x2b },
-    { 0x19,0xe7,0xfe,0xfe }, { 0x62,0xb5,0xd7,0xd7 },
-    { 0xe6,0x4d,0xab,0xab }, { 0x9a,0xec,0x76,0x76 },
-    { 0x45,0x8f,0xca,0xca }, { 0x9d,0x1f,0x82,0x82 },
-    { 0x40,0x89,0xc9,0xc9 }, { 0x87,0xfa,0x7d,0x7d },
-    { 0x15,0xef,0xfa,0xfa }, { 0xeb,0xb2,0x59,0x59 },
-    { 0xc9,0x8e,0x47,0x47 }, { 0x0b,0xfb,0xf0,0xf0 },
-    { 0xec,0x41,0xad,0xad }, { 0x67,0xb3,0xd4,0xd4 },
-    { 0xfd,0x5f,0xa2,0xa2 }, { 0xea,0x45,0xaf,0xaf },
-    { 0xbf,0x23,0x9c,0x9c }, { 0xf7,0x53,0xa4,0xa4 },
-    { 0x96,0xe4,0x72,0x72 }, { 0x5b,0x9b,0xc0,0xc0 },
-    { 0xc2,0x75,0xb7,0xb7 }, { 0x1c,0xe1,0xfd,0xfd },
-    { 0xae,0x3d,0x93,0x93 }, { 0x6a,0x4c,0x26,0x26 },
-    { 0x5a,0x6c,0x36,0x36 }, { 0x41,0x7e,0x3f,0x3f },
-    { 0x02,0xf5,0xf7,0xf7 }, { 0x4f,0x83,0xcc,0xcc },
-    { 0x5c,0x68,0x34,0x34 }, { 0xf4,0x51,0xa5,0xa5 },
-    { 0x34,0xd1,0xe5,0xe5 }, { 0x08,0xf9,0xf1,0xf1 },
-    { 0x93,0xe2,0x71,0x71 }, { 0x73,0xab,0xd8,0xd8 },
-    { 0x53,0x62,0x31,0x31 }, { 0x3f,0x2a,0x15,0x15 },
-    { 0x0c,0x08,0x04,0x04 }, { 0x52,0x95,0xc7,0xc7 },
-    { 0x65,0x46,0x23,0x23 }, { 0x5e,0x9d,0xc3,0xc3 },
-    { 0x28,0x30,0x18,0x18 }, { 0xa1,0x37,0x96,0x96 },
-    { 0x0f,0x0a,0x05,0x05 }, { 0xb5,0x2f,0x9a,0x9a },
-    { 0x09,0x0e,0x07,0x07 }, { 0x36,0x24,0x12,0x12 },
-    { 0x9b,0x1b,0x80,0x80 }, { 0x3d,0xdf,0xe2,0xe2 },
-    { 0x26,0xcd,0xeb,0xeb }, { 0x69,0x4e,0x27,0x27 },
-    { 0xcd,0x7f,0xb2,0xb2 }, { 0x9f,0xea,0x75,0x75 },
-    { 0x1b,0x12,0x09,0x09 }, { 0x9e,0x1d,0x83,0x83 },
-    { 0x74,0x58,0x2c,0x2c }, { 0x2e,0x34,0x1a,0x1a },
-    { 0x2d,0x36,0x1b,0x1b }, { 0xb2,0xdc,0x6e,0x6e },
-    { 0xee,0xb4,0x5a,0x5a }, { 0xfb,0x5b,0xa0,0xa0 },
-    { 0xf6,0xa4,0x52,0x52 }, { 0x4d,0x76,0x3b,0x3b },
-    { 0x61,0xb7,0xd6,0xd6 }, { 0xce,0x7d,0xb3,0xb3 },
-    { 0x7b,0x52,0x29,0x29 }, { 0x3e,0xdd,0xe3,0xe3 },
-    { 0x71,0x5e,0x2f,0x2f }, { 0x97,0x13,0x84,0x84 },
-    { 0xf5,0xa6,0x53,0x53 }, { 0x68,0xb9,0xd1,0xd1 },
-    { 0x00,0x00,0x00,0x00 }, { 0x2c,0xc1,0xed,0xed },
-    { 0x60,0x40,0x20,0x20 }, { 0x1f,0xe3,0xfc,0xfc },
-    { 0xc8,0x79,0xb1,0xb1 }, { 0xed,0xb6,0x5b,0x5b },
-    { 0xbe,0xd4,0x6a,0x6a }, { 0x46,0x8d,0xcb,0xcb },
-    { 0xd9,0x67,0xbe,0xbe }, { 0x4b,0x72,0x39,0x39 },
-    { 0xde,0x94,0x4a,0x4a }, { 0xd4,0x98,0x4c,0x4c },
-    { 0xe8,0xb0,0x58,0x58 }, { 0x4a,0x85,0xcf,0xcf },
-    { 0x6b,0xbb,0xd0,0xd0 }, { 0x2a,0xc5,0xef,0xef },
-    { 0xe5,0x4f,0xaa,0xaa }, { 0x16,0xed,0xfb,0xfb },
-    { 0xc5,0x86,0x43,0x43 }, { 0xd7,0x9a,0x4d,0x4d },
-    { 0x55,0x66,0x33,0x33 }, { 0x94,0x11,0x85,0x85 },
-    { 0xcf,0x8a,0x45,0x45 }, { 0x10,0xe9,0xf9,0xf9 },
-    { 0x06,0x04,0x02,0x02 }, { 0x81,0xfe,0x7f,0x7f },
-    { 0xf0,0xa0,0x50,0x50 }, { 0x44,0x78,0x3c,0x3c },
-    { 0xba,0x25,0x9f,0x9f }, { 0xe3,0x4b,0xa8,0xa8 },
-    { 0xf3,0xa2,0x51,0x51 }, { 0xfe,0x5d,0xa3,0xa3 },
-    { 0xc0,0x80,0x40,0x40 }, { 0x8a,0x05,0x8f,0x8f },
-    { 0xad,0x3f,0x92,0x92 }, { 0xbc,0x21,0x9d,0x9d },
-    { 0x48,0x70,0x38,0x38 }, { 0x04,0xf1,0xf5,0xf5 },
-    { 0xdf,0x63,0xbc,0xbc }, { 0xc1,0x77,0xb6,0xb6 },
-    { 0x75,0xaf,0xda,0xda }, { 0x63,0x42,0x21,0x21 },
-    { 0x30,0x20,0x10,0x10 }, { 0x1a,0xe5,0xff,0xff },
-    { 0x0e,0xfd,0xf3,0xf3 }, { 0x6d,0xbf,0xd2,0xd2 },
-    { 0x4c,0x81,0xcd,0xcd }, { 0x14,0x18,0x0c,0x0c },
-    { 0x35,0x26,0x13,0x13 }, { 0x2f,0xc3,0xec,0xec },
-    { 0xe1,0xbe,0x5f,0x5f }, { 0xa2,0x35,0x97,0x97 },
-    { 0xcc,0x88,0x44,0x44 }, { 0x39,0x2e,0x17,0x17 },
-    { 0x57,0x93,0xc4,0xc4 }, { 0xf2,0x55,0xa7,0xa7 },
-    { 0x82,0xfc,0x7e,0x7e }, { 0x47,0x7a,0x3d,0x3d },
-    { 0xac,0xc8,0x64,0x64 }, { 0xe7,0xba,0x5d,0x5d },
-    { 0x2b,0x32,0x19,0x19 }, { 0x95,0xe6,0x73,0x73 },
-    { 0xa0,0xc0,0x60,0x60 }, { 0x98,0x19,0x81,0x81 },
-    { 0xd1,0x9e,0x4f,0x4f }, { 0x7f,0xa3,0xdc,0xdc },
-    { 0x66,0x44,0x22,0x22 }, { 0x7e,0x54,0x2a,0x2a },
-    { 0xab,0x3b,0x90,0x90 }, { 0x83,0x0b,0x88,0x88 },
-    { 0xca,0x8c,0x46,0x46 }, { 0x29,0xc7,0xee,0xee },
-    { 0xd3,0x6b,0xb8,0xb8 }, { 0x3c,0x28,0x14,0x14 },
-    { 0x79,0xa7,0xde,0xde }, { 0xe2,0xbc,0x5e,0x5e },
-    { 0x1d,0x16,0x0b,0x0b }, { 0x76,0xad,0xdb,0xdb },
-    { 0x3b,0xdb,0xe0,0xe0 }, { 0x56,0x64,0x32,0x32 },
-    { 0x4e,0x74,0x3a,0x3a }, { 0x1e,0x14,0x0a,0x0a },
-    { 0xdb,0x92,0x49,0x49 }, { 0x0a,0x0c,0x06,0x06 },
-    { 0x6c,0x48,0x24,0x24 }, { 0xe4,0xb8,0x5c,0x5c },
-    { 0x5d,0x9f,0xc2,0xc2 }, { 0x6e,0xbd,0xd3,0xd3 },
-    { 0xef,0x43,0xac,0xac }, { 0xa6,0xc4,0x62,0x62 },
-    { 0xa8,0x39,0x91,0x91 }, { 0xa4,0x31,0x95,0x95 },
-    { 0x37,0xd3,0xe4,0xe4 }, { 0x8b,0xf2,0x79,0x79 },
-    { 0x32,0xd5,0xe7,0xe7 }, { 0x43,0x8b,0xc8,0xc8 },
-    { 0x59,0x6e,0x37,0x37 }, { 0xb7,0xda,0x6d,0x6d },
-    { 0x8c,0x01,0x8d,0x8d }, { 0x64,0xb1,0xd5,0xd5 },
-    { 0xd2,0x9c,0x4e,0x4e }, { 0xe0,0x49,0xa9,0xa9 },
-    { 0xb4,0xd8,0x6c,0x6c }, { 0xfa,0xac,0x56,0x56 },
-    { 0x07,0xf3,0xf4,0xf4 }, { 0x25,0xcf,0xea,0xea },
-    { 0xaf,0xca,0x65,0x65 }, { 0x8e,0xf4,0x7a,0x7a },
-    { 0xe9,0x47,0xae,0xae }, { 0x18,0x10,0x08,0x08 },
-    { 0xd5,0x6f,0xba,0xba }, { 0x88,0xf0,0x78,0x78 },
-    { 0x6f,0x4a,0x25,0x25 }, { 0x72,0x5c,0x2e,0x2e },
-    { 0x24,0x38,0x1c,0x1c }, { 0xf1,0x57,0xa6,0xa6 },
-    { 0xc7,0x73,0xb4,0xb4 }, { 0x51,0x97,0xc6,0xc6 },
-    { 0x23,0xcb,0xe8,0xe8 }, { 0x7c,0xa1,0xdd,0xdd },
-    { 0x9c,0xe8,0x74,0x74 }, { 0x21,0x3e,0x1f,0x1f },
-    { 0xdd,0x96,0x4b,0x4b }, { 0xdc,0x61,0xbd,0xbd },
-    { 0x86,0x0d,0x8b,0x8b }, { 0x85,0x0f,0x8a,0x8a },
-    { 0x90,0xe0,0x70,0x70 }, { 0x42,0x7c,0x3e,0x3e },
-    { 0xc4,0x71,0xb5,0xb5 }, { 0xaa,0xcc,0x66,0x66 },
-    { 0xd8,0x90,0x48,0x48 }, { 0x05,0x06,0x03,0x03 },
-    { 0x01,0xf7,0xf6,0xf6 }, { 0x12,0x1c,0x0e,0x0e },
-    { 0xa3,0xc2,0x61,0x61 }, { 0x5f,0x6a,0x35,0x35 },
-    { 0xf9,0xae,0x57,0x57 }, { 0xd0,0x69,0xb9,0xb9 },
-    { 0x91,0x17,0x86,0x86 }, { 0x58,0x99,0xc1,0xc1 },
-    { 0x27,0x3a,0x1d,0x1d }, { 0xb9,0x27,0x9e,0x9e },
-    { 0x38,0xd9,0xe1,0xe1 }, { 0x13,0xeb,0xf8,0xf8 },
-    { 0xb3,0x2b,0x98,0x98 }, { 0x33,0x22,0x11,0x11 },
-    { 0xbb,0xd2,0x69,0x69 }, { 0x70,0xa9,0xd9,0xd9 },
-    { 0x89,0x07,0x8e,0x8e }, { 0xa7,0x33,0x94,0x94 },
-    { 0xb6,0x2d,0x9b,0x9b }, { 0x22,0x3c,0x1e,0x1e },
-    { 0x92,0x15,0x87,0x87 }, { 0x20,0xc9,0xe9,0xe9 },
-    { 0x49,0x87,0xce,0xce }, { 0xff,0xaa,0x55,0x55 },
-    { 0x78,0x50,0x28,0x28 }, { 0x7a,0xa5,0xdf,0xdf },
-    { 0x8f,0x03,0x8c,0x8c }, { 0xf8,0x59,0xa1,0xa1 },
-    { 0x80,0x09,0x89,0x89 }, { 0x17,0x1a,0x0d,0x0d },
-    { 0xda,0x65,0xbf,0xbf }, { 0x31,0xd7,0xe6,0xe6 },
-    { 0xc6,0x84,0x42,0x42 }, { 0xb8,0xd0,0x68,0x68 },
-    { 0xc3,0x82,0x41,0x41 }, { 0xb0,0x29,0x99,0x99 },
-    { 0x77,0x5a,0x2d,0x2d }, { 0x11,0x1e,0x0f,0x0f },
-    { 0xcb,0x7b,0xb0,0xb0 }, { 0xfc,0xa8,0x54,0x54 },
-    { 0xd6,0x6d,0xbb,0xbb }, { 0x3a,0x2c,0x16,0x16 }
-};
+#define cpu_to_le32(x) SDL_SwapLE32(x)
+#define le32_to_cpu(x) SDL_SwapLE32(x)
 
-static const byte T3[256][4] =
-{
-    { 0x63,0xa5,0xc6,0x63 }, { 0x7c,0x84,0xf8,0x7c },
-    { 0x77,0x99,0xee,0x77 }, { 0x7b,0x8d,0xf6,0x7b },
-    { 0xf2,0x0d,0xff,0xf2 }, { 0x6b,0xbd,0xd6,0x6b },
-    { 0x6f,0xb1,0xde,0x6f }, { 0xc5,0x54,0x91,0xc5 },
-    { 0x30,0x50,0x60,0x30 }, { 0x01,0x03,0x02,0x01 },
-    { 0x67,0xa9,0xce,0x67 }, { 0x2b,0x7d,0x56,0x2b },
-    { 0xfe,0x19,0xe7,0xfe }, { 0xd7,0x62,0xb5,0xd7 },
-    { 0xab,0xe6,0x4d,0xab }, { 0x76,0x9a,0xec,0x76 },
-    { 0xca,0x45,0x8f,0xca }, { 0x82,0x9d,0x1f,0x82 },
-    { 0xc9,0x40,0x89,0xc9 }, { 0x7d,0x87,0xfa,0x7d },
-    { 0xfa,0x15,0xef,0xfa }, { 0x59,0xeb,0xb2,0x59 },
-    { 0x47,0xc9,0x8e,0x47 }, { 0xf0,0x0b,0xfb,0xf0 },
-    { 0xad,0xec,0x41,0xad }, { 0xd4,0x67,0xb3,0xd4 },
-    { 0xa2,0xfd,0x5f,0xa2 }, { 0xaf,0xea,0x45,0xaf },
-    { 0x9c,0xbf,0x23,0x9c }, { 0xa4,0xf7,0x53,0xa4 },
-    { 0x72,0x96,0xe4,0x72 }, { 0xc0,0x5b,0x9b,0xc0 },
-    { 0xb7,0xc2,0x75,0xb7 }, { 0xfd,0x1c,0xe1,0xfd },
-    { 0x93,0xae,0x3d,0x93 }, { 0x26,0x6a,0x4c,0x26 },
-    { 0x36,0x5a,0x6c,0x36 }, { 0x3f,0x41,0x7e,0x3f },
-    { 0xf7,0x02,0xf5,0xf7 }, { 0xcc,0x4f,0x83,0xcc },
-    { 0x34,0x5c,0x68,0x34 }, { 0xa5,0xf4,0x51,0xa5 },
-    { 0xe5,0x34,0xd1,0xe5 }, { 0xf1,0x08,0xf9,0xf1 },
-    { 0x71,0x93,0xe2,0x71 }, { 0xd8,0x73,0xab,0xd8 },
-    { 0x31,0x53,0x62,0x31 }, { 0x15,0x3f,0x2a,0x15 },
-    { 0x04,0x0c,0x08,0x04 }, { 0xc7,0x52,0x95,0xc7 },
-    { 0x23,0x65,0x46,0x23 }, { 0xc3,0x5e,0x9d,0xc3 },
-    { 0x18,0x28,0x30,0x18 }, { 0x96,0xa1,0x37,0x96 },
-    { 0x05,0x0f,0x0a,0x05 }, { 0x9a,0xb5,0x2f,0x9a },
-    { 0x07,0x09,0x0e,0x07 }, { 0x12,0x36,0x24,0x12 },
-    { 0x80,0x9b,0x1b,0x80 }, { 0xe2,0x3d,0xdf,0xe2 },
-    { 0xeb,0x26,0xcd,0xeb }, { 0x27,0x69,0x4e,0x27 },
-    { 0xb2,0xcd,0x7f,0xb2 }, { 0x75,0x9f,0xea,0x75 },
-    { 0x09,0x1b,0x12,0x09 }, { 0x83,0x9e,0x1d,0x83 },
-    { 0x2c,0x74,0x58,0x2c }, { 0x1a,0x2e,0x34,0x1a },
-    { 0x1b,0x2d,0x36,0x1b }, { 0x6e,0xb2,0xdc,0x6e },
-    { 0x5a,0xee,0xb4,0x5a }, { 0xa0,0xfb,0x5b,0xa0 },
-    { 0x52,0xf6,0xa4,0x52 }, { 0x3b,0x4d,0x76,0x3b },
-    { 0xd6,0x61,0xb7,0xd6 }, { 0xb3,0xce,0x7d,0xb3 },
-    { 0x29,0x7b,0x52,0x29 }, { 0xe3,0x3e,0xdd,0xe3 },
-    { 0x2f,0x71,0x5e,0x2f }, { 0x84,0x97,0x13,0x84 },
-    { 0x53,0xf5,0xa6,0x53 }, { 0xd1,0x68,0xb9,0xd1 },
-    { 0x00,0x00,0x00,0x00 }, { 0xed,0x2c,0xc1,0xed },
-    { 0x20,0x60,0x40,0x20 }, { 0xfc,0x1f,0xe3,0xfc },
-    { 0xb1,0xc8,0x79,0xb1 }, { 0x5b,0xed,0xb6,0x5b },
-    { 0x6a,0xbe,0xd4,0x6a }, { 0xcb,0x46,0x8d,0xcb },
-    { 0xbe,0xd9,0x67,0xbe }, { 0x39,0x4b,0x72,0x39 },
-    { 0x4a,0xde,0x94,0x4a }, { 0x4c,0xd4,0x98,0x4c },
-    { 0x58,0xe8,0xb0,0x58 }, { 0xcf,0x4a,0x85,0xcf },
-    { 0xd0,0x6b,0xbb,0xd0 }, { 0xef,0x2a,0xc5,0xef },
-    { 0xaa,0xe5,0x4f,0xaa }, { 0xfb,0x16,0xed,0xfb },
-    { 0x43,0xc5,0x86,0x43 }, { 0x4d,0xd7,0x9a,0x4d },
-    { 0x33,0x55,0x66,0x33 }, { 0x85,0x94,0x11,0x85 },
-    { 0x45,0xcf,0x8a,0x45 }, { 0xf9,0x10,0xe9,0xf9 },
-    { 0x02,0x06,0x04,0x02 }, { 0x7f,0x81,0xfe,0x7f },
-    { 0x50,0xf0,0xa0,0x50 }, { 0x3c,0x44,0x78,0x3c },
-    { 0x9f,0xba,0x25,0x9f }, { 0xa8,0xe3,0x4b,0xa8 },
-    { 0x51,0xf3,0xa2,0x51 }, { 0xa3,0xfe,0x5d,0xa3 },
-    { 0x40,0xc0,0x80,0x40 }, { 0x8f,0x8a,0x05,0x8f },
-    { 0x92,0xad,0x3f,0x92 }, { 0x9d,0xbc,0x21,0x9d },
-    { 0x38,0x48,0x70,0x38 }, { 0xf5,0x04,0xf1,0xf5 },
-    { 0xbc,0xdf,0x63,0xbc }, { 0xb6,0xc1,0x77,0xb6 },
-    { 0xda,0x75,0xaf,0xda }, { 0x21,0x63,0x42,0x21 },
-    { 0x10,0x30,0x20,0x10 }, { 0xff,0x1a,0xe5,0xff },
-    { 0xf3,0x0e,0xfd,0xf3 }, { 0xd2,0x6d,0xbf,0xd2 },
-    { 0xcd,0x4c,0x81,0xcd }, { 0x0c,0x14,0x18,0x0c },
-    { 0x13,0x35,0x26,0x13 }, { 0xec,0x2f,0xc3,0xec },
-    { 0x5f,0xe1,0xbe,0x5f }, { 0x97,0xa2,0x35,0x97 },
-    { 0x44,0xcc,0x88,0x44 }, { 0x17,0x39,0x2e,0x17 },
-    { 0xc4,0x57,0x93,0xc4 }, { 0xa7,0xf2,0x55,0xa7 },
-    { 0x7e,0x82,0xfc,0x7e }, { 0x3d,0x47,0x7a,0x3d },
-    { 0x64,0xac,0xc8,0x64 }, { 0x5d,0xe7,0xba,0x5d },
-    { 0x19,0x2b,0x32,0x19 }, { 0x73,0x95,0xe6,0x73 },
-    { 0x60,0xa0,0xc0,0x60 }, { 0x81,0x98,0x19,0x81 },
-    { 0x4f,0xd1,0x9e,0x4f }, { 0xdc,0x7f,0xa3,0xdc },
-    { 0x22,0x66,0x44,0x22 }, { 0x2a,0x7e,0x54,0x2a },
-    { 0x90,0xab,0x3b,0x90 }, { 0x88,0x83,0x0b,0x88 },
-    { 0x46,0xca,0x8c,0x46 }, { 0xee,0x29,0xc7,0xee },
-    { 0xb8,0xd3,0x6b,0xb8 }, { 0x14,0x3c,0x28,0x14 },
-    { 0xde,0x79,0xa7,0xde }, { 0x5e,0xe2,0xbc,0x5e },
-    { 0x0b,0x1d,0x16,0x0b }, { 0xdb,0x76,0xad,0xdb },
-    { 0xe0,0x3b,0xdb,0xe0 }, { 0x32,0x56,0x64,0x32 },
-    { 0x3a,0x4e,0x74,0x3a }, { 0x0a,0x1e,0x14,0x0a },
-    { 0x49,0xdb,0x92,0x49 }, { 0x06,0x0a,0x0c,0x06 },
-    { 0x24,0x6c,0x48,0x24 }, { 0x5c,0xe4,0xb8,0x5c },
-    { 0xc2,0x5d,0x9f,0xc2 }, { 0xd3,0x6e,0xbd,0xd3 },
-    { 0xac,0xef,0x43,0xac }, { 0x62,0xa6,0xc4,0x62 },
-    { 0x91,0xa8,0x39,0x91 }, { 0x95,0xa4,0x31,0x95 },
-    { 0xe4,0x37,0xd3,0xe4 }, { 0x79,0x8b,0xf2,0x79 },
-    { 0xe7,0x32,0xd5,0xe7 }, { 0xc8,0x43,0x8b,0xc8 },
-    { 0x37,0x59,0x6e,0x37 }, { 0x6d,0xb7,0xda,0x6d },
-    { 0x8d,0x8c,0x01,0x8d }, { 0xd5,0x64,0xb1,0xd5 },
-    { 0x4e,0xd2,0x9c,0x4e }, { 0xa9,0xe0,0x49,0xa9 },
-    { 0x6c,0xb4,0xd8,0x6c }, { 0x56,0xfa,0xac,0x56 },
-    { 0xf4,0x07,0xf3,0xf4 }, { 0xea,0x25,0xcf,0xea },
-    { 0x65,0xaf,0xca,0x65 }, { 0x7a,0x8e,0xf4,0x7a },
-    { 0xae,0xe9,0x47,0xae }, { 0x08,0x18,0x10,0x08 },
-    { 0xba,0xd5,0x6f,0xba }, { 0x78,0x88,0xf0,0x78 },
-    { 0x25,0x6f,0x4a,0x25 }, { 0x2e,0x72,0x5c,0x2e },
-    { 0x1c,0x24,0x38,0x1c }, { 0xa6,0xf1,0x57,0xa6 },
-    { 0xb4,0xc7,0x73,0xb4 }, { 0xc6,0x51,0x97,0xc6 },
-    { 0xe8,0x23,0xcb,0xe8 }, { 0xdd,0x7c,0xa1,0xdd },
-    { 0x74,0x9c,0xe8,0x74 }, { 0x1f,0x21,0x3e,0x1f },
-    { 0x4b,0xdd,0x96,0x4b }, { 0xbd,0xdc,0x61,0xbd },
-    { 0x8b,0x86,0x0d,0x8b }, { 0x8a,0x85,0x0f,0x8a },
-    { 0x70,0x90,0xe0,0x70 }, { 0x3e,0x42,0x7c,0x3e },
-    { 0xb5,0xc4,0x71,0xb5 }, { 0x66,0xaa,0xcc,0x66 },
-    { 0x48,0xd8,0x90,0x48 }, { 0x03,0x05,0x06,0x03 },
-    { 0xf6,0x01,0xf7,0xf6 }, { 0x0e,0x12,0x1c,0x0e },
-    { 0x61,0xa3,0xc2,0x61 }, { 0x35,0x5f,0x6a,0x35 },
-    { 0x57,0xf9,0xae,0x57 }, { 0xb9,0xd0,0x69,0xb9 },
-    { 0x86,0x91,0x17,0x86 }, { 0xc1,0x58,0x99,0xc1 },
-    { 0x1d,0x27,0x3a,0x1d }, { 0x9e,0xb9,0x27,0x9e },
-    { 0xe1,0x38,0xd9,0xe1 }, { 0xf8,0x13,0xeb,0xf8 },
-    { 0x98,0xb3,0x2b,0x98 }, { 0x11,0x33,0x22,0x11 },
-    { 0x69,0xbb,0xd2,0x69 }, { 0xd9,0x70,0xa9,0xd9 },
-    { 0x8e,0x89,0x07,0x8e }, { 0x94,0xa7,0x33,0x94 },
-    { 0x9b,0xb6,0x2d,0x9b }, { 0x1e,0x22,0x3c,0x1e },
-    { 0x87,0x92,0x15,0x87 }, { 0xe9,0x20,0xc9,0xe9 },
-    { 0xce,0x49,0x87,0xce }, { 0x55,0xff,0xaa,0x55 },
-    { 0x28,0x78,0x50,0x28 }, { 0xdf,0x7a,0xa5,0xdf },
-    { 0x8c,0x8f,0x03,0x8c }, { 0xa1,0xf8,0x59,0xa1 },
-    { 0x89,0x80,0x09,0x89 }, { 0x0d,0x17,0x1a,0x0d },
-    { 0xbf,0xda,0x65,0xbf }, { 0xe6,0x31,0xd7,0xe6 },
-    { 0x42,0xc6,0x84,0x42 }, { 0x68,0xb8,0xd0,0x68 },
-    { 0x41,0xc3,0x82,0x41 }, { 0x99,0xb0,0x29,0x99 },
-    { 0x2d,0x77,0x5a,0x2d }, { 0x0f,0x11,0x1e,0x0f },
-    { 0xb0,0xcb,0x7b,0xb0 }, { 0x54,0xfc,0xa8,0x54 },
-    { 0xbb,0xd6,0x6d,0xbb }, { 0x16,0x3a,0x2c,0x16 }
-};
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
 
-static const byte T4[256][4] =
-{
-    { 0x63,0x63,0xa5,0xc6 }, { 0x7c,0x7c,0x84,0xf8 },
-    { 0x77,0x77,0x99,0xee }, { 0x7b,0x7b,0x8d,0xf6 },
-    { 0xf2,0xf2,0x0d,0xff }, { 0x6b,0x6b,0xbd,0xd6 },
-    { 0x6f,0x6f,0xb1,0xde }, { 0xc5,0xc5,0x54,0x91 },
-    { 0x30,0x30,0x50,0x60 }, { 0x01,0x01,0x03,0x02 },
-    { 0x67,0x67,0xa9,0xce }, { 0x2b,0x2b,0x7d,0x56 },
-    { 0xfe,0xfe,0x19,0xe7 }, { 0xd7,0xd7,0x62,0xb5 },
-    { 0xab,0xab,0xe6,0x4d }, { 0x76,0x76,0x9a,0xec },
-    { 0xca,0xca,0x45,0x8f }, { 0x82,0x82,0x9d,0x1f },
-    { 0xc9,0xc9,0x40,0x89 }, { 0x7d,0x7d,0x87,0xfa },
-    { 0xfa,0xfa,0x15,0xef }, { 0x59,0x59,0xeb,0xb2 },
-    { 0x47,0x47,0xc9,0x8e }, { 0xf0,0xf0,0x0b,0xfb },
-    { 0xad,0xad,0xec,0x41 }, { 0xd4,0xd4,0x67,0xb3 },
-    { 0xa2,0xa2,0xfd,0x5f }, { 0xaf,0xaf,0xea,0x45 },
-    { 0x9c,0x9c,0xbf,0x23 }, { 0xa4,0xa4,0xf7,0x53 },
-    { 0x72,0x72,0x96,0xe4 }, { 0xc0,0xc0,0x5b,0x9b },
-    { 0xb7,0xb7,0xc2,0x75 }, { 0xfd,0xfd,0x1c,0xe1 },
-    { 0x93,0x93,0xae,0x3d }, { 0x26,0x26,0x6a,0x4c },
-    { 0x36,0x36,0x5a,0x6c }, { 0x3f,0x3f,0x41,0x7e },
-    { 0xf7,0xf7,0x02,0xf5 }, { 0xcc,0xcc,0x4f,0x83 },
-    { 0x34,0x34,0x5c,0x68 }, { 0xa5,0xa5,0xf4,0x51 },
-    { 0xe5,0xe5,0x34,0xd1 }, { 0xf1,0xf1,0x08,0xf9 },
-    { 0x71,0x71,0x93,0xe2 }, { 0xd8,0xd8,0x73,0xab },
-    { 0x31,0x31,0x53,0x62 }, { 0x15,0x15,0x3f,0x2a },
-    { 0x04,0x04,0x0c,0x08 }, { 0xc7,0xc7,0x52,0x95 },
-    { 0x23,0x23,0x65,0x46 }, { 0xc3,0xc3,0x5e,0x9d },
-    { 0x18,0x18,0x28,0x30 }, { 0x96,0x96,0xa1,0x37 },
-    { 0x05,0x05,0x0f,0x0a }, { 0x9a,0x9a,0xb5,0x2f },
-    { 0x07,0x07,0x09,0x0e }, { 0x12,0x12,0x36,0x24 },
-    { 0x80,0x80,0x9b,0x1b }, { 0xe2,0xe2,0x3d,0xdf },
-    { 0xeb,0xeb,0x26,0xcd }, { 0x27,0x27,0x69,0x4e },
-    { 0xb2,0xb2,0xcd,0x7f }, { 0x75,0x75,0x9f,0xea },
-    { 0x09,0x09,0x1b,0x12 }, { 0x83,0x83,0x9e,0x1d },
-    { 0x2c,0x2c,0x74,0x58 }, { 0x1a,0x1a,0x2e,0x34 },
-    { 0x1b,0x1b,0x2d,0x36 }, { 0x6e,0x6e,0xb2,0xdc },
-    { 0x5a,0x5a,0xee,0xb4 }, { 0xa0,0xa0,0xfb,0x5b },
-    { 0x52,0x52,0xf6,0xa4 }, { 0x3b,0x3b,0x4d,0x76 },
-    { 0xd6,0xd6,0x61,0xb7 }, { 0xb3,0xb3,0xce,0x7d },
-    { 0x29,0x29,0x7b,0x52 }, { 0xe3,0xe3,0x3e,0xdd },
-    { 0x2f,0x2f,0x71,0x5e }, { 0x84,0x84,0x97,0x13 },
-    { 0x53,0x53,0xf5,0xa6 }, { 0xd1,0xd1,0x68,0xb9 },
-    { 0x00,0x00,0x00,0x00 }, { 0xed,0xed,0x2c,0xc1 },
-    { 0x20,0x20,0x60,0x40 }, { 0xfc,0xfc,0x1f,0xe3 },
-    { 0xb1,0xb1,0xc8,0x79 }, { 0x5b,0x5b,0xed,0xb6 },
-    { 0x6a,0x6a,0xbe,0xd4 }, { 0xcb,0xcb,0x46,0x8d },
-    { 0xbe,0xbe,0xd9,0x67 }, { 0x39,0x39,0x4b,0x72 },
-    { 0x4a,0x4a,0xde,0x94 }, { 0x4c,0x4c,0xd4,0x98 },
-    { 0x58,0x58,0xe8,0xb0 }, { 0xcf,0xcf,0x4a,0x85 },
-    { 0xd0,0xd0,0x6b,0xbb }, { 0xef,0xef,0x2a,0xc5 },
-    { 0xaa,0xaa,0xe5,0x4f }, { 0xfb,0xfb,0x16,0xed },
-    { 0x43,0x43,0xc5,0x86 }, { 0x4d,0x4d,0xd7,0x9a },
-    { 0x33,0x33,0x55,0x66 }, { 0x85,0x85,0x94,0x11 },
-    { 0x45,0x45,0xcf,0x8a }, { 0xf9,0xf9,0x10,0xe9 },
-    { 0x02,0x02,0x06,0x04 }, { 0x7f,0x7f,0x81,0xfe },
-    { 0x50,0x50,0xf0,0xa0 }, { 0x3c,0x3c,0x44,0x78 },
-    { 0x9f,0x9f,0xba,0x25 }, { 0xa8,0xa8,0xe3,0x4b },
-    { 0x51,0x51,0xf3,0xa2 }, { 0xa3,0xa3,0xfe,0x5d },
-    { 0x40,0x40,0xc0,0x80 }, { 0x8f,0x8f,0x8a,0x05 },
-    { 0x92,0x92,0xad,0x3f }, { 0x9d,0x9d,0xbc,0x21 },
-    { 0x38,0x38,0x48,0x70 }, { 0xf5,0xf5,0x04,0xf1 },
-    { 0xbc,0xbc,0xdf,0x63 }, { 0xb6,0xb6,0xc1,0x77 },
-    { 0xda,0xda,0x75,0xaf }, { 0x21,0x21,0x63,0x42 },
-    { 0x10,0x10,0x30,0x20 }, { 0xff,0xff,0x1a,0xe5 },
-    { 0xf3,0xf3,0x0e,0xfd }, { 0xd2,0xd2,0x6d,0xbf },
-    { 0xcd,0xcd,0x4c,0x81 }, { 0x0c,0x0c,0x14,0x18 },
-    { 0x13,0x13,0x35,0x26 }, { 0xec,0xec,0x2f,0xc3 },
-    { 0x5f,0x5f,0xe1,0xbe }, { 0x97,0x97,0xa2,0x35 },
-    { 0x44,0x44,0xcc,0x88 }, { 0x17,0x17,0x39,0x2e },
-    { 0xc4,0xc4,0x57,0x93 }, { 0xa7,0xa7,0xf2,0x55 },
-    { 0x7e,0x7e,0x82,0xfc }, { 0x3d,0x3d,0x47,0x7a },
-    { 0x64,0x64,0xac,0xc8 }, { 0x5d,0x5d,0xe7,0xba },
-    { 0x19,0x19,0x2b,0x32 }, { 0x73,0x73,0x95,0xe6 },
-    { 0x60,0x60,0xa0,0xc0 }, { 0x81,0x81,0x98,0x19 },
-    { 0x4f,0x4f,0xd1,0x9e }, { 0xdc,0xdc,0x7f,0xa3 },
-    { 0x22,0x22,0x66,0x44 }, { 0x2a,0x2a,0x7e,0x54 },
-    { 0x90,0x90,0xab,0x3b }, { 0x88,0x88,0x83,0x0b },
-    { 0x46,0x46,0xca,0x8c }, { 0xee,0xee,0x29,0xc7 },
-    { 0xb8,0xb8,0xd3,0x6b }, { 0x14,0x14,0x3c,0x28 },
-    { 0xde,0xde,0x79,0xa7 }, { 0x5e,0x5e,0xe2,0xbc },
-    { 0x0b,0x0b,0x1d,0x16 }, { 0xdb,0xdb,0x76,0xad },
-    { 0xe0,0xe0,0x3b,0xdb }, { 0x32,0x32,0x56,0x64 },
-    { 0x3a,0x3a,0x4e,0x74 }, { 0x0a,0x0a,0x1e,0x14 },
-    { 0x49,0x49,0xdb,0x92 }, { 0x06,0x06,0x0a,0x0c },
-    { 0x24,0x24,0x6c,0x48 }, { 0x5c,0x5c,0xe4,0xb8 },
-    { 0xc2,0xc2,0x5d,0x9f }, { 0xd3,0xd3,0x6e,0xbd },
-    { 0xac,0xac,0xef,0x43 }, { 0x62,0x62,0xa6,0xc4 },
-    { 0x91,0x91,0xa8,0x39 }, { 0x95,0x95,0xa4,0x31 },
-    { 0xe4,0xe4,0x37,0xd3 }, { 0x79,0x79,0x8b,0xf2 },
-    { 0xe7,0xe7,0x32,0xd5 }, { 0xc8,0xc8,0x43,0x8b },
-    { 0x37,0x37,0x59,0x6e }, { 0x6d,0x6d,0xb7,0xda },
-    { 0x8d,0x8d,0x8c,0x01 }, { 0xd5,0xd5,0x64,0xb1 },
-    { 0x4e,0x4e,0xd2,0x9c }, { 0xa9,0xa9,0xe0,0x49 },
-    { 0x6c,0x6c,0xb4,0xd8 }, { 0x56,0x56,0xfa,0xac },
-    { 0xf4,0xf4,0x07,0xf3 }, { 0xea,0xea,0x25,0xcf },
-    { 0x65,0x65,0xaf,0xca }, { 0x7a,0x7a,0x8e,0xf4 },
-    { 0xae,0xae,0xe9,0x47 }, { 0x08,0x08,0x18,0x10 },
-    { 0xba,0xba,0xd5,0x6f }, { 0x78,0x78,0x88,0xf0 },
-    { 0x25,0x25,0x6f,0x4a }, { 0x2e,0x2e,0x72,0x5c },
-    { 0x1c,0x1c,0x24,0x38 }, { 0xa6,0xa6,0xf1,0x57 },
-    { 0xb4,0xb4,0xc7,0x73 }, { 0xc6,0xc6,0x51,0x97 },
-    { 0xe8,0xe8,0x23,0xcb }, { 0xdd,0xdd,0x7c,0xa1 },
-    { 0x74,0x74,0x9c,0xe8 }, { 0x1f,0x1f,0x21,0x3e },
-    { 0x4b,0x4b,0xdd,0x96 }, { 0xbd,0xbd,0xdc,0x61 },
-    { 0x8b,0x8b,0x86,0x0d }, { 0x8a,0x8a,0x85,0x0f },
-    { 0x70,0x70,0x90,0xe0 }, { 0x3e,0x3e,0x42,0x7c },
-    { 0xb5,0xb5,0xc4,0x71 }, { 0x66,0x66,0xaa,0xcc },
-    { 0x48,0x48,0xd8,0x90 }, { 0x03,0x03,0x05,0x06 },
-    { 0xf6,0xf6,0x01,0xf7 }, { 0x0e,0x0e,0x12,0x1c },
-    { 0x61,0x61,0xa3,0xc2 }, { 0x35,0x35,0x5f,0x6a },
-    { 0x57,0x57,0xf9,0xae }, { 0xb9,0xb9,0xd0,0x69 },
-    { 0x86,0x86,0x91,0x17 }, { 0xc1,0xc1,0x58,0x99 },
-    { 0x1d,0x1d,0x27,0x3a }, { 0x9e,0x9e,0xb9,0x27 },
-    { 0xe1,0xe1,0x38,0xd9 }, { 0xf8,0xf8,0x13,0xeb },
-    { 0x98,0x98,0xb3,0x2b }, { 0x11,0x11,0x33,0x22 },
-    { 0x69,0x69,0xbb,0xd2 }, { 0xd9,0xd9,0x70,0xa9 },
-    { 0x8e,0x8e,0x89,0x07 }, { 0x94,0x94,0xa7,0x33 },
-    { 0x9b,0x9b,0xb6,0x2d }, { 0x1e,0x1e,0x22,0x3c },
-    { 0x87,0x87,0x92,0x15 }, { 0xe9,0xe9,0x20,0xc9 },
-    { 0xce,0xce,0x49,0x87 }, { 0x55,0x55,0xff,0xaa },
-    { 0x28,0x28,0x78,0x50 }, { 0xdf,0xdf,0x7a,0xa5 },
-    { 0x8c,0x8c,0x8f,0x03 }, { 0xa1,0xa1,0xf8,0x59 },
-    { 0x89,0x89,0x80,0x09 }, { 0x0d,0x0d,0x17,0x1a },
-    { 0xbf,0xbf,0xda,0x65 }, { 0xe6,0xe6,0x31,0xd7 },
-    { 0x42,0x42,0xc6,0x84 }, { 0x68,0x68,0xb8,0xd0 },
-    { 0x41,0x41,0xc3,0x82 }, { 0x99,0x99,0xb0,0x29 },
-    { 0x2d,0x2d,0x77,0x5a }, { 0x0f,0x0f,0x11,0x1e },
-    { 0xb0,0xb0,0xcb,0x7b }, { 0x54,0x54,0xfc,0xa8 },
-    { 0xbb,0xbb,0xd6,0x6d }, { 0x16,0x16,0x3a,0x2c }
-};
+#define imix_col(y, x)  do {        \
+    u       = star_x(x);        \
+    v       = star_x(u);        \
+    w       = star_x(v);        \
+    t       = w ^ (x);          \
+    (y)     = u ^ v ^ w;        \
+    (y)     ^= aes_ror32(u ^ t, 8) ^    \
+        aes_ror32(v ^ t, 16) ^      \
+        aes_ror32(t, 24);       \
+} while (0)
 
-static const uint32_t rcon[30] =
-{
-    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
-    0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
-    0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
-};
+#define ls_box(x)           \
+    crypto_fl_tab[0][get_byte(x, 0)] ^  \
+    crypto_fl_tab[1][get_byte(x, 1)] ^  \
+    crypto_fl_tab[2][get_byte(x, 2)] ^  \
+    crypto_fl_tab[3][get_byte(x, 3)]
 
-static char *AES_SelfTest(void);
+#define loop4(i)    do {        \
+    t = aes_ror32(t, 8);        \
+    t = ls_box(t) ^ rco_tab[i];     \
+    t ^= ctx->key_enc[4 * i];           \
+    ctx->key_enc[4 * i + 4] = t;        \
+    t ^= ctx->key_enc[4 * i + 1];       \
+    ctx->key_enc[4 * i + 5] = t;        \
+    t ^= ctx->key_enc[4 * i + 2];       \
+    ctx->key_enc[4 * i + 6] = t;        \
+    t ^= ctx->key_enc[4 * i + 3];       \
+    ctx->key_enc[4 * i + 7] = t;        \
+} while (0)
 
-/* Perform the key setup.
+#define loop6(i)    do {        \
+    t = aes_ror32(t, 8);        \
+    t = ls_box(t) ^ rco_tab[i];     \
+    t ^= ctx->key_enc[6 * i];           \
+    ctx->key_enc[6 * i + 6] = t;        \
+    t ^= ctx->key_enc[6 * i + 1];       \
+    ctx->key_enc[6 * i + 7] = t;        \
+    t ^= ctx->key_enc[6 * i + 2];       \
+    ctx->key_enc[6 * i + 8] = t;        \
+    t ^= ctx->key_enc[6 * i + 3];       \
+    ctx->key_enc[6 * i + 9] = t;        \
+    t ^= ctx->key_enc[6 * i + 4];       \
+    ctx->key_enc[6 * i + 10] = t;       \
+    t ^= ctx->key_enc[6 * i + 5];       \
+    ctx->key_enc[6 * i + 11] = t;       \
+} while (0)
+
+#define loop8tophalf(i) do {            \
+    t = aes_ror32(t, 8);            \
+    t = ls_box(t) ^ rco_tab[i];         \
+    t ^= ctx->key_enc[8 * i];               \
+    ctx->key_enc[8 * i + 8] = t;            \
+    t ^= ctx->key_enc[8 * i + 1];           \
+    ctx->key_enc[8 * i + 9] = t;            \
+    t ^= ctx->key_enc[8 * i + 2];           \
+    ctx->key_enc[8 * i + 10] = t;           \
+    t ^= ctx->key_enc[8 * i + 3];           \
+    ctx->key_enc[8 * i + 11] = t;           \
+} while (0)
+
+#define loop8(i)    do {                \
+    loop8tophalf(i);                \
+    t  = ctx->key_enc[8 * i + 4] ^ ls_box(t);       \
+    ctx->key_enc[8 * i + 12] = t;           \
+    t ^= ctx->key_enc[8 * i + 5];           \
+    ctx->key_enc[8 * i + 13] = t;           \
+    t ^= ctx->key_enc[8 * i + 6];           \
+    ctx->key_enc[8 * i + 14] = t;           \
+    t ^= ctx->key_enc[8 * i + 7];           \
+    ctx->key_enc[8 * i + 15] = t;           \
+} while (0)
+
+/**
+ * AES_ExpandKey - Expands the AES key as described in FIPS-197
+ * @ctx:    The location where the computed key will be stored.
+ * @in_key:     The supplied key.
+ * @key_len:    The length of the supplied key.
+ *
+ * Returns 0 on success. The function fails only if an invalid key size (or
+ * pointer) is supplied.
+ * The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes
+ * key schedule plus a 16 bytes key which is used before the first round).
+ * The decryption key is prepared for the "Equivalent Inverse Cipher" as
+ * described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is
+ * for the initial combination, the second slot for the first round and so on.
  */
-static boolean AES_SetKey(RIJNDAEL_context *ctx, const byte *key,
-                          const unsigned keylen)
+static int AES_ExpandKey(aes_context_t *ctx, const uint8_t *in_key,
+                         unsigned int key_len)
 {
-    int ROUNDS;
-    byte k[MAXKC][4];
-    int i,j, r, t, rconpointer = 0;
-    byte tk[MAXKC][4];
-    int KC;
+    const uint32_t *key = (const uint32_t *)in_key;
+    uint32_t i, t, u, v, w, j;
 
-    if( keylen == 128/8 )
-    {
-        ROUNDS = 10;
-        KC = 4;
-    }
-    else if ( keylen == 192/8 )
-    {
-        ROUNDS = 12;
-        KC = 6;
-    }
-    else if ( keylen == 256/8 )
-    {
-        ROUNDS = 14;
-        KC = 8;
-    }
-    else
-    {
-	return false;
-    }
+    if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
+        key_len != AES_KEYSIZE_256)
+        return -1;
 
-    ctx->ROUNDS = ROUNDS;
+    ctx->key_length = key_len;
 
-    for (i = 0; i < keylen; i++)
-    {
-        k[i >> 2][i & 3] = key[i];
-    }
-#define W (ctx->keySched)
+    ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]);
+    ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]);
+    ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]);
+    ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]);
 
-    for (j = KC-1; j >= 0; j--)
-    {
-        *((uint32_t*)tk[j]) = *((uint32_t*)k[j]);
-    }
-    r = 0;
-    t = 0;
-    /* copy values into round key array */
-    for (j = 0; (j < KC) && (r < ROUNDS + 1); )
-    {
-        for (; (j < KC) && (t < 4); j++, t++)
-        {
-            W[r][t] = *((uint32_t*)tk[j]);
-        }
-        if (t == 4)
-        {
-            r++;
-            t = 0;
-        }
-    }
+    switch (key_len) {
+        case AES_KEYSIZE_128:
+            t = ctx->key_enc[3];
+            for (i = 0; i < 10; ++i)
+                loop4(i);
+            break;
 
-    while (r < ROUNDS + 1)
-    {
-        /* while not enough round key material calculated */
-        /* calculate new values */
-        tk[0][0] ^= S[tk[KC-1][1]];
-        tk[0][1] ^= S[tk[KC-1][2]];
-        tk[0][2] ^= S[tk[KC-1][3]];
-        tk[0][3] ^= S[tk[KC-1][0]];
-        tk[0][0] ^= rcon[rconpointer++];
+        case AES_KEYSIZE_192:
+            ctx->key_enc[4] = le32_to_cpu(key[4]);
+            t = ctx->key_enc[5] = le32_to_cpu(key[5]);
+            for (i = 0; i < 8; ++i)
+                loop6(i);
+            break;
 
-        if (KC != 8)
-        {
-            for (j = 1; j < KC; j++)
-            {
-                *((uint32_t*)tk[j]) ^= *((uint32_t*)tk[j-1]);
-            }
-        }
-        else
-        {
-            for (j = 1; j < KC/2; j++)
-            {
-                *((uint32_t*)tk[j]) ^= *((uint32_t*)tk[j-1]);
-            }
-            tk[KC/2][0] ^= S[tk[KC/2 - 1][0]];
-            tk[KC/2][1] ^= S[tk[KC/2 - 1][1]];
-            tk[KC/2][2] ^= S[tk[KC/2 - 1][2]];
-            tk[KC/2][3] ^= S[tk[KC/2 - 1][3]];
-            for (j = KC/2 + 1; j < KC; j++)
-            {
-                *((uint32_t*)tk[j]) ^= *((uint32_t*)tk[j-1]);
-            }
-        }
-        /* copy values into round key array */
-        for (j = 0; (j < KC) && (r < ROUNDS + 1); )
-        {
-            for (; (j < KC) && (t < 4); j++, t++)
-            {
-                W[r][t] = *((uint32_t*)tk[j]);
-            }
-            if (t == 4)
-            {
-                r++;
-                t = 0;
-            }
-        }
+        case AES_KEYSIZE_256:
+            ctx->key_enc[4] = le32_to_cpu(key[4]);
+            ctx->key_enc[5] = le32_to_cpu(key[5]);
+            ctx->key_enc[6] = le32_to_cpu(key[6]);
+            t = ctx->key_enc[7] = le32_to_cpu(key[7]);
+            for (i = 0; i < 6; ++i)
+                loop8(i);
+            loop8tophalf(i);
+            break;
     }
 
-#undef W
-    return true;
+    ctx->key_dec[0] = ctx->key_enc[key_len + 24];
+    ctx->key_dec[1] = ctx->key_enc[key_len + 25];
+    ctx->key_dec[2] = ctx->key_enc[key_len + 26];
+    ctx->key_dec[3] = ctx->key_enc[key_len + 27];
+
+    for (i = 4; i < key_len + 24; ++i) {
+        j = key_len + 24 - (i & ~3) + (i & 3);
+        imix_col(ctx->key_dec[j], ctx->key_enc[i]);
+    }
+    return 0;
 }
 
-/* Encrypt one block.  A and B need to be aligned on a 4 byte
-   boundary.  A and B may be the same. */
-static void AES_EncryptAligned(const RIJNDAEL_context *ctx,
-                               byte *b, const byte *a)
+/**
+ * AES_SetKey - Set the AES key.
+ * @ctx:        AES context struct.
+ * @in_key:     The input key.
+ * @key_len:    The size of the key.
+ *
+ * Returns 0 on success, on failure -1 is returned.
+ * The function uses AES_ExpandKey() to expand the key.
+ */
+static int AES_SetKey(aes_context_t *ctx, const uint8_t *in_key,
+                      unsigned int key_len)
 {
-#define rk (ctx->keySched)
-    int ROUNDS = ctx->ROUNDS;
-    int r;
-    union
-    {
-        uint32_t u32;
-        byte b[4];
-    } temp[4];
+    int ret;
 
-    temp[0].u32 = *((uint32_t*)(a   )) ^ rk[0][0];
-    temp[1].u32 = *((uint32_t*)(a+ 4)) ^ rk[0][1];
-    temp[2].u32 = *((uint32_t*)(a+ 8)) ^ rk[0][2];
-    temp[3].u32 = *((uint32_t*)(a+12)) ^ rk[0][3];
-    *((uint32_t*)(b    )) = (*((uint32_t*)T1[temp[0].b[0]])
-                           ^ *((uint32_t*)T2[temp[1].b[1]])
-                           ^ *((uint32_t*)T3[temp[2].b[2]])
-                           ^ *((uint32_t*)T4[temp[3].b[3]]));
-    *((uint32_t*)(b + 4)) = (*((uint32_t*)T1[temp[1].b[0]])
-                           ^ *((uint32_t*)T2[temp[2].b[1]])
-                           ^ *((uint32_t*)T3[temp[3].b[2]])
-                           ^ *((uint32_t*)T4[temp[0].b[3]]));
-    *((uint32_t*)(b + 8)) = (*((uint32_t*)T1[temp[2].b[0]])
-                           ^ *((uint32_t*)T2[temp[3].b[1]])
-                           ^ *((uint32_t*)T3[temp[0].b[2]])
-                           ^ *((uint32_t*)T4[temp[1].b[3]]));
-    *((uint32_t*)(b +12)) = (*((uint32_t*)T1[temp[3].b[0]])
-                           ^ *((uint32_t*)T2[temp[0].b[1]])
-                           ^ *((uint32_t*)T3[temp[1].b[2]])
-                           ^ *((uint32_t*)T4[temp[2].b[3]]));
+    ret = AES_ExpandKey(ctx, in_key, key_len);
+    if (!ret)
+        return 0;
 
-    for (r = 1; r < ROUNDS-1; r++)
-    {
-        temp[0].u32 = *((uint32_t*)(b   )) ^ rk[r][0];
-        temp[1].u32 = *((uint32_t*)(b+ 4)) ^ rk[r][1];
-        temp[2].u32 = *((uint32_t*)(b+ 8)) ^ rk[r][2];
-        temp[3].u32 = *((uint32_t*)(b+12)) ^ rk[r][3];
-
-        *((uint32_t*)(b    )) = (*((uint32_t*)T1[temp[0].b[0]])
-                               ^ *((uint32_t*)T2[temp[1].b[1]])
-                               ^ *((uint32_t*)T3[temp[2].b[2]])
-                               ^ *((uint32_t*)T4[temp[3].b[3]]));
-        *((uint32_t*)(b + 4)) = (*((uint32_t*)T1[temp[1].b[0]])
-                               ^ *((uint32_t*)T2[temp[2].b[1]])
-                               ^ *((uint32_t*)T3[temp[3].b[2]])
-                               ^ *((uint32_t*)T4[temp[0].b[3]]));
-        *((uint32_t*)(b + 8)) = (*((uint32_t*)T1[temp[2].b[0]])
-                               ^ *((uint32_t*)T2[temp[3].b[1]])
-                               ^ *((uint32_t*)T3[temp[0].b[2]])
-                               ^ *((uint32_t*)T4[temp[1].b[3]]));
-        *((uint32_t*)(b +12)) = (*((uint32_t*)T1[temp[3].b[0]])
-                               ^ *((uint32_t*)T2[temp[0].b[1]])
-                               ^ *((uint32_t*)T3[temp[1].b[2]])
-                               ^ *((uint32_t*)T4[temp[2].b[3]]));
-    }
-
-    /* Last round is special. */
-    temp[0].u32 = *((uint32_t*)(b   )) ^ rk[ROUNDS-1][0];
-    temp[1].u32 = *((uint32_t*)(b+ 4)) ^ rk[ROUNDS-1][1];
-    temp[2].u32 = *((uint32_t*)(b+ 8)) ^ rk[ROUNDS-1][2];
-    temp[3].u32 = *((uint32_t*)(b+12)) ^ rk[ROUNDS-1][3];
-    b[ 0] = T1[temp[0].b[0]][1];
-    b[ 1] = T1[temp[1].b[1]][1];
-    b[ 2] = T1[temp[2].b[2]][1];
-    b[ 3] = T1[temp[3].b[3]][1];
-    b[ 4] = T1[temp[1].b[0]][1];
-    b[ 5] = T1[temp[2].b[1]][1];
-    b[ 6] = T1[temp[3].b[2]][1];
-    b[ 7] = T1[temp[0].b[3]][1];
-    b[ 8] = T1[temp[2].b[0]][1];
-    b[ 9] = T1[temp[3].b[1]][1];
-    b[10] = T1[temp[0].b[2]][1];
-    b[11] = T1[temp[1].b[3]][1];
-    b[12] = T1[temp[3].b[0]][1];
-    b[13] = T1[temp[0].b[1]][1];
-    b[14] = T1[temp[1].b[2]][1];
-    b[15] = T1[temp[2].b[3]][1];
-    *((uint32_t*)(b   )) ^= rk[ROUNDS][0];
-    *((uint32_t*)(b+ 4)) ^= rk[ROUNDS][1];
-    *((uint32_t*)(b+ 8)) ^= rk[ROUNDS][2];
-    *((uint32_t*)(b+12)) ^= rk[ROUNDS][3];
-#undef rk
+    return -1;
 }
 
-static void AES_Encrypt(const RIJNDAEL_context *ctx,
-                        byte *bx, const byte *ax)
-{
-    /* BX and AX are not necessary correctly aligned.  Thus we need to
-       copy them here. */
-    uint32_t a[4];
-    uint32_t b[4];
+/* encrypt a block of text */
+
+#define f_rn(bo, bi, n, k)      do {                \
+    bo[n] = crypto_ft_tab[0][get_byte(bi[n], 0)] ^              \
+        crypto_ft_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^        \
+        crypto_ft_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^        \
+        crypto_ft_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n);  \
+} while (0)
 
-    memcpy(a, ax, 16);
-    AES_EncryptAligned(ctx, (byte *) b, (byte *) a);
-    memcpy(bx, b, 16);
-}
+#define f_nround(bo, bi, k)     do {\
+    f_rn(bo, bi, 0, k);     \
+    f_rn(bo, bi, 1, k);     \
+    f_rn(bo, bi, 2, k);     \
+    f_rn(bo, bi, 3, k);     \
+    k += 4;         \
+} while (0)
 
-/* Test a single encryption and decryption with each key size. */
+#define f_rl(bo, bi, n, k)      do {                \
+    bo[n] = crypto_fl_tab[0][get_byte(bi[n], 0)] ^              \
+        crypto_fl_tab[1][get_byte(bi[(n + 1) & 3], 1)] ^        \
+        crypto_fl_tab[2][get_byte(bi[(n + 2) & 3], 2)] ^        \
+        crypto_fl_tab[3][get_byte(bi[(n + 3) & 3], 3)] ^ *(k + n);  \
+} while (0)
 
-static char *AES_SelfTest(void)
+#define f_lround(bo, bi, k)     do {\
+    f_rl(bo, bi, 0, k);     \
+    f_rl(bo, bi, 1, k);     \
+    f_rl(bo, bi, 2, k);     \
+    f_rl(bo, bi, 3, k);     \
+} while (0)
+
+static void AES_Encrypt(aes_context_t *ctx, uint8_t *out,
+                        const uint8_t *in)
 {
-    RIJNDAEL_context ctx;
-    byte scratch[16];
+    const uint32_t *src = (const uint32_t *)in;
+    uint32_t *dst = (uint32_t *)out;
+    uint32_t b0[4], b1[4];
+    const uint32_t *kp = ctx->key_enc + 4;
+    const int key_len = ctx->key_length;
 
-    /* The test vectors are from the AES supplied ones; more or less
-     * randomly taken from ecb_tbl.txt (I=42,81,14)
-     */
-    static const byte plaintext[16] = {
-       0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33,
-       0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A
-    };
-    static const byte key[16] = {
-        0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0,
-        0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA
-    };
-    static const byte ciphertext[16] = {
-        0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2,
-        0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD
-    };
+    b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0];
+    b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1];
+    b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2];
+    b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3];
 
-    static const byte plaintext_192[16] = {
-        0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4,
-        0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72
-    };
-    static const byte key_192[24] = {
-        0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,
-        0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,
-        0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20
-    };
-    static const byte ciphertext_192[16] = {
-        0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC,
-        0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
-    };
+    if (key_len > 24) {
+        f_nround(b1, b0, kp);
+        f_nround(b0, b1, kp);
+    }
 
-    static const byte plaintext_256[16] = {
-        0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
-        0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
-    };
-    static const byte key_256[32] = {
-        0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,
-        0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,
-        0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,
-        0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E
-    };
-    static const byte ciphertext_256[16] = {
-        0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,
-        0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
-    };
+    if (key_len > 16) {
+        f_nround(b1, b0, kp);
+        f_nround(b0, b1, kp);
+    }
 
-    AES_SetKey(&ctx, key, sizeof(key));
-    AES_Encrypt(&ctx, scratch, plaintext);
-    if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
-        return "Rijndael-128 test encryption failed.";
+    f_nround(b1, b0, kp);
+    f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp);
+    f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp);
+    f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp);
+    f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp);
+    f_lround(b0, b1, kp);
 
-    AES_SetKey(&ctx, key_192, sizeof(key_192));
-    AES_Encrypt(&ctx, scratch, plaintext_192);
-    if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192)))
-        return "Rijndael-192 test encryption failed.";
-
-    AES_SetKey(&ctx, key_256, sizeof(key_256));
-    AES_Encrypt(&ctx, scratch, plaintext_256);
-    if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
-        return "Rijndael-256 test encryption failed.";
-
-    return NULL;
+    dst[0] = cpu_to_le32(b0[0]);
+    dst[1] = cpu_to_le32(b0[1]);
+    dst[2] = cpu_to_le32(b0[2]);
+    dst[3] = cpu_to_le32(b0[3]);
 }
 
-#ifndef TEST
-
 static boolean prng_enabled = false;
-static RIJNDAEL_context prng_context;
+static aes_context_t prng_context;
 static uint32_t prng_input_counter;
 static uint32_t prng_values[4];
 static unsigned int prng_value_index = 0;
@@ -942,15 +890,6 @@
 
 void PRNG_Start(prng_seed_t key)
 {
-    char *errormsg;
-
-    errormsg = AES_SelfTest();
-
-    if (errormsg != NULL)
-    {
-        I_Error("Failed to initialize PRNG: %s", errormsg);
-    }
-
     AES_SetKey(&prng_context, key, sizeof(prng_seed_t));
     prng_value_index = 4;
     prng_input_counter = 0;
@@ -1015,25 +954,3 @@
     return result;
 }
 
-
-#else /* #ifndef TEST */
-
-int main(int argc, char *argv[])
-{
-    char *errormsg;
-
-    errormsg = AES_SelfTest();
-
-    if (errormsg == NULL)
-    {
-        printf("AES Self test passed.\n");
-        return 0;
-    }
-    else
-    {
-        fprintf(stderr, "AES self test failed: %s\n", errormsg);
-        return 1;
-    }
-}
-
-#endif
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -183,6 +183,10 @@
     // From Doom 3: BFG Edition:
 
     "steamapps\\common\\DOOM 3 BFG Edition\\base\\wads",
+
+    // From Strife: Veteran Edition:
+
+    "steamapps\\common\\Strife",
 };
 
 #define STEAM_BFG_GUS_PATCHES \
@@ -328,7 +332,7 @@
     int len;
 
     // Already configured? Don't stomp on the user's choices.
-    current_path = M_GetStrVariable("gus_patch_path");
+    current_path = M_GetStringVariable("gus_patch_path");
     if (current_path != NULL && strlen(current_path) > 0)
     {
         return;
--- a/src/d_loop.c
+++ b/src/d_loop.c
@@ -48,6 +48,12 @@
     boolean ingame[NET_MAXPLAYERS];
 } ticcmd_set_t;
 
+// Maximum time that we wait in TryRunTics() for netgame data to be
+// received before we bail out and render a frame anyway.
+// Vanilla Doom used 20 for this value, but we use a smaller value
+// instead for better responsiveness of the menu when we're stuck.
+#define MAX_NETGAME_STALL_TICS  5
+
 //
 // gametic is the tic about to (or currently being) run
 // maketic is the tic that hasn't had control made for it yet
@@ -746,7 +752,6 @@
 	counts = 1;
 
     // wait for new tics if needed
-
     while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
     {
 	NetUpdate ();
@@ -756,15 +761,19 @@
 	if (lowtic < gametic/ticdup)
 	    I_Error ("TryRunTics: lowtic < gametic");
 
-        // Don't stay in this loop forever.  The menu is still running,
-        // so return to update the screen
+        // Still no tics to run? Sleep until some are available.
+        if (lowtic < gametic/ticdup + counts)
+        {
+            // If we're in a netgame, we might spin forever waiting for
+            // new network data to be received. So don't stay in here
+            // forever - give the menu a chance to work.
+            if (I_GetTime() / ticdup - entertic >= MAX_NETGAME_STALL_TICS)
+            {
+                return;
+            }
 
-	if (I_GetTime() / ticdup - entertic > 0)
-	{
-	    return;
-	}
-
-        I_Sleep(1);
+            I_Sleep(1);
+        }
     }
 
     // run the count * ticdup dics
--- a/src/deh_io.c
+++ b/src/deh_io.c
@@ -235,7 +235,7 @@
     {
         c = DEH_GetChar(context);
 
-        if (c < 0)
+        if (c < 0 && pos == 0)
         {
             // end of file
 
@@ -273,7 +273,7 @@
 
         // blanks before the backslash are included in the string
         // but indentation after the linefeed is not
-        if (escaped && isspace(c) && c != '\n')
+        if (escaped && c >= 0 && isspace(c) && c != '\n')
         {
             continue;
         }
@@ -282,7 +282,7 @@
             escaped = false;
         }
 
-        if (c == '\n')
+        if (c == '\n' || c < 0)
         {
             // end of line: a full line has been read
 
--- a/src/doom.desktop.in
+++ b/src/doom.desktop.in
@@ -5,3 +5,4 @@
 Type=Application
 Comment=@PACKAGE_SHORTDESC@
 Categories=Game;ActionGame;
+Keywords=first;person;shooter;vanilla;
--- a/src/doom/Makefile.am
+++ b/src/doom/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS = -I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+AM_CFLAGS = -I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 noinst_LIBRARIES=libdoom.a
 
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -359,16 +359,16 @@
     NET_BindVariables();
 #endif
 
-    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
-    M_BindVariable("sfx_volume",             &sfxVolume);
-    M_BindVariable("music_volume",           &musicVolume);
-    M_BindVariable("show_messages",          &showMessages);
-    M_BindVariable("screenblocks",           &screenblocks);
-    M_BindVariable("detaillevel",            &detailLevel);
-    M_BindVariable("snd_channels",           &snd_channels);
-    M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
-    M_BindVariable("vanilla_demo_limit",     &vanilla_demo_limit);
-    M_BindVariable("show_endoom",            &show_endoom);
+    M_BindIntVariable("mouse_sensitivity",      &mouseSensitivity);
+    M_BindIntVariable("sfx_volume",             &sfxVolume);
+    M_BindIntVariable("music_volume",           &musicVolume);
+    M_BindIntVariable("show_messages",          &showMessages);
+    M_BindIntVariable("screenblocks",           &screenblocks);
+    M_BindIntVariable("detaillevel",            &detailLevel);
+    M_BindIntVariable("snd_channels",           &snd_channels);
+    M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+    M_BindIntVariable("vanilla_demo_limit",     &vanilla_demo_limit);
+    M_BindIntVariable("show_endoom",            &show_endoom);
 
     // Multiplayer chat macros
 
@@ -377,7 +377,7 @@
         char buf[12];
 
         M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
-        M_BindVariable(buf, &chat_macros[i]);
+        M_BindStringVariable(buf, &chat_macros[i]);
     }
 }
 
@@ -1151,6 +1151,11 @@
     }
 }
 
+static void G_CheckDemoStatusAtExit (void)
+{
+    G_CheckDemoStatus();
+}
+
 //
 // D_DoomMain
 //
@@ -1470,9 +1475,12 @@
 
     if (p)
     {
+        char *uc_filename = strdup(myargv[p + 1]);
+        M_ForceUppercase(uc_filename);
+
         // With Vanilla you have to specify the file without extension,
         // but make that optional.
-        if (M_StringEndsWith(myargv[p + 1], ".lmp"))
+        if (M_StringEndsWith(uc_filename, ".LMP"))
         {
             M_StringCopy(file, myargv[p + 1], sizeof(file));
         }
@@ -1481,6 +1489,8 @@
             DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]);
         }
 
+        free(uc_filename);
+
         if (D_AddFile(file))
         {
             M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
@@ -1498,7 +1508,7 @@
         printf("Playing demo %s.\n", file);
     }
 
-    I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+    I_AtExit(G_CheckDemoStatusAtExit, true);
 
     // Generate the WAD hash table.  Speed things up a bit.
     W_GenerateHashTable();
--- a/src/doom/d_player.h
+++ b/src/doom/d_player.h
@@ -111,7 +111,7 @@
     // Is wp_nochange if not changing.
     weapontype_t	pendingweapon;
 
-    boolean		weaponowned[NUMWEAPONS];
+    int                 weaponowned[NUMWEAPONS];
     int			ammo[NUMAMMO];
     int			maxammo[NUMAMMO];
 
--- a/src/doom/doom.desktop.in
+++ /dev/null
@@ -1,7 +1,0 @@
-[Desktop Entry]
-Name=@PACKAGE_NAME@
-Exec=@PROGRAM_PREFIX@doom
-Icon=@PROGRAM_PREFIX@doom
-Type=Application
-Comment=@PACKAGE_SHORTDESC@
-Categories=Game;ActionGame;
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -281,7 +281,7 @@
 static int G_NextWeapon(int direction)
 {
     weapontype_t weapon;
-    int i;
+    int start_i, i;
 
     // Find index in the table.
 
@@ -302,13 +302,13 @@
         }
     }
 
-    // Switch weapon.
-
+    // Switch weapon. Don't loop forever.
+    start_i = i;
     do
     {
         i += direction;
         i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
-    } while (!WeaponSelectable(weapon_order_table[i].weapon));
+    } while (i != start_i && !WeaponSelectable(weapon_order_table[i].weapon));
 
     return weapon_order_table[i].weapon_num;
 }
@@ -445,12 +445,11 @@
     // next_weapon variable is set to change weapons when
     // we generate a ticcmd.  Choose a new weapon.
 
-    if (next_weapon != 0)
+    if (gamestate == GS_LEVEL && next_weapon != 0)
     {
         i = G_NextWeapon(next_weapon);
         cmd->buttons |= BT_CHANGE;
         cmd->buttons |= i << BT_WEAPONSHIFT;
-        next_weapon = 0;
     }
     else
     {
@@ -469,6 +468,8 @@
         }
     }
 
+    next_weapon = 0;
+
     // mouse
     if (mousebuttons[mousebforward]) 
     {
@@ -610,6 +611,30 @@
     //  setting one.
 
     skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME));
+
+    // The "Sky never changes in Doom II" bug was fixed in
+    // the id Anthology version of doom2.exe for Final Doom.
+    if ((gamemode == commercial) && (gameversion == exe_final2))
+    {
+        char *skytexturename;
+
+        if (gamemap < 12)
+        {
+            skytexturename = "SKY1";
+        }
+        else if (gamemap < 21)
+        {
+            skytexturename = "SKY2";
+        }
+        else
+        {
+            skytexturename = "SKY3";
+        }
+
+        skytexturename = DEH_String(skytexturename);
+
+        skytexture = R_TextureNumForName(skytexturename);
+    }
 
     levelstarttic = gametic;        // for time calculation
     
--- a/src/doom/p_inter.c
+++ b/src/doom/p_inter.c
@@ -603,8 +603,9 @@
 	break;
 	
       case SPR_MGUN:
-	if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
-	    return;
+        if (!P_GiveWeapon(player, wp_chaingun,
+                          (special->flags & MF_DROPPED) != 0))
+            return;
 	player->message = DEH_String(GOTCHAINGUN);
 	sound = sfx_wpnup;	
 	break;
@@ -631,15 +632,17 @@
 	break;
 	
       case SPR_SHOT:
-	if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
-	    return;
+        if (!P_GiveWeapon(player, wp_shotgun,
+                          (special->flags & MF_DROPPED) != 0))
+            return;
 	player->message = DEH_String(GOTSHOTGUN);
 	sound = sfx_wpnup;	
 	break;
 		
       case SPR_SGN2:
-	if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
-	    return;
+        if (!P_GiveWeapon(player, wp_supershotgun,
+                          (special->flags & MF_DROPPED) != 0))
+            return;
 	player->message = DEH_String(GOTSHOTGUN2);
 	sound = sfx_wpnup;	
 	break;
--- a/src/doom/p_map.c
+++ b/src/doom/p_map.c
@@ -357,7 +357,7 @@
     // check for special pickup
     if (thing->flags & MF_SPECIAL)
     {
-	solid = thing->flags&MF_SOLID;
+	solid = (thing->flags & MF_SOLID) != 0;
 	if (tmflags&MF_PICKUP)
 	{
 	    // can remove thing
--- a/src/doom/p_maputl.c
+++ b/src/doom/p_maputl.c
@@ -846,7 +846,7 @@
 
     InterceptsMemoryOverrun(location, intercept->frac);
     InterceptsMemoryOverrun(location + 4, intercept->isaline);
-    InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing);
+    InterceptsMemoryOverrun(location + 8, (intptr_t) intercept->d.thing);
 }
 
 
@@ -887,7 +887,7 @@
 
     int		count;
 		
-    earlyout = flags & PT_EARLYOUT;
+    earlyout = (flags & PT_EARLYOUT) != 0;
 		
     validcount++;
     intercept_p = intercepts;
--- a/src/doom/p_saveg.c
+++ b/src/doom/p_saveg.c
@@ -184,12 +184,12 @@
 
 static void *saveg_readp(void)
 {
-    return (void *) saveg_read32();
+    return (void *) (intptr_t) saveg_read32();
 }
 
 static void saveg_writep(void *p)
 {
-    saveg_write32((int) p);
+    saveg_write32((intptr_t) p);
 }
 
 // Enum values are 32-bit integers.
--- a/src/doom/p_setup.c
+++ b/src/doom/p_setup.c
@@ -770,7 +770,10 @@
 
     // UNUSED W_Profile ();
     P_InitThinkers ();
-	   
+
+    // if working with a devlopment map, reload it
+    W_Reload ();
+
     // find map name
     if ( gamemode == commercial)
     {
--- a/src/doom/p_tick.c
+++ b/src/doom/p_tick.c
@@ -93,7 +93,7 @@
 //
 void P_RunThinkers (void)
 {
-    thinker_t*	currentthinker;
+    thinker_t *currentthinker, *nextthinker;
 
     currentthinker = thinkercap.next;
     while (currentthinker != &thinkercap)
@@ -101,16 +101,18 @@
 	if ( currentthinker->function.acv == (actionf_v)(-1) )
 	{
 	    // time to remove it
+            nextthinker = currentthinker->next;
 	    currentthinker->next->prev = currentthinker->prev;
 	    currentthinker->prev->next = currentthinker->next;
-	    Z_Free (currentthinker);
+	    Z_Free(currentthinker);
 	}
 	else
 	{
 	    if (currentthinker->function.acp1)
 		currentthinker->function.acp1 (currentthinker);
+            nextthinker = currentthinker->next;
 	}
-	currentthinker = currentthinker->next;
+	currentthinker = nextthinker;
     }
 }
 
--- a/src/doom/s_sound.c
+++ b/src/doom/s_sound.c
@@ -115,6 +115,7 @@
 {  
     int i;
 
+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);
 
     S_SetSfxVolume(sfxVolume);
@@ -174,11 +175,12 @@
                 break;
             }
         }
-        
+
         // degrade usefulness of sound data
 
         c->sfxinfo->usefulness--;
         c->sfxinfo = NULL;
+        c->origin = NULL;
     }
 }
 
--- a/src/doom/st_stuff.c
+++ b/src/doom/st_stuff.c
@@ -1261,11 +1261,12 @@
     // weapons owned
     for(i=0;i<6;i++)
     {
-	STlib_initMultIcon(&w_arms[i],
-			   ST_ARMSX+(i%3)*ST_ARMSXSPACE,
-			   ST_ARMSY+(i/3)*ST_ARMSYSPACE,
-			   arms[i], (int *) &plyr->weaponowned[i+1],
-			   &st_armson);
+        STlib_initMultIcon(&w_arms[i],
+                           ST_ARMSX+(i%3)*ST_ARMSXSPACE,
+                           ST_ARMSY+(i/3)*ST_ARMSYSPACE,
+                           arms[i],
+                           &plyr->weaponowned[i+1],
+                           &st_armson);
     }
 
     // frags sum
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -21,6 +21,10 @@
 #ifndef __DOOMTYPE__
 #define __DOOMTYPE__
 
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
 // #define macros to provide functions missing in Windows.
 // Outside Windows, we use strings.h for str[n]casecmp.
 
--- a/src/gusconf.c
+++ b/src/gusconf.c
@@ -39,7 +39,7 @@
 } gus_config_t;
 
 char *gus_patch_path = "";
-unsigned int gus_ram_kb = 1024;
+int gus_ram_kb = 1024;
 
 static unsigned int MappingIndex(void)
 {
--- a/src/gusconf.h
+++ b/src/gusconf.h
@@ -21,7 +21,7 @@
 #include "doomtype.h"
 
 extern char *gus_patch_path;
-extern unsigned int gus_ram_kb;
+extern int gus_ram_kb;
 
 boolean GUS_WriteConfig(char *path);
 
--- a/src/heretic.desktop.in
+++ b/src/heretic.desktop.in
@@ -5,3 +5,4 @@
 Type=Application
 Comment=@PACKAGE_SHORTDESC@
 Categories=Game;ActionGame;
+Keywords=first;person;shooter;doom;vanilla;
--- a/src/heretic/Makefile.am
+++ b/src/heretic/Makefile.am
@@ -1,6 +1,6 @@
 
-AM_CFLAGS=-I..                                            \
-          -I$(top_builddir)/textscreen                    \
+AM_CFLAGS=-I$(top_srcdir)/src                           \
+          -I$(top_srcdir)/textscreen                    \
           @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 noinst_LIBRARIES=libheretic.a
@@ -51,11 +51,7 @@
 r_things.c                                           \
 sb_bar.c                                             \
 sounds.c               sounds.h                      \
-s_sound.c              s_sound.h                     
-
-EXTRA_DIST=                                          \
-i_sound.c                                            \
-i_ibm.c   
+s_sound.c              s_sound.h
 
 FEATURE_DEHACKED_SOURCE_FILES =            \
 deh_ammo.c                                 \
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@ -756,13 +756,13 @@
     M_BindMenuControls();
     M_BindMapControls();
 
-    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
-    M_BindVariable("sfx_volume",             &snd_MaxVolume);
-    M_BindVariable("music_volume",           &snd_MusicVolume);
-    M_BindVariable("screenblocks",           &screenblocks);
-    M_BindVariable("snd_channels",           &snd_Channels);
-    M_BindVariable("show_endoom",            &show_endoom);
-    M_BindVariable("graphical_startup",      &graphical_startup);
+    M_BindIntVariable("mouse_sensitivity",      &mouseSensitivity);
+    M_BindIntVariable("sfx_volume",             &snd_MaxVolume);
+    M_BindIntVariable("music_volume",           &snd_MusicVolume);
+    M_BindIntVariable("screenblocks",           &screenblocks);
+    M_BindIntVariable("snd_channels",           &snd_Channels);
+    M_BindIntVariable("show_endoom",            &show_endoom);
+    M_BindIntVariable("graphical_startup",      &graphical_startup);
 
     for (i=0; i<10; ++i)
     {
@@ -769,7 +769,7 @@
         char buf[12];
 
         M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
-        M_BindVariable(buf, &chat_macros[i]);
+        M_BindStringVariable(buf, &chat_macros[i]);
     }
 }
 
@@ -1001,9 +1001,12 @@
 
     if (p)
     {
+        char *uc_filename = strdup(myargv[p + 1]);
+        M_ForceUppercase(uc_filename);
+
         // In Vanilla, the filename must be specified without .lmp,
         // but make that optional.
-        if (M_StringEndsWith(myargv[p + 1], ".lmp"))
+        if (M_StringEndsWith(uc_filename, ".LMP"))
         {
             M_StringCopy(file, myargv[p + 1], sizeof(file));
         }
@@ -1011,6 +1014,8 @@
         {
             DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p + 1]);
         }
+
+        free(uc_filename);
 
         if (D_AddFile(file))
         {
--- a/src/heretic/f_finale.c
+++ b/src/heretic/f_finale.c
@@ -213,10 +213,10 @@
         }
 
         w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
-        if (cx + w->width > SCREENWIDTH)
+        if (cx + SHORT(w->width) > SCREENWIDTH)
             break;
         V_DrawPatch(cx, cy, w);
-        cx += w->width;
+        cx += SHORT(w->width);
     }
 
 }
--- a/src/heretic/g_game.c
+++ b/src/heretic/g_game.c
@@ -228,7 +228,7 @@
 static int G_NextWeapon(int direction)
 {
     weapontype_t weapon;
-    int i;
+    int start_i, i;
 
     // Find index in the table.
 
@@ -249,13 +249,13 @@
         }
     }
 
-    // Switch weapon.
-
+    // Switch weapon. Don't loop forever.
+    start_i = i;
     do
     {
         i += direction;
         i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
-    } while (!WeaponSelectable(weapon_order_table[i].weapon));
+    } while (i != start_i && !WeaponSelectable(weapon_order_table[i].weapon));
 
     return weapon_order_table[i].weapon_num;
 }
@@ -466,7 +466,8 @@
     // we generate a ticcmd.  Choose a new weapon.
     // (Can't weapon cycle when the player is a chicken)
 
-    if (players[consoleplayer].chickenTics == 0 && next_weapon != 0)
+    if (gamestate == GS_LEVEL
+     && players[consoleplayer].chickenTics == 0 && next_weapon != 0)
     {
         i = G_NextWeapon(next_weapon);
         cmd->buttons |= BT_CHANGE;
--- a/src/heretic/i_ibm.c
+++ /dev/null
@@ -1,1642 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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.
-//
-
-// I_IBM.C
-
-#include <dos.h>
-#include <conio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <graph.h>
-#include "doomdef.h"
-#include "r_local.h"
-#include "dmx.h"
-#include "v_video.h"
-
-// Macros
-
-#define DPMI_INT 0x31
-//#define NOKBD
-//#define NOTIMER
-
-// Public Data
-
-int DisplayTicker = 0;
-
-// Code
-
-void main(int argc, char **argv)
-{
-    myargc = argc;
-    myargv = argv;
-    D_DoomMain();
-}
-
-void I_StartupNet(void);
-void I_ShutdownNet(void);
-void I_ReadExternDriver(void);
-
-typedef struct
-{
-    unsigned edi, esi, ebp, reserved, ebx, edx, ecx, eax;
-    unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss;
-} dpmiregs_t;
-
-extern dpmiregs_t dpmiregs;
-
-void I_ReadMouse(void);
-void I_InitDiskFlash(void);
-
-extern int usemouse, usejoystick;
-
-extern void **lumpcache;
-
-/*
-=============================================================================
-
-							CONSTANTS
-
-=============================================================================
-*/
-
-#define SC_INDEX                0x3C4
-#define SC_RESET                0
-#define SC_CLOCK                1
-#define SC_MAPMASK              2
-#define SC_CHARMAP              3
-#define SC_MEMMODE              4
-
-#define CRTC_INDEX              0x3D4
-#define CRTC_H_TOTAL    0
-#define CRTC_H_DISPEND  1
-#define CRTC_H_BLANK    2
-#define CRTC_H_ENDBLANK 3
-#define CRTC_H_RETRACE  4
-#define CRTC_H_ENDRETRACE 5
-#define CRTC_V_TOTAL    6
-#define CRTC_OVERFLOW   7
-#define CRTC_ROWSCAN    8
-#define CRTC_MAXSCANLINE 9
-#define CRTC_CURSORSTART 10
-#define CRTC_CURSOREND  11
-#define CRTC_STARTHIGH  12
-#define CRTC_STARTLOW   13
-#define CRTC_CURSORHIGH 14
-#define CRTC_CURSORLOW  15
-#define CRTC_V_RETRACE  16
-#define CRTC_V_ENDRETRACE 17
-#define CRTC_V_DISPEND  18
-#define CRTC_OFFSET             19
-#define CRTC_UNDERLINE  20
-#define CRTC_V_BLANK    21
-#define CRTC_V_ENDBLANK 22
-#define CRTC_MODE               23
-#define CRTC_LINECOMPARE 24
-
-
-#define GC_INDEX                0x3CE
-#define GC_SETRESET             0
-#define GC_ENABLESETRESET 1
-#define GC_COLORCOMPARE 2
-#define GC_DATAROTATE   3
-#define GC_READMAP              4
-#define GC_MODE                 5
-#define GC_MISCELLANEOUS 6
-#define GC_COLORDONTCARE 7
-#define GC_BITMASK              8
-
-#define ATR_INDEX               0x3c0
-#define ATR_MODE                16
-#define ATR_OVERSCAN    17
-#define ATR_COLORPLANEENABLE 18
-#define ATR_PELPAN              19
-#define ATR_COLORSELECT 20
-
-#define STATUS_REGISTER_1    0x3da
-
-#define PEL_WRITE_ADR   0x3c8
-#define PEL_READ_ADR    0x3c7
-#define PEL_DATA                0x3c9
-#define PEL_MASK                0x3c6
-
-boolean grmode;
-
-//==================================================
-//
-// joystick vars
-//
-//==================================================
-
-boolean joystickpresent;
-extern unsigned joystickx, joysticky;
-boolean I_ReadJoystick(void);   // returns false if not connected
-
-
-//==================================================
-
-#define VBLCOUNTER              34000   // hardware tics to a frame
-
-
-#define TIMERINT 8
-#define KEYBOARDINT 9
-
-#define CRTCOFF (_inbyte(STATUS_REGISTER_1)&1)
-#define CLI     _disable()
-#define STI     _enable()
-
-#define _outbyte(x,y) (outp(x,y))
-#define _outhword(x,y) (outpw(x,y))
-
-#define _inbyte(x) (inp(x))
-#define _inhword(x) (inpw(x))
-
-#define MOUSEB1 1
-#define MOUSEB2 2
-#define MOUSEB3 4
-
-boolean mousepresent;
-//static  int tsm_ID = -1; // tsm init flag
-
-//===============================
-
-int ticcount;
-
-// REGS stuff used for int calls
-union REGS regs;
-struct SREGS segregs;
-
-boolean novideo;                // if true, stay in text mode for debugging
-
-#define KBDQUESIZE 32
-byte keyboardque[KBDQUESIZE];
-int kbdtail, kbdhead;
-
-#define KEY_LSHIFT      0xfe
-
-#define KEY_INS         (0x80+0x52)
-#define KEY_DEL         (0x80+0x53)
-#define KEY_PGUP        (0x80+0x49)
-#define KEY_PGDN        (0x80+0x51)
-#define KEY_HOME        (0x80+0x47)
-#define KEY_END         (0x80+0x4f)
-
-#define SC_RSHIFT       0x36
-#define SC_LSHIFT       0x2a
-
-byte scantokey[128] = {
-//  0           1       2       3       4       5       6       7
-//  8           9       A       B       C       D       E       F
-    0, 27, '1', '2', '3', '4', '5', '6',
-    '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9,     // 0
-    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
-    'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's',        // 1
-    'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
-    39, '`', KEY_LSHIFT, 92, 'z', 'x', 'c', 'v',        // 2
-    'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT, '*',
-    KEY_RALT, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,   // 3
-    KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME,
-    KEY_UPARROW, KEY_PGUP, '-', KEY_LEFTARROW, '5', KEY_RIGHTARROW, '+', KEY_END,       //4
-    KEY_DOWNARROW, KEY_PGDN, KEY_INS, KEY_DEL, 0, 0, 0, KEY_F11,
-    KEY_F12, 0, 0, 0, 0, 0, 0, 0,       // 5
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,     // 6
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0      // 7
-};
-
-//==========================================================================
-
-//--------------------------------------------------------------------------
-//
-// FUNC I_GetTime
-//
-// Returns time in 1/35th second tics.
-//
-//--------------------------------------------------------------------------
-
-int I_GetTime(void)
-{
-#ifdef NOTIMER
-    ticcount++;
-#endif
-    return (ticcount);
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ColorBorder
-//
-//--------------------------------------------------------------------------
-
-void I_ColorBorder(void)
-{
-    int i;
-
-    I_WaitVBL(1);
-    _outbyte(PEL_WRITE_ADR, 0);
-    for (i = 0; i < 3; i++)
-    {
-        _outbyte(PEL_DATA, 63);
-    }
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_UnColorBorder
-//
-//--------------------------------------------------------------------------
-
-void I_UnColorBorder(void)
-{
-    int i;
-
-    I_WaitVBL(1);
-    _outbyte(PEL_WRITE_ADR, 0);
-    for (i = 0; i < 3; i++)
-    {
-        _outbyte(PEL_DATA, 0);
-    }
-}
-
-/*
-============================================================================
-
-								USER INPUT
-
-============================================================================
-*/
-
-//--------------------------------------------------------------------------
-//
-// PROC I_WaitVBL
-//
-//--------------------------------------------------------------------------
-
-void I_WaitVBL(int vbls)
-{
-    int i;
-    int old;
-    int stat;
-
-    if (novideo)
-    {
-        return;
-    }
-    while (vbls--)
-    {
-        do
-        {
-            stat = inp(STATUS_REGISTER_1);
-            if (stat & 8)
-            {
-                break;
-            }
-        }
-        while (1);
-        do
-        {
-            stat = inp(STATUS_REGISTER_1);
-            if ((stat & 8) == 0)
-            {
-                break;
-            }
-        }
-        while (1);
-    }
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_SetPalette
-//
-// Palette source must use 8 bit RGB elements.
-//
-//--------------------------------------------------------------------------
-
-void I_SetPalette(byte * palette)
-{
-    int i;
-
-    if (novideo)
-    {
-        return;
-    }
-    I_WaitVBL(1);
-    _outbyte(PEL_WRITE_ADR, 0);
-    for (i = 0; i < 768; i++)
-    {
-        _outbyte(PEL_DATA, (gammatable[usegamma][*palette++]) >> 2);
-    }
-}
-
-/*
-============================================================================
-
-							GRAPHICS MODE
-
-============================================================================
-*/
-
-byte *pcscreen, *destscreen, *destview;
-
-
-/*
-==============
-=
-= I_Update
-=
-==============
-*/
-
-int UpdateState;
-extern int screenblocks;
-
-void I_Update(void)
-{
-    int i;
-    byte *dest;
-    int tics;
-    static int lasttic;
-
-//
-// blit screen to video
-//
-    if (DisplayTicker)
-    {
-        if (screenblocks > 9 || UpdateState & (I_FULLSCRN | I_MESSAGES))
-        {
-            dest = (byte *) screen;
-        }
-        else
-        {
-            dest = (byte *) pcscreen;
-        }
-        tics = ticcount - lasttic;
-        lasttic = ticcount;
-        if (tics > 20)
-        {
-            tics = 20;
-        }
-        for (i = 0; i < tics; i++)
-        {
-            *dest = 0xff;
-            dest += 2;
-        }
-        for (i = tics; i < 20; i++)
-        {
-            *dest = 0x00;
-            dest += 2;
-        }
-    }
-    if (UpdateState == I_NOUPDATE)
-    {
-        return;
-    }
-    if (UpdateState & I_FULLSCRN)
-    {
-        memcpy(pcscreen, screen, SCREENWIDTH * SCREENHEIGHT);
-        UpdateState = I_NOUPDATE;       // clear out all draw types
-    }
-    if (UpdateState & I_FULLVIEW)
-    {
-        if (UpdateState & I_MESSAGES && screenblocks > 7)
-        {
-            for (i = 0; i <
-                 (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
-            {
-                memcpy(pcscreen + i, screen + i, SCREENWIDTH);
-            }
-            UpdateState &= ~(I_FULLVIEW | I_MESSAGES);
-        }
-        else
-        {
-            for (i = viewwindowy * SCREENWIDTH + viewwindowx; i <
-                 (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
-            {
-                memcpy(pcscreen + i, screen + i, viewwidth);
-            }
-            UpdateState &= ~I_FULLVIEW;
-        }
-    }
-    if (UpdateState & I_STATBAR)
-    {
-        memcpy(pcscreen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
-               screen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
-               SCREENWIDTH * SBARHEIGHT);
-        UpdateState &= ~I_STATBAR;
-    }
-    if (UpdateState & I_MESSAGES)
-    {
-        memcpy(pcscreen, screen, SCREENWIDTH * 28);
-        UpdateState &= ~I_MESSAGES;
-    }
-
-//  memcpy(pcscreen, screen, SCREENHEIGHT*SCREENWIDTH);
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_InitGraphics
-//
-//--------------------------------------------------------------------------
-
-void I_InitGraphics(void)
-{
-    if (novideo)
-    {
-        return;
-    }
-    grmode = true;
-    regs.w.ax = 0x13;
-    int386(0x10, (const union REGS *) &regs, &regs);
-    pcscreen = destscreen = (byte *) 0xa0000;
-    I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
-    I_InitDiskFlash();
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ShutdownGraphics
-//
-//--------------------------------------------------------------------------
-
-void I_ShutdownGraphics(void)
-{
-
-    if (*(byte *) 0x449 == 0x13)        // don't reset mode if it didn't get set
-    {
-        regs.w.ax = 3;
-        int386(0x10, &regs, &regs);     // back to text mode
-    }
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ReadScreen
-//
-// Reads the screen currently displayed into a linear buffer.
-//
-//--------------------------------------------------------------------------
-
-void I_ReadScreen(byte * scr)
-{
-    memcpy(scr, screen, SCREENWIDTH * SCREENHEIGHT);
-}
-
-
-//===========================================================================
-
-/*
-===================
-=
-= I_StartTic
-=
-// called by D_DoomLoop
-// called before processing each tic in a frame
-// can call D_PostEvent
-// asyncronous interrupt functions should maintain private ques that are
-// read by the syncronous functions to be converted into events
-===================
-*/
-
-/*
- OLD STARTTIC STUFF
-
-void   I_StartTic (void)
-{
-	int             k;
-	event_t ev;
-
-
-	I_ReadMouse ();
-
-//
-// keyboard events
-//
-	while (kbdtail < kbdhead)
-	{
-		k = keyboardque[kbdtail&(KBDQUESIZE-1)];
-
-//      if (k==14)
-//              I_Error ("exited");
-
-		kbdtail++;
-
-		// extended keyboard shift key bullshit
-		if ( (k&0x7f)==KEY_RSHIFT )
-		{
-			if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
-				continue;
-			k &= 0x80;
-			k |= KEY_RSHIFT;
-		}
-
-		if (k==0xe0)
-			continue;               // special / pause keys
-		if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
-			continue;                               // pause key bullshit
-
-		if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
-		{
-			ev.type = ev_keydown;
-			ev.data1 = KEY_PAUSE;
-			D_PostEvent (&ev);
-			continue;
-		}
-
-		if (k&0x80)
-			ev.type = ev_keyup;
-		else
-			ev.type = ev_keydown;
-		k &= 0x7f;
-
-		ev.data1 = k;
-		//ev.data1 = scantokey[k];
-
-		D_PostEvent (&ev);
-	}
-}
-*/
-
-#define SC_UPARROW              0x48
-#define SC_DOWNARROW    0x50
-#define SC_LEFTARROW            0x4b
-#define SC_RIGHTARROW   0x4d
-
-void I_StartTic(void)
-{
-    int k;
-    event_t ev;
-
-
-    I_ReadMouse();
-
-//
-// keyboard events
-//
-    while (kbdtail < kbdhead)
-    {
-        k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
-        kbdtail++;
-
-        // extended keyboard shift key bullshit
-        if ((k & 0x7f) == SC_LSHIFT || (k & 0x7f) == SC_RSHIFT)
-        {
-            if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe0)
-                continue;
-            k &= 0x80;
-            k |= SC_RSHIFT;
-        }
-
-        if (k == 0xe0)
-            continue;           // special / pause keys
-        if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe1)
-            continue;           // pause key bullshit
-
-        if (k == 0xc5
-            && keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0x9d)
-        {
-            ev.type = ev_keydown;
-            ev.data1 = KEY_PAUSE;
-            D_PostEvent(&ev);
-            continue;
-        }
-
-        if (k & 0x80)
-            ev.type = ev_keyup;
-        else
-            ev.type = ev_keydown;
-        k &= 0x7f;
-        switch (k)
-        {
-            case SC_UPARROW:
-                ev.data1 = KEY_UPARROW;
-                break;
-            case SC_DOWNARROW:
-                ev.data1 = KEY_DOWNARROW;
-                break;
-            case SC_LEFTARROW:
-                ev.data1 = KEY_LEFTARROW;
-                break;
-            case SC_RIGHTARROW:
-                ev.data1 = KEY_RIGHTARROW;
-                break;
-            default:
-                ev.data1 = scantokey[k];
-                break;
-        }
-        D_PostEvent(&ev);
-    }
-
-}
-
-
-void I_ReadKeys(void)
-{
-    int k;
-    event_t ev;
-
-
-    while (1)
-    {
-        while (kbdtail < kbdhead)
-        {
-            k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
-            kbdtail++;
-            printf("0x%x\n", k);
-            if (k == 1)
-                I_Quit();
-        }
-    }
-}
-
-/*
-===============
-=
-= I_StartFrame
-=
-===============
-*/
-
-void I_StartFrame(void)
-{
-    I_JoystickEvents();
-    I_ReadExternDriver();
-}
-
-/*
-============================================================================
-
-					TIMER INTERRUPT
-
-============================================================================
-*/
-
-void I_ColorBlack(int r, int g, int b)
-{
-    _outbyte(PEL_WRITE_ADR, 0);
-    _outbyte(PEL_DATA, r);
-    _outbyte(PEL_DATA, g);
-    _outbyte(PEL_DATA, b);
-}
-
-
-/*
-================
-=
-= I_TimerISR
-=
-================
-*/
-
-int I_TimerISR(void)
-{
-    ticcount++;
-    return 0;
-}
-
-/*
-============================================================================
-
-						KEYBOARD
-
-============================================================================
-*/
-
-void (__interrupt __far * oldkeyboardisr) () = NULL;
-
-int lastpress;
-
-/*
-================
-=
-= I_KeyboardISR
-=
-================
-*/
-
-void __interrupt I_KeyboardISR(void)
-{
-// Get the scan code
-
-    keyboardque[kbdhead & (KBDQUESIZE - 1)] = lastpress = _inbyte(0x60);
-    kbdhead++;
-
-// acknowledge the interrupt
-
-    _outbyte(0x20, 0x20);
-}
-
-
-
-/*
-===============
-=
-= I_StartupKeyboard
-=
-===============
-*/
-
-void I_StartupKeyboard(void)
-{
-#ifndef NOKBD
-    oldkeyboardisr = _dos_getvect(KEYBOARDINT);
-    _dos_setvect(0x8000 | KEYBOARDINT, I_KeyboardISR);
-#endif
-
-//I_ReadKeys ();
-}
-
-
-void I_ShutdownKeyboard(void)
-{
-    if (oldkeyboardisr)
-        _dos_setvect(KEYBOARDINT, oldkeyboardisr);
-    *(short *) 0x41c = *(short *) 0x41a;        // clear bios key buffer
-}
-
-
-
-/*
-============================================================================
-
-							MOUSE
-
-============================================================================
-*/
-
-
-int I_ResetMouse(void)
-{
-    regs.w.ax = 0;              // reset
-    int386(0x33, &regs, &regs);
-    return regs.w.ax;
-}
-
-
-
-/*
-================
-=
-= StartupMouse
-=
-================
-*/
-
-void I_StartupCyberMan(void);
-
-void I_StartupMouse(void)
-{
-    int (far * function) ();
-
-    //
-    // General mouse detection
-    //
-    mousepresent = 0;
-    if (M_CheckParm("-nomouse") || !usemouse)
-        return;
-
-    if (I_ResetMouse() != 0xffff)
-    {
-        tprintf("Mouse: not present ", 0);
-        return;
-    }
-    tprintf("Mouse: detected ", 0);
-
-    mousepresent = 1;
-
-    I_StartupCyberMan();
-}
-
-
-/*
-================
-=
-= ShutdownMouse
-=
-================
-*/
-
-void I_ShutdownMouse(void)
-{
-    if (!mousepresent)
-        return;
-
-    I_ResetMouse();
-}
-
-
-/*
-================
-=
-= I_ReadMouse
-=
-================
-*/
-
-void I_ReadMouse(void)
-{
-    event_t ev;
-
-//
-// mouse events
-//
-    if (!mousepresent)
-        return;
-
-    ev.type = ev_mouse;
-
-    memset(&dpmiregs, 0, sizeof(dpmiregs));
-    dpmiregs.eax = 3;           // read buttons / position
-    DPMIInt(0x33);
-    ev.data1 = dpmiregs.ebx;
-
-    dpmiregs.eax = 11;          // read counters
-    DPMIInt(0x33);
-    ev.data2 = (short) dpmiregs.ecx;
-    ev.data3 = -(short) dpmiregs.edx;
-
-    D_PostEvent(&ev);
-}
-
-/*
-============================================================================
-
-					JOYSTICK
-
-============================================================================
-*/
-
-int joyxl, joyxh, joyyl, joyyh;
-
-boolean WaitJoyButton(void)
-{
-    int oldbuttons, buttons;
-
-    oldbuttons = 0;
-    do
-    {
-        I_WaitVBL(1);
-        buttons = ((inp(0x201) >> 4) & 1) ^ 1;
-        if (buttons != oldbuttons)
-        {
-            oldbuttons = buttons;
-            continue;
-        }
-
-        if ((lastpress & 0x7f) == 1)
-        {
-            joystickpresent = false;
-            return false;
-        }
-    }
-    while (!buttons);
-
-    do
-    {
-        I_WaitVBL(1);
-        buttons = ((inp(0x201) >> 4) & 1) ^ 1;
-        if (buttons != oldbuttons)
-        {
-            oldbuttons = buttons;
-            continue;
-        }
-
-        if ((lastpress & 0x7f) == 1)
-        {
-            joystickpresent = false;
-            return false;
-        }
-    }
-    while (buttons);
-
-    return true;
-}
-
-
-
-/*
-===============
-=
-= I_StartupJoystick
-=
-===============
-*/
-
-int basejoyx, basejoyy;
-
-void I_StartupJoystick(void)
-{
-    int buttons;
-    int count;
-    int centerx, centery;
-
-    joystickpresent = 0;
-    if (M_CheckParm("-nojoy") || !usejoystick)
-        return;
-
-    if (!I_ReadJoystick())
-    {
-        joystickpresent = false;
-        tprintf("joystick not found ", 0);
-        return;
-    }
-    printf("joystick found\n");
-    joystickpresent = true;
-
-    printf("CENTER the joystick and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    centerx = joystickx;
-    centery = joysticky;
-
-    printf
-        ("\nPush the joystick to the UPPER LEFT corner and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    joyxl = (centerx + joystickx) / 2;
-    joyyl = (centerx + joysticky) / 2;
-
-    printf
-        ("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    joyxh = (centerx + joystickx) / 2;
-    joyyh = (centery + joysticky) / 2;
-    printf("\n");
-}
-
-/*
-===============
-=
-= I_JoystickEvents
-=
-===============
-*/
-
-void I_JoystickEvents(void)
-{
-    event_t ev;
-
-//
-// joystick events
-//
-    if (!joystickpresent)
-        return;
-
-    I_ReadJoystick();
-    ev.type = ev_joystick;
-    ev.data1 = ((inp(0x201) >> 4) & 15) ^ 15;
-
-    if (joystickx < joyxl)
-        ev.data2 = -1;
-    else if (joystickx > joyxh)
-        ev.data2 = 1;
-    else
-        ev.data2 = 0;
-    if (joysticky < joyyl)
-        ev.data3 = -1;
-    else if (joysticky > joyyh)
-        ev.data3 = 1;
-    else
-        ev.data3 = 0;
-
-    D_PostEvent(&ev);
-}
-
-
-
-/*
-============================================================================
-
-					DPMI STUFF
-
-============================================================================
-*/
-
-#define REALSTACKSIZE   1024
-
-dpmiregs_t dpmiregs;
-
-unsigned realstackseg;
-
-void I_DivException(void);
-int I_SetDivException(void);
-
-void DPMIFarCall(void)
-{
-    segread(&segregs);
-    regs.w.ax = 0x301;
-    regs.w.bx = 0;
-    regs.w.cx = 0;
-    regs.x.edi = (unsigned) &dpmiregs;
-    segregs.es = segregs.ds;
-    int386x(DPMI_INT, &regs, &regs, &segregs);
-}
-
-
-void DPMIInt(int i)
-{
-    dpmiregs.ss = realstackseg;
-    dpmiregs.sp = REALSTACKSIZE - 4;
-
-    segread(&segregs);
-    regs.w.ax = 0x300;
-    regs.w.bx = i;
-    regs.w.cx = 0;
-    regs.x.edi = (unsigned) &dpmiregs;
-    segregs.es = segregs.ds;
-    int386x(DPMI_INT, &regs, &regs, &segregs);
-}
-
-
-/*
-==============
-=
-= I_StartupDPMI
-=
-==============
-*/
-
-void I_StartupDPMI(void)
-{
-    extern char __begtext;
-    extern char ___argc;
-    int n, d;
-
-//
-// allocate a decent stack for real mode ISRs
-//
-    realstackseg = (int) I_AllocLow(1024) >> 4;
-
-//
-// lock the entire program down
-//
-
-//      _dpmi_lockregion (&__begtext, &___argc - &__begtext);
-
-
-//
-// catch divide by 0 exception
-//
-#if 0
-    segread(&segregs);
-    regs.w.ax = 0x0203;         // DPMI set processor exception handler vector
-    regs.w.bx = 0;              // int 0
-    regs.w.cx = segregs.cs;
-    regs.x.edx = (int) &I_DivException;
-    printf("%x : %x\n", regs.w.cx, regs.x.edx);
-    int386(DPMI_INT, &regs, &regs);
-#endif
-
-#if 0
-    n = I_SetDivException();
-    printf("return: %i\n", n);
-    n = 100;
-    d = 0;
-    printf("100 / 0 = %i\n", n / d);
-
-    exit(1);
-#endif
-}
-
-
-
-/*
-============================================================================
-
-					TIMER INTERRUPT
-
-============================================================================
-*/
-
-void (__interrupt __far * oldtimerisr) ();
-
-
-void IO_ColorBlack(int r, int g, int b)
-{
-    _outbyte(PEL_WRITE_ADR, 0);
-    _outbyte(PEL_DATA, r);
-    _outbyte(PEL_DATA, g);
-    _outbyte(PEL_DATA, b);
-}
-
-
-/*
-================
-=
-= IO_TimerISR
-=
-================
-*/
-
-//void __interrupt IO_TimerISR (void)
-
-void __interrupt __far IO_TimerISR(void)
-{
-    ticcount++;
-    _outbyte(0x20, 0x20);       // Ack the interrupt
-}
-
-/*
-=====================
-=
-= IO_SetTimer0
-=
-= Sets system timer 0 to the specified speed
-=
-=====================
-*/
-
-void IO_SetTimer0(int speed)
-{
-    if (speed > 0 && speed < 150)
-        I_Error("INT_SetTimer0: %i is a bad value", speed);
-
-    _outbyte(0x43, 0x36);       // Change timer 0
-    _outbyte(0x40, speed);
-    _outbyte(0x40, speed >> 8);
-}
-
-
-
-/*
-===============
-=
-= IO_StartupTimer
-=
-===============
-*/
-
-void IO_StartupTimer(void)
-{
-    oldtimerisr = _dos_getvect(TIMERINT);
-
-    _dos_setvect(0x8000 | TIMERINT, IO_TimerISR);
-    IO_SetTimer0(VBLCOUNTER);
-}
-
-void IO_ShutdownTimer(void)
-{
-    if (oldtimerisr)
-    {
-        IO_SetTimer0(0);        // back to 18.4 ips
-        _dos_setvect(TIMERINT, oldtimerisr);
-    }
-}
-
-//===========================================================================
-
-
-/*
-===============
-=
-= I_Init
-=
-= hook interrupts and set graphics mode
-=
-===============
-*/
-
-void I_Init(void)
-{
-    extern void I_StartupTimer(void);
-
-    novideo = M_CheckParm("novideo");
-    tprintf("I_StartupDPMI", 1);
-    I_StartupDPMI();
-    tprintf("I_StartupMouse ", 1);
-    I_StartupMouse();
-//      tprintf("I_StartupJoystick ",1);
-//      I_StartupJoystick();
-//      tprintf("I_StartupKeyboard ",1);
-//      I_StartupKeyboard();
-}
-
-
-/*
-===============
-=
-= I_Shutdown
-=
-= return to default system state
-=
-===============
-*/
-
-void I_Shutdown(void)
-{
-    I_ShutdownGraphics();
-    IO_ShutdownTimer();
-    S_ShutDown();
-    I_ShutdownMouse();
-    I_ShutdownKeyboard();
-
-    IO_SetTimer0(0);
-}
-
-
-/*
-================
-=
-= I_Error
-=
-================
-*/
-
-void I_Error(char *error, ...)
-{
-    union REGS regs;
-
-    va_list argptr;
-
-    D_QuitNetGame();
-    I_Shutdown();
-    va_start(argptr, error);
-    regs.x.eax = 0x3;
-    int386(0x10, &regs, &regs);
-    vprintf(error, argptr);
-    va_end(argptr);
-    printf("\n");
-    exit(1);
-}
-
-//--------------------------------------------------------------------------
-//
-// I_Quit
-//
-// Shuts down net game, saves defaults, prints the exit text message,
-// goes to text mode, and exits.
-//
-//--------------------------------------------------------------------------
-
-void I_Quit(void)
-{
-    byte *scr;
-    char *lumpName;
-    int r;
-
-    D_QuitNetGame();
-    M_SaveDefaults();
-    scr = (byte *) W_CacheLumpName("ENDTEXT", PU_CACHE);
-    I_Shutdown();
-    memcpy((void *) 0xb8000, scr, 80 * 25 * 2);
-    regs.w.ax = 0x0200;
-    regs.h.bh = 0;
-    regs.h.dl = 0;
-    regs.h.dh = 23;
-    int386(0x10, (const union REGS *) &regs, &regs);    // Set text pos
-    _settextposition(24, 1);
-    exit(0);
-}
-
-/*
-===============
-=
-= I_ZoneBase
-=
-===============
-*/
-
-byte *I_ZoneBase(int *size)
-{
-    int meminfo[32];
-    int heap;
-    int i;
-    int block;
-    byte *ptr;
-
-    memset(meminfo, 0, sizeof(meminfo));
-    segread(&segregs);
-    segregs.es = segregs.ds;
-    regs.w.ax = 0x500;          // get memory info
-    regs.x.edi = (int) &meminfo;
-    int386x(0x31, &regs, &regs, &segregs);
-
-    heap = meminfo[0];
-    printf("DPMI memory: 0x%x, ", heap);
-
-    do
-    {
-        heap -= 0x10000;        // leave 64k alone
-        if (heap > 0x800000)
-            heap = 0x800000;
-        ptr = malloc(heap);
-    }
-    while (!ptr);
-
-    printf("0x%x allocated for zone\n", heap);
-    if (heap < 0x180000)
-        I_Error("Insufficient DPMI memory!");
-#if 0
-    regs.w.ax = 0x501;          // allocate linear block
-    regs.w.bx = heap >> 16;
-    regs.w.cx = heap & 0xffff;
-    int386(0x31, &regs, &regs);
-    if (regs.w.cflag)
-        I_Error("Couldn't allocate DPMI memory!");
-
-    block = (regs.w.si << 16) + regs.w.di;
-#endif
-
-    *size = heap;
-    return ptr;
-}
-
-/*
-=============================================================================
-
-					DISK ICON FLASHING
-
-=============================================================================
-*/
-
-void I_InitDiskFlash(void)
-{
-#if 0
-    void *pic;
-    byte *temp;
-
-    pic = W_CacheLumpName("STDISK", PU_CACHE);
-    temp = destscreen;
-    destscreen = (byte *) 0xac000;
-    V_DrawPatchDirect(SCREENWIDTH - 16, SCREENHEIGHT - 16, 0, pic);
-    destscreen = temp;
-#endif
-}
-
-// draw disk icon
-void I_BeginRead(void)
-{
-#if 0
-    byte *src, *dest;
-    int y;
-
-    if (!grmode)
-        return;
-
-// write through all planes
-    outp(SC_INDEX, SC_MAPMASK);
-    outp(SC_INDEX + 1, 15);
-// set write mode 1
-    outp(GC_INDEX, GC_MODE);
-    outp(GC_INDEX + 1, inp(GC_INDEX + 1) | 1);
-
-// copy to backup
-    src = currentscreen + 184 * 80 + 304 / 4;
-    dest = (byte *) 0xac000 + 184 * 80 + 288 / 4;
-    for (y = 0; y < 16; y++)
-    {
-        dest[0] = src[0];
-        dest[1] = src[1];
-        dest[2] = src[2];
-        dest[3] = src[3];
-        src += 80;
-        dest += 80;
-    }
-
-// copy disk over
-    dest = currentscreen + 184 * 80 + 304 / 4;
-    src = (byte *) 0xac000 + 184 * 80 + 304 / 4;
-    for (y = 0; y < 16; y++)
-    {
-        dest[0] = src[0];
-        dest[1] = src[1];
-        dest[2] = src[2];
-        dest[3] = src[3];
-        src += 80;
-        dest += 80;
-    }
-
-
-// set write mode 0
-    outp(GC_INDEX, GC_MODE);
-    outp(GC_INDEX + 1, inp(GC_INDEX + 1) & ~1);
-#endif
-}
-
-// erase disk icon
-void I_EndRead(void)
-{
-#if 0
-    byte *src, *dest;
-    int y;
-
-    if (!grmode)
-        return;
-
-// write through all planes
-    outp(SC_INDEX, SC_MAPMASK);
-    outp(SC_INDEX + 1, 15);
-// set write mode 1
-    outp(GC_INDEX, GC_MODE);
-    outp(GC_INDEX + 1, inp(GC_INDEX + 1) | 1);
-
-
-// copy disk over
-    dest = currentscreen + 184 * 80 + 304 / 4;
-    src = (byte *) 0xac000 + 184 * 80 + 288 / 4;
-    for (y = 0; y < 16; y++)
-    {
-        dest[0] = src[0];
-        dest[1] = src[1];
-        dest[2] = src[2];
-        dest[3] = src[3];
-        src += 80;
-        dest += 80;
-    }
-
-// set write mode 0
-    outp(GC_INDEX, GC_MODE);
-    outp(GC_INDEX + 1, inp(GC_INDEX + 1) & ~1);
-#endif
-}
-
-
-
-/*
-=============
-=
-= I_AllocLow
-=
-=============
-*/
-
-byte *I_AllocLow(int length)
-{
-    byte *mem;
-
-    // DPMI call 100h allocates DOS memory
-    segread(&segregs);
-    regs.w.ax = 0x0100;         // DPMI allocate DOS memory
-    regs.w.bx = (length + 15) / 16;
-    int386(DPMI_INT, &regs, &regs);
-//      segment = regs.w.ax;
-//   selector = regs.w.dx;
-    if (regs.w.cflag != 0)
-        I_Error("I_AllocLow: DOS alloc of %i failed, %i free",
-                length, regs.w.bx * 16);
-
-
-    mem = (void *) ((regs.x.eax & 0xFFFF) << 4);
-
-    memset(mem, 0, length);
-    return mem;
-}
-
-/*
-============================================================================
-
-						NETWORKING
-
-============================================================================
-*/
-
-/* // FUCKED LINES
-typedef struct
-{
-	char    priv[508];
-   } doomdata_t;
-*/// FUCKED LINES
-
-#define DOOMCOM_ID              0x12345678l
-
-/* // FUCKED LINES
-typedef struct
-{
-	long    id;
-	short   intnum;                 // DOOM executes an int to execute commands
-
-// communication between DOOM and the driver
-	short   command;                // CMD_SEND or CMD_GET
-	short   remotenode;             // dest for send, set by get (-1 = no packet)
-	short   datalength;             // bytes in doomdata to be sent
-
-// info common to all nodes
-	short   numnodes;               // console is allways node 0
-	short   ticdup;                 // 1 = no duplication, 2-5 = dup for slow nets
-	short   extratics;              // 1 = send a backup tic in every packet
-	short   deathmatch;             // 1 = deathmatch
-	short   savegame;               // -1 = new game, 0-5 = load savegame
-	short   episode;                // 1-3
-	short   map;                    // 1-9
-	short   skill;                  // 1-5
-
-// info specific to this node
-	short   consoleplayer;
-	short   numplayers;
-	short   angleoffset;    // 1 = left, 0 = center, -1 = right
-	short   drone;                  // 1 = drone
-
-// packet data to be sent
-	doomdata_t      data;
-   } doomcom_t;
-*/// FUCKED LINES
-
-extern doomcom_t *doomcom;
-
-/*
-====================
-=
-= I_InitNetwork
-=
-====================
-*/
-
-void I_InitNetwork(void)
-{
-    int i;
-
-    i = M_CheckParm("-net");
-    if (!i)
-    {
-        //
-        // single player game
-        //
-        doomcom = malloc(sizeof(*doomcom));
-        memset(doomcom, 0, sizeof(*doomcom));
-        netgame = false;
-        doomcom->id = DOOMCOM_ID;
-        doomcom->numplayers = doomcom->numnodes = 1;
-        doomcom->deathmatch = false;
-        doomcom->consoleplayer = 0;
-        doomcom->ticdup = 1;
-        doomcom->extratics = 0;
-        return;
-    }
-
-    netgame = true;
-    doomcom = (doomcom_t *) atoi(myargv[i + 1]);
-//DEBUG
-    doomcom->skill = startskill;
-    doomcom->episode = startepisode;
-    doomcom->map = startmap;
-    doomcom->deathmatch = deathmatch;
-
-}
-
-void I_NetCmd(void)
-{
-    if (!netgame)
-        I_Error("I_NetCmd when not in netgame");
-    DPMIInt(doomcom->intnum);
-}
-
-int i_Vector;
-externdata_t *i_ExternData;
-boolean useexterndriver;
-
-//=========================================================================
-//
-// I_CheckExternDriver
-//
-//              Checks to see if a vector, and an address for an external driver
-//                      have been passed.
-//=========================================================================
-
-void I_CheckExternDriver(void)
-{
-    int i;
-
-    if (!(i = M_CheckParm("-externdriver")))
-    {
-        return;
-    }
-    i_ExternData = (externdata_t *) atoi(myargv[i + 1]);
-    i_Vector = i_ExternData->vector;
-
-    useexterndriver = true;
-}
-
-//=========================================================================
-//
-// I_ReadExternDriver
-//
-//              calls the external interrupt, which should then update i_ExternDriver
-//=========================================================================
-
-void I_ReadExternDriver(void)
-{
-    event_t ev;
-
-    if (useexterndriver)
-    {
-        DPMIInt(i_Vector);
-    }
-}
--- a/src/heretic/i_sound.c
+++ /dev/null
@@ -1,426 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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.
-//
-
-// I_SOUND.C
-
-#include <stdio.h>
-#include "doomdef.h"
-#include "dmx.h"
-#include "sounds.h"
-#include "i_sound.h"
-#include "v_video.h"
-
-/*
-===============
-=
-= I_StartupTimer
-=
-===============
-*/
-
-int tsm_ID = -1;
-
-void I_StartupTimer(void)
-{
-#ifndef NOTIMER
-    extern int I_TimerISR(void);
-
-    tprintf("I_StartupTimer()\n", 0);
-    // installs master timer.  Must be done before StartupTimer()!
-    TSM_Install(SND_TICRATE);
-    tsm_ID = TSM_NewService(I_TimerISR, 35, 255, 0);    // max priority
-    if (tsm_ID == -1)
-    {
-        I_Error("Can't register 35 Hz timer w/ DMX library");
-    }
-#endif
-}
-
-void I_ShutdownTimer(void)
-{
-    TSM_DelService(tsm_ID);
-    TSM_Remove();
-}
-
-/*
- *
- *                           SOUND HEADER & DATA
- *
- *
- */
-
-// sound information
-#if 0
-const char *dnames[] = { "None",
-    "PC_Speaker",
-    "Adlib",
-    "Sound_Blaster",
-    "ProAudio_Spectrum16",
-    "Gravis_Ultrasound",
-    "MPU",
-    "AWE32"
-};
-#endif
-
-const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
-    'M', 'M', 'S'
-};
-
-int snd_Channels;
-int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
-int snd_MusicDevice,            // current music card # (index to dmxCodes)
-  snd_SfxDevice,                // current sfx card # (index to dmxCodes)
-  snd_MaxVolume,                // maximum volume for sound
-  snd_MusicVolume;              // maximum volume for music
-int dmxCodes[NUM_SCARDS];       // the dmx code for a given card
-
-int snd_SBport, snd_SBirq, snd_SBdma;   // sound blaster variables
-int snd_Mport;                  // midi variables
-
-extern boolean snd_MusicAvail,  // whether music is available
-  snd_SfxAvail;                 // whether sfx are available
-
-void I_PauseSong(int handle)
-{
-    MUS_PauseSong(handle);
-}
-
-void I_ResumeSong(int handle)
-{
-    MUS_ResumeSong(handle);
-}
-
-void I_SetMusicVolume(int volume)
-{
-    MUS_SetMasterVolume(volume * 8);
-//  snd_MusicVolume = volume;
-}
-
-void I_SetSfxVolume(int volume)
-{
-    snd_MaxVolume = volume;     // THROW AWAY?
-}
-
-/*
- *
- *                              SONG API
- *
- */
-
-int I_RegisterSong(void *data)
-{
-    int rc = MUS_RegisterSong(data);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_Reg() returned %d\n", rc);
-#endif
-    return rc;
-}
-
-void I_UnRegisterSong(int handle)
-{
-    int rc = MUS_UnregisterSong(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_Unreg() returned %d\n", rc);
-#endif
-}
-
-int I_QrySongPlaying(int handle)
-{
-    int rc = MUS_QrySongPlaying(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_QrySP() returned %d\n", rc);
-#endif
-    return rc;
-}
-
-// Stops a song.  MUST be called before I_UnregisterSong().
-
-void I_StopSong(int handle)
-{
-    int rc;
-    rc = MUS_StopSong(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_StopSong() returned %d\n", rc);
-#endif
-    // Fucking kluge pause
-    {
-        int s;
-        extern volatile int ticcount;
-        for (s = ticcount; ticcount - s < 10;);
-    }
-}
-
-void I_PlaySong(int handle, boolean looping)
-{
-    int rc;
-    rc = MUS_ChainSong(handle, looping ? handle : -1);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_ChainSong() returned %d\n", rc);
-#endif
-    rc = MUS_PlaySong(handle, snd_MusicVolume);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        printf("MUS_PlaySong() returned %d\n", rc);
-#endif
-
-}
-
-/*
- *
- *                                 SOUND FX API
- *
- */
-
-// Gets lump nums of the named sound.  Returns pointer which will be
-// passed to I_StartSound() when you want to start an SFX.  Must be
-// sure to pass this to UngetSoundEffect() so that they can be
-// freed!
-
-
-int I_GetSfxLumpNum(sfxinfo_t * sound)
-{
-    char namebuf[9];
-
-    if (sound->name == 0)
-        return 0;
-    if (sound->link)
-        sound = sound->link;
-//  M_snprintf(namebuf, sizeof(namebuf), "d%c%s",
-//             snd_prefixen[snd_SfxDevice], sound->name);
-    return W_GetNumForName(sound->name);
-
-}
-
-int I_StartSound(int id, void *data, int vol, int sep, int pitch,
-                 int priority)
-{
-/*
-  // hacks out certain PC sounds
-  if (snd_SfxDevice == PC
-	&& (data == S_sfx[sfx_posact].data
-	||  data == S_sfx[sfx_bgact].data
-	||  data == S_sfx[sfx_dmact].data
-	||  data == S_sfx[sfx_dmpain].data
-	||  data == S_sfx[sfx_popain].data
-	||  data == S_sfx[sfx_sawidl].data)) return -1;
-
-  else
-		*/
-    return SFX_PlayPatch(data, pitch, sep, vol, 0, 0);
-
-}
-
-void I_StopSound(int handle)
-{
-//  extern volatile long gDmaCount;
-//  long waittocount;
-    SFX_StopPatch(handle);
-//  waittocount = gDmaCount + 2;
-//  while (gDmaCount < waittocount) ;
-}
-
-int I_SoundIsPlaying(int handle)
-{
-    return SFX_Playing(handle);
-}
-
-void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
-{
-    SFX_SetOrigin(handle, pitch, sep, vol);
-}
-
-/*
- *
- *                                                      SOUND STARTUP STUFF
- *
- *
- */
-
-//
-// Why PC's Suck, Reason #8712
-//
-
-void I_sndArbitrateCards(void)
-{
-    char tmp[160];
-    boolean gus, adlib, pc, sb, midi;
-    int i, rc, mputype, p, opltype, wait, dmxlump;
-
-//  snd_MaxVolume = 127;
-    //Damn you, Dave Taylor!
-
-    snd_MusicDevice = snd_DesiredMusicDevice;
-    snd_SfxDevice = snd_DesiredSfxDevice;
-
-    // check command-line parameters- overrides config file
-    //
-    if (M_CheckParm("-nosound"))
-        snd_MusicDevice = snd_SfxDevice = snd_none;
-    if (M_CheckParm("-nosfx"))
-        snd_SfxDevice = snd_none;
-    if (M_CheckParm("-nomusic"))
-        snd_MusicDevice = snd_none;
-
-    if (snd_MusicDevice > snd_MPU && snd_MusicDevice <= snd_MPU3)
-        snd_MusicDevice = snd_MPU;
-    if (snd_MusicDevice == snd_SB)
-        snd_MusicDevice = snd_Adlib;
-    if (snd_MusicDevice == snd_PAS)
-        snd_MusicDevice = snd_Adlib;
-
-    // figure out what i've got to initialize
-    //
-    gus = snd_MusicDevice == snd_GUS || snd_SfxDevice == snd_GUS;
-    sb = snd_SfxDevice == snd_SB || snd_MusicDevice == snd_SB;
-    adlib = snd_MusicDevice == snd_Adlib;
-    pc = snd_SfxDevice == snd_PC;
-    midi = snd_MusicDevice == snd_MPU;
-
-    // initialize whatever i've got
-    //
-    if (gus)
-    {
-        if (GF1_Detect())
-            tprintf("Dude.  The GUS ain't responding.\n", 1);
-        else
-        {
-            dmxlump = W_GetNumForName("dmxgus");
-            GF1_SetMap(W_CacheLumpNum(dmxlump, PU_CACHE),
-                       lumpinfo[dmxlump].size);
-        }
-
-    }
-    if (sb)
-    {
-        if (debugmode)
-        {
-            M_snprintf(tmp, sizeof(tmp), "cfg p=0x%x, i=%d, d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-            tprintf(tmp, 0);
-        }
-        if (SB_Detect(&snd_SBport, &snd_SBirq, &snd_SBdma, 0))
-        {
-            M_snprintf(tmp, sizeof(tmp),
-                       "SB isn't responding at p=0x%x, i=%d, d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-            tprintf(tmp, 0);
-        }
-        else
-            SB_SetCard(snd_SBport, snd_SBirq, snd_SBdma);
-
-        if (debugmode)
-        {
-            M_snprintf(tmp, sizeof(tmp), "SB_Detect returned p=0x%x,i=%d,d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-            tprintf(tmp, 0);
-        }
-    }
-
-    if (adlib)
-    {
-        if (AL_Detect(&wait, 0))
-            tprintf("Dude.  The Adlib isn't responding.\n", 1);
-        else
-            AL_SetCard(wait, W_CacheLumpName("genmidi", PU_STATIC));
-    }
-
-    if (midi)
-    {
-        if (debugmode)
-        {
-            M_snprintf(tmp, sizeof(tmp), "cfg p=0x%x\n", snd_Mport);
-            tprintf(tmp, 0);
-        }
-
-        if (MPU_Detect(&snd_Mport, &i))
-        {
-            M_snprintf(tmp, sizeof(tmp),
-                       "The MPU-401 isn't reponding @ p=0x%x.\n", snd_Mport);
-            tprintf(tmp, 0);
-        }
-        else
-            MPU_SetCard(snd_Mport);
-    }
-
-}
-
-// inits all sound stuff
-
-void I_StartupSound(void)
-{
-    char tmp[80];
-    int rc, i;
-
-    if (debugmode)
-        tprintf("I_StartupSound: Hope you hear a pop.\n", 1);
-
-    // initialize dmxCodes[]
-    dmxCodes[0] = 0;
-    dmxCodes[snd_PC] = AHW_PC_SPEAKER;
-    dmxCodes[snd_Adlib] = AHW_ADLIB;
-    dmxCodes[snd_SB] = AHW_SOUND_BLASTER;
-    dmxCodes[snd_PAS] = AHW_MEDIA_VISION;
-    dmxCodes[snd_GUS] = AHW_ULTRA_SOUND;
-    dmxCodes[snd_MPU] = AHW_MPU_401;
-    dmxCodes[snd_AWE] = AHW_AWE32;
-
-    // inits sound library timer stuff
-    I_StartupTimer();
-
-    // pick the sound cards i'm going to use
-    //
-    I_sndArbitrateCards();
-
-    if (debugmode)
-    {
-        M_snprintf(tmp, sizeof(tmp), "  Music device #%d & dmxCode=%d",
-                   snd_MusicDevice, dmxCodes[snd_MusicDevice]);
-        tprintf(tmp, 0);
-        M_snprintf(tmp, sizeof(tmp),  "  Sfx device #%d & dmxCode=%d\n",
-                   snd_SfxDevice, dmxCodes[snd_SfxDevice]);
-        tprintf(tmp, 0);
-    }
-
-    // inits DMX sound library
-    tprintf("  calling DMX_Init", 0);
-    rc = DMX_Init(SND_TICRATE, SND_MAXSONGS, dmxCodes[snd_MusicDevice],
-                  dmxCodes[snd_SfxDevice]);
-
-    if (debugmode)
-    {
-        M_snprintf(tmp, sizeof(tmp), "  DMX_Init() returned %d", rc);
-        tprintf(tmp, 0);
-    }
-
-}
-
-// shuts down all sound stuff
-
-void I_ShutdownSound(void)
-{
-    DMX_DeInit();
-    I_ShutdownTimer();
-}
-
-void I_SetChannels(int channels)
-{
-    WAV_PlayMode(channels, SND_SAMPLERATE);
-}
--- a/src/heretic/in_lude.c
+++ b/src/heretic/in_lude.c
@@ -25,6 +25,7 @@
 #include "deh_str.h"
 #include "p_local.h"
 #include "s_sound.h"
+#include "i_swap.h"
 #include "i_system.h"
 #include "i_video.h"
 #include "v_video.h"
@@ -1004,7 +1005,7 @@
     if (digits == 4)
     {
         patch = FontBNumbers[val / 1000];
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2 - 12, y, patch);
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2 - 12, y, patch);
     }
     if (digits > 2)
     {
@@ -1011,7 +1012,7 @@
         if (realdigits > 2)
         {
             patch = FontBNumbers[val / 100];
-            V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+            V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
         }
         xpos += 12;
     }
@@ -1021,7 +1022,7 @@
         if (val > 9)
         {
             patch = FontBNumbers[val / 10];
-            V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+            V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
         }
         else if (digits == 2 || oldval > 99)
         {
@@ -1031,11 +1032,11 @@
     }
     val = val % 10;
     patch = FontBNumbers[val];
-    V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+    V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
     if (neg)
     {
         patch = FontBNegative;
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2 - 12 * (realdigits),
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2 - 12 * (realdigits),
                             y, patch);
     }
 }
@@ -1061,7 +1062,7 @@
         {
             p = W_CacheLumpNum(FontBLump + c - 33, PU_CACHE);
             V_DrawShadowedPatch(x, y, p);
-            x += p->width - 1;
+            x += SHORT(p->width) - 1;
         }
     }
 }
--- a/src/heretic/mn_menu.c
+++ b/src/heretic/mn_menu.c
@@ -16,6 +16,7 @@
 
 // MN_menu.c
 
+#include <stdlib.h>
 #include <ctype.h>
 
 #include "deh_str.h"
--- a/src/heretic/p_enemy.c
+++ b/src/heretic/p_enemy.c
@@ -1904,7 +1904,7 @@
 
 void A_HeadIceImpact(mobj_t * ice)
 {
-    int i;
+    unsigned int i;
     angle_t angle;
     mobj_t *shard;
 
@@ -2519,7 +2519,7 @@
 
 void A_VolcBallImpact(mobj_t * ball)
 {
-    int i;
+    unsigned int i;
     mobj_t *tiny;
     angle_t angle;
 
--- a/src/heretic/p_map.c
+++ b/src/heretic/p_map.c
@@ -428,7 +428,7 @@
     // Check for special thing
     if (thing->flags & MF_SPECIAL)
     {
-        solid = thing->flags & MF_SOLID;
+        solid = (thing->flags & MF_SOLID) != 0;
         if (tmflags & MF_PICKUP)
         {                       // Can be picked up by tmthing
             P_TouchSpecialThing(thing, tmthing);        // Can remove thing
--- a/src/heretic/p_maputl.c
+++ b/src/heretic/p_maputl.c
@@ -667,7 +667,7 @@
     int mapx, mapy, mapxstep, mapystep;
     int count;
 
-    earlyout = flags & PT_EARLYOUT;
+    earlyout = (flags & PT_EARLYOUT) != 0;
 
     validcount++;
     intercept_p = intercepts;
--- a/src/heretic/p_pspr.c
+++ b/src/heretic/p_pspr.c
@@ -1330,7 +1330,7 @@
 
 void A_SpawnRippers(mobj_t * actor)
 {
-    int i;
+    unsigned int i;
     angle_t angle;
     mobj_t *ripper;
 
--- a/src/heretic/p_saveg.c
+++ b/src/heretic/p_saveg.c
@@ -16,6 +16,8 @@
 
 // P_tick.c
 
+#include <stdlib.h>
+
 #include "doomdef.h"
 #include "i_swap.h"
 #include "i_system.h"
--- a/src/heretic/p_tick.c
+++ b/src/heretic/p_tick.c
@@ -110,7 +110,7 @@
 
 void P_RunThinkers(void)
 {
-    thinker_t *currentthinker;
+    thinker_t *currentthinker, *nextthinker;
 
     currentthinker = thinkercap.next;
     while (currentthinker != &thinkercap)
@@ -117,6 +117,7 @@
     {
         if (currentthinker->function == (think_t) - 1)
         {                       // time to remove it
+            nextthinker = currentthinker->next;
             currentthinker->next->prev = currentthinker->prev;
             currentthinker->prev->next = currentthinker->next;
             Z_Free(currentthinker);
@@ -125,8 +126,9 @@
         {
             if (currentthinker->function)
                 currentthinker->function(currentthinker);
+            nextthinker = currentthinker->next;
         }
-        currentthinker = currentthinker->next;
+        currentthinker = nextthinker;
     }
 }
 
--- a/src/heretic/r_things.c
+++ b/src/heretic/r_things.c
@@ -417,7 +417,7 @@
 
     if (vis->footclip && !vis->psprite)
     {
-        sprbotscreen = sprtopscreen + FixedMul(patch->height << FRACBITS,
+        sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height) << FRACBITS,
                                                spryscale);
         baseclip = (sprbotscreen - FixedMul(vis->footclip << FRACBITS,
                                             spryscale)) >> FRACBITS;
--- a/src/heretic/s_sound.c
+++ b/src/heretic/s_sound.c
@@ -516,6 +516,7 @@
 
 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
     if (snd_Channels > 8)
     {
--- a/src/heretic/sb_bar.c
+++ b/src/heretic/sb_bar.c
@@ -19,6 +19,7 @@
 #include "doomdef.h"
 #include "deh_str.h"
 #include "i_video.h"
+#include "i_swap.h"
 #include "m_cheat.h"
 #include "m_misc.h"
 #include "m_random.h"
@@ -353,7 +354,7 @@
     if (val > 99)
     {
         patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE);
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
     }
     val = val % 100;
     xpos += 12;
@@ -360,12 +361,12 @@
     if (val > 9 || oldval > 99)
     {
         patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE);
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
     }
     val = val % 10;
     xpos += 12;
     patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
-    V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+    V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
 }
 
 //---------------------------------------------------------------------------
--- a/src/hexen.desktop.in
+++ b/src/hexen.desktop.in
@@ -5,3 +5,4 @@
 Type=Application
 Comment=@PACKAGE_SHORTDESC@
 Categories=Game;ActionGame;
+Keywords=first;person;shooter;doom;vanilla;
--- a/src/hexen/Makefile.am
+++ b/src/hexen/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS=-I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+AM_CFLAGS=-I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 noinst_LIBRARIES=libhexen.a
 
@@ -13,10 +13,8 @@
 g_game.c                              \
                     h2def.h           \
 h2_main.c                             \
-                    i_header.h        \
 info.c              info.h            \
 in_lude.c                             \
-m_misc.c                              \
 m_random.c          m_random.h        \
 mn_menu.c                             \
 p_acs.c                               \
@@ -58,10 +56,6 @@
 st_start.c          st_start.h        \
 sv_save.c                             \
                     textdefs.h        \
-                    xddefs.h          
-
-EXTRA_DIST=                           \
-i_ibm.c                               \
-i_sound.c           
+                    xddefs.h
 
 libhexen_a_SOURCES=$(SOURCE_FILES)
--- a/src/hexen/a_action.c
+++ b/src/hexen/a_action.c
@@ -211,7 +211,7 @@
     }
     else
     {
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (!playeringame[i])
             {
@@ -905,7 +905,7 @@
 
     if (actor->args[1]-- > 0)
     {
-        for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+        for (playnum = 0; playnum < maxplayers; playnum++)
         {
             player = &players[playnum];
             if (!playeringame[playnum])
@@ -934,7 +934,7 @@
     }
     else
     {
-        for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+        for (playnum = 0; playnum < maxplayers; playnum++)
         {
             localQuakeHappening[playnum] = false;
         }
--- a/src/hexen/am_map.c
+++ b/src/hexen/am_map.c
@@ -292,7 +292,7 @@
 
     // find player to center on initially
     if (!playeringame[pnum = consoleplayer])
-        for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+        for (pnum = 0; pnum < maxplayers; pnum++)
             if (playeringame[pnum])
                 break;
     plr = &players[pnum];
@@ -1280,7 +1280,7 @@
         return;
     }
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         their_color++;
         p = &players[i];
@@ -1418,12 +1418,12 @@
     char textBuffer[80];
     int yPosition;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         fragCount[i] = 0;
         order[i] = -1;
     }
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
         {
@@ -1431,7 +1431,7 @@
         }
         else
         {
-            for (j = 0; j < MAXPLAYERS; j++)
+            for (j = 0; j < maxplayers; j++)
             {
                 if (playeringame[j])
                 {
@@ -1438,7 +1438,7 @@
                     fragCount[i] += players[i].frags[j];
                 }
             }
-            for (k = 0; k < MAXPLAYERS; k++)
+            for (k = 0; k < maxplayers; k++)
             {
                 if (order[k] == -1)
                 {
@@ -1447,7 +1447,7 @@
                 }
                 else if (fragCount[i] > fragCount[order[k]])
                 {
-                    for (m = MAXPLAYERS - 1; m > k; m--)
+                    for (m = maxplayers - 1; m > k; m--)
                     {
                         order[m] = order[m - 1];
                     }
@@ -1458,7 +1458,7 @@
         }
     }
     yPosition = 15;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[order[i]])
         {
--- a/src/hexen/ct_chat.c
+++ b/src/hexen/ct_chat.c
@@ -116,7 +116,7 @@
     tail = 0;
     chatmodeon = false;
     memset(ChatQueue, 0, QUEUESIZE);
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         chat_dest[i] = 0;
         msgptr[i] = 0;
@@ -292,7 +292,7 @@
     char c;
     int numplayers;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
         {
@@ -312,7 +312,7 @@
             else if (c == KEY_ENTER)
             {
                 numplayers = 0;
-                for (j = 0; j < MAXPLAYERS; j++)
+                for (j = 0; j < maxplayers; j++)
                 {
                     numplayers += playeringame[j];
                 }
--- a/src/hexen/d_net.c
+++ b/src/hexen/d_net.c
@@ -76,7 +76,7 @@
 
     // Check for player quits.
 
-    for (i = 0; i < MAXPLAYERS; ++i)
+    for (i = 0; i < maxplayers; ++i)
     {
         if (!demoplayback && playeringame[i] && !ingame[i])
         {
@@ -120,7 +120,7 @@
     respawnparm = settings->respawn_monsters;
     consoleplayer = settings->consoleplayer;
 
-    for (i=0; i<MAXPLAYERS; ++i)
+    for (i=0; i<maxplayers; ++i)
     {
         playeringame[i] = i < settings->num_players;
         PlayerClass[i] = settings->player_classes[i];
@@ -172,7 +172,7 @@
 
     connect_data->lowres_turn = false;
     connect_data->drone = false;
-    connect_data->max_players = MAXPLAYERS;
+    connect_data->max_players = maxplayers;
 
     //!
     // @category net
--- a/src/hexen/f_finale.c
+++ b/src/hexen/f_finale.c
@@ -24,6 +24,7 @@
 #include "s_sound.h"
 #include <ctype.h>
 #include "v_video.h"
+#include "i_swap.h"
 
 // MACROS ------------------------------------------------------------------
 
@@ -224,12 +225,12 @@
             continue;
         }
         w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
-        if (cx + w->width > SCREENWIDTH)
+        if (cx + SHORT(w->width) > SCREENWIDTH)
         {
             break;
         }
         V_DrawPatch(cx, cy, w);
-        cx += w->width;
+        cx += SHORT(w->width);
     }
 }
 
--- a/src/hexen/g_game.c
+++ b/src/hexen/g_game.c
@@ -451,9 +451,11 @@
 
     // Weapon cycling. Switch to previous or next weapon.
     // (Disabled when player is a pig).
-
-    if (players[consoleplayer].morphTics == 0 && next_weapon != 0)
+    if (gamestate == GS_LEVEL
+     && players[consoleplayer].morphTics == 0 && next_weapon != 0)
     {
+        int start_i;
+
         if (players[consoleplayer].pendingweapon == WP_NOCHANGE)
         {
             i = players[consoleplayer].readyweapon;
@@ -463,9 +465,11 @@
             i = players[consoleplayer].pendingweapon;
         }
 
+        // Don't loop forever.
+        start_i = i;
         do {
-            i = (i + next_weapon) % NUMWEAPONS;
-        } while (!players[consoleplayer].weaponowned[i]);
+            i = (i + next_weapon + NUMWEAPONS) % NUMWEAPONS;
+        } while (i != start_i && !players[consoleplayer].weaponowned[i]);
 
         cmd->buttons |= BT_CHANGE;
         cmd->buttons |= i << BT_WEAPONSHIFT;
@@ -635,7 +639,7 @@
 
     levelstarttic = gametic;    // for time calculation 
     gamestate = GS_LEVEL;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (playeringame[i] && players[i].playerstate == PST_DEAD)
             players[i].playerstate = PST_REBORN;
@@ -752,7 +756,7 @@
         do
         {
             displayplayer++;
-            if (displayplayer == MAXPLAYERS)
+            if (displayplayer == maxplayers)
             {
                 displayplayer = 0;
             }
@@ -895,7 +899,7 @@
 //
 // do player reborns if needed
 //
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
         if (playeringame[i] && players[i].playerstate == PST_REBORN)
             G_DoReborn(i);
 
@@ -959,7 +963,7 @@
     //buf = gametic%BACKUPTICS;
     buf = (gametic / ticdup) % BACKUPTICS;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
         if (playeringame[i])
         {
             cmd = &players[i].cmd;
@@ -989,7 +993,7 @@
 //
 // check for special buttons
 //
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
         if (playeringame[i])
         {
             if (players[i].cmd.buttons & BT_SPECIAL)
@@ -1331,7 +1335,7 @@
         else
         {
             // Try to spawn at one of the other player start spots
-            for (i = 0; i < MAXPLAYERS; i++)
+            for (i = 0; i < maxplayers; i++)
             {
                 if (G_CheckSpot(playernum, &playerstarts[RebornPosition][i]))
                 {               // Found an open start spot
@@ -1467,6 +1471,13 @@
 
 void G_Completed(int map, int position)
 {
+    if (gamemode == shareware && map > 4)
+    {
+        P_SetMessage(&players[consoleplayer], "ACCESS DENIED -- DEMO", true);
+        S_StartSound(NULL, SFX_CHAT);
+        return;
+    }
+
     gameaction = ga_completed;
     LeaveMap = map;
     LeavePosition = position;
@@ -1481,7 +1492,7 @@
     {
         return;
     }
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (playeringame[i])
         {
@@ -1508,7 +1519,7 @@
 	{
 		return;
 	}
-	for(i = 0; i < MAXPLAYERS; i++)
+	for(i = 0; i < maxplayers; i++)
 	{
 		if(playeringame[i])
 		{
@@ -1721,7 +1732,7 @@
     }
     M_ClearRandom();
     // Force players to be initialized upon first level load
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         players[i].playerstate = PST_REBORN;
         players[i].worldTimer = 0;
@@ -1744,7 +1755,7 @@
     // Give one null ticcmd_t
     //gametic = 0;
     //maketic = 1;
-    //for (i=0 ; i<MAXPLAYERS ; i++)
+    //for (i=0 ; i<maxplayers ; i++)
     //      nettics[i] = 1; // one null event for this gametic
     //memset (localcmds,0,sizeof(localcmds));
     //memset (netcmds,0,sizeof(netcmds));
@@ -1815,7 +1826,7 @@
     *demo_p++ = episode;
     *demo_p++ = map;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         *demo_p++ = playeringame[i];
         *demo_p++ = PlayerClass[i];
@@ -1851,7 +1862,7 @@
     episode = *demo_p++;
     map = *demo_p++;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playeringame[i] = *demo_p++;
         PlayerClass[i] = *demo_p++;
@@ -1886,7 +1897,7 @@
     episode = *demo_p++;
     map = *demo_p++;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playeringame[i] = *demo_p++;
         PlayerClass[i] = *demo_p++;
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@ -93,6 +93,7 @@
 // PUBLIC DATA DEFINITIONS -------------------------------------------------
 
 GameMode_t gamemode;
+char *gamedescription;
 char *iwadfile;
 static char demolumpname[9];    // Demo lump to start playing.
 boolean nomonsters;             // checkparm of -nomonsters
@@ -112,6 +113,7 @@
 boolean advancedemo;
 FILE *debugfile;
 int UpdateState;
+int maxplayers = MAXPLAYERS;
 
 // PRIVATE DATA DEFINITIONS ------------------------------------------------
 
@@ -149,15 +151,16 @@
     key_multi_msgplayer[6] = CT_KEY_PLAYER7;
     key_multi_msgplayer[7] = CT_KEY_PLAYER8;
 
-    M_BindVariable("graphical_startup",      &graphical_startup);
-    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
-    M_BindVariable("sfx_volume",             &snd_MaxVolume);
-    M_BindVariable("music_volume",           &snd_MusicVolume);
-    M_BindVariable("messageson",             &messageson);
-    M_BindVariable("screenblocks",           &screenblocks);
-    M_BindVariable("snd_channels",           &snd_Channels);
-    M_BindVariable("savedir",                &SavePath);
+    M_BindIntVariable("graphical_startup",      &graphical_startup);
+    M_BindIntVariable("mouse_sensitivity",      &mouseSensitivity);
+    M_BindIntVariable("sfx_volume",             &snd_MaxVolume);
+    M_BindIntVariable("music_volume",           &snd_MusicVolume);
+    M_BindIntVariable("messageson",             &messageson);
+    M_BindIntVariable("screenblocks",           &screenblocks);
+    M_BindIntVariable("snd_channels",           &snd_Channels);
 
+    M_BindStringVariable("savedir", &SavePath);
+
     // Multiplayer chat macros
 
     for (i=0; i<10; ++i)
@@ -165,7 +168,7 @@
         char buf[12];
 
         M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
-        M_BindVariable(buf, &chat_macros[i]);
+        M_BindStringVariable(buf, &chat_macros[i]);
     }
 }
 
@@ -252,6 +255,57 @@
     W_AddFile(filename);
 }
 
+// Find out what version of Hexen is playing.
+
+void D_IdentifyVersion(void)
+{
+    // The Hexen Shareware, ne 4 Level Demo Version, is missing the SKY1 lump
+    // and uses the SKY2 lump instead. Let's use this fact and the missing
+    // levels from MAP05 onward to identify it and set gamemode accordingly.
+
+    if (W_CheckNumForName("SKY1") == -1 &&
+        W_CheckNumForName("MAP05") == -1 )
+    {
+	gamemode = shareware;
+	maxplayers = 4;
+    }
+
+    // The v1.0 IWAD file is missing a bunch of lumps.
+    if (gamemode != shareware && W_CheckNumForName("CLUS1MSG") == -1)
+    {
+        printf(
+            "** WARNING: You are playing with the Hexen v1.0 IWAD. This\n"
+            "** isn't supported by " PACKAGE_NAME ", and you may find that\n"
+            "** the game will crash. Please upgrade to the v1.1 IWAD file.\n"
+            "** See here for more information:\n"
+            "**   http://www.doomworld.com/classicdoom/info/patches.php\n");
+    }
+}
+
+// Set the gamedescription string.
+
+void D_SetGameDescription(void)
+{
+/*
+    NB: The 4 Level Demo Version actually prints a four-lined banner
+    (and indeed waits for a keypress):
+
+    Hexen:  Beyond Heretic
+
+    4 Level Demo Version
+    Press any key to continue.
+*/
+
+    if (gamemode == shareware)
+    {
+	gamedescription = "Hexen: 4 Level Demo Version";
+    }
+    else
+    {
+	gamedescription = "Hexen";
+    }
+}
+
 //==========================================================================
 //
 // H2_Main
@@ -331,11 +385,13 @@
 
     D_AddFile(iwadfile);
     W_CheckCorrectIWAD(hexen);
+    D_IdentifyVersion();
+    D_SetGameDescription();
     AdjustForMacIWAD();
 
     HandleArgs();
 
-    I_PrintStartupBanner("Hexen");
+    I_PrintStartupBanner(gamedescription);
 
     ST_Message("MN_Init: Init menu system.\n");
     MN_Init();
@@ -578,6 +634,7 @@
 
     if (p)
     {
+        char *uc_filename;
         char file[256];
 
         M_StringCopy(file, myargv[p+1], sizeof(file));
@@ -584,11 +641,16 @@
 
         // With Vanilla Hexen you have to specify the file without
         // extension, but make that optional.
-        if (!M_StringEndsWith(myargv[p+1], ".lmp"))
+        uc_filename = strdup(myargv[p + 1]);
+        M_ForceUppercase(uc_filename);
+
+        if (!M_StringEndsWith(uc_filename, ".LMP"))
         {
             M_StringConcat(file, ".lmp", sizeof(file));
         }
 
+        free(uc_filename);
+
         if (W_AddFile(file) != NULL)
         {
             M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
@@ -663,7 +725,7 @@
         M_snprintf(filename, sizeof(filename), "debug%i.txt", consoleplayer);
         debugfile = fopen(filename, "w");
     }
-    I_SetWindowTitle("Hexen");
+    I_SetWindowTitle(gamedescription);
     I_GraphicsCheckCommandLine();
     I_SetGrabMouseCallback(D_GrabMouseCallback);
     I_InitGraphics();
@@ -804,7 +866,7 @@
     player_t *player;
 
     player = &players[consoleplayer];
-    if (player->messageTics <= 0 || !player->message)
+    if (player->messageTics <= 0)
     {                           // No message
         return;
     }
--- a/src/hexen/h2def.h
+++ b/src/hexen/h2def.h
@@ -655,6 +655,7 @@
 
 #define MAX_PLAYER_STARTS 8
 extern mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+extern int maxplayers;
 
 extern int mouseSensitivity;
 
--- a/src/hexen/i_header.h
+++ /dev/null
@@ -1,92 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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 __I_HEADER_H__
-#define __I_HEADER_H__
-
-#include "h2def.h"
-
-//--------
-//SOUND IO
-//--------
-#define	FREQ_LOW		0x40
-#define FREQ_NORM		0x80
-#define FREQ_HIGH		0xff
-
-void I_SetMasterVolume(int volume);
-
-void I_TurnOffSfx(void);
-void I_TurnOnSfx(void);
-void I_TurnOffMusic(void);
-void I_TurnOnMusic(void);
-
-//  MUSIC I/O
-//
-
-int I_RegisterSong(void *songdata);
-// called by anything that wants to register a song lump with the sound lib
-// calls Paul's function of the similar name to register music only.
-// note that the song data is the same for any sound card and is paul's
-// MUS format.  Returns a handle which will be passed to all other music
-// functions.
-
-void I_UnregisterSong(int handle);
-// called by anything which is finished with a song and no longer needs
-// the sound library to be aware of it.  All songs should be stopped
-// before calling this, but it will double check and stop it if necessary.
-
-void I_LoopSong(int handle);
-// called by anything that wishes to start music.
-// plays a song, and when the song is done, starts playing it again in
-// an endless loop.  the start is faded in over three seconds.
-
-void I_FadeOutSong(int handle, int fotime);
-// called by anything that wishes to stop music.
-// fades out the song over <fotime> milliseconds.
-
-void I_StopSong(int handle);
-// called by anything that wishes to stop music.
-// stops a song abruptly.
-
-//  SFX I/O
-//
-
-void *I_GetSoundEffect(char *soundname);
-// called by routines which wish to play a sound effect at some later
-// time.  Pass it the lump name of a sound effect WITHOUT the sfx
-// prefix.  This means the maximum name length is 7 letters/digits.
-// The prefixes for different sound cards are 'S','M','A', and 'P'.
-// They refer to the card type.  The routine will cache in the
-// appropriate sound effect when it is played.
-
-void I_UngetSoundEffect(void *soundset);
-// called by routines which wish to no longer use the sounds at all
-// frees up the associated structure.  It stops any currently playing
-// sound effects.
-
-void I_StartSound(channel_t * c, int vol, int sep, int pitch, int priority);
-// Starts a sound in a particular sound channel
-
-void I_UpdateSoundParams(channel_t * c, int vol, int sep, int pitch);
-// Updates the volume, separation, and pitch of a sound channel
-
-void I_StopSound(channel_t * c);
-// Stops a sound channel
-
-int I_SoundIsPlaying(channel_t * c);
-// called by S_*()'s to see if a channel is still playing.  Returns 0
-// if no longer playing, 1 if playing.
-
-#endif
--- a/src/hexen/i_ibm.c
+++ /dev/null
@@ -1,1837 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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.
-//
-
-
-#include <dos.h>
-#include <conio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <graph.h>
-#include "h2def.h"
-#include "i_system.h"
-#include "m_argv.h"
-#include "r_local.h"
-#include "p_local.h"            // for P_AproxDistance
-#include "sounds.h"
-#include "i_sound.h"
-#include "st_start.h"
-#include "dmx.h"
-#include "dpmiapi.h"
-
-// Macros
-
-#define DPMI_INT 0x31
-
-#define SEQ_ADDR 0x3C4
-#define SEQ_DATA 0x3C5
-#define REG_MAPMASK 0x02
-
-#define MASK_PLANE0 0x01
-#define MASK_PLANE1 0x02
-#define MASK_PLANE2 0x04
-#define MASK_PLANE3 0x08
-
-#define P0OFFSET 38400*0
-#define P1OFFSET 38400*1
-#define P2OFFSET 38400*2
-#define P3OFFSET 38400*3
-
-#define VID_INT 0x10
-#define VB_SYNC {while(!(inp(0x3da)&8)); while(inp(0x3da)&8);}
-#define BITPLANE(p) (outp(SEQ_ADDR,REG_MAPMASK),outp(SEQ_DATA,(p)))
-
-//#define NOKBD
-//#define NOTIMER
-
-// Public Data
-
-int DisplayTicker = 0;
-
-// Code
-
-void main(int argc, char **argv)
-{
-    myargc = argc;
-    myargv = argv;
-    H2_Main();
-}
-
-void I_StartupNet(void);
-void I_ShutdownNet(void);
-void I_ReadExternDriver(void);
-
-typedef struct
-{
-    unsigned edi, esi, ebp, reserved, ebx, edx, ecx, eax;
-    unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss;
-} dpmiregs_t;
-
-extern dpmiregs_t dpmiregs;
-
-void I_ReadMouse(void);
-
-extern int usemouse, usejoystick;
-
-extern void **lumpcache;
-
-int i_Vector;
-externdata_t *i_ExternData;
-boolean useexterndriver;
-
-//==========================================================================
-//
-// I_UpdateCDMusic
-//
-// Updates playing time for current track, and restarts the track, if
-// needed
-//
-//==========================================================================
-
-void I_UpdateCDMusic(void)
-{
-    extern boolean MenuActive;
-
-    if (MusicPaused || i_CDMusicLength < 0 || (paused && !MenuActive))
-    {                           // Non-looping song/song paused
-        return;
-    }
-    i_CDMusicLength -= gametic - oldTic;
-    oldTic = gametic;
-    if (i_CDMusicLength <= 0)
-    {
-        S_StartSong(gamemap, true);
-    }
-}
-
-/*
-============================================================================
-
-							CONSTANTS
-
-============================================================================
-*/
-
-#define SC_INDEX                0x3C4
-#define SC_RESET                0
-#define SC_CLOCK                1
-#define SC_MAPMASK              2
-#define SC_CHARMAP              3
-#define SC_MEMMODE              4
-
-#define CRTC_INDEX              0x3D4
-#define CRTC_H_TOTAL    0
-#define CRTC_H_DISPEND  1
-#define CRTC_H_BLANK    2
-#define CRTC_H_ENDBLANK 3
-#define CRTC_H_RETRACE  4
-#define CRTC_H_ENDRETRACE 5
-#define CRTC_V_TOTAL    6
-#define CRTC_OVERFLOW   7
-#define CRTC_ROWSCAN    8
-#define CRTC_MAXSCANLINE 9
-#define CRTC_CURSORSTART 10
-#define CRTC_CURSOREND  11
-#define CRTC_STARTHIGH  12
-#define CRTC_STARTLOW   13
-#define CRTC_CURSORHIGH 14
-#define CRTC_CURSORLOW  15
-#define CRTC_V_RETRACE  16
-#define CRTC_V_ENDRETRACE 17
-#define CRTC_V_DISPEND  18
-#define CRTC_OFFSET             19
-#define CRTC_UNDERLINE  20
-#define CRTC_V_BLANK    21
-#define CRTC_V_ENDBLANK 22
-#define CRTC_MODE               23
-#define CRTC_LINECOMPARE 24
-
-
-#define GC_INDEX                0x3CE
-#define GC_SETRESET             0
-#define GC_ENABLESETRESET 1
-#define GC_COLORCOMPARE 2
-#define GC_DATAROTATE   3
-#define GC_READMAP              4
-#define GC_MODE                 5
-#define GC_MISCELLANEOUS 6
-#define GC_COLORDONTCARE 7
-#define GC_BITMASK              8
-
-#define ATR_INDEX               0x3c0
-#define ATR_MODE                16
-#define ATR_OVERSCAN    17
-#define ATR_COLORPLANEENABLE 18
-#define ATR_PELPAN              19
-#define ATR_COLORSELECT 20
-
-#define STATUS_REGISTER_1    0x3da
-
-#define PEL_WRITE_ADR   0x3c8
-#define PEL_READ_ADR    0x3c7
-#define PEL_DATA                0x3c9
-#define PEL_MASK                0x3c6
-
-// boolean grmode;
-
-//==================================================
-//
-// joystick vars
-//
-//==================================================
-
-boolean joystickpresent;
-extern unsigned joystickx, joysticky;
-boolean I_ReadJoystick(void);   // returns false if not connected
-
-
-//==================================================
-
-#define VBLCOUNTER              34000   // hardware tics to a frame
-
-
-#define TIMERINT 8
-#define KEYBOARDINT 9
-
-#define CRTCOFF (_inbyte(STATUS_REGISTER_1)&1)
-#define CLI     _disable()
-#define STI     _enable()
-
-#define _outbyte(x,y) (outp(x,y))
-#define _outhword(x,y) (outpw(x,y))
-
-#define _inbyte(x) (inp(x))
-#define _inhword(x) (inpw(x))
-
-#define MOUSEB1 1
-#define MOUSEB2 2
-#define MOUSEB3 4
-
-boolean mousepresent;
-//static  int tsm_ID = -1; // tsm init flag
-
-//===============================
-
-int ticcount;
-
-// REGS stuff used for int calls
-union REGS regs;
-struct SREGS segregs;
-
-boolean novideo;                // if true, stay in text mode for debugging
-
-#define KBDQUESIZE 32
-byte keyboardque[KBDQUESIZE];
-int kbdtail, kbdhead;
-
-#define KEY_LSHIFT      0xfe
-
-#define KEY_INS         (0x80+0x52)
-#define KEY_DEL         (0x80+0x53)
-#define KEY_PGUP        (0x80+0x49)
-#define KEY_PGDN        (0x80+0x51)
-#define KEY_HOME        (0x80+0x47)
-#define KEY_END         (0x80+0x4f)
-
-#define SC_RSHIFT       0x36
-#define SC_LSHIFT       0x2a
-
-byte scantokey[128] = {
-//  0           1       2       3       4       5       6       7
-//  8           9       A       B       C       D       E       F
-    0, 27, '1', '2', '3', '4', '5', '6',
-    '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9,     // 0
-    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
-    'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's',        // 1
-    'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
-    39, '`', KEY_LSHIFT, 92, 'z', 'x', 'c', 'v',        // 2
-    'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT, '*',
-    KEY_RALT, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,   // 3
-    KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME,
-    KEY_UPARROW, KEY_PGUP, '-', KEY_LEFTARROW, '5', KEY_RIGHTARROW, '+', KEY_END,       //4
-    KEY_DOWNARROW, KEY_PGDN, KEY_INS, KEY_DEL, 0, 0, 0, KEY_F11,
-    KEY_F12, 0, 0, 0, 0, 0, 0, 0,       // 5
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,     // 6
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0      // 7
-};
-
-//==========================================================================
-
-//--------------------------------------------------------------------------
-//
-// FUNC I_GetTime
-//
-// Returns time in 1/35th second tics.
-//
-//--------------------------------------------------------------------------
-
-int I_GetTime(void)
-{
-#ifdef NOTIMER
-    ticcount++;
-#endif
-    return (ticcount);
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ColorBorder
-//
-//--------------------------------------------------------------------------
-
-/*
-void I_ColorBorder(void)
-{
-	int i;
-
-	I_WaitVBL(1);
-	_outbyte(PEL_WRITE_ADR, 0);
-	for(i = 0; i < 3; i++)
-	{
-		_outbyte(PEL_DATA, 63);
-	}
-}
-*/
-
-//--------------------------------------------------------------------------
-//
-// PROC I_UnColorBorder
-//
-//--------------------------------------------------------------------------
-
-/*
-void I_UnColorBorder(void)
-{
-	int i;
-
-	I_WaitVBL(1);
-	_outbyte(PEL_WRITE_ADR, 0);
-	for(i = 0; i < 3; i++)
-	{
-		_outbyte(PEL_DATA, 0);
-	}
-}
-*/
-
-/*
-============================================================================
-
-								USER INPUT
-
-============================================================================
-*/
-
-//--------------------------------------------------------------------------
-//
-// PROC I_WaitVBL
-//
-//--------------------------------------------------------------------------
-
-void I_WaitVBL(int vbls)
-{
-    int stat;
-
-    if (novideo)
-    {
-        return;
-    }
-    while (vbls--)
-    {
-        do
-        {
-            stat = inp(STATUS_REGISTER_1);
-            if (stat & 8)
-            {
-                break;
-            }
-        }
-        while (1);
-        do
-        {
-            stat = inp(STATUS_REGISTER_1);
-            if ((stat & 8) == 0)
-            {
-                break;
-            }
-        }
-        while (1);
-    }
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_SetPalette
-//
-// Palette source must use 8 bit RGB elements.
-//
-//--------------------------------------------------------------------------
-
-void I_SetPalette(byte * palette)
-{
-    int i;
-
-    if (novideo)
-    {
-        return;
-    }
-    I_WaitVBL(1);
-    _outbyte(PEL_WRITE_ADR, 0);
-    for (i = 0; i < 768; i++)
-    {
-        _outbyte(PEL_DATA, (gammatable[usegamma][*palette++]) >> 2);
-    }
-}
-
-/*
-============================================================================
-
-							GRAPHICS MODE
-
-============================================================================
-*/
-
-byte *pcscreen, *destscreen, *destview;
-
-
-/*
-==============
-=
-= I_Update
-=
-==============
-*/
-
-int UpdateState;
-extern int screenblocks;
-
-void I_Update(void)
-{
-    int i;
-    byte *dest;
-    int tics;
-    static int lasttic;
-
-//
-// blit screen to video
-//
-    if (DisplayTicker)
-    {
-        if (screenblocks > 9 || UpdateState & (I_FULLSCRN | I_MESSAGES))
-        {
-            dest = (byte *) screen;
-        }
-        else
-        {
-            dest = (byte *) pcscreen;
-        }
-        tics = ticcount - lasttic;
-        lasttic = ticcount;
-        if (tics > 20)
-        {
-            tics = 20;
-        }
-        for (i = 0; i < tics; i++)
-        {
-            *dest = 0xff;
-            dest += 2;
-        }
-        for (i = tics; i < 20; i++)
-        {
-            *dest = 0x00;
-            dest += 2;
-        }
-    }
-
-    //memset(pcscreen, 255, SCREENHEIGHT*SCREENWIDTH);
-
-    if (UpdateState == I_NOUPDATE)
-    {
-        return;
-    }
-    if (UpdateState & I_FULLSCRN)
-    {
-        memcpy(pcscreen, screen, SCREENWIDTH * SCREENHEIGHT);
-        UpdateState = I_NOUPDATE;       // clear out all draw types
-    }
-    if (UpdateState & I_FULLVIEW)
-    {
-        if (UpdateState & I_MESSAGES && screenblocks > 7)
-        {
-            for (i = 0; i <
-                 (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
-            {
-                memcpy(pcscreen + i, screen + i, SCREENWIDTH);
-            }
-            UpdateState &= ~(I_FULLVIEW | I_MESSAGES);
-        }
-        else
-        {
-            for (i = viewwindowy * SCREENWIDTH + viewwindowx; i <
-                 (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
-            {
-                memcpy(pcscreen + i, screen + i, viewwidth);
-            }
-            UpdateState &= ~I_FULLVIEW;
-        }
-    }
-    if (UpdateState & I_STATBAR)
-    {
-        memcpy(pcscreen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
-               screen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
-               SCREENWIDTH * SBARHEIGHT);
-        UpdateState &= ~I_STATBAR;
-    }
-    if (UpdateState & I_MESSAGES)
-    {
-        memcpy(pcscreen, screen, SCREENWIDTH * 28);
-        UpdateState &= ~I_MESSAGES;
-    }
-
-
-//  memcpy(pcscreen, screen, SCREENHEIGHT*SCREENWIDTH);
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_InitGraphics
-//
-//--------------------------------------------------------------------------
-
-void I_InitGraphics(void)
-{
-    if (novideo)
-    {
-        return;
-    }
-    //grmode = true;
-    regs.w.ax = 0x13;
-    int386(0x10, (const union REGS *) &regs, &regs);
-    pcscreen = destscreen = (byte *) 0xa0000;
-    I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ShutdownGraphics
-//
-//--------------------------------------------------------------------------
-
-void I_ShutdownGraphics(void)
-{
-    byte mode;
-
-    // don't reset mode if it didn't get set
-    mode = *(byte *) 0x449;
-    if (mode == 0x12 || mode == 0x13)
-    {
-        regs.w.ax = 3;
-        int386(0x10, &regs, &regs);     // back to text mode
-    }
-}
-
-//--------------------------------------------------------------------------
-//
-// PROC I_ReadScreen
-//
-// Reads the screen currently displayed into a linear buffer.
-//
-//--------------------------------------------------------------------------
-
-/*
-void I_ReadScreen(byte *scr)
-{
-	memcpy(scr, screen, SCREENWIDTH*SCREENHEIGHT);
-}
-*/
-
-//===========================================================================
-
-/*
-===================
-=
-= I_StartTic
-=
-// called by D_DoomLoop
-// called before processing each tic in a frame
-// can call D_PostEvent
-// asyncronous interrupt functions should maintain private ques that are
-// read by the syncronous functions to be converted into events
-===================
-*/
-
-/*
- OLD STARTTIC STUFF
-
-void   I_StartTic (void)
-{
-	int             k;
-	event_t ev;
-
-
-	I_ReadMouse ();
-
-//
-// keyboard events
-//
-	while (kbdtail < kbdhead)
-	{
-		k = keyboardque[kbdtail&(KBDQUESIZE-1)];
-
-//      if (k==14)
-//              I_Error ("exited");
-
-		kbdtail++;
-
-		// extended keyboard shift key bullshit
-		if ( (k&0x7f)==KEY_RSHIFT )
-		{
-			if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
-				continue;
-			k &= 0x80;
-			k |= KEY_RSHIFT;
-		}
-
-		if (k==0xe0)
-			continue;               // special / pause keys
-		if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
-			continue;                               // pause key bullshit
-
-		if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
-		{
-			ev.type = ev_keydown;
-			ev.data1 = KEY_PAUSE;
-			D_PostEvent (&ev);
-			continue;
-		}
-
-		if (k&0x80)
-			ev.type = ev_keyup;
-		else
-			ev.type = ev_keydown;
-		k &= 0x7f;
-
-		ev.data1 = k;
-		//ev.data1 = scantokey[k];
-
-		D_PostEvent (&ev);
-	}
-}
-*/
-
-#define SC_UPARROW              0x48
-#define SC_DOWNARROW    0x50
-#define SC_LEFTARROW            0x4b
-#define SC_RIGHTARROW   0x4d
-
-void I_StartTic(void)
-{
-    int k;
-    event_t ev;
-
-
-    I_ReadMouse();
-
-//
-// keyboard events
-//
-    while (kbdtail < kbdhead)
-    {
-        k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
-        kbdtail++;
-
-        // extended keyboard shift key bullshit
-        if ((k & 0x7f) == SC_LSHIFT || (k & 0x7f) == SC_RSHIFT)
-        {
-            if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe0)
-                continue;
-            k &= 0x80;
-            k |= SC_RSHIFT;
-        }
-
-        if (k == 0xe0)
-            continue;           // special / pause keys
-        if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe1)
-            continue;           // pause key bullshit
-
-        if (k == 0xc5
-            && keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0x9d)
-        {
-            ev.type = ev_keydown;
-            ev.data1 = KEY_PAUSE;
-            H2_PostEvent(&ev);
-            continue;
-        }
-
-        if (k & 0x80)
-            ev.type = ev_keyup;
-        else
-            ev.type = ev_keydown;
-        k &= 0x7f;
-        switch (k)
-        {
-            case SC_UPARROW:
-                ev.data1 = KEY_UPARROW;
-                break;
-            case SC_DOWNARROW:
-                ev.data1 = KEY_DOWNARROW;
-                break;
-            case SC_LEFTARROW:
-                ev.data1 = KEY_LEFTARROW;
-                break;
-            case SC_RIGHTARROW:
-                ev.data1 = KEY_RIGHTARROW;
-                break;
-            default:
-                ev.data1 = scantokey[k];
-                break;
-        }
-        H2_PostEvent(&ev);
-    }
-
-}
-
-
-/*
-void   I_ReadKeys (void)
-{
-	int             k;
-
-
-	while (1)
-	{
-	   while (kbdtail < kbdhead)
-	   {
-		   k = keyboardque[kbdtail&(KBDQUESIZE-1)];
-		   kbdtail++;
-		   printf ("0x%x\n",k);
-		   if (k == 1)
-			   I_Quit ();
-	   }
-	}
-}
-*/
-
-/*
-===============
-=
-= I_StartFrame
-=
-===============
-*/
-
-void I_StartFrame(void)
-{
-    I_JoystickEvents();
-    if (useexterndriver)
-    {
-        DPMIInt(i_Vector);
-    }
-}
-
-/*
-============================================================================
-
-					TIMER INTERRUPT
-
-============================================================================
-*/
-
-/*
-void I_ColorBlack (int r, int g, int b)
-{
-_outbyte (PEL_WRITE_ADR,0);
-_outbyte(PEL_DATA,r);
-_outbyte(PEL_DATA,g);
-_outbyte(PEL_DATA,b);
-}
-*/
-
-
-/*
-================
-=
-= I_TimerISR
-=
-================
-*/
-
-int I_TimerISR(void)
-{
-    ticcount++;
-    return 0;
-}
-
-/*
-============================================================================
-
-						KEYBOARD
-
-============================================================================
-*/
-
-void (__interrupt __far * oldkeyboardisr) () = NULL;
-
-int lastpress;
-
-/*
-================
-=
-= I_KeyboardISR
-=
-================
-*/
-
-void __interrupt I_KeyboardISR(void)
-{
-// Get the scan code
-
-    keyboardque[kbdhead & (KBDQUESIZE - 1)] = lastpress = _inbyte(0x60);
-    kbdhead++;
-
-// acknowledge the interrupt
-
-    _outbyte(0x20, 0x20);
-}
-
-
-
-/*
-===============
-=
-= I_StartupKeyboard
-=
-===============
-*/
-
-void I_StartupKeyboard(void)
-{
-#ifndef NOKBD
-    oldkeyboardisr = _dos_getvect(KEYBOARDINT);
-    _dos_setvect(0x8000 | KEYBOARDINT, I_KeyboardISR);
-#endif
-
-//I_ReadKeys ();
-}
-
-
-void I_ShutdownKeyboard(void)
-{
-    if (oldkeyboardisr)
-        _dos_setvect(KEYBOARDINT, oldkeyboardisr);
-    *(short *) 0x41c = *(short *) 0x41a;        // clear bios key buffer
-}
-
-
-
-/*
-============================================================================
-
-							MOUSE
-
-============================================================================
-*/
-
-
-int I_ResetMouse(void)
-{
-    regs.w.ax = 0;              // reset
-    int386(0x33, &regs, &regs);
-    return regs.w.ax;
-}
-
-
-
-/*
-================
-=
-= StartupMouse
-=
-================
-*/
-
-void I_StartupCyberMan(void);
-
-void I_StartupMouse(void)
-{
-    //
-    // General mouse detection
-    //
-    mousepresent = 0;
-    if (M_CheckParm("-nomouse") || !usemouse)
-        return;
-
-    if (I_ResetMouse() != 0xffff)
-    {
-        ST_Message("Mouse: not present\n");
-        return;
-    }
-    ST_Message("Mouse: detected\n");
-
-    mousepresent = 1;
-
-    I_StartupCyberMan();
-}
-
-
-/*
-================
-=
-= ShutdownMouse
-=
-================
-*/
-
-void I_ShutdownMouse(void)
-{
-    if (!mousepresent)
-        return;
-
-    I_ResetMouse();
-}
-
-
-/*
-================
-=
-= I_ReadMouse
-=
-================
-*/
-
-void I_ReadMouse(void)
-{
-    event_t ev;
-
-//
-// mouse events
-//
-    if (!mousepresent)
-        return;
-
-    ev.type = ev_mouse;
-
-    memset(&dpmiregs, 0, sizeof(dpmiregs));
-    dpmiregs.eax = 3;           // read buttons / position
-    DPMIInt(0x33);
-    ev.data1 = dpmiregs.ebx;
-
-    dpmiregs.eax = 11;          // read counters
-    DPMIInt(0x33);
-    ev.data2 = (short) dpmiregs.ecx;
-    ev.data3 = -(short) dpmiregs.edx;
-
-    H2_PostEvent(&ev);
-}
-
-/*
-============================================================================
-
-					JOYSTICK
-
-============================================================================
-*/
-
-int joyxl, joyxh, joyyl, joyyh;
-
-boolean WaitJoyButton(void)
-{
-    int oldbuttons, buttons;
-
-    oldbuttons = 0;
-    do
-    {
-        I_WaitVBL(1);
-        buttons = ((inp(0x201) >> 4) & 1) ^ 1;
-        if (buttons != oldbuttons)
-        {
-            oldbuttons = buttons;
-            continue;
-        }
-
-        if ((lastpress & 0x7f) == 1)
-        {
-            joystickpresent = false;
-            return false;
-        }
-    }
-    while (!buttons);
-
-    do
-    {
-        I_WaitVBL(1);
-        buttons = ((inp(0x201) >> 4) & 1) ^ 1;
-        if (buttons != oldbuttons)
-        {
-            oldbuttons = buttons;
-            continue;
-        }
-
-        if ((lastpress & 0x7f) == 1)
-        {
-            joystickpresent = false;
-            return false;
-        }
-    }
-    while (buttons);
-
-    return true;
-}
-
-
-
-/*
-===============
-=
-= I_StartupJoystick
-=
-===============
-*/
-
-int basejoyx, basejoyy;
-
-void I_StartupJoystick(void)
-{
-    int centerx, centery;
-
-    joystickpresent = 0;
-    if (M_CheckParm("-nojoy") || !usejoystick)
-        return;
-
-    if (!I_ReadJoystick())
-    {
-        joystickpresent = false;
-        ST_Message("joystick not found\n ");
-        return;
-    }
-    ST_Message("joystick found\n");
-    joystickpresent = true;
-
-    ST_RealMessage("CENTER the joystick and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    centerx = joystickx;
-    centery = joysticky;
-
-    ST_RealMessage
-        ("\nPush the joystick to the UPPER LEFT corner and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    joyxl = (centerx + joystickx) / 2;
-    joyyl = (centerx + joysticky) / 2;
-
-    ST_RealMessage
-        ("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
-    if (!WaitJoyButton())
-        return;
-    I_ReadJoystick();
-    joyxh = (centerx + joystickx) / 2;
-    joyyh = (centery + joysticky) / 2;
-    ST_RealMessage("\n");
-}
-
-/*
-===============
-=
-= I_JoystickEvents
-=
-===============
-*/
-
-void I_JoystickEvents(void)
-{
-    event_t ev;
-
-//
-// joystick events
-//
-    if (!joystickpresent)
-        return;
-
-    I_ReadJoystick();
-    ev.type = ev_joystick;
-    ev.data1 = ((inp(0x201) >> 4) & 15) ^ 15;
-
-    if (joystickx < joyxl)
-        ev.data2 = -1;
-    else if (joystickx > joyxh)
-        ev.data2 = 1;
-    else
-        ev.data2 = 0;
-    if (joysticky < joyyl)
-        ev.data3 = -1;
-    else if (joysticky > joyyh)
-        ev.data3 = 1;
-    else
-        ev.data3 = 0;
-
-    H2_PostEvent(&ev);
-}
-
-
-
-/*
-============================================================================
-
-					DPMI STUFF
-
-============================================================================
-*/
-
-#define REALSTACKSIZE   1024
-
-dpmiregs_t dpmiregs;
-
-unsigned realstackseg;
-
-void I_DivException(void);
-int I_SetDivException(void);
-
-/*
-void DPMIFarCall (void)
-{
-	segread (&segregs);
-	regs.w.ax = 0x301;
-	regs.w.bx = 0;
-	regs.w.cx = 0;
-	regs.x.edi = (unsigned)&dpmiregs;
-	segregs.es = segregs.ds;
-	int386x( DPMI_INT, &regs, &regs, &segregs );
-}
-*/
-
-void DPMIInt(int i)
-{
-    dpmiregs.ss = realstackseg;
-    dpmiregs.sp = REALSTACKSIZE - 4;
-
-    segread(&segregs);
-    regs.w.ax = 0x300;
-    regs.w.bx = i;
-    regs.w.cx = 0;
-    regs.x.edi = (unsigned) &dpmiregs;
-    segregs.es = segregs.ds;
-    int386x(DPMI_INT, &regs, &regs, &segregs);
-}
-
-
-/*
-==============
-=
-= I_StartupDPMI
-=
-==============
-*/
-
-void I_StartupDPMI(void)
-{
-//      extern char __begtext;
-//      extern char ___argc;
-//      int     n,d;
-
-//
-// allocate a decent stack for real mode ISRs
-//
-    realstackseg = (int) I_AllocLow(1024) >> 4;
-
-//
-// lock the entire program down
-//
-
-//      _dpmi_lockregion (&__begtext, &___argc - &__begtext);
-
-
-//
-// catch divide by 0 exception
-//
-#if 0
-    segread(&segregs);
-    regs.w.ax = 0x0203;         // DPMI set processor exception handler vector
-    regs.w.bx = 0;              // int 0
-    regs.w.cx = segregs.cs;
-    regs.x.edx = (int) &I_DivException;
-    printf("%x : %x\n", regs.w.cx, regs.x.edx);
-    int386(DPMI_INT, &regs, &regs);
-#endif
-
-#if 0
-    n = I_SetDivException();
-    printf("return: %i\n", n);
-    n = 100;
-    d = 0;
-    printf("100 / 0 = %i\n", n / d);
-
-    exit(1);
-#endif
-}
-
-
-
-/*
-============================================================================
-
-					TIMER INTERRUPT
-
-============================================================================
-*/
-
-void (__interrupt __far * oldtimerisr) ();
-
-
-/*
-void IO_ColorBlack (int r, int g, int b)
-{
-_outbyte (PEL_WRITE_ADR,0);
-_outbyte(PEL_DATA,r);
-_outbyte(PEL_DATA,g);
-_outbyte(PEL_DATA,b);
-}
-*/
-
-
-/*
-================
-=
-= IO_TimerISR
-=
-================
-*/
-
-//void __interrupt IO_TimerISR (void)
-
-void __interrupt __far IO_TimerISR(void)
-{
-    ticcount++;
-    _outbyte(0x20, 0x20);       // Ack the interrupt
-}
-
-/*
-=====================
-=
-= IO_SetTimer0
-=
-= Sets system timer 0 to the specified speed
-=
-=====================
-*/
-
-void IO_SetTimer0(int speed)
-{
-    if (speed > 0 && speed < 150)
-        I_Error("INT_SetTimer0: %i is a bad value", speed);
-
-    _outbyte(0x43, 0x36);       // Change timer 0
-    _outbyte(0x40, speed);
-    _outbyte(0x40, speed >> 8);
-}
-
-
-
-/*
-===============
-=
-= IO_StartupTimer
-=
-===============
-*/
-
-/*
-void IO_StartupTimer (void)
-{
-	oldtimerisr = _dos_getvect(TIMERINT);
-
-	_dos_setvect (0x8000 | TIMERINT, IO_TimerISR);
-	IO_SetTimer0 (VBLCOUNTER);
-}
-*/
-
-void IO_ShutdownTimer(void)
-{
-    if (oldtimerisr)
-    {
-        IO_SetTimer0(0);        // back to 18.4 ips
-        _dos_setvect(TIMERINT, oldtimerisr);
-    }
-}
-
-//===========================================================================
-
-
-/*
-===============
-=
-= I_Init
-=
-= hook interrupts and set graphics mode
-=
-===============
-*/
-
-void I_Init(void)
-{
-    extern void I_StartupTimer(void);
-
-    novideo = M_CheckParm("novideo");
-    ST_Message("  I_StartupDPMI\n");
-    I_StartupDPMI();
-    ST_Message("  I_StartupMouse ");
-    I_StartupMouse();
-//      tprintf("I_StartupJoystick ",1);
-//      I_StartupJoystick();
-//      tprintf("I_StartupKeyboard ",1);
-//      I_StartupKeyboard();
-    ST_Message("  S_Init... ");
-    S_Init();
-    //IO_StartupTimer();
-    S_Start();
-}
-
-
-/*
-===============
-=
-= I_Shutdown
-=
-= return to default system state
-=
-===============
-*/
-
-void I_Shutdown(void)
-{
-    I_ShutdownGraphics();
-    IO_ShutdownTimer();
-    S_ShutDown();
-    I_ShutdownMouse();
-    I_ShutdownKeyboard();
-
-    IO_SetTimer0(0);
-}
-
-
-/*
-================
-=
-= I_Error
-=
-================
-*/
-
-void I_Error(char *error, ...)
-{
-    union REGS regs;
-
-    va_list argptr;
-
-    D_QuitNetGame();
-    I_Shutdown();
-    va_start(argptr, error);
-    regs.x.eax = 0x3;
-    int386(0x10, &regs, &regs);
-    vprintf(error, argptr);
-    va_end(argptr);
-    printf("\n");
-    exit(1);
-}
-
-//--------------------------------------------------------------------------
-//
-// I_Quit
-//
-// Shuts down net game, saves defaults, prints the exit text message,
-// goes to text mode, and exits.
-//
-//--------------------------------------------------------------------------
-
-void I_Quit(void)
-{
-    D_QuitNetGame();
-    M_SaveDefaults();
-    I_Shutdown();
-
-//      scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
-/*
-	memcpy((void *)0xb8000, scr, 80*25*2);
-	regs.w.ax = 0x0200;
-	regs.h.bh = 0;
-	regs.h.dl = 0;
-	regs.h.dh = 23;
-	int386(0x10, (const union REGS *)&regs, &regs); // Set text pos
-	_settextposition(24, 1);
-*/
-    printf("\nHexen: Beyond Heretic\n");
-    exit(0);
-}
-
-/*
-===============
-=
-= I_ZoneBase
-=
-===============
-*/
-
-byte *I_ZoneBase(int *size)
-{
-    int meminfo[32];
-    int heap;
-    byte *ptr;
-
-    memset(meminfo, 0, sizeof(meminfo));
-    segread(&segregs);
-    segregs.es = segregs.ds;
-    regs.w.ax = 0x500;          // get memory info
-    regs.x.edi = (int) &meminfo;
-    int386x(0x31, &regs, &regs, &segregs);
-
-    heap = meminfo[0];
-    ST_Message("  DPMI memory: 0x%x, ", heap);
-    ST_Message("Maxzone: 0x%x\n", maxzone);
-
-    do
-    {
-        heap -= 0x10000;        // leave 64k alone
-        if (heap > maxzone)
-            heap = maxzone;
-        ptr = malloc(heap);
-    }
-    while (!ptr);
-
-    ST_Message("  0x%x allocated for zone, ", heap);
-    ST_Message("ZoneBase: 0x%X\n", (int) ptr);
-
-    if (heap < 0x180000)
-        I_Error("  Insufficient DPMI memory!");
-#if 0
-    regs.w.ax = 0x501;          // allocate linear block
-    regs.w.bx = heap >> 16;
-    regs.w.cx = heap & 0xffff;
-    int386(0x31, &regs, &regs);
-    if (regs.w.cflag)
-        I_Error("  Couldn't allocate DPMI memory!");
-
-    block = (regs.w.si << 16) + regs.w.di;
-#endif
-
-    *size = heap;
-    return ptr;
-}
-
-/*
-=============
-=
-= I_AllocLow
-=
-=============
-*/
-
-byte *I_AllocLow(int length)
-{
-    byte *mem;
-
-    // DPMI call 100h allocates DOS memory
-    segread(&segregs);
-    regs.w.ax = 0x0100;         // DPMI allocate DOS memory
-    regs.w.bx = (length + 15) / 16;
-    int386(DPMI_INT, &regs, &regs);
-//      segment = regs.w.ax;
-//   selector = regs.w.dx;
-    if (regs.w.cflag != 0)
-        I_Error("I_AllocLow: DOS alloc of %i failed, %i free",
-                length, regs.w.bx * 16);
-
-
-    mem = (void *) ((regs.x.eax & 0xFFFF) << 4);
-
-    memset(mem, 0, length);
-    return mem;
-}
-
-/*
-============================================================================
-
-						NETWORKING
-
-============================================================================
-*/
-
-/* // FUCKED LINES
-typedef struct
-{
-	char    priv[508];
-   } doomdata_t;
-*/// FUCKED LINES
-
-#define DOOMCOM_ID              0x12345678l
-
-/* // FUCKED LINES
-typedef struct
-{
-	long    id;
-	short   intnum;                 // DOOM executes an int to execute commands
-
-// communication between DOOM and the driver
-	short   command;                // CMD_SEND or CMD_GET
-	short   remotenode;             // dest for send, set by get (-1 = no packet)
-	short   datalength;             // bytes in doomdata to be sent
-
-// info common to all nodes
-	short   numnodes;               // console is allways node 0
-	short   ticdup;                 // 1 = no duplication, 2-5 = dup for slow nets
-	short   extratics;              // 1 = send a backup tic in every packet
-	short   deathmatch;             // 1 = deathmatch
-	short   savegame;               // -1 = new game, 0-5 = load savegame
-	short   episode;                // 1-3
-	short   map;                    // 1-9
-	short   skill;                  // 1-5
-
-// info specific to this node
-	short   consoleplayer;
-	short   numplayers;
-	short   angleoffset;    // 1 = left, 0 = center, -1 = right
-	short   drone;                  // 1 = drone
-
-// packet data to be sent
-	doomdata_t      data;
-   } doomcom_t;
-*/// FUCKED LINES
-
-extern doomcom_t *doomcom;
-
-/*
-====================
-=
-= I_InitNetwork
-=
-====================
-*/
-
-void I_InitNetwork(void)
-{
-    int i;
-
-    i = M_CheckParm("-net");
-    if (!i)
-    {
-        //
-        // single player game
-        //
-        doomcom = malloc(sizeof(*doomcom));
-        memset(doomcom, 0, sizeof(*doomcom));
-        netgame = false;
-        doomcom->id = DOOMCOM_ID;
-        doomcom->numplayers = doomcom->numnodes = 1;
-        doomcom->deathmatch = false;
-        doomcom->consoleplayer = 0;
-        doomcom->ticdup = 1;
-        doomcom->extratics = 0;
-        return;
-    }
-
-    netgame = true;
-    doomcom = (doomcom_t *) atoi(myargv[i + 1]);
-//DEBUG
-    doomcom->skill = startskill;
-    doomcom->episode = startepisode;
-    doomcom->map = startmap;
-    doomcom->deathmatch = deathmatch;
-
-}
-
-void I_NetCmd(void)
-{
-    if (!netgame)
-        I_Error("I_NetCmd when not in netgame");
-    DPMIInt(doomcom->intnum);
-}
-
-//=========================================================================
-//
-// I_CheckExternDriver
-//
-//              Checks to see if a vector, and an address for an external driver
-//                      have been passed.
-//=========================================================================
-
-void I_CheckExternDriver(void)
-{
-    int i;
-
-    if (!(i = M_CheckParm("-externdriver")))
-    {
-        return;
-    }
-    i_ExternData = (externdata_t *) atoi(myargv[i + 1]);
-    i_Vector = i_ExternData->vector;
-
-    useexterndriver = true;
-}
-
-//=========================================================================
-//=========================================================================
-// Hi-Res (mode 12) stuff
-//=========================================================================
-//=========================================================================
-
-
-//==========================================================================
-//
-// SetVideoModeHR - Set video mode to 640x480x16
-//
-//==========================================================================
-
-
-void SetVideoModeHR(void)
-{
-    union REGS regs;
-    regs.x.eax = 0x12;
-    int386(VID_INT, &regs, &regs);
-}
-
-
-//==========================================================================
-//
-// ClearScreenHR - Clear the screen to color 0
-//
-//==========================================================================
-
-void ClearScreenHR(void)
-{
-    BITPLANE(MASK_PLANE0 | MASK_PLANE1 | MASK_PLANE2 | MASK_PLANE3);
-    memset((char *) 0xa0000, 0, 38400);
-}
-
-
-//==========================================================================
-//
-// SlamHR - copy 4-plane buffer to screen
-//
-//==========================================================================
-
-void SlamHR(char *buffer)
-{
-    BITPLANE(MASK_PLANE0);
-    memcpy((char *) 0xA0000, buffer + P0OFFSET, 38400);
-    BITPLANE(MASK_PLANE1);
-    memcpy((char *) 0xA0000, buffer + P1OFFSET, 38400);
-    BITPLANE(MASK_PLANE2);
-    memcpy((char *) 0xA0000, buffer + P2OFFSET, 38400);
-    BITPLANE(MASK_PLANE3);
-    memcpy((char *) 0xA0000, buffer + P3OFFSET, 38400);
-}
-
-
-//==========================================================================
-//
-// SlamHR - copy 4-plane buffer to screen
-//
-// X and Width should be a multiple of 8
-// src should be 4 planes of block size, back to back
-//==========================================================================
-
-void SlamBlockHR(int x, int y, int w, int h, char *src)
-{
-    int srcwid = w >> 3;
-    char *dest = ((char *) 0xA0000) + (y * (640 / 8)) + (x >> 3);
-    char *dst;
-    int i;
-
-    VB_SYNC;
-
-    BITPLANE(MASK_PLANE0);
-    dst = dest;
-    for (i = 0; i < h; i++)
-    {
-        memcpy(dst, src, srcwid);
-        dst += 640 / 8;
-        src += srcwid;
-    }
-    BITPLANE(MASK_PLANE1);
-    dst = dest;
-    for (i = 0; i < h; i++)
-    {
-        memcpy(dst, src, srcwid);
-        dst += 640 / 8;
-        src += srcwid;
-    }
-    BITPLANE(MASK_PLANE2);
-    dst = dest;
-    for (i = 0; i < h; i++)
-    {
-        memcpy(dst, src, srcwid);
-        dst += 640 / 8;
-        src += srcwid;
-    }
-    BITPLANE(MASK_PLANE3);
-    dst = dest;
-    for (i = 0; i < h; i++)
-    {
-        memcpy(dst, src, srcwid);
-        dst += 640 / 8;
-        src += srcwid;
-    }
-}
-
-//==========================================================================
-//
-// InitPaletteHR
-//
-//==========================================================================
-
-void InitPaletteHR(void)
-{
-    int i;
-    union REGS regs;
-
-    // Set palette registers to point into color registers
-    for (i = 0; i < 16; i++)
-    {
-        regs.x.eax = (0x10 << 8) | 0x00;
-        regs.x.ebx = (i << 8) | i;
-        int386(VID_INT, &regs, &regs);
-    }
-
-}
-
-
-//==========================================================================
-//
-// SetPaletteHR - Set the HR palette
-//
-//==========================================================================
-
-void SetPaletteHR(byte * palette)
-{
-    int i;
-    VB_SYNC;
-    outp(PEL_WRITE_ADR, 0);
-
-    for (i = 0; i < 16 * 3; i++)
-    {
-        outp(PEL_DATA, (*palette++));
-    }
-}
-
-
-//==========================================================================
-//
-// GetPaletteHR - Get the HR palette
-//
-//==========================================================================
-
-void GetPaletteHR(byte * palette)
-{
-    int i;
-    outp(PEL_READ_ADR, 0);
-    for (i = 0; i < 16 * 3; i++)
-    {
-        *palette++ = inp(PEL_DATA);
-    }
-}
-
-
-//==========================================================================
-//
-// FadeToPaletteHR
-//
-//==========================================================================
-
-void FadeToPaletteHR(byte * palette)
-{
-    int i, j;
-    int steps = 140;            // two-seconds
-    byte basep[16 * 3];
-    byte work[16 * 3];
-    int delta;
-
-    GetPaletteHR(basep);
-    for (i = 0; i < steps; i++)
-    {
-        for (j = 0; j < 16 * 3; j++)
-        {
-            delta = palette[j] - basep[j];
-            work[j] = basep[j] + delta * i / steps;
-        }
-        SetPaletteHR(work);
-    }
-    SetPaletteHR(palette);
-}
-
-
-//==========================================================================
-//
-// FadeToBlackHR - Fades the palette out to black
-//
-//==========================================================================
-
-/*
-void FadeToBlackHR(void)
-{
-	char work[16*3];
-	char base[16*3];
-	int i,j,steps=70;
-
-	GetPaletteHR(base);
-	for (i=0; i<steps; i++)
-	{
-		for (j=0; j<16*3; j++)
-		{
-			work[j] = base[j]-(base[j]*i/steps);
-		}
-		VB_SYNC;
-		SetPaletteHR(work);
-	}
-	memset(work,0,16*3);
-	SetPaletteHR(work);
-}
-*/
-
-//==========================================================================
-//
-// BlackPaletteHR - Instantly blacks out the palette
-//
-//==========================================================================
-
-void BlackPaletteHR(void)
-{
-    char blackpal[16 * 3];
-
-    memset(blackpal, 0, 16 * 3);
-    SetPaletteHR(blackpal);
-}
-
-//==========================================================================
-//
-//
-// I_StartupReadKeys
-//
-//
-//==========================================================================
-
-void I_StartupReadKeys(void)
-{
-    int k;
-
-    while (kbdtail < kbdhead)
-    {
-        k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
-        kbdtail++;
-        if (k == 1)
-            I_Quit();
-    }
-}
--- a/src/hexen/i_sound.c
+++ /dev/null
@@ -1,402 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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.
-//
-
-// I_SOUND.C
-
-#include <stdio.h>
-#include "h2def.h"
-#include "i_system.h"
-#include "m_argv.h"
-#include "dmx.h"
-#include "sounds.h"
-#include "i_sound.h"
-
-/*
-===============
-=
-= I_StartupTimer
-=
-===============
-*/
-
-int tsm_ID = -1;
-
-void I_StartupTimer(void)
-{
-#ifndef NOTIMER
-    extern int I_TimerISR(void);
-
-    ST_Message("  I_StartupTimer()\n");
-    // installs master timer.  Must be done before StartupTimer()!
-    TSM_Install(SND_TICRATE);
-    tsm_ID = TSM_NewService(I_TimerISR, 35, 255, 0);    // max priority
-    if (tsm_ID == -1)
-    {
-        I_Error("Can't register 35 Hz timer w/ DMX library");
-    }
-#endif
-}
-
-void I_ShutdownTimer(void)
-{
-    TSM_DelService(tsm_ID);
-    TSM_Remove();
-}
-
-/*
- *
- *                           SOUND HEADER & DATA
- *
- *
- */
-
-// sound information
-#if 0
-const char *dnames[] = { "None",
-    "PC_Speaker",
-    "Adlib",
-    "Sound_Blaster",
-    "ProAudio_Spectrum16",
-    "Gravis_Ultrasound",
-    "MPU",
-    "AWE32"
-};
-#endif
-
-const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
-    'M', 'M', 'S'
-};
-
-int snd_Channels;
-int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
-int snd_MusicDevice,            // current music card # (index to dmxCodes)
-  snd_SfxDevice,                // current sfx card # (index to dmxCodes)
-  snd_MaxVolume,                // maximum volume for sound
-  snd_MusicVolume;              // maximum volume for music
-int dmxCodes[NUM_SCARDS];       // the dmx code for a given card
-
-int snd_SBport, snd_SBirq, snd_SBdma;   // sound blaster variables
-int snd_Mport;                  // midi variables
-
-extern boolean snd_MusicAvail,  // whether music is available
-  snd_SfxAvail;                 // whether sfx are available
-
-void I_PauseSong(int handle)
-{
-    MUS_PauseSong(handle);
-}
-
-void I_ResumeSong(int handle)
-{
-    MUS_ResumeSong(handle);
-}
-
-void I_SetMusicVolume(int volume)
-{
-    MUS_SetMasterVolume(volume * 8);
-//  snd_MusicVolume = volume;
-}
-
-void I_SetSfxVolume(int volume)
-{
-    snd_MaxVolume = volume;     // THROW AWAY?
-}
-
-/*
- *
- *                              SONG API
- *
- */
-
-int I_RegisterSong(void *data)
-{
-    int rc = MUS_RegisterSong(data);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_Reg() returned %d\n", rc);
-#endif
-    return rc;
-}
-
-void I_UnRegisterSong(int handle)
-{
-    int rc = MUS_UnregisterSong(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_Unreg() returned %d\n", rc);
-#endif
-}
-
-int I_QrySongPlaying(int handle)
-{
-    int rc = MUS_QrySongPlaying(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_QrySP() returned %d\n", rc);
-#endif
-    return rc;
-}
-
-// Stops a song.  MUST be called before I_UnregisterSong().
-
-void I_StopSong(int handle)
-{
-    int rc;
-    rc = MUS_StopSong(handle);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_StopSong() returned %d\n", rc);
-#endif
-/*
-  // Fucking kluge pause
-  {
-	int s;
-	extern volatile int ticcount;
-	for (s=ticcount ; ticcount - s < 10 ; );
-  }
-*/
-}
-
-void I_PlaySong(int handle, boolean looping)
-{
-    int rc;
-    rc = MUS_ChainSong(handle, looping ? handle : -1);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_ChainSong() returned %d\n", rc);
-#endif
-    rc = MUS_PlaySong(handle, snd_MusicVolume);
-#ifdef SNDDEBUG
-    if (rc < 0)
-        ST_Message("    MUS_PlaySong() returned %d\n", rc);
-#endif
-
-}
-
-/*
- *
- *                                 SOUND FX API
- *
- */
-
-// Gets lump nums of the named sound.  Returns pointer which will be
-// passed to I_StartSound() when you want to start an SFX.  Must be
-// sure to pass this to UngetSoundEffect() so that they can be
-// freed!
-
-
-int I_GetSfxLumpNum(sfxinfo_t * sound)
-{
-    return W_GetNumForName(sound->lumpname);
-
-}
-
-int I_StartSound(int id, void *data, int vol, int sep, int pitch,
-                 int priority)
-{
-    return SFX_PlayPatch(data, pitch, sep, vol, 0, 0);
-}
-
-void I_StopSound(int handle)
-{
-//  extern volatile long gDmaCount;
-//  long waittocount;
-    SFX_StopPatch(handle);
-//  waittocount = gDmaCount + 2;
-//  while (gDmaCount < waittocount) ;
-}
-
-int I_SoundIsPlaying(int handle)
-{
-    return SFX_Playing(handle);
-}
-
-void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
-{
-    SFX_SetOrigin(handle, pitch, sep, vol);
-}
-
-/*
- *
- *                                                      SOUND STARTUP STUFF
- *
- *
- */
-
-//
-// Why PC's Suck, Reason #8712
-//
-
-void I_sndArbitrateCards(void)
-{
-    char tmp[160];
-    boolean gus, adlib, pc, sb, midi;
-    int i, rc, mputype, p, opltype, wait, dmxlump;
-
-    snd_MusicDevice = snd_DesiredMusicDevice;
-    snd_SfxDevice = snd_DesiredSfxDevice;
-
-    // check command-line parameters- overrides config file
-    //
-    if (M_CheckParm("-nosound"))
-        snd_MusicDevice = snd_SfxDevice = snd_none;
-    if (M_CheckParm("-nosfx"))
-        snd_SfxDevice = snd_none;
-    if (M_CheckParm("-nomusic"))
-        snd_MusicDevice = snd_none;
-
-    if (snd_MusicDevice > snd_MPU && snd_MusicDevice <= snd_MPU3)
-        snd_MusicDevice = snd_MPU;
-    if (snd_MusicDevice == snd_SB)
-        snd_MusicDevice = snd_Adlib;
-    if (snd_MusicDevice == snd_PAS)
-        snd_MusicDevice = snd_Adlib;
-
-    // figure out what i've got to initialize
-    //
-    gus = snd_MusicDevice == snd_GUS || snd_SfxDevice == snd_GUS;
-    sb = snd_SfxDevice == snd_SB || snd_MusicDevice == snd_SB;
-    adlib = snd_MusicDevice == snd_Adlib;
-    pc = snd_SfxDevice == snd_PC;
-    midi = snd_MusicDevice == snd_MPU;
-
-    // initialize whatever i've got
-    //
-    if (gus)
-    {
-        if (GF1_Detect())
-            ST_Message("    Dude.  The GUS ain't responding.\n");
-        else
-        {
-            dmxlump = W_GetNumForName("dmxgus");
-            GF1_SetMap(W_CacheLumpNum(dmxlump, PU_CACHE),
-                       lumpinfo[dmxlump].size);
-        }
-
-    }
-    if (sb)
-    {
-        if (debugmode)
-        {
-            ST_Message("  Sound cfg p=0x%x, i=%d, d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-        }
-        if (SB_Detect(&snd_SBport, &snd_SBirq, &snd_SBdma, 0))
-        {
-            ST_Message("    SB isn't responding at p=0x%x, i=%d, d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-        }
-        else
-            SB_SetCard(snd_SBport, snd_SBirq, snd_SBdma);
-
-        if (debugmode)
-        {
-            ST_Message("    SB_Detect returned p=0x%x, i=%d, d=%d\n",
-                       snd_SBport, snd_SBirq, snd_SBdma);
-        }
-    }
-
-    if (adlib)
-    {
-        if (AL_Detect(&wait, 0))
-        {
-            ST_Message("    Dude.  The Adlib isn't responding.\n");
-        }
-        else
-        {
-            AL_SetCard(wait, W_CacheLumpName("genmidi", PU_STATIC));
-        }
-    }
-
-    if (midi)
-    {
-        if (debugmode)
-        {
-            ST_Message("    cfg p=0x%x\n", snd_Mport);
-        }
-
-        if (MPU_Detect(&snd_Mport, &i))
-        {
-            ST_Message("    The MPU-401 isn't reponding @ p=0x%x.\n",
-                       snd_Mport);
-        }
-        else
-            MPU_SetCard(snd_Mport);
-    }
-
-}
-
-// inits all sound stuff
-
-void I_StartupSound(void)
-{
-    int rc, i;
-
-    if (debugmode)
-        ST_Message("I_StartupSound: Hope you hear a pop.\n");
-
-    // initialize dmxCodes[]
-    dmxCodes[0] = 0;
-    dmxCodes[snd_PC] = AHW_PC_SPEAKER;
-    dmxCodes[snd_Adlib] = AHW_ADLIB;
-    dmxCodes[snd_SB] = AHW_SOUND_BLASTER;
-    dmxCodes[snd_PAS] = AHW_MEDIA_VISION;
-    dmxCodes[snd_GUS] = AHW_ULTRA_SOUND;
-    dmxCodes[snd_MPU] = AHW_MPU_401;
-    dmxCodes[snd_MPU2] = AHW_MPU_401;
-    dmxCodes[snd_MPU3] = AHW_MPU_401;
-    dmxCodes[snd_AWE] = AHW_AWE32;
-    dmxCodes[snd_CDMUSIC] = 0;
-
-    // inits sound library timer stuff
-    I_StartupTimer();
-
-    // pick the sound cards i'm going to use
-    //
-    I_sndArbitrateCards();
-
-    if (debugmode)
-    {
-        ST_Message("    Music device #%d & dmxCode=%d,", snd_MusicDevice,
-                   dmxCodes[snd_MusicDevice]);
-        ST_Message(" Sfx device #%d & dmxCode=%d\n", snd_SfxDevice,
-                   dmxCodes[snd_SfxDevice]);
-    }
-
-    // inits DMX sound library
-    ST_Message("    Calling DMX_Init...");
-    rc = DMX_Init(SND_TICRATE, SND_MAXSONGS, dmxCodes[snd_MusicDevice],
-                  dmxCodes[snd_SfxDevice]);
-
-    if (debugmode)
-    {
-        ST_Message(" DMX_Init() returned %d\n", rc);
-    }
-
-}
-
-// shuts down all sound stuff
-
-void I_ShutdownSound(void)
-{
-    DMX_DeInit();
-    I_ShutdownTimer();
-}
-
-void I_SetChannels(int channels)
-{
-    WAV_PlayMode(channels, SND_SAMPLERATE);
-}
--- a/src/hexen/in_lude.c
+++ b/src/hexen/in_lude.c
@@ -23,6 +23,7 @@
 #include "m_misc.h"
 #include "p_local.h"
 #include "v_video.h"
+#include "i_swap.h"
 
 // MACROS ------------------------------------------------------------------
 
@@ -105,7 +106,7 @@
     skipintermission = false;
     intertime = 0;
     AM_Stop();
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         players[i].messageTics = 0;
         players[i].message[0] = 0;
@@ -207,13 +208,13 @@
         posnum = 0;
         playercount = 0;
         slaughtercount = 0;
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             totalFrags[i] = 0;
             if (playeringame[i])
             {
                 playercount++;
-                for (j = 0; j < MAXPLAYERS; j++)
+                for (j = 0; j < maxplayers; j++)
                 {
                     if (playeringame[j])
                     {
@@ -337,7 +338,7 @@
     player_t *player;
     static boolean triedToSkip;
 
-    for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
+    for (i = 0, player = players; i < maxplayers; i++, player++)
     {
         if (playeringame[i])
         {
@@ -477,10 +478,10 @@
         S_StartSound(NULL, SFX_PLATFORM_STOP);
     }
     y = yPos >> FRACBITS;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         xPos = xStart;
-        for (j = 0; j < MAXPLAYERS; j++, xPos += xDelta)
+        for (j = 0; j < maxplayers; j++, xPos += xDelta)
         {
             x = xPos >> FRACBITS;
             bold = (i == consoleplayer || j == consoleplayer);
@@ -600,11 +601,11 @@
             continue;
         }
         w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
-        if (cx + w->width > SCREENWIDTH)
+        if (cx + SHORT(w->width) > SCREENWIDTH)
         {
             break;
         }
         V_DrawPatch(cx, cy, w);
-        cx += w->width;
+        cx += SHORT(w->width);
     }
 }
--- a/src/hexen/m_misc.c
+++ /dev/null
@@ -1,21 +1,0 @@
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 1993-2008 Raven Software
-// 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.
-//
-
-
-// HEADER FILES ------------------------------------------------------------
-
-#include "h2def.h"
-
--- a/src/hexen/mn_menu.c
+++ b/src/hexen/mn_menu.c
@@ -378,7 +378,7 @@
         {
             p = W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE);
             V_DrawPatch(x, y, p);
-            x += p->width - 1;
+            x += SHORT(p->width) - 1;
         }
     }
 }
@@ -1190,11 +1190,13 @@
 
     if (InfoType)
     {
+        /* The 4-Level Demo Version also has 3 Info pages
         if (gamemode == shareware)
         {
             InfoType = (InfoType + 1) % 5;
         }
         else
+        */
         {
             InfoType = (InfoType + 1) % 4;
         }
--- a/src/hexen/p_acs.c
+++ b/src/hexen/p_acs.c
@@ -1681,7 +1681,7 @@
 {
     int i;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (playeringame[i])
         {
@@ -1722,7 +1722,7 @@
     int count;
 
     count = 0;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         count += playeringame[i];
     }
--- a/src/hexen/p_enemy.c
+++ b/src/hexen/p_enemy.c
@@ -546,8 +546,8 @@
     // stop = (actor->lastlook - 1) & 3;
     // for (;; actor->lastlook = (actor->lastlook + 1) & 3)
 
-    stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS;
-    for (;; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS)
+    stop = (actor->lastlook + maxplayers - 1) % maxplayers;
+    for (;; actor->lastlook = (actor->lastlook + 1) % maxplayers)
     {
         if (!playeringame[actor->lastlook])
             continue;
@@ -1179,7 +1179,7 @@
     actor->target = NULL;
     if (deathmatch)             // Quick search for players
     {
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (!playeringame[i])
                 continue;
@@ -3855,7 +3855,7 @@
 void A_IceGuyMissileExplode(mobj_t * actor)
 {
     mobj_t *mo;
-    int i;
+    unsigned int i;
 
     for (i = 0; i < 8; i++)
     {
--- a/src/hexen/p_inter.c
+++ b/src/hexen/p_inter.c
@@ -747,6 +747,12 @@
         TXT_ARTIPUZZGEAR
     };
 
+    if (gamemode == shareware)
+    {
+        artifactMessages[arti_blastradius] = TXT_ARTITELEPORT;
+        artifactMessages[arti_teleport] = TXT_ARTIBLASTRADIUS;
+    }
+
     if (P_GiveArtifact(player, artifactType, artifact))
     {
         if (artifact->special)
--- a/src/hexen/p_map.c
+++ b/src/hexen/p_map.c
@@ -661,7 +661,7 @@
     // Check for special thing
     if (thing->flags & MF_SPECIAL)
     {
-        solid = thing->flags & MF_SOLID;
+        solid = (thing->flags & MF_SOLID) != 0;
         if (tmflags & MF_PICKUP)
         {                       // Can be picked up by tmthing
             P_TouchSpecialThing(thing, tmthing);        // Can remove thing
--- a/src/hexen/p_maputl.c
+++ b/src/hexen/p_maputl.c
@@ -699,7 +699,7 @@
     int mapx, mapy, mapxstep, mapystep;
     int count;
 
-    earlyout = flags & PT_EARLYOUT;
+    earlyout = (flags & PT_EARLYOUT) != 0;
 
     validcount++;
     intercept_p = intercepts;
--- a/src/hexen/p_mobj.c
+++ b/src/hexen/p_mobj.c
@@ -1190,7 +1190,7 @@
     {
         mobj->reactiontime = info->reactiontime;
     }
-    mobj->lastlook = P_Random() % MAXPLAYERS;
+    mobj->lastlook = P_Random() % maxplayers;
 
     // Set the state, but do not use P_SetMobjState, because action
     // routines can't be called yet.  If the spawnstate has an action
@@ -1295,7 +1295,7 @@
     fixed_t x, y, z;
     mobj_t *mobj;
 
-    if (mthing->type - 1 >= MAXPLAYERS || !playeringame[mthing->type - 1])
+    if (mthing->type - 1 >= maxplayers || !playeringame[mthing->type - 1])
     {                           // Not playing
         return;
     }
@@ -1500,7 +1500,7 @@
     else if (deathmatch == false)
     {                           // Cooperative
         spawnMask = 0;
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (playeringame[i])
             {
--- a/src/hexen/p_setup.c
+++ b/src/hexen/p_setup.c
@@ -387,7 +387,7 @@
         return;
     }
     playerCount = 0;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playerCount += playeringame[i];
     }
@@ -672,7 +672,7 @@
     int lumpnum;
     mobj_t *mobj;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         players[i].killcount = players[i].secretcount
             = players[i].itemcount = 0;
@@ -722,7 +722,7 @@
     TimerGame = 0;
     if (deathmatch)
     {
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (playeringame[i])
             {                   // must give a player spot before deathmatchspawn
@@ -796,9 +796,15 @@
     int mcmdValue;
     mapInfo_t *info;
     char songMulch[10];
+    char *default_sky_name = DEFAULT_SKY_NAME;
 
     mapMax = 1;
 
+    if (gamemode == shareware)
+    {
+	default_sky_name = "SKY2";
+    }
+
     // Put defaults into MapInfo[0]
     info = MapInfo;
     info->cluster = 0;
@@ -805,7 +811,7 @@
     info->warpTrans = 0;
     info->nextMap = 1;          // Always go to map 1 if not specified
     info->cdTrack = 1;
-    info->sky1Texture = R_TextureNumForName(DEFAULT_SKY_NAME);
+    info->sky1Texture = R_TextureNumForName(default_sky_name);
     info->sky2Texture = info->sky1Texture;
     info->sky1ScrollDelta = 0;
     info->sky2ScrollDelta = 0;
--- a/src/hexen/p_spec.c
+++ b/src/hexen/p_spec.c
@@ -864,7 +864,7 @@
         if (line->flags & ML_SECRET)
             return false;       // never open secret doors
     }
-    repeat = line->flags & ML_REPEAT_SPECIAL;
+    repeat = (line->flags & ML_REPEAT_SPECIAL) != 0;
     buttonSuccess = false;
 
     // Construct args[] array to contain the arguments from the line, as we
--- a/src/hexen/p_switch.c
+++ b/src/hexen/p_switch.c
@@ -25,9 +25,16 @@
 //      CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
 //
 //==================================================================
-switchlist_t alphSwitchList[] = {
+switchlist_t alphSwitchListDemo[] = {
     {"SW_1_UP", "SW_1_DN", SFX_SWITCH1},
     {"SW_2_UP", "SW_2_DN", SFX_SWITCH1},
+    {"SW52_OFF", "SW52_ON", SFX_SWITCH2},
+    {"\0", "\0", 0}
+};
+
+switchlist_t alphSwitchListFull[] = {
+    {"SW_1_UP", "SW_1_DN", SFX_SWITCH1},
+    {"SW_2_UP", "SW_2_DN", SFX_SWITCH1},
     {"VALVE1", "VALVE2", SFX_VALVE_TURN},
     {"SW51_OFF", "SW51_ON", SFX_SWITCH2},
     {"SW52_OFF", "SW52_ON", SFX_SWITCH2},
@@ -39,6 +46,8 @@
     {"\0", "\0", 0}
 };
 
+switchlist_t *alphSwitchList = NULL;
+
 int switchlist[MAXSWITCHES * 2];
 int numswitches;
 button_t buttonlist[MAXBUTTONS];
@@ -57,6 +66,18 @@
 {
     int i;
     int index;
+
+    if (!alphSwitchList)
+    {
+        if (gamemode == shareware)
+        {
+            alphSwitchList = alphSwitchListDemo;
+        }
+        else
+        {
+            alphSwitchList = alphSwitchListFull;
+        }
+    }
 
     for (index = 0, i = 0; i < MAXSWITCHES; i++)
     {
--- a/src/hexen/p_tick.c
+++ b/src/hexen/p_tick.c
@@ -58,7 +58,7 @@
     {
         return;
     }
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (playeringame[i])
         {
@@ -86,7 +86,7 @@
 
 static void RunThinkers(void)
 {
-    thinker_t *currentthinker;
+    thinker_t *currentthinker, *nextthinker;
 
     currentthinker = thinkercap.next;
     while (currentthinker != &thinkercap)
@@ -93,15 +93,19 @@
     {
         if (currentthinker->function == (think_t) - 1)
         {                       // Time to remove it
+            nextthinker = currentthinker->next;
             currentthinker->next->prev = currentthinker->prev;
             currentthinker->prev->next = currentthinker->next;
             Z_Free(currentthinker);
         }
-        else if (currentthinker->function)
+        else
         {
-            currentthinker->function(currentthinker);
+            if (currentthinker->function)
+                currentthinker->function(currentthinker);
+            nextthinker = currentthinker->next;
         }
-        currentthinker = currentthinker->next;
+
+        currentthinker = nextthinker;
     }
 }
 
--- a/src/hexen/p_user.c
+++ b/src/hexen/p_user.c
@@ -480,7 +480,7 @@
 {
     int i;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (player == &players[i])
         {
@@ -1017,7 +1017,7 @@
     fixed_t destX, destY;
     angle_t destAngle;
 
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
             continue;
--- a/src/hexen/r_draw.c
+++ b/src/hexen/r_draw.c
@@ -320,9 +320,9 @@
     V_LoadTintTable();
 
     // Allocate translation tables
-    translationtables = Z_Malloc(256 * 3 * (MAXPLAYERS - 1), PU_STATIC, 0);
+    translationtables = Z_Malloc(256 * 3 * (maxplayers - 1), PU_STATIC, 0);
 
-    for (i = 0; i < 3 * (MAXPLAYERS - 1); i++)
+    for (i = 0; i < 3 * (maxplayers - 1); i++)
     {
         lumpnum = W_GetNumForName("trantbl0") + i;
         transLump = W_CacheLumpNum(lumpnum, PU_STATIC);
--- a/src/hexen/r_things.c
+++ b/src/hexen/r_things.c
@@ -388,7 +388,7 @@
         {
             colfunc = R_DrawTranslatedTLColumn;
             dc_translation = translationtables - 256
-                + vis->class * ((MAXPLAYERS - 1) * 256) +
+                + vis->class * ((maxplayers - 1) * 256) +
                 ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
         }
         else if (vis->mobjflags & MF_SHADOW)
@@ -405,7 +405,7 @@
         // Draw using translated column function
         colfunc = R_DrawTranslatedColumn;
         dc_translation = translationtables - 256
-            + vis->class * ((MAXPLAYERS - 1) * 256) +
+            + vis->class * ((maxplayers - 1) * 256) +
             ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
     }
 
@@ -426,7 +426,7 @@
 
     if (vis->floorclip && !vis->psprite)
     {
-        sprbotscreen = sprtopscreen + FixedMul(patch->height << FRACBITS,
+        sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height) << FRACBITS,
                                                spryscale);
         baseclip = (sprbotscreen - FixedMul(vis->floorclip,
                                             spryscale)) >> FRACBITS;
--- a/src/hexen/s_sound.c
+++ b/src/hexen/s_sound.c
@@ -787,6 +787,7 @@
 
 void S_Init(void)
 {
+    I_SetOPLDriverVer(opl_v_old);
     SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC);
 //      SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
 
--- a/src/hexen/sb_bar.c
+++ b/src/hexen/sb_bar.c
@@ -26,6 +26,7 @@
 #include "p_local.h"
 #include "s_sound.h"
 #include "v_video.h"
+#include "i_swap.h"
 
 // TYPES -------------------------------------------------------------------
 
@@ -241,6 +242,10 @@
     {CheatRevealFunc, &CheatRevealSeq},
 };
 
+#define SET_CHEAT(cheat, seq) \
+    { memcpy(cheat.sequence, seq, sizeof(seq)); \
+      cheat.sequence_len = sizeof(seq) - 1; }
+
 // CODE --------------------------------------------------------------------
 
 //==========================================================================
@@ -302,6 +307,34 @@
         PatchKILLS = W_CacheLumpName("KILLS", PU_STATIC);
     }
     SB_SetClassData();
+
+    if (gamemode == shareware)
+    {
+	SET_CHEAT(CheatGodSeq, "bgokey");
+	SET_CHEAT(CheatNoClipSeq, "rjohnson");
+	SET_CHEAT(CheatWeaponsSeq, "crhinehart");
+	SET_CHEAT(CheatHealthSeq,"sgurno");
+	SET_CHEAT(CheatKeysSeq, "mraymondjudy");
+	SET_CHEAT(CheatSoundSeq, "kschilder");
+	SET_CHEAT(CheatTickerSeq, "rrettenmund");
+	SET_CHEAT(CheatArtifactAllSeq, "braffel");
+	SET_CHEAT(CheatPuzzleSeq, "tmoore");
+	SET_CHEAT(CheatWarpSeq, "bpelletier");
+	SET_CHEAT(CheatPigSeq, "ebiessman");
+	SET_CHEAT(CheatMassacreSeq, "cstika");
+	SET_CHEAT(CheatIDKFASeq, "rambo");
+	SET_CHEAT(CheatQuickenSeq1, "quicken");
+	SET_CHEAT(CheatQuickenSeq2, "quickenquicken");
+	SET_CHEAT(CheatQuickenSeq3, "quickenquickenquicken");
+	SET_CHEAT(CheatClass1Seq, "plipo");
+	SET_CHEAT(CheatClass2Seq, "plipo");
+	SET_CHEAT(CheatVersionSeq, "pmacarther");
+	SET_CHEAT(CheatDebugSeq, "jsumwalt");
+	SET_CHEAT(CheatScriptSeq1, "mwagabaza");
+	SET_CHEAT(CheatScriptSeq2, "mwagabaza");
+	SET_CHEAT(CheatScriptSeq3, "mwagabaza");
+	SET_CHEAT(CheatRevealSeq, "reveal");
+    }
 }
 
 //==========================================================================
@@ -329,12 +362,12 @@
     if (!netgame)
     {                           // single player game uses red life gem (the second gem)
         PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem")
-                                      + MAXPLAYERS * class + 1, PU_STATIC);
+                                      + maxplayers * class + 1, PU_STATIC);
     }
     else
     {
         PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem")
-                                      + MAXPLAYERS * class + consoleplayer,
+                                      + maxplayers * class + consoleplayer,
                                       PU_STATIC);
     }
     SB_state = -1;
@@ -496,7 +529,7 @@
     if (val > 99)
     {
         patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE);
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
     }
     val = val % 100;
     xpos += 12;
@@ -503,12 +536,12 @@
     if (val > 9 || oldval > 99)
     {
         patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE);
-        V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+        V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
     }
     val = val % 10;
     xpos += 12;
     patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
-    V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+    V_DrawShadowedPatch(xpos + 6 - SHORT(patch->width) / 2, y, patch);
 }
 
 //==========================================================================
@@ -1023,7 +1056,7 @@
     if (deathmatch)
     {
         temp = 0;
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             temp += CPlayer->frags[i];
         }
@@ -1350,7 +1383,7 @@
     if (deathmatch)
     {
         temp = 0;
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (playeringame[i])
             {
--- a/src/hexen/sv_save.c
+++ b/src/hexen/sv_save.c
@@ -346,7 +346,7 @@
 
     // mobj_t *mo;
     // Pointer value is reset on load.
-    GET_LONG;
+    str->mo = (void *) (intptr_t) GET_LONG;
     str->mo = NULL;
 
     // playerstate_t playerstate;
@@ -416,7 +416,7 @@
     str->pieces = GET_LONG;
 
     // signed int frags[MAXPLAYERS];
-    for (i=0; i<MAXPLAYERS; ++i)
+    for (i=0; i<maxplayers; ++i)
     {
         str->frags[i] = GET_LONG;
     }
@@ -478,12 +478,12 @@
 
     // mobj_t *poisoner;
     // Pointer value is reset.
-    GET_LONG;
+    str->poisoner = (void *) (intptr_t) GET_LONG;
     str->poisoner = NULL;
 
     // mobj_t *attacker;
     // Pointer value is reset.
-    GET_LONG;
+    str->attacker = (void *) (intptr_t) GET_LONG;
     str->attacker = NULL;
 
     // int extralight;
@@ -585,7 +585,7 @@
     StreamOutLong(str->pieces);
 
     // signed int frags[MAXPLAYERS];
-    for (i=0; i<MAXPLAYERS; ++i)
+    for (i=0; i<maxplayers; ++i)
     {
         StreamOutLong(str->frags[i]);
     }
@@ -685,14 +685,14 @@
 {
     // struct thinker_s *prev, *next;
     // Pointers are discarded:
-    GET_LONG;
+    str->prev = (void *) (intptr_t) GET_LONG;
     str->prev = NULL;
-    GET_LONG;
+    str->next = (void *) (intptr_t) GET_LONG;
     str->next = NULL;
 
     // think_t function;
     // Function pointer is discarded:
-    GET_LONG;
+    str->function = (void *) (intptr_t) GET_LONG;
     str->function = NULL;
 }
 
@@ -766,9 +766,9 @@
 
     // struct mobj_s *snext, *sprev;
     // Pointer values are discarded:
-    GET_LONG;
+    str->snext = (void *) (intptr_t) GET_LONG;
     str->snext = NULL;
-    GET_LONG;
+    str->sprev = (void *) (intptr_t) GET_LONG;
     str->sprev = NULL;
 
     // angle_t angle;
@@ -783,14 +783,14 @@
     // struct mobj_s *bnext, *bprev;
     // Values are read but discarded; this will be restored when the thing's
     // position is set.
-    GET_LONG;
+    str->bnext = (void *) (intptr_t) GET_LONG;
     str->bnext = NULL;
-    GET_LONG;
+    str->bprev = (void *) (intptr_t) GET_LONG;
     str->bprev = NULL;
 
     // struct subsector_s *subsector;
     // Read but discard: pointer will be restored when thing position is set.
-    GET_LONG;
+    str->subsector = (void *) (intptr_t) GET_LONG;
     str->subsector = NULL;
 
     // fixed_t floorz, ceilingz;
@@ -817,7 +817,7 @@
 
     // mobjinfo_t *info;
     // Pointer value is read but discarded.
-    GET_LONG;
+    str->info = (void *) (intptr_t) GET_LONG;
     str->info = NULL;
 
     // int tics;
@@ -2081,7 +2081,7 @@
     Z_Free(SaveBuffer);
 
     // Save player structs
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playerBackup[i] = players[i];
     }
@@ -2095,7 +2095,7 @@
     // Restore player structs
     inv_ptr = 0;
     curpos = 0;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         mobj = players[i].mo;
         players[i] = playerBackup[i];
@@ -2170,7 +2170,7 @@
     // Store player structs for later
     rClass = randomclass;
     randomclass = false;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playerBackup[i] = players[i];
     }
@@ -2194,7 +2194,7 @@
         G_InitNew(gameskill, gameepisode, gamemap);
 
         // Destroy all freshly spawned players
-        for (i = 0; i < MAXPLAYERS; i++)
+        for (i = 0; i < maxplayers; i++)
         {
             if (playeringame[i])
             {
@@ -2205,7 +2205,7 @@
 
     // Restore player structs
     targetPlayerMobj = NULL;
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
         {
@@ -2286,7 +2286,7 @@
     }
 
     // Destroy all things touching players
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (playeringame[i])
         {
@@ -2403,11 +2403,11 @@
     int i;
 
     StreamOutLong(ASEG_PLAYERS);
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         StreamOutByte(playeringame[i]);
     }
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
         {
@@ -2429,11 +2429,11 @@
     int i;
 
     AssertSegment(ASEG_PLAYERS);
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         playeringame[i] = GET_BYTE;
     }
-    for (i = 0; i < MAXPLAYERS; i++)
+    for (i = 0; i < maxplayers; i++)
     {
         if (!playeringame[i])
         {
@@ -2968,7 +2968,7 @@
     int ix;
 
     StreamOutLong(ASEG_MISC);
-    for (ix = 0; ix < MAXPLAYERS; ix++)
+    for (ix = 0; ix < maxplayers; ix++)
     {
         StreamOutLong(localQuakeHappening[ix]);
     }
@@ -2985,7 +2985,7 @@
     int ix;
 
     AssertSegment(ASEG_MISC);
-    for (ix = 0; ix < MAXPLAYERS; ix++)
+    for (ix = 0; ix < maxplayers; ix++)
     {
         localQuakeHappening[ix] = GET_LONG;
     }
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -328,20 +328,20 @@
 {
     int i;
 
-    M_BindVariable("use_joystick",          &usejoystick);
-    M_BindVariable("joystick_index",        &joystick_index);
-    M_BindVariable("joystick_x_axis",       &joystick_x_axis);
-    M_BindVariable("joystick_y_axis",       &joystick_y_axis);
-    M_BindVariable("joystick_strafe_axis",  &joystick_strafe_axis);
-    M_BindVariable("joystick_x_invert",     &joystick_x_invert);
-    M_BindVariable("joystick_y_invert",     &joystick_y_invert);
-    M_BindVariable("joystick_strafe_invert",&joystick_strafe_invert);
+    M_BindIntVariable("use_joystick",          &usejoystick);
+    M_BindIntVariable("joystick_index",        &joystick_index);
+    M_BindIntVariable("joystick_x_axis",       &joystick_x_axis);
+    M_BindIntVariable("joystick_y_axis",       &joystick_y_axis);
+    M_BindIntVariable("joystick_strafe_axis",  &joystick_strafe_axis);
+    M_BindIntVariable("joystick_x_invert",     &joystick_x_invert);
+    M_BindIntVariable("joystick_y_invert",     &joystick_y_invert);
+    M_BindIntVariable("joystick_strafe_invert",&joystick_strafe_invert);
 
     for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
     {
         char name[32];
         M_snprintf(name, sizeof(name), "joystick_physical_button%i", i);
-        M_BindVariable(name, &joystick_physical_buttons[i]);
+        M_BindIntVariable(name, &joystick_physical_buttons[i]);
     }
 }
 
--- a/src/i_main.c
+++ b/src/i_main.c
@@ -34,97 +34,6 @@
 
 void D_DoomMain (void);
 
-#if defined(_WIN32_WCE)
-
-// Windows CE?  I doubt it even supports SMP..
-
-static void LockCPUAffinity(void)
-{
-}
-
-#elif defined(_WIN32)
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef BOOL (WINAPI *SetAffinityFunc)(HANDLE hProcess, DWORD mask);
-
-// This is a bit more complicated than it really needs to be.  We really
-// just need to call the SetProcessAffinityMask function, but that
-// function doesn't exist on systems before Windows 2000.  Instead,
-// dynamically look up the function and call the pointer to it.  This
-// way, the program will run on older versions of Windows (Win9x, etc.)
-
-static void LockCPUAffinity(void)
-{
-    HMODULE kernel32_dll;
-    SetAffinityFunc SetAffinity;
-
-    // Find the kernel interface DLL.
-
-    kernel32_dll = LoadLibrary("kernel32.dll");
-
-    if (kernel32_dll == NULL)
-    {
-        // This should never happen...
-
-        fprintf(stderr, "Failed to load kernel32.dll\n");
-        return;
-    }
-    // Find the SetProcessAffinityMask function.
-
-    SetAffinity = (SetAffinityFunc)GetProcAddress(kernel32_dll, "SetProcessAffinityMask");
-
-    // If the function was not found, we are on an old (Win9x) system
-    // that doesn't have this function.  That's no problem, because
-    // those systems don't support SMP anyway.
-
-    if (SetAffinity != NULL)
-    {
-        if (!SetAffinity(GetCurrentProcess(), 1))
-        {
-            fprintf(stderr, "Failed to set process affinity (%d)\n",
-                            (int) GetLastError());
-        }
-    }
-}
-
-#elif defined(HAVE_SCHED_SETAFFINITY)
-
-#include <unistd.h>
-#include <sched.h>
-
-// Unix (Linux) version:
-
-static void LockCPUAffinity(void)
-{
-#ifdef CPU_SET
-    cpu_set_t set;
-
-    CPU_ZERO(&set);
-    CPU_SET(0, &set);
-
-    sched_setaffinity(getpid(), sizeof(set), &set);
-#else
-    unsigned long mask = 1;
-    sched_setaffinity(getpid(), sizeof(mask), &mask);
-#endif
-}
-
-#else
-
-#warning No known way to set processor affinity on this platform.
-#warning You may experience crashes due to SDL_mixer.
-
-static void LockCPUAffinity(void)
-{
-    fprintf(stderr, 
-    "WARNING: No known way to set processor affinity on this platform.\n"
-    "         You may experience crashes due to SDL_mixer.\n");
-}
-
-#endif
-
 int main(int argc, char **argv)
 {
     // save arguments
@@ -131,11 +40,6 @@
 
     myargc = argc;
     myargv = argv;
-
-    // Only schedule on a single core, if we have multiple
-    // cores.  This is to work around a bug in SDL_mixer.
-
-    LockCPUAffinity();
 
     M_FindResponseFile();
 
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -86,6 +86,10 @@
 
     int volume;
 
+    // Pan
+
+    int pan;
+
     // Pitch bend value:
 
     int bend;
@@ -115,6 +119,9 @@
     // The operators used by this voice:
     int op1, op2;
 
+    // Array used by voice:
+    int array;
+
     // Currently-loaded instrument data
     genmidi_instr_t *current_instr;
 
@@ -143,6 +150,12 @@
     // The current volume (register value) that has been set for this channel.
     unsigned int reg_volume;
 
+    // Pan.
+    unsigned int reg_pan;
+
+    // Priority.
+    unsigned int priority;
+
     // Next in linked list; a voice is always either in the
     // free list or the allocated list.
     opl_voice_t *next;
@@ -294,6 +307,7 @@
     124, 124, 125, 125, 126, 126, 127, 127
 };
 
+static opl_driver_ver_t opl_drv_ver = opl_v_new;
 static boolean music_initialized = false;
 
 //static boolean musicpaused = false;
@@ -308,9 +322,12 @@
 
 // Voices:
 
-static opl_voice_t voices[OPL_NUM_VOICES];
+static opl_voice_t voices[OPL_NUM_VOICES * 2];
 static opl_voice_t *voice_free_list;
 static opl_voice_t *voice_alloced_list;
+static int voice_alloced_num;
+static int opl_opl3mode;
+static int num_opl_voices;
 
 // Track data for playing tracks:
 
@@ -333,6 +350,7 @@
 // adlib chip.
 
 int opl_io_port = 0x388;
+int opl_type = 0;
 
 // Load instrument table from GENMIDI lump:
 
@@ -353,7 +371,8 @@
 
     main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER));
     percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS;
-    main_instr_names = (char (*)[32]) (percussion_instrs + GENMIDI_NUM_PERCUSSION);
+    main_instr_names =
+        (char (*)[32]) (percussion_instrs + GENMIDI_NUM_PERCUSSION);
     percussion_names = main_instr_names + GENMIDI_NUM_INSTRS;
 
     return true;
@@ -390,6 +409,8 @@
     *rover = result;
     result->next = NULL;
 
+    voice_alloced_num++;
+
     return result;
 }
 
@@ -409,6 +430,7 @@
         {
             *rover = voice->next;
             voice->next = NULL;
+            voice_alloced_num--;
             break;
         }
 
@@ -418,13 +440,20 @@
 
 // Release a voice back to the freelist.
 
+static void VoiceKeyOff(opl_voice_t *voice);
+
 static void ReleaseVoice(opl_voice_t *voice)
 {
     opl_voice_t **rover;
+    opl_voice_t *next;
+    boolean double_voice;
 
     voice->channel = NULL;
     voice->note = 0;
 
+    double_voice = voice->current_instr_voice != 0;
+    next = voice->next;
+
     // Remove from alloced list.
 
     RemoveVoiceFromAllocedList(voice);
@@ -440,6 +469,12 @@
 
     *rover = voice;
     voice->next = NULL;
+
+    if (next != NULL && double_voice && opl_drv_ver == opl_v_old)
+    {
+        VoiceKeyOff(next);
+        ReleaseVoice(next);
+    }
 }
 
 // Load data to the specified operator
@@ -497,19 +532,24 @@
     // is set in SetVoiceVolume (below).  If we are not using
     // modulating mode, we must set both to minimum volume.
 
-    LoadOperatorData(voice->op2, &data->carrier, true);
-    LoadOperatorData(voice->op1, &data->modulator, !modulating);
+    LoadOperatorData(voice->op2 | voice->array, &data->carrier, true);
+    LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating);
 
     // Set feedback register that control the connection between the
     // two operators.  Turn on bits in the upper nybble; I think this
     // is for OPL3, where it turns on channel A/B.
 
-    OPL_WriteRegister(OPL_REGS_FEEDBACK + voice->index,
-                      data->feedback | 0x30);
+    OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
+                      data->feedback | voice->reg_pan);
 
     // Hack to force a volume update.
 
     voice->reg_volume = 999;
+
+    // Calculate voice priority.
+
+    voice->priority = 0x0f - (data->carrier.attack >> 4)
+                    + 0x0f - (data->carrier.sustain & 0x0f);
 }
 
 static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
@@ -529,7 +569,8 @@
     midi_volume = 2 * (volume_mapping_table[(voice->channel->volume
                   * current_music_volume) / 127] + 1);
 
-    full_volume = (volume_mapping_table[voice->note_volume] * midi_volume) >> 9;
+    full_volume = (volume_mapping_table[voice->note_volume] * midi_volume)
+                >> 9;
 
     // The volume value to use in the register:
     car_volume = 0x3f - full_volume;
@@ -540,12 +581,14 @@
     {
         voice->reg_volume = car_volume | (opl_voice->carrier.scale & 0xc0);
 
-        OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, voice->reg_volume);
+        OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array,
+                          voice->reg_volume);
 
         // If we are using non-modulated feedback mode, we must set the
         // volume for both voices.
 
-        if ((opl_voice->feedback & 0x01) != 0 && opl_voice->modulator.level != 0x3f)
+        if ((opl_voice->feedback & 0x01) != 0
+         && opl_voice->modulator.level != 0x3f)
         {
             mod_volume = 0x3f - opl_voice->modulator.level;
             if (mod_volume >= car_volume)
@@ -552,12 +595,24 @@
             {
                 mod_volume = car_volume;
             }
-            OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1,
-                              mod_volume | (opl_voice->modulator.scale & 0xc0));
+            OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
+                              mod_volume |
+                              (opl_voice->modulator.scale & 0xc0));
         }
     }
 }
 
+static void SetVoicePan(opl_voice_t *voice, unsigned int pan)
+{
+    genmidi_voice_t *opl_voice;
+
+    voice->reg_pan = pan;
+    opl_voice = &voice->current_instr->voices[voice->current_instr_voice];;
+
+    OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
+                      opl_voice->feedback | pan);
+}
+
 // Initialize the voice table and freelist
 
 static void InitVoices(void)
@@ -570,11 +625,12 @@
 
     // Initialize each voice.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
-        voices[i].index = i;
-        voices[i].op1 = voice_operators[0][i];
-        voices[i].op2 = voice_operators[1][i];
+        voices[i].index = i % OPL_NUM_VOICES;
+        voices[i].op1 = voice_operators[0][i % OPL_NUM_VOICES];
+        voices[i].op2 = voice_operators[1][i % OPL_NUM_VOICES];
+        voices[i].array = (i / OPL_NUM_VOICES) << 8;
         voices[i].current_instr = NULL;
 
         // Add this voice to the freelist.
@@ -595,7 +651,7 @@
 
     // Update the volume of all voices.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
         if (voices[i].channel != NULL)
         {
@@ -606,7 +662,8 @@
 
 static void VoiceKeyOff(opl_voice_t *voice)
 {
-    OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8);
+    OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array,
+                      voice->freq >> 8);
 }
 
 static opl_channel_data_t *TrackChannelForEvent(opl_track_data_t *track,
@@ -634,8 +691,9 @@
 static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event)
 {
     opl_channel_data_t *channel;
+    opl_voice_t *rover;
+    opl_voice_t *prev;
     unsigned int key;
-    unsigned int i;
 
 /*
     printf("note off: channel %i, %i, %i\n",
@@ -650,16 +708,32 @@
     // Turn off voices being used to play this key.
     // If it is a double voice instrument there will be two.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    rover = voice_alloced_list;
+    prev = NULL;
+
+    while (rover != NULL)
     {
-        if (voices[i].channel == channel && voices[i].key == key)
+        if (rover->channel == channel && rover->key == key)
         {
-            VoiceKeyOff(&voices[i]);
+            VoiceKeyOff(rover);
 
             // Finished with this voice now.
 
-            ReleaseVoice(&voices[i]);
+            ReleaseVoice(rover);
+            if (prev == NULL)
+            {
+                rover = voice_alloced_list;
+            }
+            else
+            {
+                rover = prev->next;
+            }
         }
+        else
+        {
+            prev = rover;
+            rover = rover->next;
+        }
     }
 }
 
@@ -668,7 +742,7 @@
 // passed to the function is the channel for the new note to be
 // played.
 
-static void ReplaceExistingVoice()
+static void ReplaceExistingVoice(void)
 {
     opl_voice_t *rover;
     opl_voice_t *result;
@@ -696,7 +770,43 @@
     ReleaseVoice(result);
 }
 
+// Alternate version of ReplaceExistingVoice() used when emulating old
+// versions of the DMX library used in Heretic and Hexen.
 
+static void ReplaceExistingVoiceOld(opl_channel_data_t *channel)
+{
+    opl_voice_t *rover;
+    opl_voice_t *result;
+    opl_voice_t *roverend;
+    int i;
+    int priority;
+
+    result = voice_alloced_list;
+
+    roverend = voice_alloced_list;
+
+    for (i = 0; i < voice_alloced_num - 3; i++)
+    {
+        roverend = roverend->next;
+    }
+
+    priority = 0x8000;
+
+    for (rover = voice_alloced_list; rover != roverend; rover = rover->next)
+    {
+        if (rover->priority < priority
+         && rover->channel >= channel)
+        {
+            priority = rover->priority;
+            result = rover;
+        }
+    }
+
+    VoiceKeyOff(result);
+    ReleaseVoice(result);
+}
+
+
 static unsigned int FrequencyForVoice(opl_voice_t *voice)
 {
     genmidi_voice_t *gm_voice;
@@ -786,8 +896,10 @@
 
     if (voice->freq != freq)
     {
-        OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff);
-        OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20);
+        OPL_WriteRegister((OPL_REGS_FREQ_1 + voice->index) | voice->array,
+                          freq & 0xff);
+        OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array,
+                          (freq >> 8) | 0x20);
 
         voice->freq = freq;
     }
@@ -830,6 +942,8 @@
         voice->note = note;
     }
 
+    voice->reg_pan = channel->pan;
+
     // Program the voice with the instrument data:
 
     SetVoiceInstrument(voice, instrument, instrument_voice);
@@ -849,6 +963,7 @@
     genmidi_instr_t *instrument;
     opl_channel_data_t *channel;
     unsigned int note, key, volume;
+    boolean double_voice;
 
 /*
     printf("note on: channel %i, %i, %i\n",
@@ -892,19 +1007,45 @@
         instrument = channel->instrument;
     }
 
-    if (voice_free_list == NULL)
+    double_voice = (SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0;
+
+    if (opl_drv_ver == opl_v_old)
     {
-        ReplaceExistingVoice();
-    }
+        if (voice_alloced_num == num_opl_voices)
+        {
+            ReplaceExistingVoiceOld(channel);
+        }
+        if (voice_alloced_num == num_opl_voices - 1 && double_voice)
+        {
+            ReplaceExistingVoiceOld(channel);
+        }
 
-    // Find and program a voice for this instrument.  If this
-    // is a double voice instrument, we must do this twice.
+        // Find and program a voice for this instrument.  If this
+        // is a double voice instrument, we must do this twice.
 
-    VoiceKeyOn(channel, instrument, 0, note, key, volume);
+        if (double_voice)
+        {
+            VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        }
 
-    if ((SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0)
+        VoiceKeyOn(channel, instrument, 0, note, key, volume);
+    }
+    else
     {
-        VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        if (voice_free_list == NULL)
+        {
+            ReplaceExistingVoice();
+        }
+
+        // Find and program a voice for this instrument.  If this
+        // is a double voice instrument, we must do this twice.
+
+        VoiceKeyOn(channel, instrument, 0, note, key, volume);
+
+        if (double_voice)
+        {
+            VoiceKeyOn(channel, instrument, 1, note, key, volume);
+        }
     }
 }
 
@@ -931,7 +1072,7 @@
 
     // Update all voices that this channel is using.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
         if (voices[i].channel == channel)
         {
@@ -940,18 +1081,71 @@
     }
 }
 
+static void SetChannelPan(opl_channel_data_t *channel, unsigned int pan)
+{
+    unsigned int reg_pan;
+    unsigned int i;
+
+    if (opl_opl3mode)
+    {
+        if (pan >= 96)
+        {
+            reg_pan = 0x10;
+        }
+        else if (pan <= 48)
+        {
+            reg_pan = 0x20;
+        }
+        else
+        {
+            reg_pan = 0x30;
+        }
+        if (channel->pan != reg_pan)
+        {
+            channel->pan = reg_pan;
+            for (i = 0; i < num_opl_voices; i++)
+            {
+                if (voices[i].channel == channel)
+                {
+                    SetVoicePan(&voices[i], reg_pan);
+                }
+            }
+        }
+    }
+}
+
 // Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
 static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
 {
-    unsigned int i;
+    opl_voice_t *rover;
+    opl_voice_t *prev;
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    rover = voice_alloced_list;
+    prev = NULL;
+
+    while (rover!=NULL)
     {
-        if (voices[i].channel == channel)
+        if (rover->channel == channel)
         {
-            VoiceKeyOff(&voices[i]);
-            ReleaseVoice(&voices[i]);
+            VoiceKeyOff(rover);
+
+            // Finished with this voice now.
+
+            ReleaseVoice(rover);
+            if (prev == NULL)
+            {
+                rover = voice_alloced_list;
+            }
+            else
+            {
+                rover = prev->next;
+            }
         }
+        else
+        {
+            prev = rover;
+            rover = rover->next;
+        }
     }
 }
 
@@ -978,6 +1172,10 @@
             SetChannelVolume(channel, param);
             break;
 
+        case MIDI_CONTROLLER_PAN:
+            SetChannelPan(channel, param);
+            break;
+
         case MIDI_CONTROLLER_ALL_NOTES_OFF:
             AllNotesOff(channel, param);
             break;
@@ -1005,7 +1203,7 @@
 
     // Update all voices for this channel.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
         if (voices[i].channel == channel)
         {
@@ -1193,6 +1391,7 @@
 
     channel->instrument = &main_instrs[0];
     channel->volume = 127;
+    channel->pan = 0x30;
     channel->bend = 0;
 }
 
@@ -1267,7 +1466,7 @@
     // Turn off all main instrument voices (not percussion).
     // This is what Vanilla does.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
         if (voices[i].channel != NULL
          && voices[i].current_instr < percussion_instrs)
@@ -1304,7 +1503,7 @@
 
     // Free all voices.
 
-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < num_opl_voices; ++i)
     {
         if (voices[i].channel != NULL)
         {
@@ -1451,14 +1650,32 @@
 
 static boolean I_OPL_InitMusic(void)
 {
+    int opl_chip_type;
+
     OPL_SetSampleRate(snd_samplerate);
 
-    if (!OPL_Init(opl_io_port))
+    opl_chip_type = OPL_Init(opl_io_port);
+    if (!opl_chip_type)
     {
         printf("Dude.  The Adlib isn't responding.\n");
         return false;
     }
 
+    if (opl_chip_type == 2 && opl_type)
+    {
+        opl_opl3mode = 1;
+        num_opl_voices = OPL_NUM_VOICES * 2;
+    }
+    else
+    {
+        opl_opl3mode = 0;
+        num_opl_voices = OPL_NUM_VOICES;
+    }
+
+    // Initialize all registers.
+
+    OPL_InitRegisters(opl_opl3mode);
+
     // Load instruments from GENMIDI lump:
 
     if (!LoadInstrumentTable())
@@ -1498,6 +1715,11 @@
     I_OPL_MusicIsPlaying,
     NULL,  // Poll
 };
+
+void I_SetOPLDriverVer(opl_driver_ver_t ver)
+{
+    opl_drv_ver = ver;
+}
 
 //----------------------------------------------------------------------
 //
--- a/src/i_scale.c
+++ b/src/i_scale.c
@@ -28,10 +28,6 @@
 #include "m_argv.h"
 #include "z_zone.h"
 
-#if defined(_MSC_VER) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 // Should be I_VideoBuffer
 
 static byte *src_buffer;
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -20,6 +20,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
+
 #include "SDL.h"
 #include "SDL_mixer.h"
 
@@ -422,7 +424,7 @@
     sha1_context_t context;
     sha1_digest_t hash;
     char *filename;
-    int i;
+    unsigned int i;
 
     // Don't bother doing a hash if we're never going to find anything.
     if (subst_music_len == 0)
@@ -631,7 +633,7 @@
     FILE *fs;
     char *error;
     int linenum = 1;
-    int old_subst_music_len;
+//    int old_subst_music_len;
 
     fs = fopen(filename, "r");
 
@@ -640,7 +642,7 @@
         return false;
     }
 
-    old_subst_music_len = subst_music_len;
+//    old_subst_music_len = subst_music_len;
 
     while (!feof(fs))
     {
@@ -734,7 +736,8 @@
     char name[9];
     byte *data;
     FILE *fs;
-    int lumpnum, h;
+    unsigned int lumpnum;
+    size_t h;
 
     fs = fopen(filename, "w");
 
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -340,7 +340,7 @@
 {
     SRC_DATA src_data;
     uint32_t i, abuf_index=0, clipped=0;
-    uint32_t alen;
+//    uint32_t alen;
     int retn;
     int16_t *expanded;
     Mix_Chunk *chunk;
@@ -372,7 +372,7 @@
 
     // Allocate the new chunk.
 
-    alen = src_data.output_frames_gen * 4;
+//    alen = src_data.output_frames_gen * 4;
 
     chunk = AllocateSound(sfxinfo, src_data.output_frames_gen * 4);
 
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -66,7 +66,9 @@
 
 // For OPL module:
 
+extern opl_driver_ver_t opl_drv_ver;
 extern int opl_io_port;
+extern int opl_type;
 
 // For native music module:
 
@@ -434,25 +436,26 @@
     extern int use_libsamplerate;
     extern float libsamplerate_scale;
 
-    M_BindVariable("snd_musicdevice",   &snd_musicdevice);
-    M_BindVariable("snd_sfxdevice",     &snd_sfxdevice);
-    M_BindVariable("snd_sbport",        &snd_sbport);
-    M_BindVariable("snd_sbirq",         &snd_sbirq);
-    M_BindVariable("snd_sbdma",         &snd_sbdma);
-    M_BindVariable("snd_mport",         &snd_mport);
-    M_BindVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms);
-    M_BindVariable("snd_musiccmd",      &snd_musiccmd);
-    M_BindVariable("snd_samplerate",    &snd_samplerate);
-    M_BindVariable("snd_cachesize",     &snd_cachesize);
-    M_BindVariable("opl_io_port",       &opl_io_port);
+    M_BindIntVariable("snd_musicdevice",         &snd_musicdevice);
+    M_BindIntVariable("snd_sfxdevice",           &snd_sfxdevice);
+    M_BindIntVariable("snd_sbport",              &snd_sbport);
+    M_BindIntVariable("snd_sbirq",               &snd_sbirq);
+    M_BindIntVariable("snd_sbdma",               &snd_sbdma);
+    M_BindIntVariable("snd_mport",               &snd_mport);
+    M_BindIntVariable("snd_maxslicetime_ms",     &snd_maxslicetime_ms);
+    M_BindStringVariable("snd_musiccmd",         &snd_musiccmd);
+    M_BindIntVariable("snd_samplerate",          &snd_samplerate);
+    M_BindIntVariable("snd_cachesize",           &snd_cachesize);
+    M_BindIntVariable("opl_io_port",             &opl_io_port);
+    M_BindIntVariable("opl_type",                &opl_type);
 
-    M_BindVariable("timidity_cfg_path", &timidity_cfg_path);
-    M_BindVariable("gus_patch_path",    &gus_patch_path);
-    M_BindVariable("gus_ram_kb",        &gus_ram_kb);
+    M_BindStringVariable("timidity_cfg_path",    &timidity_cfg_path);
+    M_BindStringVariable("gus_patch_path",       &gus_patch_path);
+    M_BindIntVariable("gus_ram_kb",              &gus_ram_kb);
 
 #ifdef FEATURE_SOUND
-    M_BindVariable("use_libsamplerate",   &use_libsamplerate);
-    M_BindVariable("libsamplerate_scale", &libsamplerate_scale);
+    M_BindIntVariable("use_libsamplerate",       &use_libsamplerate);
+    M_BindFloatVariable("libsamplerate_scale",   &libsamplerate_scale);
 #endif
 
     // Before SDL_mixer version 1.2.11, MIDI music caused the game
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -234,5 +234,13 @@
 
 void I_BindSoundVariables(void);
 
+// DMX version to emulate for OPL emulation:
+typedef enum {
+    opl_v_old,   // Hexen, Heretic
+    opl_v_new    // Doom, Strife
+} opl_driver_ver_t;
+
+void I_SetOPLDriverVer(opl_driver_ver_t ver);
+
 #endif
 
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -435,6 +435,7 @@
 
 static int TranslateKey(SDL_Keysym *sym)
 {
+<<<<<<< HEAD
     int scancode = sym->scancode;
 
     switch (scancode)
@@ -446,7 +447,92 @@
         case SDL_SCANCODE_LSHIFT:
         case SDL_SCANCODE_RSHIFT:
             return KEY_RSHIFT;
+=======
+    switch(sym->sym)
+    {
+      case SDLK_LEFT:	return KEY_LEFTARROW;
+      case SDLK_RIGHT:	return KEY_RIGHTARROW;
+      case SDLK_DOWN:	return KEY_DOWNARROW;
+      case SDLK_UP:	return KEY_UPARROW;
+      case SDLK_ESCAPE:	return KEY_ESCAPE;
+      case SDLK_RETURN:	return KEY_ENTER;
+      case SDLK_TAB:	return KEY_TAB;
+      case SDLK_F1:	return KEY_F1;
+      case SDLK_F2:	return KEY_F2;
+      case SDLK_F3:	return KEY_F3;
+      case SDLK_F4:	return KEY_F4;
+      case SDLK_F5:	return KEY_F5;
+      case SDLK_F6:	return KEY_F6;
+      case SDLK_F7:	return KEY_F7;
+      case SDLK_F8:	return KEY_F8;
+      case SDLK_F9:	return KEY_F9;
+      case SDLK_F10:	return KEY_F10;
+      case SDLK_F11:	return KEY_F11;
+      case SDLK_F12:	return KEY_F12;
+      case SDLK_PRINT:  return KEY_PRTSCR;
 
+      case SDLK_BACKSPACE: return KEY_BACKSPACE;
+      case SDLK_DELETE:	return KEY_DEL;
+
+      case SDLK_PAUSE:	return KEY_PAUSE;
+
+      case SDLK_EQUALS: return KEY_EQUALS;
+
+      case SDLK_MINUS:          return KEY_MINUS;
+
+      case SDLK_LSHIFT:
+      case SDLK_RSHIFT:
+	return KEY_RSHIFT;
+	
+      case SDLK_LCTRL:
+      case SDLK_RCTRL:
+	return KEY_RCTRL;
+	
+      case SDLK_LALT:
+      case SDLK_RALT:
+      case SDLK_LMETA:
+      case SDLK_RMETA:
+        return KEY_RALT;
+
+      case SDLK_CAPSLOCK: return KEY_CAPSLOCK;
+      case SDLK_SCROLLOCK: return KEY_SCRLCK;
+      case SDLK_NUMLOCK: return KEY_NUMLOCK;
+
+      case SDLK_KP0: return KEYP_0;
+      case SDLK_KP1: return KEYP_1;
+      case SDLK_KP2: return KEYP_2;
+      case SDLK_KP3: return KEYP_3;
+      case SDLK_KP4: return KEYP_4;
+      case SDLK_KP5: return KEYP_5;
+      case SDLK_KP6: return KEYP_6;
+      case SDLK_KP7: return KEYP_7;
+      case SDLK_KP8: return KEYP_8;
+      case SDLK_KP9: return KEYP_9;
+
+      case SDLK_KP_PERIOD:   return KEYP_PERIOD;
+      case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY;
+      case SDLK_KP_PLUS:     return KEYP_PLUS;
+      case SDLK_KP_MINUS:    return KEYP_MINUS;
+      case SDLK_KP_DIVIDE:   return KEYP_DIVIDE;
+      case SDLK_KP_EQUALS:   return KEYP_EQUALS;
+      case SDLK_KP_ENTER:    return KEYP_ENTER;
+
+      case SDLK_HOME: return KEY_HOME;
+      case SDLK_INSERT: return KEY_INS;
+      case SDLK_END: return KEY_END;
+      case SDLK_PAGEUP: return KEY_PGUP;
+      case SDLK_PAGEDOWN: return KEY_PGDN;
+
+#ifdef SDL_HAVE_APP_KEYS
+        case SDLK_APP1:        return KEY_F1;
+        case SDLK_APP2:        return KEY_F2;
+        case SDLK_APP3:        return KEY_F3;
+        case SDLK_APP4:        return KEY_F4;
+        case SDLK_APP5:        return KEY_F5;
+        case SDLK_APP6:        return KEY_F6;
+#endif
+>>>>>>> master
+
         case SDL_SCANCODE_LALT:
             return KEY_LALT;
 
@@ -882,8 +968,13 @@
         // because we're at an end of level intermission screen, for
         // example.
 
+<<<<<<< HEAD
         SDL_GetWindowSize(screen, &screen_w, &screen_h);
         SDL_WarpMouseInWindow(screen, screen_w - 16, screen_h - 16);
+=======
+        SDL_WarpMouse(screen->w - 16, screen->h - 16);
+        SDL_PumpEvents();
+>>>>>>> master
         SDL_GetRelativeMouseState(NULL, NULL);
     }
 
@@ -1934,6 +2025,15 @@
         I_Error("Failed to initialize video: %s", SDL_GetError());
     }
 
+<<<<<<< HEAD
+=======
+    // Set up title and icon.  Windows cares about the ordering; this
+    // has to be done before the call to SDL_SetVideoMode.
+
+    I_InitWindowTitle();
+    I_InitWindowIcon();
+
+>>>>>>> master
     // Warning to OS X users... though they might never see it :(
 #ifdef __MACOSX__
     if (fullscreen)
@@ -2052,6 +2152,7 @@
 
 void I_BindVideoVariables(void)
 {
+<<<<<<< HEAD
     M_BindVariable("use_mouse",                 &usemouse);
     M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
     M_BindVariable("fullscreen",                &fullscreen);
@@ -2068,6 +2169,25 @@
     M_BindVariable("vanilla_keyboard_mapping",  &vanilla_keyboard_mapping);
     M_BindVariable("novert",                    &novert);
     M_BindVariable("png_screenshots",           &png_screenshots);
+=======
+    M_BindIntVariable("use_mouse",                 &usemouse);
+    M_BindIntVariable("autoadjust_video_settings", &autoadjust_video_settings);
+    M_BindIntVariable("fullscreen",                &fullscreen);
+    M_BindIntVariable("aspect_ratio_correct",      &aspect_ratio_correct);
+    M_BindIntVariable("startup_delay",             &startup_delay);
+    M_BindIntVariable("screen_width",              &screen_width);
+    M_BindIntVariable("screen_height",             &screen_height);
+    M_BindIntVariable("screen_bpp",                &screen_bpp);
+    M_BindIntVariable("grabmouse",                 &grabmouse);
+    M_BindFloatVariable("mouse_acceleration",      &mouse_acceleration);
+    M_BindIntVariable("mouse_threshold",           &mouse_threshold);
+    M_BindStringVariable("video_driver",           &video_driver);
+    M_BindStringVariable("window_position",        &window_position);
+    M_BindIntVariable("usegamma",                  &usegamma);
+    M_BindIntVariable("vanilla_keyboard_mapping",  &vanilla_keyboard_mapping);
+    M_BindIntVariable("novert",                    &novert);
+    M_BindIntVariable("png_screenshots",           &png_screenshots);
+>>>>>>> master
 
     // Disable fullscreen by default on OS X, as there is an SDL bug
     // where some old versions of OS X (<= Snow Leopard) crash.
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
+#include <assert.h>
 
 #include "config.h"
 
@@ -64,7 +65,11 @@
     char *name;
 
     // Pointer to the location in memory of the variable
-    void *location;
+    union {
+        int *i;
+        char **s;
+        float *f;
+    } location;
 
     // Type of the variable
     default_type_t type;
@@ -93,7 +98,7 @@
 } default_collection_t;
 
 #define CONFIG_VARIABLE_GENERIC(name, type) \
-    { #name, NULL, type, 0, 0, false }
+    { #name, {NULL}, type, 0, 0, false }
 
 #define CONFIG_VARIABLE_KEY(name) \
     CONFIG_VARIABLE_GENERIC(name, DEFAULT_KEY)
@@ -811,6 +816,11 @@
     CONFIG_VARIABLE_INT_HEX(opl_io_port),
 
     //!
+    // OPL chip type.
+    //
+    CONFIG_VARIABLE_INT(opl_type),
+
+    //!
     // @game doom heretic strife
     //
     // If non-zero, the ENDOOM text screen is displayed when exiting the
@@ -1638,7 +1648,7 @@
                 // the possibility of screwing up the user's config
                 // file
                 
-                v = * (int *) defaults[i].location;
+                v = *defaults[i].location.i;
 
                 if (v == KEY_RSHIFT)
                 {
@@ -1679,19 +1689,19 @@
                 break;
 
             case DEFAULT_INT:
-	        fprintf(f, "%i", * (int *) defaults[i].location);
+	        fprintf(f, "%i", *defaults[i].location.i);
                 break;
 
             case DEFAULT_INT_HEX:
-	        fprintf(f, "0x%x", * (int *) defaults[i].location);
+	        fprintf(f, "0x%x", *defaults[i].location.i);
                 break;
 
             case DEFAULT_FLOAT:
-                fprintf(f, "%f", * (float *) defaults[i].location);
+                fprintf(f, "%f", *defaults[i].location.f);
                 break;
 
             case DEFAULT_STRING:
-	        fprintf(f,"\"%s\"", * (char **) (defaults[i].location));
+	        fprintf(f,"\"%s\"", *defaults[i].location.s);
                 break;
         }
 
@@ -1724,12 +1734,12 @@
     switch (def->type)
     {
         case DEFAULT_STRING:
-            * (char **) def->location = M_StringDuplicate(value);
+            *def->location.s = M_StringDuplicate(value);
             break;
 
         case DEFAULT_INT:
         case DEFAULT_INT_HEX:
-            * (int *) def->location = ParseIntParameter(value);
+            *def->location.i = ParseIntParameter(value);
             break;
 
         case DEFAULT_KEY:
@@ -1749,11 +1759,11 @@
             }
 
             def->original_translated = intparm;
-            * (int *) def->location = intparm;
+            *def->location.i = intparm;
             break;
 
         case DEFAULT_FLOAT:
-            * (float *) def->location = (float) atof(value);
+            *def->location.f = (float) atof(value);
             break;
     }
 }
@@ -1949,16 +1959,41 @@
 // Bind a variable to a given configuration file variable, by name.
 //
 
-void M_BindVariable(char *name, void *location)
+void M_BindIntVariable(char *name, int *location)
 {
     default_t *variable;
 
     variable = GetDefaultForName(name);
+    assert(variable->type == DEFAULT_INT
+        || variable->type == DEFAULT_INT_HEX
+        || variable->type == DEFAULT_KEY);
 
-    variable->location = location;
+    variable->location.i = location;
     variable->bound = true;
 }
 
+void M_BindFloatVariable(char *name, float *location)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+    assert(variable->type == DEFAULT_FLOAT);
+
+    variable->location.f = location;
+    variable->bound = true;
+}
+
+void M_BindStringVariable(char *name, char **location)
+{
+    default_t *variable;
+
+    variable = GetDefaultForName(name);
+    assert(variable->type == DEFAULT_STRING);
+
+    variable->location.s = location;
+    variable->bound = true;
+}
+
 // Set the value of a particular variable; an API function for other
 // parts of the program to assign values to config variables by name.
 
@@ -1992,10 +2027,10 @@
         return 0;
     }
 
-    return *((int *) variable->location);
+    return *variable->location.i;
 }
 
-const char *M_GetStrVariable(char *name)
+const char *M_GetStringVariable(char *name)
 {
     default_t *variable;
 
@@ -2007,7 +2042,7 @@
         return NULL;
     }
 
-    return *((const char **) variable->location);
+    return *variable->location.s;
 }
 
 float M_GetFloatVariable(char *name)
@@ -2022,7 +2057,7 @@
         return 0;
     }
 
-    return *((float *) variable->location);
+    return *variable->location.f;
 }
 
 // Get the path to the default configuration dir to use, if NULL
--- a/src/m_config.h
+++ b/src/m_config.h
@@ -26,10 +26,12 @@
 void M_SaveDefaults(void);
 void M_SaveDefaultsAlternate(char *main, char *extra);
 void M_SetConfigDir(char *dir);
-void M_BindVariable(char *name, void *variable);
+void M_BindIntVariable(char *name, int *variable);
+void M_BindFloatVariable(char *name, float *variable);
+void M_BindStringVariable(char *name, char **variable);
 boolean M_SetVariable(char *name, char *value);
 int M_GetIntVariable(char *name);
-const char *M_GetStrVariable(char *name);
+const char *M_GetStringVariable(char *name);
 float M_GetFloatVariable(char *name);
 void M_SetConfigFilenames(char *main_config, char *extra_config);
 char *M_GetSaveGameDir(char *iwadname);
--- a/src/m_controls.c
+++ b/src/m_controls.c
@@ -204,70 +204,70 @@
 
 void M_BindBaseControls(void)
 {
-    M_BindVariable("key_right",          &key_right);
-    M_BindVariable("key_left",           &key_left);
-    M_BindVariable("key_up",             &key_up);
-    M_BindVariable("key_down",           &key_down);
-    M_BindVariable("key_strafeleft",     &key_strafeleft);
-    M_BindVariable("key_straferight",    &key_straferight);
-    M_BindVariable("key_fire",           &key_fire);
-    M_BindVariable("key_use",            &key_use);
-    M_BindVariable("key_strafe",         &key_strafe);
-    M_BindVariable("key_speed",          &key_speed);
+    M_BindIntVariable("key_right",          &key_right);
+    M_BindIntVariable("key_left",           &key_left);
+    M_BindIntVariable("key_up",             &key_up);
+    M_BindIntVariable("key_down",           &key_down);
+    M_BindIntVariable("key_strafeleft",     &key_strafeleft);
+    M_BindIntVariable("key_straferight",    &key_straferight);
+    M_BindIntVariable("key_fire",           &key_fire);
+    M_BindIntVariable("key_use",            &key_use);
+    M_BindIntVariable("key_strafe",         &key_strafe);
+    M_BindIntVariable("key_speed",          &key_speed);
 
-    M_BindVariable("mouseb_fire",        &mousebfire);
-    M_BindVariable("mouseb_strafe",      &mousebstrafe);
-    M_BindVariable("mouseb_forward",     &mousebforward);
+    M_BindIntVariable("mouseb_fire",        &mousebfire);
+    M_BindIntVariable("mouseb_strafe",      &mousebstrafe);
+    M_BindIntVariable("mouseb_forward",     &mousebforward);
 
-    M_BindVariable("joyb_fire",          &joybfire);
-    M_BindVariable("joyb_strafe",        &joybstrafe);
-    M_BindVariable("joyb_use",           &joybuse);
-    M_BindVariable("joyb_speed",         &joybspeed);
+    M_BindIntVariable("joyb_fire",          &joybfire);
+    M_BindIntVariable("joyb_strafe",        &joybstrafe);
+    M_BindIntVariable("joyb_use",           &joybuse);
+    M_BindIntVariable("joyb_speed",         &joybspeed);
 
-    M_BindVariable("joyb_menu_activate", &joybmenu);
+    M_BindIntVariable("joyb_menu_activate", &joybmenu);
 
     // Extra controls that are not in the Vanilla versions:
 
-    M_BindVariable("joyb_strafeleft",    &joybstrafeleft);
-    M_BindVariable("joyb_straferight",   &joybstraferight);
-    M_BindVariable("mouseb_strafeleft",  &mousebstrafeleft);
-    M_BindVariable("mouseb_straferight", &mousebstraferight);
-    M_BindVariable("mouseb_use",         &mousebuse);
-    M_BindVariable("mouseb_backward",    &mousebbackward);
-    M_BindVariable("dclick_use",         &dclick_use);
-    M_BindVariable("key_pause",          &key_pause);
-    M_BindVariable("key_message_refresh", &key_message_refresh);
+    M_BindIntVariable("joyb_strafeleft",     &joybstrafeleft);
+    M_BindIntVariable("joyb_straferight",    &joybstraferight);
+    M_BindIntVariable("mouseb_strafeleft",   &mousebstrafeleft);
+    M_BindIntVariable("mouseb_straferight",  &mousebstraferight);
+    M_BindIntVariable("mouseb_use",          &mousebuse);
+    M_BindIntVariable("mouseb_backward",     &mousebbackward);
+    M_BindIntVariable("dclick_use",          &dclick_use);
+    M_BindIntVariable("key_pause",           &key_pause);
+    M_BindIntVariable("key_message_refresh", &key_message_refresh);
 }
 
 void M_BindHereticControls(void)
 {
-    M_BindVariable("key_flyup",          &key_flyup);
-    M_BindVariable("key_flydown",        &key_flydown);
-    M_BindVariable("key_flycenter",      &key_flycenter);
+    M_BindIntVariable("key_flyup",          &key_flyup);
+    M_BindIntVariable("key_flydown",        &key_flydown);
+    M_BindIntVariable("key_flycenter",      &key_flycenter);
 
-    M_BindVariable("key_lookup",         &key_lookup);
-    M_BindVariable("key_lookdown",       &key_lookdown);
-    M_BindVariable("key_lookcenter",     &key_lookcenter);
+    M_BindIntVariable("key_lookup",         &key_lookup);
+    M_BindIntVariable("key_lookdown",       &key_lookdown);
+    M_BindIntVariable("key_lookcenter",     &key_lookcenter);
 
-    M_BindVariable("key_invleft",        &key_invleft);
-    M_BindVariable("key_invright",       &key_invright);
-    M_BindVariable("key_useartifact",    &key_useartifact);
+    M_BindIntVariable("key_invleft",        &key_invleft);
+    M_BindIntVariable("key_invright",       &key_invright);
+    M_BindIntVariable("key_useartifact",    &key_useartifact);
 }
 
 void M_BindHexenControls(void)
 {
-    M_BindVariable("key_jump",           &key_jump);
-    M_BindVariable("mouseb_jump",        &mousebjump);
-    M_BindVariable("joyb_jump",          &joybjump);
+    M_BindIntVariable("key_jump",           &key_jump);
+    M_BindIntVariable("mouseb_jump",        &mousebjump);
+    M_BindIntVariable("joyb_jump",          &joybjump);
 
-    M_BindVariable("key_arti_all",             &key_arti_all);
-    M_BindVariable("key_arti_health",          &key_arti_health);
-    M_BindVariable("key_arti_poisonbag",       &key_arti_poisonbag);
-    M_BindVariable("key_arti_blastradius",     &key_arti_blastradius);
-    M_BindVariable("key_arti_teleport",        &key_arti_teleport);
-    M_BindVariable("key_arti_teleportother",   &key_arti_teleportother);
-    M_BindVariable("key_arti_egg",             &key_arti_egg);
-    M_BindVariable("key_arti_invulnerability", &key_arti_invulnerability);
+    M_BindIntVariable("key_arti_all",             &key_arti_all);
+    M_BindIntVariable("key_arti_health",          &key_arti_health);
+    M_BindIntVariable("key_arti_poisonbag",       &key_arti_poisonbag);
+    M_BindIntVariable("key_arti_blastradius",     &key_arti_blastradius);
+    M_BindIntVariable("key_arti_teleport",        &key_arti_teleport);
+    M_BindIntVariable("key_arti_teleportother",   &key_arti_teleportother);
+    M_BindIntVariable("key_arti_egg",             &key_arti_egg);
+    M_BindIntVariable("key_arti_invulnerability", &key_arti_invulnerability);
 }
 
 void M_BindStrifeControls(void)
@@ -282,95 +282,95 @@
     key_invleft  = KEY_INS;
     key_invright = KEY_DEL;
 
-    M_BindVariable("key_jump",           &key_jump);
-    M_BindVariable("key_lookUp",         &key_lookup);
-    M_BindVariable("key_lookDown",       &key_lookdown);
-    M_BindVariable("key_invLeft",        &key_invleft);
-    M_BindVariable("key_invRight",       &key_invright);
+    M_BindIntVariable("key_jump",           &key_jump);
+    M_BindIntVariable("key_lookUp",         &key_lookup);
+    M_BindIntVariable("key_lookDown",       &key_lookdown);
+    M_BindIntVariable("key_invLeft",        &key_invleft);
+    M_BindIntVariable("key_invRight",       &key_invright);
 
     // Custom Strife-only Keys:
-    M_BindVariable("key_useHealth",      &key_usehealth);
-    M_BindVariable("key_invquery",       &key_invquery);
-    M_BindVariable("key_mission",        &key_mission);
-    M_BindVariable("key_invPop",         &key_invpop);
-    M_BindVariable("key_invKey",         &key_invkey);
-    M_BindVariable("key_invHome",        &key_invhome);
-    M_BindVariable("key_invEnd",         &key_invend);
-    M_BindVariable("key_invUse",         &key_invuse);
-    M_BindVariable("key_invDrop",        &key_invdrop);
+    M_BindIntVariable("key_useHealth",      &key_usehealth);
+    M_BindIntVariable("key_invquery",       &key_invquery);
+    M_BindIntVariable("key_mission",        &key_mission);
+    M_BindIntVariable("key_invPop",         &key_invpop);
+    M_BindIntVariable("key_invKey",         &key_invkey);
+    M_BindIntVariable("key_invHome",        &key_invhome);
+    M_BindIntVariable("key_invEnd",         &key_invend);
+    M_BindIntVariable("key_invUse",         &key_invuse);
+    M_BindIntVariable("key_invDrop",        &key_invdrop);
 
     // Strife also supports jump on mouse and joystick, and in the exact same
     // manner as Hexen!
-    M_BindVariable("mouseb_jump",        &mousebjump);
-    M_BindVariable("joyb_jump",          &joybjump);
+    M_BindIntVariable("mouseb_jump",        &mousebjump);
+    M_BindIntVariable("joyb_jump",          &joybjump);
 }
 
 void M_BindWeaponControls(void)
 {
-    M_BindVariable("key_weapon1",        &key_weapon1);
-    M_BindVariable("key_weapon2",        &key_weapon2);
-    M_BindVariable("key_weapon3",        &key_weapon3);
-    M_BindVariable("key_weapon4",        &key_weapon4);
-    M_BindVariable("key_weapon5",        &key_weapon5);
-    M_BindVariable("key_weapon6",        &key_weapon6);
-    M_BindVariable("key_weapon7",        &key_weapon7);
-    M_BindVariable("key_weapon8",        &key_weapon8);
+    M_BindIntVariable("key_weapon1",        &key_weapon1);
+    M_BindIntVariable("key_weapon2",        &key_weapon2);
+    M_BindIntVariable("key_weapon3",        &key_weapon3);
+    M_BindIntVariable("key_weapon4",        &key_weapon4);
+    M_BindIntVariable("key_weapon5",        &key_weapon5);
+    M_BindIntVariable("key_weapon6",        &key_weapon6);
+    M_BindIntVariable("key_weapon7",        &key_weapon7);
+    M_BindIntVariable("key_weapon8",        &key_weapon8);
 
-    M_BindVariable("key_prevweapon",     &key_prevweapon);
-    M_BindVariable("key_nextweapon",     &key_nextweapon);
+    M_BindIntVariable("key_prevweapon",     &key_prevweapon);
+    M_BindIntVariable("key_nextweapon",     &key_nextweapon);
 
-    M_BindVariable("joyb_prevweapon",    &joybprevweapon);
-    M_BindVariable("joyb_nextweapon",    &joybnextweapon);
+    M_BindIntVariable("joyb_prevweapon",    &joybprevweapon);
+    M_BindIntVariable("joyb_nextweapon",    &joybnextweapon);
 
-    M_BindVariable("mouseb_prevweapon",  &mousebprevweapon);
-    M_BindVariable("mouseb_nextweapon",  &mousebnextweapon);
+    M_BindIntVariable("mouseb_prevweapon",  &mousebprevweapon);
+    M_BindIntVariable("mouseb_nextweapon",  &mousebnextweapon);
 }
 
 void M_BindMapControls(void)
 {
-    M_BindVariable("key_map_north",      &key_map_north);
-    M_BindVariable("key_map_south",      &key_map_south);
-    M_BindVariable("key_map_east",       &key_map_east);
-    M_BindVariable("key_map_west",       &key_map_west);
-    M_BindVariable("key_map_zoomin",     &key_map_zoomin);
-    M_BindVariable("key_map_zoomout",    &key_map_zoomout);
-    M_BindVariable("key_map_toggle",     &key_map_toggle);
-    M_BindVariable("key_map_maxzoom",    &key_map_maxzoom);
-    M_BindVariable("key_map_follow",     &key_map_follow);
-    M_BindVariable("key_map_grid",       &key_map_grid);
-    M_BindVariable("key_map_mark",       &key_map_mark);
-    M_BindVariable("key_map_clearmark",  &key_map_clearmark);
+    M_BindIntVariable("key_map_north",      &key_map_north);
+    M_BindIntVariable("key_map_south",      &key_map_south);
+    M_BindIntVariable("key_map_east",       &key_map_east);
+    M_BindIntVariable("key_map_west",       &key_map_west);
+    M_BindIntVariable("key_map_zoomin",     &key_map_zoomin);
+    M_BindIntVariable("key_map_zoomout",    &key_map_zoomout);
+    M_BindIntVariable("key_map_toggle",     &key_map_toggle);
+    M_BindIntVariable("key_map_maxzoom",    &key_map_maxzoom);
+    M_BindIntVariable("key_map_follow",     &key_map_follow);
+    M_BindIntVariable("key_map_grid",       &key_map_grid);
+    M_BindIntVariable("key_map_mark",       &key_map_mark);
+    M_BindIntVariable("key_map_clearmark",  &key_map_clearmark);
 }
 
 void M_BindMenuControls(void)
 {
-    M_BindVariable("key_menu_activate",  &key_menu_activate);
-    M_BindVariable("key_menu_up",        &key_menu_up);
-    M_BindVariable("key_menu_down",      &key_menu_down);
-    M_BindVariable("key_menu_left",      &key_menu_left);
-    M_BindVariable("key_menu_right",     &key_menu_right);
-    M_BindVariable("key_menu_back",      &key_menu_back);
-    M_BindVariable("key_menu_forward",   &key_menu_forward);
-    M_BindVariable("key_menu_confirm",   &key_menu_confirm);
-    M_BindVariable("key_menu_abort",     &key_menu_abort);
+    M_BindIntVariable("key_menu_activate",  &key_menu_activate);
+    M_BindIntVariable("key_menu_up",        &key_menu_up);
+    M_BindIntVariable("key_menu_down",      &key_menu_down);
+    M_BindIntVariable("key_menu_left",      &key_menu_left);
+    M_BindIntVariable("key_menu_right",     &key_menu_right);
+    M_BindIntVariable("key_menu_back",      &key_menu_back);
+    M_BindIntVariable("key_menu_forward",   &key_menu_forward);
+    M_BindIntVariable("key_menu_confirm",   &key_menu_confirm);
+    M_BindIntVariable("key_menu_abort",     &key_menu_abort);
 
-    M_BindVariable("key_menu_help",      &key_menu_help);
-    M_BindVariable("key_menu_save",      &key_menu_save);
-    M_BindVariable("key_menu_load",      &key_menu_load);
-    M_BindVariable("key_menu_volume",    &key_menu_volume);
-    M_BindVariable("key_menu_detail",    &key_menu_detail);
-    M_BindVariable("key_menu_qsave",     &key_menu_qsave);
-    M_BindVariable("key_menu_endgame",   &key_menu_endgame);
-    M_BindVariable("key_menu_messages",  &key_menu_messages);
-    M_BindVariable("key_menu_qload",     &key_menu_qload);
-    M_BindVariable("key_menu_quit",      &key_menu_quit);
-    M_BindVariable("key_menu_gamma",     &key_menu_gamma);
+    M_BindIntVariable("key_menu_help",      &key_menu_help);
+    M_BindIntVariable("key_menu_save",      &key_menu_save);
+    M_BindIntVariable("key_menu_load",      &key_menu_load);
+    M_BindIntVariable("key_menu_volume",    &key_menu_volume);
+    M_BindIntVariable("key_menu_detail",    &key_menu_detail);
+    M_BindIntVariable("key_menu_qsave",     &key_menu_qsave);
+    M_BindIntVariable("key_menu_endgame",   &key_menu_endgame);
+    M_BindIntVariable("key_menu_messages",  &key_menu_messages);
+    M_BindIntVariable("key_menu_qload",     &key_menu_qload);
+    M_BindIntVariable("key_menu_quit",      &key_menu_quit);
+    M_BindIntVariable("key_menu_gamma",     &key_menu_gamma);
 
-    M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
-    M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
-    M_BindVariable("key_menu_screenshot",&key_menu_screenshot);
-    M_BindVariable("key_demo_quit",      &key_demo_quit);
-    M_BindVariable("key_spy",            &key_spy);
+    M_BindIntVariable("key_menu_incscreen", &key_menu_incscreen);
+    M_BindIntVariable("key_menu_decscreen", &key_menu_decscreen);
+    M_BindIntVariable("key_menu_screenshot",&key_menu_screenshot);
+    M_BindIntVariable("key_demo_quit",      &key_demo_quit);
+    M_BindIntVariable("key_spy",            &key_spy);
 }
 
 void M_BindChatControls(unsigned int num_players)
@@ -378,12 +378,12 @@
     char name[32];  // haleyjd: 20 not large enough - Thank you, come again!
     unsigned int i; // haleyjd: signedness conflict
 
-    M_BindVariable("key_multi_msg",     &key_multi_msg);
+    M_BindIntVariable("key_multi_msg",     &key_multi_msg);
 
     for (i=0; i<num_players; ++i)
     {
         M_snprintf(name, sizeof(name), "key_multi_msgplayer%i", i + 1);
-        M_BindVariable(name, &key_multi_msgplayer[i]);
+        M_BindIntVariable(name, &key_multi_msgplayer[i]);
     }
 }
 
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -372,12 +372,20 @@
 
 boolean M_StringCopy(char *dest, const char *src, size_t dest_size)
 {
+    size_t len;
+
     if (dest_size >= 1)
     {
         dest[dest_size - 1] = '\0';
         strncpy(dest, src, dest_size - 1);
     }
-    return strlen(dest) == strlen(src);
+    else
+    {
+        return false;
+    }
+
+    len = strlen(dest);
+    return src[len] == '\0';
 }
 
 // Safe string concat function that works like OpenBSD's strlcat().
--- a/src/midifile.c
+++ b/src/midifile.c
@@ -130,7 +130,7 @@
 static boolean ReadVariableLength(unsigned int *result, FILE *stream)
 {
     int i;
-    byte b;
+    byte b = 0;
 
     *result = 0;
 
@@ -203,7 +203,7 @@
                                 byte event_type, boolean two_param,
                                 FILE *stream)
 {
-    byte b;
+    byte b = 0;
 
     // Set basics:
 
@@ -269,7 +269,7 @@
 
 static boolean ReadMetaEvent(midi_event_t *event, FILE *stream)
 {
-    byte b;
+    byte b = 0;
 
     event->event_type = MIDI_EVENT_META;
 
@@ -308,7 +308,7 @@
 static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type,
                          FILE *stream)
 {
-    byte event_type;
+    byte event_type = 0;
 
     if (!ReadVariableLength(&event->delta_time, stream))
     {
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -279,8 +279,8 @@
 
         // Advance the window
 
-        memcpy(recvwindow, recvwindow + 1, 
-               sizeof(net_server_recv_t) * (BACKUPTICS - 1));
+        memmove(recvwindow, recvwindow + 1,
+                sizeof(net_server_recv_t) * (BACKUPTICS - 1));
         memset(&recvwindow[BACKUPTICS-1], 0, sizeof(net_server_recv_t));
 
         ++recvwindow_start;
@@ -1102,5 +1102,5 @@
 
 void NET_BindVariables(void)
 {
-    M_BindVariable("player_name", &net_player_name);
+    M_BindStringVariable("player_name", &net_player_name);
 }
--- a/src/net_sdl.c
+++ b/src/net_sdl.c
@@ -302,15 +302,27 @@
 void NET_SDL_AddrToString(net_addr_t *addr, char *buffer, int buffer_len)
 {
     IPaddress *ip;
+    uint32_t host;
+    uint16_t port;
 
     ip = (IPaddress *) addr->handle;
-    
-    M_snprintf(buffer, buffer_len, 
-               "%i.%i.%i.%i",
-               ip->host & 0xff,
-               (ip->host >> 8) & 0xff,
-               (ip->host >> 16) & 0xff,
-               (ip->host >> 24) & 0xff);
+    host = SDLNet_Read32(&ip->host);
+    port = SDLNet_Read16(&ip->port);
+
+    M_snprintf(buffer, buffer_len, "%i.%i.%i.%i",
+               (host >> 24) & 0xff, (host >> 16) & 0xff,
+               (host >> 8) & 0xff, host & 0xff);
+
+    // If we are using the default port we just need to show the IP address,
+    // but otherwise we need to include the port. This is important because
+    // we use the string representation in the setup tool to provided an
+    // address to connect to.
+    if (port != DEFAULT_PORT)
+    {
+        char portbuf[10];
+        M_snprintf(portbuf, sizeof(portbuf), ":%i", port);
+        M_StringConcat(buffer, portbuf, buffer_len);
+    }
 }
 
 net_addr_t *NET_SDL_ResolveAddress(char *address)
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -514,7 +514,8 @@
         
         // Advance the window
 
-        memcpy(recvwindow, recvwindow + 1, sizeof(*recvwindow) * (BACKUPTICS - 1));
+        memmove(recvwindow, recvwindow + 1,
+                sizeof(*recvwindow) * (BACKUPTICS - 1));
         memset(&recvwindow[BACKUPTICS-1], 0, sizeof(*recvwindow));
         ++recvwindow_start;
 
--- a/src/net_structrw.c
+++ b/src/net_structrw.c
@@ -316,7 +316,7 @@
 
 void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest)
 {
-    memcpy(dest, src, sizeof(ticcmd_t));
+    memmove(dest, src, sizeof(ticcmd_t));
 
     // Apply the diff
 
--- a/src/resource.rc.in
+++ b/src/resource.rc.in
@@ -1,6 +1,6 @@
-1 ICON "../data/doom.ico"
+1 ICON "@top_srcdir@/data/doom.ico"
 
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@top_srcdir@/src/manifest.xml"
 
 1 VERSIONINFO
 PRODUCTVERSION @WINDOWS_RC_VERSION@
--- a/src/setup-res.rc.in
+++ b/src/setup-res.rc.in
@@ -1,6 +1,6 @@
-1 ICON "../data/setup.ico"
+1 ICON "@top_srcdir@/data/setup.ico"
 
-1 24 MOVEABLE PURE "setup/setup-manifest.xml"
+1 24 MOVEABLE PURE "@top_builddir@/src/setup/setup-manifest.xml"
 
 1 VERSIONINFO
 PRODUCTVERSION @WINDOWS_RC_VERSION@
--- a/src/setup/Makefile.am
+++ b/src/setup/Makefile.am
@@ -3,7 +3,7 @@
 
 AM_CFLAGS = @SDL_CFLAGS@                                           \
             @SDLMIXER_CFLAGS@                                      \
-            -I$(top_builddir)/textscreen -I..
+            -I$(top_srcdir)/textscreen -I$(top_srcdir)/src
 
 noinst_LIBRARIES = libsetup.a
 
--- a/src/setup/compatibility.c
+++ b/src/setup/compatibility.c
@@ -22,6 +22,8 @@
 
 #include "compatibility.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-compat"
+
 int vanilla_savegame_limit = 1;
 int vanilla_demo_limit = 1;
 
@@ -31,7 +33,9 @@
 
     window = TXT_NewWindow("Compatibility");
 
-    TXT_AddWidgets(window, 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
+    TXT_AddWidgets(window,
                    TXT_NewCheckBox("Vanilla savegame limit",
                                    &vanilla_savegame_limit),
                    TXT_NewCheckBox("Vanilla demo limit",
@@ -43,8 +47,8 @@
 {
     if (gamemission == doom || gamemission == strife)
     {
-        M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
-        M_BindVariable("vanilla_demo_limit",     &vanilla_demo_limit);
+        M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+        M_BindIntVariable("vanilla_demo_limit",     &vanilla_demo_limit);
     }
 }
 
--- a/src/setup/display.c
+++ b/src/setup/display.c
@@ -28,6 +28,8 @@
 #include "display.h"
 #include "config.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-display"
+
 extern void RestartTextscreen(void);
 
 typedef struct
@@ -331,6 +333,8 @@
 
     window = TXT_NewWindow("Advanced display options");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_SetColumnWidths(window, 35);
 
     TXT_AddWidgets(window,
@@ -383,6 +387,8 @@
 
     window = TXT_NewWindow("Display Configuration");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     // Some machines can have lots of video modes.  This tries to
     // keep a limit of six lines by increasing the number of
     // columns.  In extreme cases, the window is moved up slightly.
@@ -464,27 +470,26 @@
 
 void BindDisplayVariables(void)
 {
-    M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
-    M_BindVariable("aspect_ratio_correct",      &aspect_ratio_correct);
-    M_BindVariable("fullscreen",                &fullscreen);
-    M_BindVariable("screen_width",              &screen_width);
-    M_BindVariable("screen_height",             &screen_height);
-    M_BindVariable("startup_delay",             &startup_delay);
-    M_BindVariable("video_driver",              &video_driver);
-    M_BindVariable("window_position",           &window_position);
-    M_BindVariable("usegamma",                  &usegamma);
-    M_BindVariable("png_screenshots",           &png_screenshots);
+    M_BindIntVariable("autoadjust_video_settings", &autoadjust_video_settings);
+    M_BindIntVariable("aspect_ratio_correct",      &aspect_ratio_correct);
+    M_BindIntVariable("fullscreen",                &fullscreen);
+    M_BindIntVariable("screen_width",              &screen_width);
+    M_BindIntVariable("screen_height",             &screen_height);
+    M_BindIntVariable("startup_delay",             &startup_delay);
+    M_BindStringVariable("video_driver",           &video_driver);
+    M_BindStringVariable("window_position",        &window_position);
+    M_BindIntVariable("usegamma",                  &usegamma);
+    M_BindIntVariable("png_screenshots",           &png_screenshots);
 
-
     if (gamemission == doom || gamemission == heretic
      || gamemission == strife)
     {
-        M_BindVariable("show_endoom",               &show_endoom);
+        M_BindIntVariable("show_endoom",               &show_endoom);
     }
 
     if (gamemission == heretic || gamemission == hexen || gamemission == strife)
     {
-        M_BindVariable("graphical_startup",        &graphical_startup);
+        M_BindIntVariable("graphical_startup",        &graphical_startup);
     }
 
     // Disable fullscreen by default on OS X, as there is an SDL bug
--- a/src/setup/execute.c
+++ b/src/setup/execute.c
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #include <sys/types.h>
 
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -14,6 +14,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "doomtype.h"
 #include "i_joystick.h"
@@ -28,6 +29,8 @@
 #include "txt_joyaxis.h"
 #include "txt_joybinput.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-gamepad"
+
 typedef struct
 {
     char *name;  // Config file name
@@ -136,6 +139,7 @@
     {"joyb_straferight",       -1},
     {"joyb_prevweapon",        -1},
     {"joyb_nextweapon",        -1},
+    {"joyb_jump",              -1},
     {"joyb_menu_activate",     -1},
     {NULL, 0},
 };
@@ -292,6 +296,24 @@
     {NULL, 0},
 };
 
+// Config for if the user is actually using an old PC joystick or gamepad,
+// probably via a USB-Gameport adapter.
+static const joystick_config_t pc_gameport_controller[] =
+{
+    {"joystick_x_axis",        0},
+    {"joystick_y_axis",        1},
+    // Button configuration is the default as used for Vanilla Doom,
+    // Heretic and Hexen. When playing with a Gravis Gamepad, this
+    // layout should also be vaguely similar to the standard layout
+    // described above.
+    {"joyb_fire",              0},
+    {"joyb_strafe",            1},
+    {"joyb_use",               3},
+    {"joyb_speed",             2},
+    {NULL, 0},
+};
+
+
 static const known_joystick_t known_joysticks[] =
 {
     {
@@ -331,7 +353,14 @@
         xbox360_controller_linux,
     },
 
+    // Xbox One controller as it appears on Linux.
     {
+        "Microsoft X-Box One pad",
+        6, 11, 1,
+        xbox360_controller_linux,
+    },
+
+    {
         "Logitech Dual Action",
         4, 12, 1,
         logitech_f310_controller,
@@ -357,6 +386,25 @@
         6, 14, 1,
         ps4_ds4_controller,
     },
+
+    // This is the configuration for the USB-Gameport adapter listed on
+    // this page as the "Mayflash USB to Gameport Adapter" (though the
+    // device is labeled as "Super Joy Box 7"):
+    // https://sites.google.com/site/joystickrehab/itemcatal
+    // TODO: Add extra configurations here for other USB-Gameport adapters,
+    // which should just be the same configuration.
+    {
+        "WiseGroup.,Ltd Gameport to USB Controller",
+        4, 8, 1,
+        pc_gameport_controller,
+    },
+
+    // How the Super Joy Box 7 appears on Mac OS X.
+    {
+        "Gameport to USB Controller",
+        2, 8, 1,
+        pc_gameport_controller,
+    },
 };
 
 static const known_joystick_t *GetJoystickType(int index)
@@ -520,7 +568,7 @@
 
     result = 0;
 
-    for (i=0; i<num_joysticks; ++i) 
+    for (i = 0; i < num_joysticks; ++i)
     {
         all_joysticks[i] = SDL_JoystickOpen(i);
 
@@ -556,7 +604,7 @@
 
     num_joysticks = SDL_NumJoysticks();
 
-    for (i=0; i<num_joysticks; ++i)
+    for (i = 0; i < num_joysticks; ++i)
     {
         if (all_joysticks[i] != NULL)
         {
@@ -587,6 +635,7 @@
     // At this point, we have a button press.
     // In the first "center" stage, we're just trying to work out which
     // joystick is being configured and which button the user is pressing.
+    usejoystick = 1;
     joystick_index = event->jbutton.which;
     calibrate_button = event->jbutton.button;
 
@@ -595,7 +644,6 @@
     if (IsKnownJoystick(joystick_index))
     {
         LoadKnownConfiguration();
-        usejoystick = 1;
         TXT_CloseWindow(calibration_window);
     }
     else
@@ -613,11 +661,12 @@
 
 static void NoJoystick(void)
 {
-    TXT_MessageBox(NULL, "No joysticks or gamepads could be found.\n\n"
+    TXT_MessageBox(NULL, "No gamepads or joysticks could be found.\n\n"
                          "Try configuring your controller from within\n"
                          "your OS first. Maybe you need to install\n"
                          "some drivers or otherwise configure it.");
 
+    usejoystick = 0;
     joystick_index = -1;
     SetJoystickButtonLabel();
 }
@@ -659,7 +708,7 @@
     TXT_SignalConnect(calibration_window, "closed", CalibrateWindowClosed, NULL);
 
     // Start calibration
-
+    usejoystick = 0;
     joystick_index = -1;
 }
 
@@ -685,8 +734,9 @@
 
     window = TXT_NewWindow("Gamepad/Joystick configuration");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_AddWidgets(window,
-                   TXT_NewCheckBox("Enable gamepad/joystick", &usejoystick),
                    joystick_table = TXT_NewTable(2),
                    TXT_NewSeparator("Axes"),
                    axis_table = TXT_NewTable(2),
@@ -694,6 +744,13 @@
                    button_table = TXT_NewTable(4),
                    NULL);
 
+    TXT_SetColumnWidths(joystick_table, 13, 40);
+
+    TXT_AddWidgets(joystick_table,
+                   TXT_NewLabel("Controller"),
+                   joystick_button = TXT_NewButton("zzzz"),
+                   NULL);
+
     TXT_SetColumnWidths(axis_table, 20, 15);
 
     TXT_AddWidgets(axis_table,
@@ -711,13 +768,6 @@
                                         JOYSTICK_AXIS_HORIZONTAL),
                    NULL);
 
-    TXT_SetColumnWidths(joystick_table, 20, 15);
-
-    TXT_AddWidgets(joystick_table,
-                   TXT_NewLabel("Current controller"),
-                   joystick_button = TXT_NewButton("zzzz"),
-                   NULL);
-
     TXT_SetColumnWidths(button_table, 16, 12, 14, 11);
 
     AddJoystickControl(button_table, "Fire/Attack", &joybfire);
@@ -757,20 +807,20 @@
 {
     int i;
 
-    M_BindVariable("use_joystick",          &usejoystick);
-    M_BindVariable("joystick_index",        &joystick_index);
-    M_BindVariable("joystick_x_axis",       &joystick_x_axis);
-    M_BindVariable("joystick_y_axis",       &joystick_y_axis);
-    M_BindVariable("joystick_strafe_axis",  &joystick_strafe_axis);
-    M_BindVariable("joystick_x_invert",     &joystick_x_invert);
-    M_BindVariable("joystick_y_invert",     &joystick_y_invert);
-    M_BindVariable("joystick_strafe_invert",&joystick_strafe_invert);
+    M_BindIntVariable("use_joystick",           &usejoystick);
+    M_BindIntVariable("joystick_index",         &joystick_index);
+    M_BindIntVariable("joystick_x_axis",        &joystick_x_axis);
+    M_BindIntVariable("joystick_y_axis",        &joystick_y_axis);
+    M_BindIntVariable("joystick_strafe_axis",   &joystick_strafe_axis);
+    M_BindIntVariable("joystick_x_invert",      &joystick_x_invert);
+    M_BindIntVariable("joystick_y_invert",      &joystick_y_invert);
+    M_BindIntVariable("joystick_strafe_invert", &joystick_strafe_invert);
 
     for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
     {
         char name[32];
         M_snprintf(name, sizeof(name), "joystick_physical_button%i", i);
-        M_BindVariable(name, &joystick_physical_buttons[i]);
+        M_BindIntVariable(name, &joystick_physical_buttons[i]);
     }
 }
 
--- a/src/setup/keyboard.c
+++ b/src/setup/keyboard.c
@@ -25,6 +25,8 @@
 #include "joystick.h"
 #include "keyboard.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-keyboard"
+
 int vanilla_keyboard_mapping = 1;
 
 static int always_run = 0;
@@ -181,6 +183,8 @@
 
     window = TXT_NewWindow("Extra keyboard controls");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     table = TXT_NewTable(2);
 
     TXT_SetColumnWidths(table, 21, 9);
@@ -270,6 +274,8 @@
 
     window = TXT_NewWindow("Other keys");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     table = TXT_NewTable(2);
 
     TXT_SetColumnWidths(table, 25, 9);
@@ -356,6 +362,8 @@
 
     window = TXT_NewWindow("Keyboard configuration");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_AddWidgets(window,
                    TXT_NewSeparator("Movement"),
                    movement_table = TXT_NewTable(4),
@@ -408,5 +416,5 @@
 
 void BindKeyboardVariables(void)
 {
-    M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
+    M_BindIntVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
 }
--- a/src/setup/mainmenu.c
+++ b/src/setup/mainmenu.c
@@ -38,6 +38,8 @@
 #include "multiplayer.h"
 #include "sound.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup"
+
 static const int cheat_sequence[] =
 {
     KEY_UPARROW, KEY_UPARROW, KEY_DOWNARROW, KEY_DOWNARROW,
@@ -209,6 +211,8 @@
 
     window = TXT_NewWindow("Main Menu");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_AddWidgets(window,
           TXT_NewButton2("Configure Display",
                          (TxtWidgetSignalFunc) ConfigDisplay, NULL),
@@ -247,7 +251,7 @@
           NULL);
 
     quit_action = TXT_NewWindowAction(KEY_ESCAPE, "Quit");
-    warp_action = TXT_NewWindowAction(KEY_F1, "Warp");
+    warp_action = TXT_NewWindowAction(KEY_F2, "Warp");
     TXT_SignalConnect(quit_action, "pressed", QuitConfirm, NULL);
     TXT_SignalConnect(warp_action, "pressed",
                       (TxtWidgetSignalFunc) WarpMenu, NULL);
--- a/src/setup/mode.c
+++ b/src/setup/mode.c
@@ -115,14 +115,14 @@
 {
     if (gamemission == doom)
     {
-        M_BindVariable("detaillevel",       &detailLevel);
-        M_BindVariable("show_messages",     &showMessages);
+        M_BindIntVariable("detaillevel",   &detailLevel);
+        M_BindIntVariable("show_messages", &showMessages);
     }
 
     if (gamemission == hexen)
     {
-        M_BindVariable("savedir",           &savedir);
-        M_BindVariable("messageson",        &showMessages);
+        M_BindStringVariable("savedir", &savedir);
+        M_BindIntVariable("messageson", &showMessages);
 
         // Hexen has a variable to control the savegame directory
         // that is used.
@@ -140,14 +140,15 @@
 
     if (gamemission == strife)
     {
-        M_BindVariable("back_flat",         &back_flat);
-        M_BindVariable("screensize"  ,      &screenblocks);
-        M_BindVariable("comport",           &comport);
-        M_BindVariable("nickname",          &nickname);
+        M_BindStringVariable("back_flat",   &back_flat);
+        M_BindStringVariable("nickname",    &nickname);
+
+        M_BindIntVariable("screensize",     &screenblocks);
+        M_BindIntVariable("comport",        &comport);
     }
     else
     {
-        M_BindVariable("screenblocks",      &screenblocks);
+        M_BindIntVariable("screenblocks",   &screenblocks);
     }
 
 }
--- a/src/setup/mouse.c
+++ b/src/setup/mouse.c
@@ -25,6 +25,8 @@
 #include "mode.h"
 #include "mouse.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-mouse"
+
 static int usemouse = 1;
 
 static int mouseSensitivity = 5;
@@ -84,6 +86,8 @@
 
     window = TXT_NewWindow("Additional mouse buttons");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_AddWidgets(window,
                    buttons_table = TXT_NewTable(2),
                    NULL);
@@ -112,6 +116,8 @@
 
     window = TXT_NewWindow("Mouse configuration");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_AddWidgets(window,
                    TXT_NewCheckBox("Enable mouse", &usemouse),
                    TXT_NewInvertedCheckBox("Allow vertical mouse movement", 
@@ -153,10 +159,10 @@
 
 void BindMouseVariables(void)
 {
-    M_BindVariable("use_mouse",            &usemouse);
-    M_BindVariable("novert",               &novert);
-    M_BindVariable("mouse_sensitivity",    &mouseSensitivity);
-    M_BindVariable("mouse_acceleration",   &mouse_acceleration);
-    M_BindVariable("mouse_threshold",      &mouse_threshold);
-    M_BindVariable("grabmouse",            &grabmouse);
+    M_BindIntVariable("use_mouse",               &usemouse);
+    M_BindIntVariable("novert",                  &novert);
+    M_BindIntVariable("grabmouse",               &grabmouse);
+    M_BindIntVariable("mouse_sensitivity",       &mouseSensitivity);
+    M_BindIntVariable("mouse_threshold",         &mouse_threshold);
+    M_BindFloatVariable("mouse_acceleration",    &mouse_acceleration);
 }
--- a/src/setup/multiplayer.c
+++ b/src/setup/multiplayer.c
@@ -34,6 +34,10 @@
 #include "net_io.h"
 #include "net_query.h"
 
+#define MULTI_START_HELP_URL "http://www.chocolate-doom.org/setup-multi-start"
+#define MULTI_JOIN_HELP_URL "http://www.chocolate-doom.org/setup-multi-join"
+#define MULTI_CONFIG_HELP_URL "http://www.chocolate-doom.org/setup-multi-config"
+
 #define NUM_WADS 10
 #define NUM_EXTRA_PARAMS 10
 
@@ -355,7 +359,7 @@
 {
     int l;
 
-    l = (int) val;
+    l = (intptr_t) val;
 
     warpepisode = l / 10;
     warpmap = l % 10;
@@ -367,7 +371,7 @@
 {
     int l;
 
-    l = (int) val;
+    l = (intptr_t) val;
 
     warpmap = l;
 
@@ -389,8 +393,8 @@
     const iwad_t *iwad;
     char buf[10];
     int episodes;
-    int x, y;
-    int l;
+    intptr_t x, y;
+    intptr_t l;
     int i;
 
     window = TXT_NewWindow("Select level");
@@ -711,6 +715,7 @@
     txt_widget_t *iwad_selector;
 
     window = TXT_NewWindow(window_title);
+    TXT_SetWindowHelpURL(window, MULTI_START_HELP_URL);
 
     TXT_AddWidgets(window, 
                    gameopt_table = TXT_NewTable(2),
@@ -957,7 +962,7 @@
                   TXT_NewScrollPane(70, 10,
                                     results_table = TXT_NewTable(3)));
 
-    TXT_SetColumnWidths(results_table, 7, 16, 46);
+    TXT_SetColumnWidths(results_table, 7, 22, 40);
     TXT_SetPeriodicCallback(QueryPeriodicCallback, results_table, 1);
 
     TXT_SignalConnect(query_window, "closed", QueryWindowClosed, NULL);
@@ -985,6 +990,7 @@
     txt_inputbox_t *address_box;
 
     window = TXT_NewWindow("Join multiplayer game");
+    TXT_SetWindowHelpURL(window, MULTI_JOIN_HELP_URL);
 
     TXT_AddWidgets(window, 
         gameopt_table = TXT_NewTable(2),
@@ -1093,6 +1099,7 @@
     int i;
 
     window = TXT_NewWindow("Multiplayer Configuration");
+    TXT_SetWindowHelpURL(window, MULTI_CONFIG_HELP_URL);
 
     TXT_AddWidgets(window, 
                    TXT_NewStrut(0, 1),
@@ -1127,13 +1134,13 @@
     int i;
 
 #ifdef FEATURE_MULTIPLAYER
-    M_BindVariable("player_name", &net_player_name);
+    M_BindStringVariable("player_name", &net_player_name);
 #endif
 
     for (i=0; i<10; ++i)
     {
         M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
-        M_BindVariable(buf, &chat_macros[i]);
+        M_BindStringVariable(buf, &chat_macros[i]);
     }
 
     switch (gamemission)
--- a/src/setup/sound.c
+++ b/src/setup/sound.c
@@ -25,6 +25,8 @@
 #include "mode.h"
 #include "sound.h"
 
+#define WINDOW_HELP_URL "http://www.chocolate-doom.org/setup-sound"
+
 typedef enum
 {
     SFXMODE_DISABLED,
@@ -57,6 +59,12 @@
     "Native MIDI",
 };
 
+static char *opltype_strings[] =
+{
+    "OPL2",
+    "OPL3"
+};
+
 static char *cfg_extension[] = { "cfg", NULL };
 
 // Config file variables:
@@ -79,7 +87,8 @@
 
 static char *timidity_cfg_path = NULL;
 static char *gus_patch_path = NULL;
-static unsigned int gus_ram_kb = 1024;
+static int gus_ram_kb = 1024;
+static int opl_type = 0;
 
 // DOS specific variables: these are unused but should be maintained
 // so that the config file can be shared between chocolate
@@ -132,29 +141,36 @@
 {
     TXT_CAST_ARG(txt_table_t, extra_table);
 
-    // Rebuild the GUS table. Start by emptying it, then only add the
-    // GUS control widget if we are in GUS music mode.
-
-    TXT_ClearTable(extra_table);
-
-    if (snd_musicmode == MUSICMODE_GUS)
+    switch (snd_musicmode)
     {
+    case MUSICMODE_OPL:
+        TXT_InitTable(extra_table, 2);
+        TXT_SetColumnWidths(extra_table, 19, 4);
         TXT_AddWidgets(extra_table,
-                       TXT_NewLabel("GUS patch path:"),
-                       TXT_NewFileSelector(&gus_patch_path, 30,
-                                           "Select path to GUS patches",
-                                           TXT_DIRECTORY),
-                       NULL);
-    }
+                        TXT_NewLabel("OPL type"),
+                        TXT_NewDropdownList(&opl_type, opltype_strings, 2),
+                        NULL);
+        break;
 
-    if (snd_musicmode == MUSICMODE_NATIVE)
-    {
+    case MUSICMODE_GUS:
+        TXT_InitTable(extra_table, 1);
         TXT_AddWidgets(extra_table,
-                       TXT_NewLabel("Timidity configuration file:"),
-                       TXT_NewFileSelector(&timidity_cfg_path, 30,
-                                           "Select Timidity config file",
-                                           cfg_extension),
-                       NULL);
+                        TXT_NewLabel("GUS patch path:"),
+                        TXT_NewFileSelector(&gus_patch_path, 30,
+                                            "Select path to GUS patches",
+                                            TXT_DIRECTORY),
+                        NULL);
+        break;
+
+    case MUSICMODE_NATIVE:
+        TXT_InitTable(extra_table, 1);
+        TXT_AddWidgets(extra_table,
+                        TXT_NewLabel("Timidity configuration file:"),
+                        TXT_NewFileSelector(&timidity_cfg_path, 30,
+                                            "Select Timidity config file",
+                                            cfg_extension),
+                        NULL);
+        break;
     }
 }
 
@@ -218,6 +234,8 @@
 
     window = TXT_NewWindow("Sound configuration");
 
+    TXT_SetWindowHelpURL(window, WINDOW_HELP_URL);
+
     TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP,
                                   TXT_SCREEN_W / 2, 5);
 
@@ -278,32 +296,35 @@
 
 void BindSoundVariables(void)
 {
-    M_BindVariable("snd_sfxdevice",       &snd_sfxdevice);
-    M_BindVariable("snd_musicdevice",     &snd_musicdevice);
-    M_BindVariable("snd_channels",        &numChannels);
-    M_BindVariable("sfx_volume",          &sfxVolume);
-    M_BindVariable("music_volume",        &musicVolume);
-    M_BindVariable("snd_samplerate",      &snd_samplerate);
-    M_BindVariable("use_libsamplerate",   &use_libsamplerate);
-    M_BindVariable("libsamplerate_scale", &libsamplerate_scale);
-    M_BindVariable("timidity_cfg_path",   &timidity_cfg_path);
-    M_BindVariable("gus_patch_path",      &gus_patch_path);
-    M_BindVariable("gus_ram_kb",          &gus_ram_kb);
+    M_BindIntVariable("snd_sfxdevice",            &snd_sfxdevice);
+    M_BindIntVariable("snd_musicdevice",          &snd_musicdevice);
+    M_BindIntVariable("snd_channels",             &numChannels);
+    M_BindIntVariable("snd_samplerate",           &snd_samplerate);
+    M_BindIntVariable("sfx_volume",               &sfxVolume);
+    M_BindIntVariable("music_volume",             &musicVolume);
 
-    M_BindVariable("snd_sbport",          &snd_sbport);
-    M_BindVariable("snd_sbirq",           &snd_sbirq);
-    M_BindVariable("snd_sbdma",           &snd_sbdma);
-    M_BindVariable("snd_mport",           &snd_mport);
-    M_BindVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms);
-    M_BindVariable("snd_musiccmd",        &snd_musiccmd);
+    M_BindIntVariable("use_libsamplerate",        &use_libsamplerate);
+    M_BindFloatVariable("libsamplerate_scale",    &libsamplerate_scale);
 
-    M_BindVariable("snd_cachesize",       &snd_cachesize);
-    M_BindVariable("opl_io_port",         &opl_io_port);
+    M_BindIntVariable("gus_ram_kb",               &gus_ram_kb);
+    M_BindStringVariable("gus_patch_path",        &gus_patch_path);
+    M_BindStringVariable("timidity_cfg_path",     &timidity_cfg_path);
 
+    M_BindIntVariable("snd_sbport",               &snd_sbport);
+    M_BindIntVariable("snd_sbirq",                &snd_sbirq);
+    M_BindIntVariable("snd_sbdma",                &snd_sbdma);
+    M_BindIntVariable("snd_mport",                &snd_mport);
+    M_BindIntVariable("snd_maxslicetime_ms",      &snd_maxslicetime_ms);
+    M_BindStringVariable("snd_musiccmd",          &snd_musiccmd);
+
+    M_BindIntVariable("snd_cachesize",            &snd_cachesize);
+    M_BindIntVariable("opl_io_port",              &opl_io_port);
+    M_BindIntVariable("opl_type",                 &opl_type);
+
     if (gamemission == strife)
     {
-        M_BindVariable("voice_volume",    &voiceVolume);
-        M_BindVariable("show_talk",       &show_talk);
+        M_BindIntVariable("voice_volume",         &voiceVolume);
+        M_BindIntVariable("show_talk",            &show_talk);
     }
 
     timidity_cfg_path = M_StringDuplicate("");
--- a/src/setup/txt_joyaxis.c
+++ b/src/setup/txt_joyaxis.c
@@ -63,6 +63,8 @@
                        "right, and press the button.";
             }
     }
+
+    return NULL;
 }
 
 static void SetCalibrationLabel(txt_joystick_axis_t *joystick_axis)
@@ -265,6 +267,8 @@
         case CONFIG_STAGE2:
             return CONFIG_CENTER;
     }
+
+    return -1;
 }
 
 static int EventCallback(SDL_Event *event, TXT_UNCAST_ARG(joystick_axis))
--- a/src/sha1.c
+++ b/src/sha1.c
@@ -7,7 +7,7 @@
  *
  * GnuPG 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 3 of the License, or
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -16,7 +16,9 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 
--- a/src/strife.desktop.in
+++ b/src/strife.desktop.in
@@ -5,3 +5,4 @@
 Type=Application
 Comment=@PACKAGE_SHORTDESC@
 Categories=Game;ActionGame;
+Keywords=first;person;shooter;doom;vanilla;
--- a/src/strife/Makefile.am
+++ b/src/strife/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS = -I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+AM_CFLAGS = -I$(top_srcdir)/src @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
 
 noinst_LIBRARIES=libstrife.a
 
--- a/src/strife/d_englsh.h
+++ b/src/strife/d_englsh.h
@@ -173,7 +173,7 @@
 #define HUSTR_26        "AREA 26: proving grounds"
 #define HUSTR_27        "AREA 27: The Lab"
 #define HUSTR_28        "AREA 28: Alien Ship"
-#define HUSTR_29        "AREA 29: Entity"
+#define HUSTR_29        "AREA 29: Entity's Lair"
 
 #define HUSTR_30        "AREA 30: Abandoned Front Base"
 #define HUSTR_31        "AREA 31: Training Facility"
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -431,22 +431,23 @@
     // * screenblocks -> screensize
     // * Added nickname, comport
 
-    M_BindVariable("mouse_sensitivity",      &mouseSensitivity);
-    M_BindVariable("sfx_volume",             &sfxVolume);
-    M_BindVariable("music_volume",           &musicVolume);
-    M_BindVariable("voice_volume",           &voiceVolume); 
-    M_BindVariable("show_talk",              &dialogshowtext);
-    M_BindVariable("screensize",             &screenblocks);
-    M_BindVariable("snd_channels",           &snd_channels);
-    M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
-    M_BindVariable("vanilla_demo_limit",     &vanilla_demo_limit);
-    M_BindVariable("show_endoom",            &show_endoom);
-    M_BindVariable("back_flat",              &back_flat);
-    M_BindVariable("graphical_startup",      &graphical_startup);
+    M_BindIntVariable("mouse_sensitivity",      &mouseSensitivity);
+    M_BindIntVariable("sfx_volume",             &sfxVolume);
+    M_BindIntVariable("music_volume",           &musicVolume);
+    M_BindIntVariable("voice_volume",           &voiceVolume); 
+    M_BindIntVariable("show_talk",              &dialogshowtext);
+    M_BindIntVariable("screensize",             &screenblocks);
+    M_BindIntVariable("snd_channels",           &snd_channels);
+    M_BindIntVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+    M_BindIntVariable("vanilla_demo_limit",     &vanilla_demo_limit);
+    M_BindIntVariable("show_endoom",            &show_endoom);
+    M_BindIntVariable("graphical_startup",      &graphical_startup);
 
-    M_BindVariable("nickname",               &nickname);
-    M_BindVariable("comport",                &comport);
+    M_BindStringVariable("back_flat",           &back_flat);
+    M_BindStringVariable("nickname",            &nickname);
 
+    M_BindIntVariable("comport",                &comport);
+
     // Multiplayer chat macros
 
     for (i=0; i<10; ++i)
@@ -454,7 +455,7 @@
         char buf[12];
 
         M_snprintf(buf, sizeof(buf), "chatmacro%i", i);
-        M_BindVariable(buf, &chat_macros[i]);
+        M_BindStringVariable(buf, &chat_macros[i]);
     }
 }
 
@@ -1284,6 +1285,11 @@
 //
 //=============================================================================
 
+static void G_CheckDemoStatusAtExit (void)
+{
+    G_CheckDemoStatus();
+}
+
 //
 // D_DoomMain
 //
@@ -1605,9 +1611,12 @@
 
     if (p)
     {
+        char *uc_filename = strdup(myargv[p + 1]);
+        M_ForceUppercase(uc_filename);
+
         // With Vanilla you have to specify the file without extension,
         // but make that optional.
-        if (M_StringEndsWith(myargv[p + 1], ".lmp"))
+        if (M_StringEndsWith(uc_filename, ".LMP"))
         {
             M_StringCopy(file, myargv[p + 1], sizeof(file));
         }
@@ -1616,6 +1625,8 @@
             DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]);
         }
 
+        free(uc_filename);
+
         if (D_AddFile (file))
         {
             M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
@@ -1633,7 +1644,7 @@
         printf("Playing demo %s.\n", file);
     }
 
-    I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+    I_AtExit(G_CheckDemoStatusAtExit, true);
 
     // Generate the WAD hash table.  Speed things up a bit.
 
--- a/src/strife/f_finale.c
+++ b/src/strife/f_finale.c
@@ -934,11 +934,11 @@
 {
     signed int  scrolled;
     int         x;
-    patch_t*    p1;
-    patch_t*    p2;
+//    patch_t*    p1;
+//    patch_t*    p2;
 
-    p1 = W_CacheLumpName (DEH_String("credit"),  PU_LEVEL);
-    p2 = W_CacheLumpName (DEH_String("vellogo"), PU_LEVEL);
+//    p1 = W_CacheLumpName (DEH_String("credit"),  PU_LEVEL);
+//    p2 = W_CacheLumpName (DEH_String("vellogo"), PU_LEVEL);
 
     V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
 
--- a/src/strife/g_game.c
+++ b/src/strife/g_game.c
@@ -289,7 +289,7 @@
 static int G_NextWeapon(int direction)
 {
     weapontype_t weapon;
-    int i;
+    int start_i, i;
 
     // Find index in the table.
 
@@ -311,12 +311,12 @@
     }
 
     // Switch weapon.
-
+    start_i = i;
     do
     {
         i += direction;
         i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
-    } while (!WeaponSelectable(weapon_order_table[i].weapon));
+    } while (i != start_i && !WeaponSelectable(weapon_order_table[i].weapon));
 
     return weapon_order_table[i].weapon_num;
 }
@@ -511,12 +511,11 @@
     // next_weapon variable is set to change weapons when
     // we generate a ticcmd.  Choose a new weapon.
 
-    if (next_weapon != 0)
+    if (gamestate == GS_LEVEL && next_weapon != 0)
     {
         i = G_NextWeapon(next_weapon);
         cmd->buttons |= BT_CHANGE;
         cmd->buttons |= i << BT_WEAPONSHIFT;
-        next_weapon = 0;
     }
     else
     {
@@ -535,6 +534,8 @@
         }
     }
 
+    next_weapon = 0;
+
     // mouse
     if (mousebuttons[mousebforward]) 
     {
@@ -983,7 +984,6 @@
                 && turbodetected[i])
             {
                 static char turbomessage[80];
-                extern char player_names[8][16];
                 M_snprintf(turbomessage, sizeof(turbomessage),
                            "%s is turbo!", player_names[i]);
                 players[consoleplayer].message = turbomessage;
--- a/src/strife/p_dialog.c
+++ b/src/strife/p_dialog.c
@@ -762,6 +762,7 @@
     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))
--- a/src/strife/p_enemy.c
+++ b/src/strife/p_enemy.c
@@ -891,7 +891,7 @@
     // as a parameter to control allaround look behavior. Did they just run out of
     // flags, or what? 
     // STRIFE-TODO: Needs serious verification.
-    if (!P_LookForPlayers (actor, actor->flags & MF_GIVEQUEST) )
+    if (!P_LookForPlayers(actor, (actor->flags & MF_GIVEQUEST) != 0))
         return;
 
     // go into chase state
@@ -975,7 +975,7 @@
             gamemap != 3 && gamemap != 34)
         {
             // STRIFE-TODO: Needs serious verification.
-            if(P_LookForPlayers(actor, actor->flags & MF_GIVEQUEST))
+            if(P_LookForPlayers(actor, (actor->flags & MF_GIVEQUEST) != 0))
             {
                 P_SetMobjState(actor, actor->info->seestate);
                 actor->flags |= MF_NODIALOG;
--- a/src/strife/p_inter.c
+++ b/src/strife/p_inter.c
@@ -537,7 +537,7 @@
 
     // rifle
     case SPR_RIFL:
-        if(!P_GiveWeapon(player, wp_rifle, special->flags & MF_DROPPED))
+        if(!P_GiveWeapon(player, wp_rifle, (special->flags & MF_DROPPED) != 0))
             return;
         sound = sfx_wpnup; // haleyjd: SHK-CHK!
         break;
@@ -560,7 +560,8 @@
 
     // grenade launcher
     case SPR_GRND:
-        if(!P_GiveWeapon(player, wp_hegrenade, special->flags & MF_DROPPED))
+        if(!P_GiveWeapon(player, wp_hegrenade,
+                         (special->flags & MF_DROPPED) != 0))
             return;
         sound = sfx_wpnup; // haleyjd: SHK-CHK!
         break;
@@ -574,7 +575,8 @@
 
     // electric bolt crossbow
     case SPR_CBOW:
-        if(!P_GiveWeapon(player, wp_elecbow, special->flags & MF_DROPPED))
+        if(!P_GiveWeapon(player, wp_elecbow,
+                         (special->flags & MF_DROPPED) != 0))
             return;
         sound = sfx_wpnup; // haleyjd: SHK-CHK!
         break;
@@ -581,7 +583,7 @@
 
     // haleyjd 09/21/10: missed case: THE SIGIL!
     case SPR_SIGL:
-        if(!P_GiveWeapon(player, wp_sigil, special->flags & MF_DROPPED))
+        if(!P_GiveWeapon(player, wp_sigil, (special->flags & MF_DROPPED) != 0))
         {
             player->sigiltype = special->frame;
             return;
--- a/src/strife/p_map.c
+++ b/src/strife/p_map.c
@@ -384,7 +384,7 @@
     // check for special pickup
     if (thing->flags & MF_SPECIAL)
     {
-        solid = thing->flags&MF_SOLID;
+        solid = (thing->flags & MF_SOLID) != 0;
         if (tmthing->player) // villsa [STRIFE] no longer checks MF_PICKUP flag
         {
             // can remove thing
--- a/src/strife/p_maputl.c
+++ b/src/strife/p_maputl.c
@@ -941,7 +941,7 @@
 
     int     count;
 
-    earlyout = flags & PT_EARLYOUT;
+    earlyout = (flags & PT_EARLYOUT) != 0;
 
     validcount++;
     intercept_p = intercepts;
--- a/src/strife/p_saveg.c
+++ b/src/strife/p_saveg.c
@@ -186,12 +186,12 @@
 
 static void *saveg_readp(void)
 {
-    return (void *) saveg_read32();
+    return (void *) (intptr_t) saveg_read32();
 }
 
 static void saveg_writep(void *p)
 {
-    saveg_write32((int) p);
+    saveg_write32((intptr_t) p);
 }
 
 // Enum values are 32-bit integers.
--- a/src/strife/p_setup.c
+++ b/src/strife/p_setup.c
@@ -324,7 +324,7 @@
     mapthing_t         *mt;
     mapthing_t          spawnthing;
     int			numthings;
-    boolean		spawn;
+//    boolean		spawn;
 
     data = W_CacheLumpNum (lump,PU_STATIC);
     numthings = W_LumpLength (lump) / sizeof(mapthing_t);
@@ -332,7 +332,7 @@
     mt = (mapthing_t *)data;
     for (i=0 ; i<numthings ; i++, mt++)
     {
-        spawn = true;
+//        spawn = true;
 
         // Do not spawn cool, new monsters if !commercial
         // STRIFE-TODO: replace with isregistered stuff
@@ -784,6 +784,9 @@
 
     // UNUSED W_Profile ();
     P_InitThinkers ();
+
+    // if working with a devlopment map, reload it
+    W_Reload();
 
     // [STRIFE] Removed ExMy map support
     if (map<10)
--- a/src/strife/p_tick.c
+++ b/src/strife/p_tick.c
@@ -99,7 +99,7 @@
 //
 void P_RunThinkers (void)
 {
-    thinker_t*  currentthinker;
+    thinker_t *currentthinker, *nextthinker;
 
     currentthinker = thinkercap.next;
     while (currentthinker != &thinkercap)
@@ -107,6 +107,7 @@
         if ( currentthinker->function.acv == (actionf_v)(-1) )
         {
             // time to remove it
+            nextthinker = currentthinker->next;
             currentthinker->next->prev = currentthinker->prev;
             currentthinker->prev->next = currentthinker->next;
             Z_Free (currentthinker);
@@ -115,8 +116,10 @@
         {
             if (currentthinker->function.acp1)
                 currentthinker->function.acp1 (currentthinker);
+            nextthinker = currentthinker->next;
         }
-        currentthinker = currentthinker->next;
+
+        currentthinker = nextthinker;
     }
 }
 
--- a/src/strife/r_things.c
+++ b/src/strife/r_things.c
@@ -445,8 +445,18 @@
             dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
         }
     }
-    else if (translation)     // villsa [STRIFE] new translation tables
+    else if(vis->mobjflags & MF_MVIS)
     {
+        // haleyjd 20141215: [STRIFE] Objects which are *only* MF_MVIS (players
+        // using double Shadow Armors, in particular) are totally invisible. 
+        // Upstreamed after discovered in SVE. Note this causes a 
+        // vanilla-accurate glitch with Shadow Acolytes - if they die while
+        // MF_MVIS is set, A_Fall fails to remove it and their corpse will
+        // completely disappear (that's also fixed in SVE, but not here).
+        return;
+    }
+    else if(translation)     // villsa [STRIFE] new translation tables
+    {
         colfunc = transcolfunc;
         dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
     }
@@ -460,7 +470,7 @@
     // villsa [STRIFE] clip sprite's feet if needed
     if(vis->mobjflags & MF_FEETCLIPPED)
     {
-        sprbotscreen = sprtopscreen + FixedMul(spryscale, patch->height << FRACBITS);
+        sprbotscreen = sprtopscreen + FixedMul(spryscale, SHORT(patch->height) << FRACBITS);
         clip = (sprbotscreen - FixedMul(10*FRACUNIT, spryscale)) >> FRACBITS;
     }
     else
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -137,6 +137,7 @@
 {  
     int i;
 
+    I_SetOPLDriverVer(opl_v_new);
     I_PrecacheSounds(S_sfx, NUMSFX);
 
     S_SetSfxVolume(sfxVolume);
@@ -277,7 +278,7 @@
     channel_t*        c;
 
     // Find an open channel
-     for (cnum=0 ; cnum<snd_channels ; cnum++)
+    for (cnum=0 ; cnum<snd_channels ; cnum++)
     {
         if (!channels[cnum].sfxinfo)
         {
@@ -286,6 +287,11 @@
         else if (origin && channels[cnum].origin == origin &&
                  (isvoice || cnum != i_voicehandle)) // haleyjd
         {
+            // haleyjd 20150220: [STRIFE] missing sound channel priority check
+            // Is a higher priority sound by same origin already playing?
+            if(!isvoice && sfxinfo->priority > channels[cnum].sfxinfo->priority)
+                return -1;
+
             S_StopChannel(cnum);
             break;
         }
--- a/src/strife/st_stuff.c
+++ b/src/strife/st_stuff.c
@@ -1495,8 +1495,8 @@
 
 void ST_loadData(void)
 {
-    static int dword_8848C = 1; // STRIFE-TODO: what is the purpose of this?
-    dword_8848C = 0;
+//    static int dword_8848C = 1; // STRIFE-TODO: what is the purpose of this?
+//    dword_8848C = 0;
 
     lu_palette = W_GetNumForName (DEH_String("PLAYPAL"));
     ST_loadGraphics();
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -39,7 +39,7 @@
 typedef struct
 {
     // Should be "IWAD" or "PWAD".
-    char		identification[4];		
+    char		identification[4];
     int			numlumps;
     int			infotableofs;
 } PACKEDATTR wadinfo_t;
@@ -57,16 +57,20 @@
 //
 
 // Location of each lump on disk.
-
-lumpinfo_t *lumpinfo;		
+lumpinfo_t *lumpinfo;
 unsigned int numlumps = 0;
 
 // Hash table for fast lookups
-
 static lumpinfo_t **lumphash;
 
-// Hash function used for lump names.
+// Variables for the reload hack: filename of the PWAD to reload, and the
+// lumps from WADs before the reload file, so we can resent numlumps and
+// load the file again.
+static wad_file_t *reloadhandle = NULL;
+static char *reloadname = NULL;
+static int reloadlump = -1;
 
+// Hash function used for lump names.
 unsigned int W_LumpNameHash(const char *s)
 {
     // This is the djb2 string hash function, modded to work on strings
@@ -148,8 +152,26 @@
     filelump_t *filerover;
     int newnumlumps;
 
-    // open the file and add to directory
+    // If the filename begins with a ~, it indicates that we should use the
+    // reload hack.
+    if (filename[0] == '~')
+    {
+        if (reloadname != NULL)
+        {
+            I_Error("Prefixing a WAD filename with '~' indicates that the "
+                    "WAD should be reloaded\n"
+                    "on each level restart, for use by level authors for "
+                    "rapid development. You\n"
+                    "can only reload one WAD file, and it must be the last "
+                    "file in the -file list.");
+        }
 
+        reloadname = strdup(filename);
+        reloadlump = numlumps;
+        ++filename;
+    }
+
+    // Open the file and add to directory
     wad_file = W_OpenFile(filename);
 
     if (wad_file == NULL)
@@ -158,6 +180,13 @@
 	return NULL;
     }
 
+    // If this is the reload file, we need to save the file handle so that we
+    // can close it later on when we do a reload.
+    if (reloadname)
+    {
+        reloadhandle = wad_file;
+    }
+
     newnumlumps = numlumps;
 
     if (strcasecmp(filename+strlen(filename)-3 , "wad" ) )
@@ -539,8 +568,7 @@
 {
     unsigned int i;
 
-    // Free the old hash table, if there is one
-
+    // Free the old hash table, if there is one:
     if (lumphash != NULL)
     {
         Z_Free(lumphash);
@@ -566,6 +594,49 @@
     }
 
     // All done!
+}
+
+// The Doom reload hack. The idea here is that if you give a WAD file to -file
+// prefixed with the ~ hack, that WAD file will be reloaded each time a new
+// level is loaded. This lets you use a level editor in parallel and make
+// incremental changes to the level you're working on without having to restart
+// the game after every change.
+// But: the reload feature is a fragile hack...
+void W_Reload(void)
+{
+    char *filename;
+    int i;
+
+    if (reloadname == NULL)
+    {
+        return;
+    }
+
+    // We must release any lumps being held in the PWAD we're about to reload:
+    for (i = reloadlump; i < numlumps; ++i)
+    {
+        if (lumpinfo[i].cache != NULL)
+        {
+            W_ReleaseLumpNum(i);
+        }
+    }
+
+    // Reset numlumps to remove the reload WAD file:
+    numlumps = reloadlump;
+
+    // Now reload the WAD file.
+    filename = reloadname;
+
+    W_CloseFile(reloadhandle);
+    reloadname = NULL;
+    reloadlump = -1;
+    reloadhandle = NULL;
+    W_AddFile(filename);
+    free(filename);
+
+    // The WAD directory has changed, so we have to regenerate the
+    // fast lookup hashtable:
+    W_GenerateHashTable();
 }
 
 // Lump names that are unique to particular game types. This lets us check
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -56,6 +56,7 @@
 extern unsigned int numlumps;
 
 wad_file_t *W_AddFile (char *filename);
+void    W_Reload (void);
 
 int	W_CheckNumForName (char* name);
 int	W_GetNumForName (char* name);
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -16,12 +16,15 @@
 //	Zone Memory Allocation. Neat.
 //
 
+#include <string.h>
 
-#include "z_zone.h"
-#include "i_system.h"
 #include "doomtype.h"
+#include "i_system.h"
+#include "m_argv.h"
 
+#include "z_zone.h"
 
+
 //
 // ZONE MEMORY ALLOCATION
 //
@@ -61,10 +64,11 @@
 
 
 
-memzone_t*	mainzone;
+static memzone_t *mainzone;
+static boolean zero_on_free;
+static boolean scan_on_free;
 
 
-
 //
 // Z_ClearZone
 //
@@ -110,16 +114,64 @@
     mainzone->blocklist.user = (void *)mainzone;
     mainzone->blocklist.tag = PU_STATIC;
     mainzone->rover = block;
-	
+
     block->prev = block->next = &mainzone->blocklist;
 
     // free block
     block->tag = PU_FREE;
-    
+
     block->size = mainzone->size - sizeof(memzone_t);
+
+    //!
+    // Zone memory debugging flag. If set, memory is zeroed after it is freed
+    // to deliberately break any code that attempts to use it after free.
+    //
+    zero_on_free = M_ParmExists("-zonezero");
+
+    //!
+    // Zone memory debugging flag. If set, each time memory is freed, the zone
+    // heap is scanned to look for remaining pointers to the freed block.
+    //
+    scan_on_free = M_ParmExists("-zonescan");
 }
 
+// Scan the zone heap for pointers within the specified range, and warn about
+// any remaining pointers.
+static void ScanForBlock(void *start, void *end)
+{
+    memblock_t *block;
+    void **mem;
+    int i, len, tag;
 
+    block = mainzone->blocklist.next;
+
+    while (block->next != &mainzone->blocklist)
+    {
+        tag = block->tag;
+
+        if (tag == PU_STATIC || tag == PU_LEVEL || tag == PU_LEVSPEC)
+        {
+            // Scan for pointers on the assumption that pointers are aligned
+            // on word boundaries (word size depending on pointer size):
+            mem = (void **) ((byte *) block + sizeof(memblock_t));
+            len = (block->size - sizeof(memblock_t)) / sizeof(void *);
+
+            for (i = 0; i < len; ++i)
+            {
+                if (start <= mem[i] && mem[i] <= end)
+                {
+                    fprintf(stderr,
+                            "%p has dangling pointer into freed block "
+                            "%p (%p -> %p)\n",
+                            mem, start, &mem[i], mem[i]);
+                }
+            }
+        }
+
+        block = block->next;
+    }
+}
+
 //
 // Z_Free
 //
@@ -127,12 +179,12 @@
 {
     memblock_t*		block;
     memblock_t*		other;
-	
+
     block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
 
     if (block->id != ZONEID)
 	I_Error ("Z_Free: freed a pointer without ZONEID");
-		
+
     if (block->tag != PU_FREE && block->user != NULL)
     {
     	// clear the user's mark
@@ -143,7 +195,19 @@
     block->tag = PU_FREE;
     block->user = NULL;
     block->id = 0;
-	
+
+    // If the -zonezero flag is provided, we zero out the block on free
+    // to break code that depends on reading freed memory.
+    if (zero_on_free)
+    {
+        memset(ptr, 0, block->size - sizeof(memblock_t));
+    }
+    if (scan_on_free)
+    {
+        ScanForBlock(ptr,
+                     (byte *) ptr + block->size - sizeof(memblock_t));
+    }
+
     other = block->prev;
 
     if (other->tag == PU_FREE)
@@ -158,7 +222,7 @@
 
         block = other;
     }
-	
+
     other = block->next;
     if (other->tag == PU_FREE)
     {
@@ -285,7 +349,7 @@
     mainzone->rover = base->next;	
 	
     base->id = ZONEID;
-    
+   
     return result;
 }
 
--- a/textscreen/Makefile.am
+++ b/textscreen/Makefile.am
@@ -1,5 +1,5 @@
 
-AM_CFLAGS = -I$(top_builddir)/src
+AM_CFLAGS = -I$(top_srcdir)/src
 
 CTAGS_ARGS=-I TXT_UNCAST_ARG+
 
--- a/textscreen/examples/Makefile.am
+++ b/textscreen/examples/Makefile.am
@@ -1,5 +1,5 @@
 
-AM_CFLAGS = -I.. -I$(top_builddir)/src
+AM_CFLAGS =  -I$(top_srcdir)/src -I$(top_srcdir)/textscreen
 
 noinst_PROGRAMS=guitest calculator
 
--- a/textscreen/examples/guitest.c
+++ b/textscreen/examples/guitest.c
@@ -96,6 +96,8 @@
     
     window = TXT_NewWindow("Window test");
 
+    TXT_SetWindowHelpURL(window, "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
+
     TXT_AddWidget(window, TXT_NewSeparator("Main section"));
     table = TXT_NewTable(3);
 
--- a/textscreen/txt_desktop.c
+++ b/textscreen/txt_desktop.c
@@ -25,6 +25,7 @@
 #include "txt_separator.h"
 #include "txt_window.h"
 
+#define HELP_KEY KEY_F1
 #define MAXWINDOWS 128
 
 static char *desktop_title;
@@ -188,6 +189,37 @@
     TXT_Puts(title);
 }
 
+static void DrawHelpIndicator(void)
+{
+    char keybuf[10];
+    int fgcolor;
+    int x, y;
+
+    TXT_GetKeyDescription(HELP_KEY, keybuf, sizeof(keybuf));
+
+    TXT_GetMousePosition(&x, &y);
+
+    if (y == 0 && x >= TXT_SCREEN_W - 9)
+    {
+        fgcolor = TXT_COLOR_GREY;
+        TXT_BGColor(TXT_COLOR_BLACK, 0);
+    }
+    else
+    {
+        fgcolor = TXT_COLOR_BLACK;
+        TXT_BGColor(TXT_COLOR_GREY, 0);
+    }
+
+    TXT_GotoXY(TXT_SCREEN_W - 9, 0);
+
+    TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
+    TXT_DrawString(" ");
+    TXT_DrawString(keybuf);
+
+    TXT_FGColor(fgcolor);
+    TXT_DrawString("=Help ");
+}
+
 void TXT_SetDesktopTitle(char *title)
 {
     free(desktop_title);
@@ -197,8 +229,9 @@
 
 void TXT_DrawDesktop(void)
 {
-    int i;
+    txt_window_t *active_window;
     const char *title;
+    int i;
 
     TXT_InitClipArea();
 
@@ -209,6 +242,12 @@
 
     DrawDesktopBackground(title);
 
+    active_window = TXT_GetActiveWindow();
+    if (active_window != NULL && active_window->help_url != NULL)
+    {
+        DrawHelpIndicator();
+    }
+
     for (i=0; i<num_windows; ++i)
     {
         TXT_DrawWindow(all_windows[i]);
@@ -217,17 +256,53 @@
     TXT_UpdateScreen();
 }
 
+// Fallback function to handle key/mouse events that are not handled by
+// the active window.
+static void DesktopInputEvent(int c)
+{
+    txt_window_t *active_window;
+    int x, y;
+
+    switch (c)
+    {
+        case TXT_MOUSE_LEFT:
+            TXT_GetMousePosition(&x, &y);
+
+            // Clicking the top-right of the screen is equivalent
+            // to pressing the help key.
+            if (y == 0 && x >= TXT_SCREEN_W - 9)
+            {
+                DesktopInputEvent(HELP_KEY);
+            }
+            break;
+
+        case HELP_KEY:
+            active_window = TXT_GetActiveWindow();
+            if (active_window != NULL)
+            {
+                TXT_OpenWindowHelpURL(active_window);
+            }
+            break;
+
+        default:
+            break;
+    }
+
+
+}
+
 void TXT_DispatchEvents(void)
 {
+    txt_window_t *active_window;
     int c;
 
     while ((c = TXT_GetChar()) > 0)
     {
-        if (num_windows > 0)
-        {
-            // Send the keypress to the top window
+        active_window = TXT_GetActiveWindow();
 
-            TXT_WindowKeyPress(all_windows[num_windows - 1], c);
+        if (active_window != NULL && !TXT_WindowKeyPress(active_window, c))
+        {
+            DesktopInputEvent(c);
         }
     }
 }
--- a/textscreen/txt_desktop.h
+++ b/textscreen/txt_desktop.h
@@ -31,7 +31,7 @@
 void TXT_DispatchEvents(void);
 void TXT_DrawWindow(txt_window_t *window);
 void TXT_SetWindowFocus(txt_window_t *window, int focused);
-void TXT_WindowKeyPress(txt_window_t *window, int c);
+int TXT_WindowKeyPress(txt_window_t *window, int c);
 
 /**
  * Set the title displayed at the top of the screen.
--- a/textscreen/txt_gui.c
+++ b/textscreen/txt_gui.c
@@ -488,8 +488,8 @@
         cliparea = malloc(sizeof(txt_cliparea_t));
         cliparea->x1 = 0;
         cliparea->x2 = TXT_SCREEN_W;
-        cliparea->y1 = 1;
-        cliparea->y2 = TXT_SCREEN_H - 1;
+        cliparea->y1 = 0;
+        cliparea->y2 = TXT_SCREEN_H;
         cliparea->next = NULL;
     }
 }
--- a/textscreen/txt_io.c
+++ b/textscreen/txt_io.c
@@ -39,8 +39,8 @@
 
         cur_y = TXT_SCREEN_H - 1;
 
-        memcpy(screendata, screendata + TXT_SCREEN_W * 2,
-               TXT_SCREEN_W * 2 * (TXT_SCREEN_H -1));
+        memmove(screendata, screendata + TXT_SCREEN_W * 2,
+                TXT_SCREEN_W * 2 * (TXT_SCREEN_H -1));
 
         // Clear the bottom line
 
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -215,12 +215,12 @@
     {
         font = &large_font;
     }
-#else
-    else if (desktop_info.w >= 1920 && desktop_info.h >= 1080)
-    {
-        font = &large_font;
-    }
 #endif
+    // TODO: Detect high DPI on Linux by inquiring about Gtk+ scale
+    // settings. This looks like it should just be a case of shelling
+    // out to invoke the 'gsettings' command, eg.
+    //   gsettings get org.gnome.desktop.interface text-scaling-factor
+    // and using large_font if the result is >= 2.
     else
     {
         font = &main_font;
--- a/textscreen/txt_window.c
+++ b/textscreen/txt_window.c
@@ -12,6 +12,7 @@
 // GNU General Public License for more details.
 //
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
@@ -70,6 +71,7 @@
     win->vert_align = TXT_VERT_CENTER;
     win->key_listener = NULL;
     win->mouse_listener = NULL;
+    win->help_url = NULL;
 
     TXT_AddWidget(win, TXT_NewSeparator(NULL));
 
@@ -365,7 +367,7 @@
     window->y = y;
 }
 
-static void MouseButtonPress(txt_window_t *window, int b)
+static int MouseButtonPress(txt_window_t *window, int b)
 {
     int x, y;
     int i;
@@ -375,7 +377,7 @@
     // Lay out the window, set positions and sizes of all widgets
 
     TXT_LayoutWindow(window);
-    
+
     // Get the current mouse position
 
     TXT_GetMousePosition(&x, &y);
@@ -390,10 +392,10 @@
         if (window->mouse_listener(window, x, y, b, 
                                    window->mouse_listener_data))
         {
-            return;
+            return 1;
         }
     }
-    
+
     // Is it within the table range?
 
     widgets = (txt_widget_t *) window;
@@ -402,7 +404,7 @@
      && y >= widgets->y && y < (signed) (widgets->y + widgets->h))
     {
         TXT_WidgetMousePress(window, x, y, b);
-        return;
+        return 1;
     }
 
     // Was one of the action area buttons pressed?
@@ -429,21 +431,22 @@
             // Pass through mouse press.
 
             TXT_WidgetMousePress(widget, x, y, b);
-            return;
+            return 1;
         }
     }
+
+    return 0;
 }
 
-void TXT_WindowKeyPress(txt_window_t *window, int c)
+int TXT_WindowKeyPress(txt_window_t *window, int c)
 {
     int i;
 
     // Is this a mouse button ?
-    
+
     if (c >= TXT_MOUSE_BASE && c < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS)
     {
-        MouseButtonPress(window, c);
-        return;
+        return MouseButtonPress(window, c);
     }
 
     // Try the window key spy
@@ -454,15 +457,15 @@
 
         if (window->key_listener(window, c, window->key_listener_data))
         {
-            return;
+            return 1;
         }
     }
 
-    // Send to the currently selected widget 
+    // Send to the currently selected widget:
 
     if (TXT_WidgetKeyPress(window, c))
     {
-        return;
+        return 1;
     }
 
     // Try all of the action buttons
@@ -472,9 +475,11 @@
         if (window->actions[i] != NULL
          && TXT_WidgetKeyPress(window->actions[i], c))
         {
-            return;
+            return 1;
         }
     }
+
+    return 0;
 }
 
 void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener, 
@@ -495,6 +500,48 @@
 void TXT_SetWindowFocus(txt_window_t *window, int focused)
 {
     TXT_SetWidgetFocus(window, focused);
+}
+
+void TXT_SetWindowHelpURL(txt_window_t *window, char *help_url)
+{
+    window->help_url = help_url;
+}
+
+void TXT_OpenURL(char *url)
+{
+    char *cmd;
+    size_t cmd_len;
+
+    cmd_len = strlen(url) + 30;
+    cmd = malloc(cmd_len);
+
+#if defined(_WIN32)
+    TXT_snprintf(cmd, cmd_len, "cmd /c start \"%s\"", url);
+#elif defined(__MACOSX__)
+    TXT_snprintf(cmd, cmd_len, "open \"%s\"", url);
+#else
+    // The Unix situation sucks as usual, but the closest thing to a
+    // standard that exists is the xdg-utils package.
+    if (system("xdg-open --version 2>/dev/null") != 0)
+    {
+        fprintf(stderr,
+                "xdg-utils is not installed. Can't open this URL:\n%s\n", url);
+        return;
+    }
+
+    TXT_snprintf(cmd, cmd_len, "xdg-open \"%s\"", url);
+#endif
+
+    system(cmd);
+    free(cmd);
+}
+
+void TXT_OpenWindowHelpURL(txt_window_t *window)
+{
+    if (window->help_url != NULL)
+    {
+        TXT_OpenURL(window->help_url);
+    }
 }
 
 txt_window_t *TXT_MessageBox(char *title, char *message, ...)
--- a/textscreen/txt_window.h
+++ b/textscreen/txt_window.h
@@ -85,6 +85,10 @@
 
     int window_x, window_y;
     unsigned int window_w, window_h;
+
+    // URL of a webpage with help about this window. If set, a help key
+    // indicator is shown while this window is active.
+    char *help_url;
 };
 
 /**
@@ -193,6 +197,24 @@
  */
 
 txt_window_t *TXT_MessageBox(char *title, char *message, ...);
+
+/**
+ * Set the help URL for the given window.
+ *
+ * @param window          The window.
+ * @param help_url        String containing URL of the help page for this
+ *                        window, or NULL to set no help for this window.
+ */
+
+void TXT_SetWindowHelpURL(txt_window_t *window, char *help_url);
+
+/**
+ * Open the help URL for the given window, if one is set.
+ *
+ * @param window          The window.
+ */
+
+void TXT_OpenWindowHelpURL(txt_window_t *window);
 
 #endif /* #ifndef TXT_WINDOW_H */
 
--- a/textscreen/txt_window_action.c
+++ b/textscreen/txt_window_action.c
@@ -14,6 +14,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "doomkeys.h"